{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"command","type":"registry:ui","title":"Command","description":"Command from react-fancy","package":"react-fancy","dependencies":["lucide-react"],"registryDependencies":["portal"],"files":[{"path":"components\/fancy\/command\/Command.context.ts","content":"import { createContext, useContext } from \"react\";\r\nimport type { CommandContextValue } from \".\/Command.types\";\r\n\r\nexport const CommandContext = createContext<CommandContextValue | null>(null);\r\n\r\nexport function useCommand(): CommandContextValue {\r\n  const ctx = useContext(CommandContext);\r\n  if (!ctx) {\r\n    throw new Error(\r\n      \"Command compound components must be used within <Command>\",\r\n    );\r\n  }\r\n  return ctx;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/command\/Command.context.ts"},{"path":"components\/fancy\/command\/Command.tsx","content":"import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { Portal } from \"..\/Portal\";\r\nimport { CommandContext } from \".\/Command.context\";\r\nimport { CommandInput } from \".\/CommandInput\";\r\nimport { CommandList } from \".\/CommandList\";\r\nimport { CommandItem } from \".\/CommandItem\";\r\nimport { CommandGroup } from \".\/CommandGroup\";\r\nimport { CommandEmpty } from \".\/CommandEmpty\";\r\nimport { useFocusTrap } from \"..\/..\/hooks\/use-focus-trap\";\r\nimport { useEscapeKey } from \"..\/..\/hooks\/use-escape-key\";\r\nimport { useAnimation } from \"..\/..\/hooks\/use-animation\";\r\nimport type { CommandProps } from \".\/Command.types\";\r\n\r\nfunction CommandRoot({ children, open, onClose, className }: CommandProps) {\r\n  const [query, setQuery] = useState(\"\");\r\n  const [activeIndex, setActiveIndex] = useState(-1);\r\n  const panelRef = useRef<HTMLDivElement>(null);\r\n\r\n  const close = useCallback(() => {\r\n    onClose();\r\n    setQuery(\"\");\r\n    setActiveIndex(-1);\r\n  }, [onClose]);\r\n\r\n  useEscapeKey(close, open);\r\n  useFocusTrap(panelRef, open);\r\n\r\n  \/\/ Cmd+K global shortcut is handled by the consumer\r\n  useEffect(() => {\r\n    if (open) {\r\n      const original = document.body.style.overflow;\r\n      document.body.style.overflow = \"hidden\";\r\n      return () => {\r\n        document.body.style.overflow = original;\r\n      };\r\n    }\r\n  }, [open]);\r\n\r\n  \/\/ Keyboard navigation\r\n  useEffect(() => {\r\n    if (!open) return;\r\n\r\n    const handleKeyDown = (e: KeyboardEvent) => {\r\n      const items = panelRef.current?.querySelectorAll<HTMLElement>(\r\n        '[role=\"option\"]',\r\n      );\r\n      if (!items?.length) return;\r\n\r\n      if (e.key === \"ArrowDown\") {\r\n        e.preventDefault();\r\n        const next = activeIndex < items.length - 1 ? activeIndex + 1 : 0;\r\n        setActiveIndex(next);\r\n        items[next]?.focus();\r\n      } else if (e.key === \"ArrowUp\") {\r\n        e.preventDefault();\r\n        const prev = activeIndex > 0 ? activeIndex - 1 : items.length - 1;\r\n        setActiveIndex(prev);\r\n        items[prev]?.focus();\r\n      }\r\n    };\r\n\r\n    document.addEventListener(\"keydown\", handleKeyDown);\r\n    return () => document.removeEventListener(\"keydown\", handleKeyDown);\r\n  }, [open, activeIndex]);\r\n\r\n  const { mounted, className: animClass, ref: animRef } = useAnimation({\r\n    open,\r\n    enterClass: \"fancy-slide-up\",\r\n    exitClass: \"fancy-fade-out\",\r\n  });\r\n\r\n  const ctx = useMemo(\r\n    () => ({ open, close, query, setQuery, activeIndex, setActiveIndex }),\r\n    [open, close, query, activeIndex],\r\n  );\r\n\r\n  if (!mounted) return null;\r\n\r\n  return (\r\n    <CommandContext.Provider value={ctx}>\r\n      <Portal>\r\n        <div className=\"fixed inset-0 z-50 flex items-start justify-center pt-[20vh]\">\r\n          <div\r\n            className=\"absolute inset-0 bg-black\/50 backdrop-blur-sm\"\r\n            onClick={close}\r\n            aria-hidden=\"true\"\r\n          \/>\r\n          <div\r\n            ref={(node) => {\r\n              panelRef.current = node;\r\n              (animRef as React.MutableRefObject<HTMLElement | null>).current =\r\n                node;\r\n            }}\r\n            data-react-fancy-command=\"\"\r\n            className={cn(\r\n              \"relative w-full max-w-lg overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-2xl dark:border-zinc-700 dark:bg-zinc-900\",\r\n              animClass,\r\n              className,\r\n            )}\r\n          >\r\n            {children}\r\n          <\/div>\r\n        <\/div>\r\n      <\/Portal>\r\n    <\/CommandContext.Provider>\r\n  );\r\n}\r\n\r\nexport const Command = Object.assign(CommandRoot, {\r\n  Input: CommandInput,\r\n  List: CommandList,\r\n  Item: CommandItem,\r\n  Group: CommandGroup,\r\n  Empty: CommandEmpty,\r\n});\r\n","type":"registry:ui","target":"components\/fancy\/command\/Command.tsx"},{"path":"components\/fancy\/command\/Command.types.ts","content":"import type { ReactNode } from \"react\";\r\n\r\nexport interface CommandContextValue {\r\n  open: boolean;\r\n  close: () => void;\r\n  query: string;\r\n  setQuery: (query: string) => void;\r\n  activeIndex: number;\r\n  setActiveIndex: (index: number) => void;\r\n}\r\n\r\nexport interface CommandProps {\r\n  children: ReactNode;\r\n  open: boolean;\r\n  onClose: () => void;\r\n  className?: string;\r\n}\r\n\r\nexport interface CommandInputProps {\r\n  placeholder?: string;\r\n  className?: string;\r\n}\r\n\r\nexport interface CommandListProps {\r\n  children: ReactNode;\r\n  className?: string;\r\n}\r\n\r\nexport interface CommandItemProps {\r\n  children: ReactNode;\r\n  value?: string;\r\n  onSelect?: () => void;\r\n  className?: string;\r\n}\r\n\r\nexport interface CommandGroupProps {\r\n  children: ReactNode;\r\n  heading?: string;\r\n  className?: string;\r\n}\r\n\r\nexport interface CommandEmptyProps {\r\n  children?: ReactNode;\r\n  className?: string;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/command\/Command.types.ts"},{"path":"components\/fancy\/command\/CommandEmpty.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport type { CommandEmptyProps } from \".\/Command.types\";\r\n\r\nexport function CommandEmpty({\r\n  children = \"No results found.\",\r\n  className,\r\n}: CommandEmptyProps) {\r\n  return (\r\n    <div\r\n      data-react-fancy-command-empty=\"\"\r\n      className={cn(\r\n        \"py-6 text-center text-sm text-zinc-500 dark:text-zinc-400\",\r\n        className,\r\n      )}\r\n    >\r\n      {children}\r\n    <\/div>\r\n  );\r\n}\r\n\r\nCommandEmpty.displayName = \"CommandEmpty\";\r\n","type":"registry:ui","target":"components\/fancy\/command\/CommandEmpty.tsx"},{"path":"components\/fancy\/command\/CommandGroup.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport type { CommandGroupProps } from \".\/Command.types\";\r\n\r\nexport function CommandGroup({\r\n  children,\r\n  heading,\r\n  className,\r\n}: CommandGroupProps) {\r\n  return (\r\n    <div data-react-fancy-command-group=\"\" role=\"group\" className={cn(\"py-1\", className)}>\r\n      {heading && (\r\n        <div className=\"px-3 py-1.5 text-xs font-medium text-zinc-400\">\r\n          {heading}\r\n        <\/div>\r\n      )}\r\n      {children}\r\n    <\/div>\r\n  );\r\n}\r\n\r\nCommandGroup.displayName = \"CommandGroup\";\r\n","type":"registry:ui","target":"components\/fancy\/command\/CommandGroup.tsx"},{"path":"components\/fancy\/command\/CommandInput.tsx","content":"import { Search } from \"lucide-react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { useCommand } from \".\/Command.context\";\r\nimport type { CommandInputProps } from \".\/Command.types\";\r\n\r\nexport function CommandInput({\r\n  placeholder = \"Type a command or search...\",\r\n  className,\r\n}: CommandInputProps) {\r\n  const { query, setQuery } = useCommand();\r\n\r\n  return (\r\n    <div data-react-fancy-command-input=\"\" className=\"flex items-center border-b border-zinc-200 px-4 dark:border-zinc-700\">\r\n      <Search size={16} className=\"shrink-0 text-zinc-400\" \/>\r\n      <input\r\n        type=\"text\"\r\n        value={query}\r\n        onChange={(e) => setQuery(e.target.value)}\r\n        placeholder={placeholder}\r\n        className={cn(\r\n          \"flex-1 bg-transparent px-3 py-3 text-sm outline-none placeholder:text-zinc-400\",\r\n          className,\r\n        )}\r\n        autoFocus\r\n      \/>\r\n    <\/div>\r\n  );\r\n}\r\n\r\nCommandInput.displayName = \"CommandInput\";\r\n","type":"registry:ui","target":"components\/fancy\/command\/CommandInput.tsx"},{"path":"components\/fancy\/command\/CommandItem.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport { useCommand } from \".\/Command.context\";\r\nimport type { CommandItemProps } from \".\/Command.types\";\r\n\r\nexport function CommandItem({\r\n  children,\r\n  value,\r\n  onSelect,\r\n  className,\r\n}: CommandItemProps) {\r\n  const { query, close } = useCommand();\r\n\r\n  \/\/ Filter by query\r\n  const text = value ?? (typeof children === \"string\" ? children : \"\");\r\n  if (query && !text.toLowerCase().includes(query.toLowerCase())) {\r\n    return null;\r\n  }\r\n\r\n  return (\r\n    <button\r\n      data-react-fancy-command-item=\"\"\r\n      type=\"button\"\r\n      role=\"option\"\r\n      className={cn(\r\n        \"flex w-full items-center rounded-lg px-3 py-2 text-left text-sm transition-colors\",\r\n        \"text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800\",\r\n        className,\r\n      )}\r\n      onClick={() => {\r\n        onSelect?.();\r\n        close();\r\n      }}\r\n    >\r\n      {children}\r\n    <\/button>\r\n  );\r\n}\r\n\r\nCommandItem.displayName = \"CommandItem\";\r\n","type":"registry:ui","target":"components\/fancy\/command\/CommandItem.tsx"},{"path":"components\/fancy\/command\/CommandList.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport type { CommandListProps } from \".\/Command.types\";\r\n\r\nexport function CommandList({ children, className }: CommandListProps) {\r\n  return (\r\n    <div\r\n      data-react-fancy-command-list=\"\"\r\n      role=\"listbox\"\r\n      className={cn(\"max-h-72 overflow-y-auto p-2\", className)}\r\n    >\r\n      {children}\r\n    <\/div>\r\n  );\r\n}\r\n\r\nCommandList.displayName = \"CommandList\";\r\n","type":"registry:ui","target":"components\/fancy\/command\/CommandList.tsx"},{"path":"components\/fancy\/command\/index.ts","content":"export { Command } from \".\/Command\";\r\nexport { useCommand } from \".\/Command.context\";\r\nexport type {\r\n  CommandProps,\r\n  CommandInputProps,\r\n  CommandListProps,\r\n  CommandItemProps,\r\n  CommandGroupProps,\r\n  CommandEmptyProps,\r\n  CommandContextValue,\r\n} from \".\/Command.types\";\r\n","type":"registry:ui","target":"components\/fancy\/command\/index.ts"}]}