{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "prompt-library",
  "type": "registry:ui",
  "description": "Browse, insert, and manage prompt templates with categories and custom prompts",
  "dependencies": [
    "@hugeicons/core-free-icons",
    "@hugeicons/react"
  ],
  "registryDependencies": [
    "button",
    "command",
    "dialog",
    "hover-card",
    "input",
    "popover",
    "textarea"
  ],
  "files": [
    {
      "path": "registry/default/ui/prompt-library.tsx",
      "content": "\"use client\"\n\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useMemo,\n  useState,\n  type ComponentProps,\n  type PropsWithChildren,\n  type ReactNode,\n} from \"react\"\nimport { LibraryIcon, PlusSignIcon } from \"@hugeicons/core-free-icons\"\nimport { HugeiconsIcon } from \"@hugeicons/react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Command,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n} from \"@/components/ui/command\"\nimport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  type DialogDescriptionProps,\n  type DialogTitleProps,\n} from \"@/components/ui/dialog\"\nimport {\n  HoverCard,\n  HoverCardContent,\n  HoverCardTrigger,\n} from \"@/components/ui/hover-card\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface Prompt {\n  /** Unique identifier for the prompt */\n  id: string\n  /** Display title for the prompt */\n  title: string\n  /** Short description shown in the list */\n  description: string\n  /** The actual prompt content to insert/copy */\n  prompt: string\n  /** Optional category for grouping */\n  category?: string\n  /** Whether this is a user-created prompt */\n  isCustom?: boolean\n}\n\nexport interface PromptLibraryContextValue {\n  /** All available prompts */\n  prompts: Prompt[]\n  /** Add a custom prompt */\n  addCustom: (prompt: Omit<Prompt, \"id\" | \"isCustom\">) => void\n  /** Remove a custom prompt */\n  removeCustom: (id: string) => void\n  /** Select a prompt (insert or copy) */\n  selectPrompt: (prompt: Prompt) => void\n  /** Last selected prompt ID */\n  lastSelectedId: string | null\n  /** Open state for the popover */\n  open: boolean\n  /** Set open state for the popover */\n  setOpen: (open: boolean) => void\n  /** Open state for the create dialog */\n  createDialogOpen: boolean\n  /** Set open state for the create dialog */\n  setCreateDialogOpen: (open: boolean) => void\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst PromptLibraryContext = createContext<PromptLibraryContextValue | null>(\n  null\n)\n\n/**\n * Hook to access the PromptLibrary context\n * @throws Error if used outside of PromptLibrary provider\n */\nexport const usePromptLibrary = () => {\n  const ctx = useContext(PromptLibraryContext)\n  if (!ctx) {\n    throw new Error(\n      \"usePromptLibrary must be used within a PromptLibrary provider\"\n    )\n  }\n  return ctx\n}\n\n// ============================================================================\n// Controllable State Hook\n// ============================================================================\n\nfunction useControllableState<T>(\n  controlledValue: T | undefined,\n  defaultValue: T,\n  onChange?: (value: T) => void\n): [T, (value: T | ((prev: T) => T)) => void] {\n  const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue)\n  const isControlled = controlledValue !== undefined\n  const value = isControlled ? controlledValue : uncontrolledValue\n\n  const setValue = useCallback(\n    (nextValue: T | ((prev: T) => T)) => {\n      const resolvedValue =\n        typeof nextValue === \"function\"\n          ? (nextValue as (prev: T) => T)(value)\n          : nextValue\n\n      if (!isControlled) {\n        setUncontrolledValue(resolvedValue)\n      }\n      onChange?.(resolvedValue)\n    },\n    [isControlled, onChange, value]\n  )\n\n  return [value, setValue]\n}\n\n// ============================================================================\n// Root Component\n// ============================================================================\n\nexport type PromptLibraryProps = PropsWithChildren<{\n  /** Initial set of prompts */\n  prompts?: Prompt[]\n  /** Callback when prompts change (for custom prompts) */\n  onPromptsChange?: (prompts: Prompt[]) => void\n  /** Callback when a prompt is selected */\n  onSelect?: (prompt: Prompt) => void\n  /**\n   * Inserts the selected prompt into your input instead of copying it to the\n   * clipboard, e.g. AI Elements' `controller.textInput.setInput`.\n   */\n  onInsert?: (text: string) => void\n  /** Controlled open state for popover */\n  open?: boolean\n  /** Callback when open state changes */\n  onOpenChange?: (open: boolean) => void\n}>\n\n/**\n * Root component for the PromptLibrary widget.\n * Provides context for all child components.\n */\nexport function PromptLibrary({\n  prompts: controlledPrompts,\n  onPromptsChange,\n  onSelect,\n  onInsert,\n  open: controlledOpen,\n  onOpenChange,\n  children,\n}: PromptLibraryProps) {\n  const [internalPrompts, setInternalPrompts] = useState<Prompt[]>(\n    controlledPrompts ?? []\n  )\n\n  const prompts = controlledPrompts ?? internalPrompts\n\n  const [open, setOpen] = useControllableState(\n    controlledOpen,\n    false,\n    onOpenChange\n  )\n  const [createDialogOpen, setCreateDialogOpen] = useState(false)\n  const [lastSelectedId, setLastSelectedId] = useState<string | null>(null)\n\n  const selectPrompt = useCallback(\n    async (prompt: Prompt) => {\n      setLastSelectedId(prompt.id)\n\n      if (onInsert) {\n        onInsert(prompt.prompt)\n      } else {\n        try {\n          await navigator.clipboard.writeText(prompt.prompt)\n        } catch (err) {\n          console.error(\"Failed to copy to clipboard:\", err)\n        }\n      }\n\n      // Close popover after selection\n      setOpen(false)\n\n      // Call onSelect callback\n      onSelect?.(prompt)\n    },\n    [onInsert, setOpen, onSelect]\n  )\n\n  const addCustom = useCallback(\n    (prompt: Omit<Prompt, \"id\" | \"isCustom\">) => {\n      const newPrompt: Prompt = {\n        ...prompt,\n        id: `custom-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,\n        isCustom: true,\n      }\n\n      if (controlledPrompts) {\n        onPromptsChange?.([...controlledPrompts, newPrompt])\n      } else {\n        setInternalPrompts((prev) => [...prev, newPrompt])\n      }\n    },\n    [controlledPrompts, onPromptsChange]\n  )\n\n  const removeCustom = useCallback(\n    (id: string) => {\n      if (controlledPrompts) {\n        onPromptsChange?.(controlledPrompts.filter((p) => p.id !== id))\n      } else {\n        setInternalPrompts((prev) => prev.filter((p) => p.id !== id))\n      }\n    },\n    [controlledPrompts, onPromptsChange]\n  )\n\n  const contextValue = useMemo<PromptLibraryContextValue>(\n    () => ({\n      prompts,\n      addCustom,\n      removeCustom,\n      selectPrompt,\n      lastSelectedId,\n      open,\n      setOpen,\n      createDialogOpen,\n      setCreateDialogOpen,\n    }),\n    [\n      prompts,\n      addCustom,\n      removeCustom,\n      selectPrompt,\n      lastSelectedId,\n      open,\n      setOpen,\n      createDialogOpen,\n    ]\n  )\n\n  return (\n    <PromptLibraryContext.Provider value={contextValue}>\n      <Popover onOpenChange={setOpen} open={open}>\n        {children}\n      </Popover>\n    </PromptLibraryContext.Provider>\n  )\n}\n\n// ============================================================================\n// Trigger Component\n// ============================================================================\n\nexport type PromptLibraryTriggerProps = ComponentProps<typeof Button> & {\n  /** Custom label for the trigger button */\n  label?: ReactNode\n}\n\n/**\n * Button that opens the prompt library popover.\n */\nexport function PromptLibraryTrigger({\n  className,\n  label,\n  children,\n  ...props\n}: PromptLibraryTriggerProps) {\n  return (\n    <PopoverTrigger asChild>\n      <Button\n        className={cn(\"gap-1.5\", className)}\n        size=\"sm\"\n        type=\"button\"\n        variant=\"ghost\"\n        {...props}\n      >\n        {children ?? (\n          <>\n            <HugeiconsIcon\n              className=\"size-3.5\"\n              icon={LibraryIcon}\n              strokeWidth={2}\n            />\n            {label ?? \"Prompts\"}\n          </>\n        )}\n      </Button>\n    </PopoverTrigger>\n  )\n}\n\n// ============================================================================\n// Content Component\n// ============================================================================\n\nexport type PromptLibraryContentProps = ComponentProps<typeof PopoverContent>\n\n/**\n * Popover content container for the prompt library list.\n */\nexport function PromptLibraryContent({\n  className,\n  children,\n  ...props\n}: PromptLibraryContentProps) {\n  return (\n    <PopoverContent\n      align=\"start\"\n      className={cn(\"w-80 p-0\", className)}\n      side=\"top\"\n      sideOffset={8}\n      {...props}\n    >\n      <Command className=\"rounded-lg\" data-slot=\"prompt-library-content\">\n        {children}\n      </Command>\n    </PopoverContent>\n  )\n}\n\n// ============================================================================\n// Search Component\n// ============================================================================\n\nexport type PromptLibrarySearchProps = ComponentProps<typeof CommandInput>\n\n/**\n * Search input for filtering prompts.\n */\nexport function PromptLibrarySearch({\n  placeholder = \"Search prompts...\",\n  className,\n  ...props\n}: PromptLibrarySearchProps) {\n  return (\n    <CommandInput\n      className={cn(className)}\n      data-slot=\"prompt-library-search\"\n      placeholder={placeholder}\n      {...props}\n    />\n  )\n}\n\n// ============================================================================\n// List Component\n// ============================================================================\n\nexport type PromptLibraryListProps = ComponentProps<typeof CommandList>\n\n/**\n * Scrollable list container for prompts.\n */\nexport function PromptLibraryList({\n  className,\n  children,\n  ...props\n}: PromptLibraryListProps) {\n  return (\n    <CommandList\n      className={cn(\"max-h-64\", className)}\n      data-slot=\"prompt-library-list\"\n      {...props}\n    >\n      {children}\n    </CommandList>\n  )\n}\n\n// ============================================================================\n// Empty Component\n// ============================================================================\n\nexport type PromptLibraryEmptyProps = ComponentProps<typeof CommandEmpty>\n\n/**\n * Empty state shown when no prompts match the search.\n */\nexport function PromptLibraryEmpty({\n  children = \"No prompts found.\",\n  className,\n  ...props\n}: PromptLibraryEmptyProps) {\n  return (\n    <CommandEmpty\n      className={cn(className)}\n      data-slot=\"prompt-library-empty\"\n      {...props}\n    >\n      {children}\n    </CommandEmpty>\n  )\n}\n\n// ============================================================================\n// Group Component\n// ============================================================================\n\nexport type PromptLibraryGroupProps = ComponentProps<typeof CommandGroup>\n\n/**\n * Group container for categorizing prompts.\n */\nexport function PromptLibraryGroup({\n  className,\n  ...props\n}: PromptLibraryGroupProps) {\n  return (\n    <CommandGroup\n      className={cn(\n        // Remove default rounding from all items\n        \"**:[[cmdk-item]]:rounded-none\",\n        // First child in group gets rounded top\n        \"[&_[cmdk-group-items]>:first-child_[cmdk-item]]:rounded-t-md\",\n        // Last child in group gets rounded bottom\n        \"[&_[cmdk-group-items]>:last-child_[cmdk-item]]:rounded-b-md\",\n        className\n      )}\n      data-slot=\"prompt-library-group\"\n      {...props}\n    />\n  )\n}\n\n// ============================================================================\n// Separator Component\n// ============================================================================\n\nexport type PromptLibrarySeparatorProps = ComponentProps<\n  typeof CommandSeparator\n>\n\n/**\n * Visual separator between prompt groups.\n */\nexport function PromptLibrarySeparator({\n  className,\n  ...props\n}: PromptLibrarySeparatorProps) {\n  return (\n    <CommandSeparator\n      className={cn(className)}\n      data-slot=\"prompt-library-separator\"\n      {...props}\n    />\n  )\n}\n\n// ============================================================================\n// Item Component\n// ============================================================================\n\nexport type PromptLibraryItemProps = Omit<\n  ComponentProps<typeof CommandItem>,\n  \"value\" | \"onSelect\"\n> & {\n  /** The prompt data */\n  prompt: Prompt\n  /** Disable hover card preview */\n  disablePreview?: boolean\n}\n\n/**\n * Individual prompt item with click-to-select and optional hover preview.\n */\nexport function PromptLibraryItem({\n  prompt,\n  disablePreview = false,\n  className,\n  children,\n  ...props\n}: PromptLibraryItemProps) {\n  const { selectPrompt, lastSelectedId } = usePromptLibrary()\n  const isLastSelected = lastSelectedId === prompt.id\n\n  const handleSelect = () => {\n    selectPrompt(prompt)\n  }\n\n  const itemContent = (\n    <CommandItem\n      className={cn(\n        \"group/prompt-item flex cursor-pointer items-start gap-3 py-2\",\n        isLastSelected && \"bg-accent/50\",\n        className\n      )}\n      data-slot=\"prompt-library-item\"\n      data-state={isLastSelected ? \"selected\" : \"idle\"}\n      onSelect={handleSelect}\n      value={prompt.title}\n      {...props}\n    >\n      <div className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n        {children ?? (\n          <>\n            <PromptLibraryItemTitle>{prompt.title}</PromptLibraryItemTitle>\n            <PromptLibraryItemDescription>\n              {prompt.description}\n            </PromptLibraryItemDescription>\n          </>\n        )}\n      </div>\n    </CommandItem>\n  )\n\n  if (disablePreview || !prompt.prompt) {\n    return itemContent\n  }\n\n  return (\n    <PromptLibraryHoverCard prompt={prompt}>\n      {itemContent}\n    </PromptLibraryHoverCard>\n  )\n}\n\n// ============================================================================\n// Item Title Component\n// ============================================================================\n\nexport type PromptLibraryItemTitleProps = ComponentProps<\"span\">\n\n/**\n * Title text for a prompt item.\n */\nexport function PromptLibraryItemTitle({\n  className,\n  ...props\n}: PromptLibraryItemTitleProps) {\n  return (\n    <span\n      className={cn(\"text-foreground text-xs font-medium\", className)}\n      data-slot=\"prompt-library-item-title\"\n      {...props}\n    />\n  )\n}\n\n// ============================================================================\n// Item Description Component\n// ============================================================================\n\nexport type PromptLibraryItemDescriptionProps = ComponentProps<\"span\">\n\n/**\n * Description text for a prompt item.\n */\nexport function PromptLibraryItemDescription({\n  className,\n  ...props\n}: PromptLibraryItemDescriptionProps) {\n  return (\n    <span\n      className={cn(\"text-muted-foreground line-clamp-2 text-xs\", className)}\n      data-slot=\"prompt-library-item-description\"\n      {...props}\n    />\n  )\n}\n\n// ============================================================================\n// Hover Card Component\n// ============================================================================\n\nexport interface PromptLibraryHoverCardProps {\n  /** The prompt to preview */\n  prompt: Prompt\n  /** The trigger element (prompt item) */\n  children: ReactNode\n}\n\n/**\n * Hover card that shows the full prompt content on hover.\n */\nexport function PromptLibraryHoverCard({\n  prompt,\n  children,\n}: PromptLibraryHoverCardProps) {\n  return (\n    <HoverCard openDelay={300} closeDelay={100}>\n      <HoverCardTrigger>{children}</HoverCardTrigger>\n      <HoverCardContent\n        align=\"start\"\n        className=\"w-80\"\n        data-slot=\"prompt-library-hover-card\"\n        side=\"right\"\n        sideOffset={8}\n      >\n        <div className=\"flex flex-col gap-2\">\n          <div className=\"flex flex-col gap-1\">\n            <span className=\"text-sm font-medium\">{prompt.title}</span>\n            <span className=\"text-muted-foreground text-xs\">\n              {prompt.description}\n            </span>\n          </div>\n          {prompt.prompt && (\n            <div className=\"bg-muted/50 rounded-md p-2\">\n              <p className=\"text-muted-foreground line-clamp-6 text-xs whitespace-pre-wrap\">\n                {prompt.prompt}\n              </p>\n            </div>\n          )}\n          {prompt.category && (\n            <span className=\"text-muted-foreground text-[0.625rem]\">\n              Category: {prompt.category}\n            </span>\n          )}\n          {prompt.isCustom && (\n            <span className=\"text-muted-foreground text-[0.625rem]\">\n              Custom prompt\n            </span>\n          )}\n        </div>\n      </HoverCardContent>\n    </HoverCard>\n  )\n}\n\n// ============================================================================\n// Footer Component\n// ============================================================================\n\nexport type PromptLibraryFooterProps = ComponentProps<\"div\">\n\n/**\n * Footer container that stays fixed at the bottom of the popover.\n * Use this to place the create trigger outside the scrollable list.\n */\nexport function PromptLibraryFooter({\n  className,\n  children,\n  ...props\n}: PromptLibraryFooterProps) {\n  return (\n    <div\n      className={cn(\"border-t p-1\", className)}\n      data-slot=\"prompt-library-footer\"\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n\n// ============================================================================\n// Create Trigger Component\n// ============================================================================\n\nexport type PromptLibraryCreateTriggerProps = Omit<\n  ComponentProps<typeof CommandItem>,\n  \"onSelect\"\n> & {\n  /** Custom label for the create button */\n  label?: ReactNode\n}\n\n/**\n * Button that opens the create prompt dialog.\n */\nexport function PromptLibraryCreateTrigger({\n  label = \"New Prompt\",\n  className,\n  children,\n  ...props\n}: PromptLibraryCreateTriggerProps) {\n  const { setCreateDialogOpen, setOpen } = usePromptLibrary()\n\n  const handleSelect = () => {\n    setOpen(false)\n    setCreateDialogOpen(true)\n  }\n\n  return (\n    <CommandItem\n      className={cn(\n        \"text-muted-foreground flex cursor-pointer items-center gap-2\",\n        className\n      )}\n      data-slot=\"prompt-library-create-trigger\"\n      onSelect={handleSelect}\n      value=\"__new_prompt__\"\n      {...props}\n    >\n      {children ?? (\n        <>\n          <HugeiconsIcon\n            className=\"size-3.5\"\n            icon={PlusSignIcon}\n            strokeWidth={2}\n          />\n          {label}\n        </>\n      )}\n    </CommandItem>\n  )\n}\n\n// ============================================================================\n// Create Dialog Component\n// ============================================================================\n\nexport type PromptLibraryCreateDialogProps = Omit<\n  ComponentProps<typeof Dialog>,\n  \"open\" | \"onOpenChange\" | \"children\"\n> & {\n  /** Dialog title */\n  title?: DialogTitleProps[\"children\"]\n  /** Dialog description */\n  description?: DialogDescriptionProps[\"children\"]\n  /** Custom form content to replace the default form */\n  children?: ReactNode\n}\n\n/**\n * Modal dialog for creating custom prompts.\n */\nexport function PromptLibraryCreateDialog({\n  title = \"Create Prompt\",\n  description = \"Create a custom prompt template for quick access.\",\n  children,\n  ...props\n}: PromptLibraryCreateDialogProps) {\n  const { createDialogOpen, setCreateDialogOpen, addCustom } =\n    usePromptLibrary()\n  const [formTitle, setFormTitle] = useState(\"\")\n  const [formDescription, setFormDescription] = useState(\"\")\n  const [formPrompt, setFormPrompt] = useState(\"\")\n  const [formCategory, setFormCategory] = useState(\"\")\n\n  const handleSubmit = (e: React.FormEvent) => {\n    e.preventDefault()\n\n    if (!(formTitle.trim() && formDescription.trim() && formPrompt.trim())) {\n      return\n    }\n\n    addCustom({\n      title: formTitle.trim(),\n      description: formDescription.trim(),\n      prompt: formPrompt.trim(),\n      category: formCategory.trim() || undefined,\n    })\n\n    // Reset form\n    setFormTitle(\"\")\n    setFormDescription(\"\")\n    setFormPrompt(\"\")\n    setFormCategory(\"\")\n    setCreateDialogOpen(false)\n  }\n\n  const handleOpenChange = (open: boolean) => {\n    setCreateDialogOpen(open)\n    if (!open) {\n      // Reset form when closing\n      setFormTitle(\"\")\n      setFormDescription(\"\")\n      setFormPrompt(\"\")\n      setFormCategory(\"\")\n    }\n  }\n\n  return (\n    <Dialog\n      data-slot=\"prompt-library-create-dialog\"\n      onOpenChange={handleOpenChange}\n      open={createDialogOpen}\n      {...props}\n    >\n      <DialogContent className=\"sm:max-w-md\">\n        <DialogHeader>\n          <DialogTitle>{title}</DialogTitle>\n          <DialogDescription>{description}</DialogDescription>\n        </DialogHeader>\n        {children ?? (\n          <form className=\"flex flex-col gap-4\" onSubmit={handleSubmit}>\n            <div className=\"flex flex-col gap-2\">\n              <label className=\"text-xs font-medium\" htmlFor=\"prompt-title\">\n                Title\n              </label>\n              <Input\n                id=\"prompt-title\"\n                onChange={(e) => setFormTitle(e.target.value)}\n                placeholder=\"e.g., Code Review\"\n                required\n                value={formTitle}\n              />\n            </div>\n            <div className=\"flex flex-col gap-2\">\n              <label\n                className=\"text-xs font-medium\"\n                htmlFor=\"prompt-description\"\n              >\n                Description\n              </label>\n              <Input\n                id=\"prompt-description\"\n                onChange={(e) => setFormDescription(e.target.value)}\n                placeholder=\"e.g., Review code for best practices\"\n                required\n                value={formDescription}\n              />\n            </div>\n            <div className=\"flex flex-col gap-2\">\n              <label className=\"text-xs font-medium\" htmlFor=\"prompt-content\">\n                Prompt\n              </label>\n              <Textarea\n                className=\"min-h-24 resize-none\"\n                id=\"prompt-content\"\n                onChange={(e) => setFormPrompt(e.target.value)}\n                placeholder=\"Enter the prompt text...\"\n                required\n                value={formPrompt}\n              />\n            </div>\n            <div className=\"flex flex-col gap-2\">\n              <label className=\"text-xs font-medium\" htmlFor=\"prompt-category\">\n                Category (optional)\n              </label>\n              <Input\n                id=\"prompt-category\"\n                onChange={(e) => setFormCategory(e.target.value)}\n                placeholder=\"e.g., Development\"\n                value={formCategory}\n              />\n            </div>\n            <DialogFooter>\n              <DialogClose asChild>\n                <Button type=\"button\" variant=\"outline\">\n                  Cancel\n                </Button>\n              </DialogClose>\n              <Button type=\"submit\">Create</Button>\n            </DialogFooter>\n          </form>\n        )}\n      </DialogContent>\n    </Dialog>\n  )\n}\n\n// ============================================================================\n// Compound Export\n// ============================================================================\n\nexport const PromptLibraryWidget = Object.assign(PromptLibrary, {\n  Trigger: PromptLibraryTrigger,\n  Content: PromptLibraryContent,\n  Search: PromptLibrarySearch,\n  List: PromptLibraryList,\n  Empty: PromptLibraryEmpty,\n  Group: PromptLibraryGroup,\n  Separator: PromptLibrarySeparator,\n  Item: PromptLibraryItem,\n  ItemTitle: PromptLibraryItemTitle,\n  ItemDescription: PromptLibraryItemDescription,\n  HoverCard: PromptLibraryHoverCard,\n  Footer: PromptLibraryFooter,\n  CreateTrigger: PromptLibraryCreateTrigger,\n  CreateDialog: PromptLibraryCreateDialog,\n})\n",
      "type": "registry:ui"
    }
  ]
}