{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "extends": "none",
  "name": "command-menu",
  "title": "command-menu",
  "description": "command-menu",
  "dependencies": [
    "@heroicons/react",
    "react-aria-components",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "https://intentui.com/r/primitive",
    "https://intentui.com/r/dropdown",
    "https://intentui.com/r/loader",
    "https://intentui.com/r/menu"
  ],
  "files": [
    {
      "path": "src/components/ui/command-menu.tsx",
      "content": "'use client'\n\nimport { MagnifyingGlassIcon } from '@heroicons/react/20/solid'\nimport { createContext, use, useEffect } from 'react'\nimport { Autocomplete, type AutocompleteProps, useFilter } from 'react-aria-components/Autocomplete'\nimport { Button } from 'react-aria-components/Button'\nimport { Collection } from 'react-aria-components/Collection'\nimport {\n  type CollectionRenderer,\n  CollectionRendererContext,\n  DefaultCollectionRenderer,\n} from 'react-aria-components/CollectionBuilder'\nimport { Dialog, OverlayTriggerStateContext } from 'react-aria-components/Dialog'\nimport { Header } from 'react-aria-components/Header'\nimport { Input } from 'react-aria-components/Input'\nimport type { MenuProps, MenuTriggerProps } from 'react-aria-components/Menu'\nimport { Menu as MenuPrimitive, MenuSection } from 'react-aria-components/Menu'\nimport type { ModalOverlayProps } from 'react-aria-components/Modal'\nimport { Modal, ModalContext, ModalOverlay } from 'react-aria-components/Modal'\nimport { SearchField, type SearchFieldProps } from 'react-aria-components/SearchField'\nimport { twMerge } from 'tailwind-merge'\nimport { cx } from '@/lib/primitive'\nimport { DropdownKeyboard } from './dropdown'\nimport { Loader } from './loader'\nimport { MenuDescription, MenuItem, MenuLabel, type MenuSectionProps, MenuSeparator } from './menu'\n\ninterface CommandMenuProviderProps {\n  isPending?: boolean\n  escapeButton?: boolean\n}\n\nconst CommandMenuContext = createContext<CommandMenuProviderProps | undefined>(undefined)\n\nconst useCommandMenu = () => {\n  const context = use(CommandMenuContext)\n\n  if (!context) {\n    throw new Error('useCommandMenu must be used within a <CommandMenuProvider />')\n  }\n\n  return context\n}\n\nconst sizes = {\n  xs: 'sm:max-w-xs',\n  sm: 'sm:max-w-sm',\n  md: 'sm:max-w-md',\n  lg: 'sm:max-w-lg',\n  xl: 'sm:max-w-xl',\n  '2xl': 'sm:max-w-2xl',\n  '3xl': 'sm:max-w-3xl',\n}\n\ninterface CommandMenuProps extends AutocompleteProps, MenuTriggerProps, CommandMenuProviderProps {\n  isDismissable?: boolean\n  'aria-label'?: string\n  shortcut?: string\n  className?: string\n  size?: keyof typeof sizes\n  overlay?: Pick<ModalOverlayProps, 'className'>\n}\n\nconst CommandMenu = ({\n  onOpenChange,\n  className,\n  isDismissable = true,\n  escapeButton = true,\n  isPending,\n  overlay,\n  size = 'lg',\n  shortcut,\n  ...props\n}: CommandMenuProps) => {\n  const { contains } = useFilter({ sensitivity: 'base' })\n  const filter = (textValue: string, inputValue: string) => contains(textValue, inputValue)\n  useEffect(() => {\n    if (!shortcut) return\n\n    const onKeyDown = (e: KeyboardEvent) => {\n      if (e.key === shortcut && (e.metaKey || e.ctrlKey)) {\n        onOpenChange?.(true)\n      }\n    }\n\n    document.addEventListener('keydown', onKeyDown)\n    return () => document.removeEventListener('keydown', onKeyDown)\n  }, [shortcut, onOpenChange])\n  return (\n    <CommandMenuContext value={{ isPending: isPending, escapeButton: escapeButton }}>\n      <ModalContext value={{ isOpen: props.isOpen, onOpenChange: onOpenChange }}>\n        <ModalOverlay\n          {...props}\n          isDismissable={isDismissable}\n          className={cx(\n            'fixed inset-0 z-50 h-(--visual-viewport-height,100vh) w-screen overflow-hidden bg-black/15',\n            'grid grid-rows-[1fr_auto] justify-items-center text-center sm:grid-rows-[1fr_auto_3fr]',\n            'entering:fade-in entering:animate-in entering:duration-300 entering:ease-out',\n            'exiting:fade-out exiting:animate-out exiting:ease-in',\n            overlay?.className\n          )}\n        >\n          <Modal\n            className={cx(\n              'row-start-2 bg-overlay text-start text-overlay-fg shadow-lg outline-none ring ring-muted-fg/15 md:row-start-1 dark:ring-border',\n              'max-h-[calc(var(--visual-viewport-height)*0.8)] w-full sm:fixed sm:top-[10%] sm:left-1/2 sm:-translate-x-1/2',\n              'rounded-t-2xl md:rounded-xl',\n              sizes[size],\n              'entering:slide-in-from-bottom sm:entering:zoom-in-95 sm:entering:slide-in-from-bottom-0 entering:animate-in entering:duration-300 entering:ease-out',\n              'exiting:slide-out-to-bottom sm:exiting:zoom-out-95 sm:exiting:slide-out-to-bottom-0 exiting:animate-out exiting:ease-in',\n              className\n            )}\n          >\n            <Dialog\n              aria-label={props['aria-label'] ?? 'Command Menu'}\n              className=\"flex max-h-[inherit] flex-col overflow-hidden outline-hidden\"\n            >\n              <Autocomplete filter={filter} {...props} />\n            </Dialog>\n          </Modal>\n        </ModalOverlay>\n      </ModalContext>\n    </CommandMenuContext>\n  )\n}\n\ninterface CommandMenuSearchProps extends SearchFieldProps {\n  placeholder?: string\n  className?: string\n}\n\nconst CommandMenuSearch = ({ className, placeholder, ...props }: CommandMenuSearchProps) => {\n  const state = use(OverlayTriggerStateContext)!\n  const { isPending, escapeButton } = useCommandMenu()\n  return (\n    <SearchField\n      aria-label=\"Quick search\"\n      autoFocus\n      className={cx('flex w-full items-center px-2.5 py-1', className)}\n      {...props}\n    >\n      {isPending ? (\n        <Loader className=\"size-4.5\" variant=\"spin\" />\n      ) : (\n        <MagnifyingGlassIcon\n          data-slot=\"command-menu-search-icon\"\n          className=\"size-5 shrink-0 text-muted-fg\"\n        />\n      )}\n      <Input\n        placeholder={placeholder ?? 'Search...'}\n        className=\"w-full min-w-0 bg-transparent px-2.5 py-2 text-base text-fg placeholder-muted-fg outline-hidden focus:outline-hidden sm:px-2 sm:py-1.5 sm:text-sm [&::-ms-reveal]:hidden [&::-webkit-search-cancel-button]:hidden\"\n      />\n      {escapeButton && (\n        <Button\n          onPress={() => state?.close()}\n          className=\"hidden cursor-default rounded border text-current/90 hover:bg-muted lg:inline lg:px-1.5 lg:py-0.5 lg:text-xs\"\n        >\n          Esc\n        </Button>\n      )}\n    </SearchField>\n  )\n}\n\nconst CommandMenuList = <T extends object>({ className, ...props }: MenuProps<T>) => {\n  return (\n    <CollectionRendererContext.Provider value={renderer}>\n      <MenuPrimitive\n        className={cx(\n          'grid max-h-full flex-1 grid-cols-[auto_1fr] content-start overflow-y-auto border-t p-2 sm:max-h-110 *:[[role=group]]:mb-6 *:[[role=group]]:last:mb-0',\n          className\n        )}\n        {...props}\n      />\n    </CollectionRendererContext.Provider>\n  )\n}\n\nconst CommandMenuSection = <T extends object>({\n  className,\n  ref,\n  ...props\n}: MenuSectionProps<T>) => {\n  return (\n    <MenuSection\n      ref={ref}\n      className={twMerge(\n        'col-span-full grid grid-cols-[auto_1fr] content-start gap-y-0.25',\n        className\n      )}\n      {...props}\n    >\n      {'label' in props && (\n        <Header className=\"col-span-full mb-1 block min-w-(--trigger-width) truncate px-2.5 text-muted-fg text-xs\">\n          {props.label}\n        </Header>\n      )}\n      <Collection items={props.items}>{props.children}</Collection>\n    </MenuSection>\n  )\n}\n\nconst CommandMenuItem = ({ className, ...props }: React.ComponentProps<typeof MenuItem>) => {\n  const textValue =\n    props.textValue || (typeof props.children === 'string' ? props.children : undefined)\n  return (\n    <MenuItem\n      {...props}\n      textValue={textValue}\n      className={cx('items-center gap-y-0.5', className)}\n    />\n  )\n}\n\ninterface CommandMenuDescriptionProps extends React.ComponentProps<typeof MenuDescription> {}\n\nconst CommandMenuDescription = ({ className, ...props }: CommandMenuDescriptionProps) => {\n  return (\n    <MenuDescription className={twMerge('col-start-3 row-start-1 ms-auto', className)} {...props} />\n  )\n}\n\nconst renderer: CollectionRenderer = {\n  CollectionRoot(props) {\n    if (props.collection.size === 0) {\n      return (\n        <div className=\"col-span-full p-4 text-center text-muted-fg text-sm\">No results found.</div>\n      )\n    }\n    return <DefaultCollectionRenderer.CollectionRoot {...props} />\n  },\n  CollectionBranch: DefaultCollectionRenderer.CollectionBranch,\n}\n\nconst CommandMenuSeparator = ({\n  className,\n  ...props\n}: React.ComponentProps<typeof MenuSeparator>) => (\n  <MenuSeparator className={twMerge('-mx-2', className)} {...props} />\n)\n\nconst CommandMenuFooter = ({ className, ...props }: React.ComponentProps<'div'>) => {\n  return (\n    <div\n      className={twMerge(\n        'col-span-full flex-none border-t px-2 py-1.5 text-muted-fg text-sm',\n        '*:[kbd]:inset-ring *:[kbd]:inset-ring-fg/10 *:[kbd]:mx-1 *:[kbd]:inline-grid *:[kbd]:h-4 *:[kbd]:min-w-4 *:[kbd]:place-content-center *:[kbd]:rounded-xs *:[kbd]:bg-secondary',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nconst CommandMenuLabel = MenuLabel\nconst CommandMenuShortcut = ({\n  className,\n  ...props\n}: React.ComponentProps<typeof DropdownKeyboard>) => (\n  <DropdownKeyboard\n    className={twMerge(\n      'gap-0.5 font-sans text-[10.5px] uppercase *:inset-ring *:inset-ring-muted-fg/20 *:grid *:size-5.5 *:place-content-center *:rounded-xs *:bg-bg',\n      className\n    )}\n    {...props}\n  />\n)\n\nexport type { CommandMenuDescriptionProps, CommandMenuProps, CommandMenuSearchProps }\nexport {\n  CommandMenu,\n  CommandMenuDescription,\n  CommandMenuFooter,\n  CommandMenuItem,\n  CommandMenuLabel,\n  CommandMenuList,\n  CommandMenuSearch,\n  CommandMenuSection,\n  CommandMenuSeparator,\n  CommandMenuShortcut,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}