{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command",
  "title": "Command",
  "author": "AlgorizeTech",
  "description": "A command palette with fuzzy search, grouped results and a dialog mode. Use it for the ⌘K quick-action menu in an application.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/custom/blocks/CommandBlock.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Search } from \"lucide-react\";\nimport React, {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useRef,\n  useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\n// ==========================================\n// 1. CONTEXT\n// ==========================================\ninterface CommandContextType {\n  /** When false the caller owns filtering and every item stays visible. */\n  shouldFilter: boolean;\n  search: string;\n  setSearch: (search: string) => void;\n  /**\n   * The command root node itself, held in state rather than a ref. A ref shared\n   * through context makes every read of this context a ref read during render.\n   */\n  command: HTMLDivElement | null;\n}\n\nconst CommandContext = createContext<CommandContextType | undefined>(undefined);\n\nfunction useCommand() {\n  const context = useContext(CommandContext);\n  if (!context)\n    throw new Error(\"Command components must be used within a <Command> root.\");\n  return context;\n}\n\n// ==========================================\n// 2. ROOT COMPONENT\n// ==========================================\nexport interface CommandProps extends React.HTMLAttributes<HTMLDivElement> {\n  shouldFilter?: boolean;\n}\n\nexport function Command({\n  className,\n  shouldFilter = true,\n  children,\n  ...props\n}: CommandProps) {\n  const [search, setSearch] = useState(\"\");\n  const [command, setCommand] = useState<HTMLDivElement | null>(null);\n\n  // High-performance DOM-based keyboard navigation\n  useEffect(() => {\n    const handleKeyDown = (e: KeyboardEvent) => {\n      const node = command;\n      if (!node) return;\n\n      const items = Array.from(\n        node.querySelectorAll('[cmdk-item=\"true\"]:not([hidden])'),\n      ) as HTMLElement[];\n      if (!items.length) return;\n\n      const currentIndex = items.findIndex(\n        (item) => item.getAttribute(\"data-selected\") === \"true\",\n      );\n\n      if (e.key === \"ArrowDown\") {\n        e.preventDefault();\n        const nextIndex =\n          currentIndex + 1 < items.length ? currentIndex + 1 : 0;\n        items.forEach((i) => i.removeAttribute(\"data-selected\"));\n        items[nextIndex].setAttribute(\"data-selected\", \"true\");\n        items[nextIndex].scrollIntoView({ block: \"nearest\" });\n      } else if (e.key === \"ArrowUp\") {\n        e.preventDefault();\n        const nextIndex =\n          currentIndex - 1 >= 0 ? currentIndex - 1 : items.length - 1;\n        items.forEach((i) => i.removeAttribute(\"data-selected\"));\n        items[nextIndex].setAttribute(\"data-selected\", \"true\");\n        items[nextIndex].scrollIntoView({ block: \"nearest\" });\n      } else if (e.key === \"Enter\") {\n        e.preventDefault();\n        if (currentIndex !== -1) items[currentIndex].click();\n      }\n    };\n\n    command?.addEventListener(\"keydown\", handleKeyDown);\n    return () => command?.removeEventListener(\"keydown\", handleKeyDown);\n  }, [command]);\n\n  // Auto-select the first visible item when search changes\n  useEffect(() => {\n    const timer = setTimeout(() => {\n      const node = command;\n      if (!node) return;\n      const items = Array.from(\n        node.querySelectorAll('[cmdk-item=\"true\"]:not([hidden])'),\n      ) as HTMLElement[];\n      items.forEach((i) => i.removeAttribute(\"data-selected\"));\n      if (items.length > 0) items[0].setAttribute(\"data-selected\", \"true\");\n    }, 0);\n    return () => clearTimeout(timer);\n  }, [search, command]);\n\n  return (\n    <CommandContext.Provider value={{ search, setSearch, command, shouldFilter }}>\n      <div\n        ref={setCommand}\n        cmdk-root=\"true\"\n        className={cn(\n          \"flex h-full w-full flex-col overflow-hidden rounded-xl bg-popover text-popover-foreground border border-border shadow-sm\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </div>\n    </CommandContext.Provider>\n  );\n}\n\n// ==========================================\n// 3. DIALOG WRAPPER\n// ==========================================\nexport interface CommandDialogProps extends CommandProps {\n  open: boolean;\n  onOpenChange: (open: boolean) => void;\n}\n\nexport function CommandDialog({\n  open,\n  onOpenChange,\n  children,\n  className,\n  ...props\n}: CommandDialogProps) {\n  const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null);\n\n  // Resolves the document this dialog actually lives in, which is not always\n  // the global one — previews portal components into an iframe. Resolving in a\n  // callback ref rather than reading a ref during render keeps render pure, and\n  // a null target doubles as the \"not mounted yet\" signal that guards SSR.\n  const setAnchor = useCallback((node: HTMLSpanElement | null) => {\n    setPortalTarget(node ? node.ownerDocument.body : null);\n  }, []);\n\n  useEffect(() => {\n    const doc = portalTarget?.ownerDocument ?? document;\n    const handleEscape = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") onOpenChange(false);\n    };\n    if (open) doc.addEventListener(\"keydown\", handleEscape);\n    return () => doc.removeEventListener(\"keydown\", handleEscape);\n  }, [open, onOpenChange, portalTarget]);\n\n  if (!portalTarget || !open) return <span ref={setAnchor} hidden />;\n\n  return (\n    <>\n      <span ref={setAnchor} hidden />\n      {createPortal(\n        <div className=\"fixed inset-0 z-50 flex items-start justify-center pt-[15vh] sm:pt-[20vh] bg-zinc-950/50 dark:bg-zinc-950/80 backdrop-blur-sm\">\n          <div\n            className=\"fixed inset-0 z-40\"\n            onClick={() => onOpenChange(false)}\n            aria-hidden=\"true\"\n          />\n          <div className=\"z-50 w-full max-w-xl animate-in fade-in zoom-in-95 slide-in-from-top-[10%] duration-200 px-4 sm:px-0\">\n            <Command\n              className={cn(\n                \"shadow-2xl h-auto border-none ring-1 ring-border\",\n                className,\n              )}\n              {...props}\n            >\n              {children}\n            </Command>\n          </div>\n        </div>,\n        portalTarget,\n      )}\n    </>\n  );\n}\n\n// ==========================================\n// 4. SUB-COMPONENTS\n// ==========================================\nexport function CommandInput({\n  className,\n  ...props\n}: React.InputHTMLAttributes<HTMLInputElement>) {\n  const { search, setSearch } = useCommand();\n\n  return (\n    <div\n      className=\"flex items-center border-b border-border px-3\"\n      cmdk-input-wrapper=\"\"\n    >\n      <Search className=\"mr-2 h-4 w-4 shrink-0 text-muted-foreground\" />\n      <input\n        autoFocus\n        value={search}\n        onChange={(e) => setSearch(e.target.value)}\n        className={cn(\n          \"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n          className,\n        )}\n        {...props}\n      />\n    </div>\n  );\n}\n\nexport function CommandList({\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n  return (\n    <div\n      className={cn(\n        \"max-h-[300px] overflow-y-auto overflow-x-hidden p-1\",\n        className,\n      )}\n      cmdk-list=\"true\"\n      role=\"listbox\"\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport function CommandEmpty({\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n  const { search, command } = useCommand();\n  const [hasResults, setHasResults] = useState(true);\n\n  useEffect(() => {\n    // Slight delay to allow items to apply their hidden attributes based on search\n    const timer = setTimeout(() => {\n      if (!command) return;\n      const visibleItems = command.querySelectorAll(\n        '[cmdk-item=\"true\"]:not([hidden])',\n      );\n      setHasResults(visibleItems.length > 0);\n    }, 10);\n    return () => clearTimeout(timer);\n  }, [search, command]);\n\n  if (hasResults) return null;\n\n  return (\n    <div\n      className={cn(\"py-6 text-center text-sm text-muted-foreground\", className)}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport function CommandGroup({\n  heading,\n  className,\n  children,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement> & { heading?: string }) {\n  return (\n    <div\n      cmdk-group=\"true\"\n      className={cn(\n        \"overflow-hidden p-1 text-foreground\",\n        // Magic CSS: Hide group if it contains no visible items\n        \"hidden [&:has([cmdk-item=true]:not([hidden]))]:block\",\n        className,\n      )}\n      {...props}\n    >\n      {heading && (\n        <div className=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n          {heading}\n        </div>\n      )}\n      {children}\n    </div>\n  );\n}\n\nexport function CommandSeparator({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n  return (\n    <div\n      className={cn(\"-mx-1 h-px bg-muted\", className)}\n      {...props}\n    />\n  );\n}\n\nexport interface CommandItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onSelect\"> {\n  value?: string;\n  onSelect?: (value: string) => void;\n}\n\n/**\n * Flattens a node tree to its text. Filtering used to read\n * `itemRef.current.textContent` during render, which is empty on the first pass\n * — an item could not match a search until something re-rendered it.\n */\nfunction textFromChildren(node: React.ReactNode): string {\n  if (node === null || node === undefined || typeof node === \"boolean\") return \"\";\n  if (typeof node === \"string\" || typeof node === \"number\") return String(node);\n  if (Array.isArray(node)) return node.map(textFromChildren).join(\"\");\n  if (React.isValidElement(node)) {\n    return textFromChildren(\n      (node.props as { children?: React.ReactNode }).children,\n    );\n  }\n  return \"\";\n}\n\nexport function CommandItem({\n  className,\n  value,\n  onSelect,\n  children,\n  ...props\n}: CommandItemProps) {\n  const { search, command, shouldFilter } = useCommand();\n  const itemRef = useRef<HTMLDivElement>(null);\n\n  // Extract text content for fuzzy matching if no explicit value is provided\n  const textValue = value || textFromChildren(children);\n  // With `shouldFilter={false}` the caller owns the list and every item\n  // stays visible, however the query reads.\n  const isMatch =\n    !shouldFilter ||\n    !search ||\n    textValue.toLowerCase().includes(search.toLowerCase());\n\n  const handleSelect = () => {\n    if (onSelect) onSelect(textValue);\n  };\n\n  const handleMouseEnter = () => {\n    if (!command) return;\n    const items = command.querySelectorAll('[cmdk-item=\"true\"]');\n    items.forEach((i) => i.removeAttribute(\"data-selected\"));\n    itemRef.current?.setAttribute(\"data-selected\", \"true\");\n  };\n\n  return (\n    <div\n      ref={itemRef}\n      cmdk-item=\"true\"\n      hidden={!isMatch}\n      onClick={handleSelect}\n      onMouseEnter={handleMouseEnter}\n      className={cn(\n        \"group/cmd-item relative flex cursor-pointer select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-colors\",\n        \"hover:bg-primary/10 hover:text-primary dark:hover:bg-primary/20\",\n        \"data-[selected=true]:bg-primary/10 data-[selected=true]:text-primary dark:data-[selected=true]:bg-primary/20\",\n        \"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport function CommandShortcut({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLSpanElement>) {\n  return (\n    <span\n      className={cn(\n        \"ml-auto text-xs tracking-widest text-muted-foreground group-hover/cmd-item:text-primary/70 group-data-[selected=true]/cmd-item:text-primary/70\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n",
      "type": "registry:component",
      "target": "components/custom/blocks/CommandBlock.tsx"
    }
  ],
  "docs": "Named exports: Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator. Use CommandDialog with `open` / `onOpenChange` for the overlay form, or Command inline. Set `shouldFilter` false to filter server-side yourself. Bind your own ⌘K listener — no global shortcut is registered for you.",
  "categories": [
    "navigation",
    "overlays"
  ],
  "type": "registry:component"
}
