{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "comp-234",
  "type": "registry:component",
  "title": "Comp 234",
  "description": "Comp 234",
  "files": [
    {
      "path": "registry/ui-basic/comp-234.tsx",
      "content": "import { useId } from \"react\";\n\nimport { Label } from \"@/components/ui/label\";\nimport MultipleSelector, { Option } from \"@/components/ui/multiselect\";\n\nconst frameworks: Option[] = [\n\t{\n\t\tvalue: \"next.js\",\n\t\tlabel: \"Next.js\",\n\t},\n\t{\n\t\tvalue: \"sveltekit\",\n\t\tlabel: \"SvelteKit\",\n\t},\n\t{\n\t\tvalue: \"nuxt.js\",\n\t\tlabel: \"Nuxt.js\",\n\t\tdisable: true,\n\t},\n\t{\n\t\tvalue: \"remix\",\n\t\tlabel: \"Remix\",\n\t},\n\t{\n\t\tvalue: \"astro\",\n\t\tlabel: \"Astro\",\n\t},\n\t{\n\t\tvalue: \"angular\",\n\t\tlabel: \"Angular\",\n\t},\n\t{\n\t\tvalue: \"vue\",\n\t\tlabel: \"Vue.js\",\n\t},\n\t{\n\t\tvalue: \"react\",\n\t\tlabel: \"React\",\n\t},\n\t{\n\t\tvalue: \"ember\",\n\t\tlabel: \"Ember.js\",\n\t},\n\t{\n\t\tvalue: \"gatsby\",\n\t\tlabel: \"Gatsby\",\n\t},\n\t{\n\t\tvalue: \"eleventy\",\n\t\tlabel: \"Eleventy\",\n\t\tdisable: true,\n\t},\n\t{\n\t\tvalue: \"solid\",\n\t\tlabel: \"SolidJS\",\n\t},\n\t{\n\t\tvalue: \"preact\",\n\t\tlabel: \"Preact\",\n\t},\n\t{\n\t\tvalue: \"qwik\",\n\t\tlabel: \"Qwik\",\n\t},\n\t{\n\t\tvalue: \"alpine\",\n\t\tlabel: \"Alpine.js\",\n\t},\n\t{\n\t\tvalue: \"lit\",\n\t\tlabel: \"Lit\",\n\t},\n];\n\nexport default function Component() {\n\tconst id = useId();\n\treturn (\n\t\t<div className=\"not-first:*:mt-2\">\n\t\t\t<Label>Multiselect</Label>\n\t\t\t<MultipleSelector\n\t\t\t\tcommandProps={{\n\t\t\t\t\tlabel: \"Select frameworks\",\n\t\t\t\t}}\n\t\t\t\tvalue={frameworks.slice(0, 2)}\n\t\t\t\tdefaultOptions={frameworks}\n\t\t\t\tplaceholder=\"Select frameworks\"\n\t\t\t\thideClearAllButton\n\t\t\t\thidePlaceholderWhenSelected\n\t\t\t\temptyIndicator={\n\t\t\t\t\t<p className=\"text-center text-sm\">No results found</p>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<p\n\t\t\t\tclassName=\"text-muted-foreground mt-2 text-xs\"\n\t\t\t\trole=\"region\"\n\t\t\t\taria-live=\"polite\"\n\t\t\t>\n\t\t\t\tInspired by{\" \"}\n\t\t\t\t<a\n\t\t\t\t\tclassName=\"hover:text-foreground underline\"\n\t\t\t\t\thref=\"https://shadcnui-expansions.typeart.cc/docs/multiple-selector\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener nofollow\"\n\t\t\t\t>\n\t\t\t\t\tshadcn/ui expansions\n\t\t\t\t</a>\n\t\t\t</p>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/label.tsx",
      "content": "\"use client\";\n\nimport React from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nconst labelVariants = cva(\n\t\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n);\n\nconst Label = React.forwardRef<\n\tReact.ElementRef<typeof LabelPrimitive.Root>,\n\tReact.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &\n\t\tVariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n\t<LabelPrimitive.Root\n\t\tref={ref}\n\t\tclassName={cn(labelVariants(), className)}\n\t\t{...props}\n\t/>\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/utilities/cn.ts",
      "content": "import { ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n\treturn twMerge(clsx(inputs));\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/multiselect.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { useEffect } from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport { Command as CommandPrimitive, useCommandState } from \"cmdk\";\nimport { XIcon } from \"lucide-react\";\n\nimport { Command, CommandGroup, CommandItem, CommandList } from \"./command\";\n\nexport interface Option {\n\tvalue: string;\n\tlabel: string;\n\tdisable?: boolean;\n\t/** fixed option that can't be removed. */\n\tfixed?: boolean;\n\t/** Group the options by providing key. */\n\t[key: string]: string | boolean | undefined;\n}\ninterface GroupOption {\n\t[key: string]: Option[];\n}\n\ninterface MultipleSelectorProps {\n\tvalue?: Option[];\n\tdefaultOptions?: Option[];\n\t/** manually controlled options */\n\toptions?: Option[];\n\tplaceholder?: string;\n\t/** Loading component. */\n\tloadingIndicator?: React.ReactNode;\n\t/** Empty component. */\n\temptyIndicator?: React.ReactNode;\n\t/** Debounce time for async search. Only work with `onSearch`. */\n\tdelay?: number;\n\t/**\n\t * Only work with `onSearch` prop. Trigger search when `onFocus`.\n\t * For example, when user click on the input, it will trigger the search to get initial options.\n\t **/\n\ttriggerSearchOnFocus?: boolean;\n\t/** async search */\n\tonSearch?: (value: string) => Promise<Option[]>;\n\t/**\n\t * sync search. This search will not showing loadingIndicator.\n\t * The rest props are the same as async search.\n\t * i.e.: creatable, groupBy, delay.\n\t **/\n\tonSearchSync?: (value: string) => Option[];\n\tonChange?: (options: Option[]) => void;\n\t/** Limit the maximum number of selected options. */\n\tmaxSelected?: number;\n\t/** When the number of selected options exceeds the limit, the onMaxSelected will be called. */\n\tonMaxSelected?: (maxLimit: number) => void;\n\t/** Hide the placeholder when there are options selected. */\n\thidePlaceholderWhenSelected?: boolean;\n\tdisabled?: boolean;\n\t/** Group the options base on provided key. */\n\tgroupBy?: string;\n\tclassName?: string;\n\tbadgeClassName?: string;\n\t/**\n\t * First item selected is a default behavior by cmdk. That is why the default is true.\n\t * This is a workaround solution by add a dummy item.\n\t *\n\t * @reference: https://github.com/pacocoursey/cmdk/issues/171\n\t */\n\tselectFirstItem?: boolean;\n\t/** Allow user to create option when there is no option matched. */\n\tcreatable?: boolean;\n\t/** Props of `Command` */\n\tcommandProps?: React.ComponentPropsWithoutRef<typeof Command>;\n\t/** Props of `CommandInput` */\n\tinputProps?: Omit<\n\t\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>,\n\t\t\"value\" | \"placeholder\" | \"disabled\"\n\t>;\n\t/** hide the clear all button. */\n\thideClearAllButton?: boolean;\n}\n\nexport interface MultipleSelectorRef {\n\tselectedValue: Option[];\n\tinput: HTMLInputElement;\n\tfocus: () => void;\n\treset: () => void;\n}\n\nexport function useDebounce<T>(value: T, delay?: number): T {\n\tconst [debouncedValue, setDebouncedValue] = React.useState<T>(value);\n\n\tuseEffect(() => {\n\t\tconst timer = setTimeout(() => setDebouncedValue(value), delay || 500);\n\n\t\treturn () => {\n\t\t\tclearTimeout(timer);\n\t\t};\n\t}, [value, delay]);\n\n\treturn debouncedValue;\n}\n\nfunction transToGroupOption(options: Option[], groupBy?: string) {\n\tif (options.length === 0) {\n\t\treturn {};\n\t}\n\tif (!groupBy) {\n\t\treturn {\n\t\t\t\"\": options,\n\t\t};\n\t}\n\n\tconst groupOption: GroupOption = {};\n\toptions.forEach((option) => {\n\t\tconst key = (option[groupBy] as string) || \"\";\n\t\tif (!groupOption[key]) {\n\t\t\tgroupOption[key] = [];\n\t\t}\n\t\tgroupOption[key].push(option);\n\t});\n\treturn groupOption;\n}\n\nfunction removePickedOption(groupOption: GroupOption, picked: Option[]) {\n\tconst cloneOption = JSON.parse(JSON.stringify(groupOption)) as GroupOption;\n\n\tfor (const [key, value] of Object.entries(cloneOption)) {\n\t\tcloneOption[key] = value.filter(\n\t\t\t(val) => !picked.find((p) => p.value === val.value)\n\t\t);\n\t}\n\treturn cloneOption;\n}\n\nfunction isOptionsExist(groupOption: GroupOption, targetOption: Option[]) {\n\tfor (const [, value] of Object.entries(groupOption)) {\n\t\tif (\n\t\t\tvalue.some((option) =>\n\t\t\t\ttargetOption.find((p) => p.value === option.value)\n\t\t\t)\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nconst CommandEmpty = ({\n\tclassName,\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive.Empty>) => {\n\tconst render = useCommandState((state) => state.filtered.count === 0);\n\n\tif (!render) return null;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"px-2 py-4 text-center text-sm\", className)}\n\t\t\tcmdk-empty=\"\"\n\t\t\trole=\"presentation\"\n\t\t\t{...props}\n\t\t/>\n\t);\n};\n\nCommandEmpty.displayName = \"CommandEmpty\";\n\nconst MultipleSelector = ({\n\tvalue,\n\tonChange,\n\tplaceholder,\n\tdefaultOptions: arrayDefaultOptions = [],\n\toptions: arrayOptions,\n\tdelay,\n\tonSearch,\n\tonSearchSync,\n\tloadingIndicator,\n\temptyIndicator,\n\tmaxSelected = Number.MAX_SAFE_INTEGER,\n\tonMaxSelected,\n\thidePlaceholderWhenSelected,\n\tdisabled,\n\tgroupBy,\n\tclassName,\n\tbadgeClassName,\n\tselectFirstItem = true,\n\tcreatable = false,\n\ttriggerSearchOnFocus = false,\n\tcommandProps,\n\tinputProps,\n\thideClearAllButton = false,\n}: MultipleSelectorProps) => {\n\tconst inputRef = React.useRef<HTMLInputElement>(null);\n\tconst [open, setOpen] = React.useState(false);\n\tconst [onScrollbar, setOnScrollbar] = React.useState(false);\n\tconst [isLoading, setIsLoading] = React.useState(false);\n\tconst dropdownRef = React.useRef<HTMLDivElement>(null); // Added this\n\n\tconst [selected, setSelected] = React.useState<Option[]>(value || []);\n\tconst [options, setOptions] = React.useState<GroupOption>(\n\t\ttransToGroupOption(arrayDefaultOptions, groupBy)\n\t);\n\tconst [inputValue, setInputValue] = React.useState(\"\");\n\tconst debouncedSearchTerm = useDebounce(inputValue, delay || 500);\n\n\tconst handleClickOutside = (event: MouseEvent | TouchEvent) => {\n\t\tif (\n\t\t\tdropdownRef.current &&\n\t\t\t!dropdownRef.current.contains(event.target as Node) &&\n\t\t\tinputRef.current &&\n\t\t\t!inputRef.current.contains(event.target as Node)\n\t\t) {\n\t\t\tsetOpen(false);\n\t\t\tinputRef.current.blur();\n\t\t}\n\t};\n\n\tconst handleUnselect = React.useCallback(\n\t\t(option: Option) => {\n\t\t\tconst newOptions = selected.filter((s) => s.value !== option.value);\n\t\t\tsetSelected(newOptions);\n\t\t\tonChange?.(newOptions);\n\t\t},\n\t\t[onChange, selected]\n\t);\n\n\tconst handleKeyDown = React.useCallback(\n\t\t(e: React.KeyboardEvent<HTMLDivElement>) => {\n\t\t\tconst input = inputRef.current;\n\t\t\tif (input) {\n\t\t\t\tif (e.key === \"Delete\" || e.key === \"Backspace\") {\n\t\t\t\t\tif (input.value === \"\" && selected.length > 0) {\n\t\t\t\t\t\tconst lastSelectOption = selected[selected.length - 1];\n\t\t\t\t\t\t// If last item is fixed, we should not remove it.\n\t\t\t\t\t\tif (!lastSelectOption.fixed) {\n\t\t\t\t\t\t\thandleUnselect(selected[selected.length - 1]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// This is not a default behavior of the <input /> field\n\t\t\t\tif (e.key === \"Escape\") {\n\t\t\t\t\tinput.blur();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[handleUnselect, selected]\n\t);\n\n\tuseEffect(() => {\n\t\tif (open) {\n\t\t\tdocument.addEventListener(\"mousedown\", handleClickOutside);\n\t\t\tdocument.addEventListener(\"touchend\", handleClickOutside);\n\t\t} else {\n\t\t\tdocument.removeEventListener(\"mousedown\", handleClickOutside);\n\t\t\tdocument.removeEventListener(\"touchend\", handleClickOutside);\n\t\t}\n\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"mousedown\", handleClickOutside);\n\t\t\tdocument.removeEventListener(\"touchend\", handleClickOutside);\n\t\t};\n\t}, [open]);\n\n\tuseEffect(() => {\n\t\tif (value) {\n\t\t\tsetSelected(value);\n\t\t}\n\t}, [value]);\n\n\tuseEffect(() => {\n\t\t/** If `onSearch` is provided, do not trigger options updated. */\n\t\tif (!arrayOptions || onSearch) {\n\t\t\treturn;\n\t\t}\n\t\tconst newOption = transToGroupOption(arrayOptions || [], groupBy);\n\t\tif (JSON.stringify(newOption) !== JSON.stringify(options)) {\n\t\t\tsetOptions(newOption);\n\t\t}\n\t}, [arrayDefaultOptions, arrayOptions, groupBy, onSearch, options]);\n\n\tuseEffect(() => {\n\t\t/** sync search */\n\n\t\tconst doSearchSync = () => {\n\t\t\tconst res = onSearchSync?.(debouncedSearchTerm);\n\t\t\tsetOptions(transToGroupOption(res || [], groupBy));\n\t\t};\n\n\t\tconst exec = async () => {\n\t\t\tif (!onSearchSync || !open) return;\n\n\t\t\tif (triggerSearchOnFocus) {\n\t\t\t\tdoSearchSync();\n\t\t\t}\n\n\t\t\tif (debouncedSearchTerm) {\n\t\t\t\tdoSearchSync();\n\t\t\t}\n\t\t};\n\n\t\tvoid exec();\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]);\n\n\tuseEffect(() => {\n\t\t/** async search */\n\n\t\tconst doSearch = async () => {\n\t\t\tsetIsLoading(true);\n\t\t\tconst res = await onSearch?.(debouncedSearchTerm);\n\t\t\tsetOptions(transToGroupOption(res || [], groupBy));\n\t\t\tsetIsLoading(false);\n\t\t};\n\n\t\tconst exec = async () => {\n\t\t\tif (!onSearch || !open) return;\n\n\t\t\tif (triggerSearchOnFocus) {\n\t\t\t\tawait doSearch();\n\t\t\t}\n\n\t\t\tif (debouncedSearchTerm) {\n\t\t\t\tawait doSearch();\n\t\t\t}\n\t\t};\n\n\t\tvoid exec();\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]);\n\n\tconst CreatableItem = () => {\n\t\tif (!creatable) return undefined;\n\t\tif (\n\t\t\tisOptionsExist(options, [{ value: inputValue, label: inputValue }]) ||\n\t\t\tselected.find((s) => s.value === inputValue)\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst Item = (\n\t\t\t<CommandItem\n\t\t\t\tvalue={inputValue}\n\t\t\t\tclassName=\"cursor-pointer\"\n\t\t\t\tonMouseDown={(e) => {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}}\n\t\t\t\tonSelect={(value: string) => {\n\t\t\t\t\tif (selected.length >= maxSelected) {\n\t\t\t\t\t\tonMaxSelected?.(selected.length);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsetInputValue(\"\");\n\t\t\t\t\tconst newOptions = [...selected, { value, label: value }];\n\t\t\t\t\tsetSelected(newOptions);\n\t\t\t\t\tonChange?.(newOptions);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{`Create \"${inputValue}\"`}\n\t\t\t</CommandItem>\n\t\t);\n\n\t\t// For normal creatable\n\t\tif (!onSearch && inputValue.length > 0) {\n\t\t\treturn Item;\n\t\t}\n\n\t\t// For async search creatable. avoid showing creatable item before loading at first.\n\t\tif (onSearch && debouncedSearchTerm.length > 0 && !isLoading) {\n\t\t\treturn Item;\n\t\t}\n\n\t\treturn undefined;\n\t};\n\n\tconst EmptyItem = React.useCallback(() => {\n\t\tif (!emptyIndicator) return undefined;\n\n\t\t// For async search that showing emptyIndicator\n\t\tif (onSearch && !creatable && Object.keys(options).length === 0) {\n\t\t\treturn (\n\t\t\t\t<CommandItem value=\"-\" disabled>\n\t\t\t\t\t{emptyIndicator}\n\t\t\t\t</CommandItem>\n\t\t\t);\n\t\t}\n\n\t\treturn <CommandEmpty>{emptyIndicator}</CommandEmpty>;\n\t}, [creatable, emptyIndicator, onSearch, options]);\n\n\tconst selectables = React.useMemo<GroupOption>(\n\t\t() => removePickedOption(options, selected),\n\t\t[options, selected]\n\t);\n\n\t/** Avoid Creatable Selector freezing or lagging when paste a long string. */\n\tconst commandFilter = React.useCallback(() => {\n\t\tif (commandProps?.filter) {\n\t\t\treturn commandProps.filter;\n\t\t}\n\n\t\tif (creatable) {\n\t\t\treturn (value: string, search: string) => {\n\t\t\t\treturn value.toLowerCase().includes(search.toLowerCase()) ? 1 : -1;\n\t\t\t};\n\t\t}\n\t\t// Using default filter in `cmdk`. We don&lsquo;t have to provide it.\n\t\treturn undefined;\n\t}, [creatable, commandProps?.filter]);\n\n\treturn (\n\t\t<Command\n\t\t\tref={dropdownRef}\n\t\t\t{...commandProps}\n\t\t\tonKeyDown={(e) => {\n\t\t\t\thandleKeyDown(e);\n\t\t\t\tcommandProps?.onKeyDown?.(e);\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\t\"h-auto overflow-visible bg-transparent\",\n\t\t\t\tcommandProps?.className\n\t\t\t)}\n\t\t\tshouldFilter={\n\t\t\t\tcommandProps?.shouldFilter !== undefined\n\t\t\t\t\t? commandProps.shouldFilter\n\t\t\t\t\t: !onSearch\n\t\t\t} // When onSearch is provided, we don&lsquo;t want to filter the options. You can still override it.\n\t\t\tfilter={commandFilter()}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"border-input focus-within:border-ring focus-within:ring-ring/50 has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40 has-aria-invalid:border-destructive relative min-h-[38px] rounded-md border text-sm transition-[color,box-shadow] outline-hidden focus-within:ring-[3px] has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50\",\n\t\t\t\t\t{\n\t\t\t\t\t\t\"p-1\": selected.length !== 0,\n\t\t\t\t\t\t\"cursor-text\": !disabled && selected.length !== 0,\n\t\t\t\t\t},\n\t\t\t\t\t!hideClearAllButton && \"pe-9\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tonClick={() => {\n\t\t\t\t\tif (disabled) return;\n\t\t\t\t\tinputRef?.current?.focus();\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div className=\"flex flex-wrap gap-1\">\n\t\t\t\t\t{selected.map((option) => {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={option.value}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"animate-fadeIn bg-background text-secondary-foreground hover:bg-background relative inline-flex h-7 cursor-default items-center rounded-md border ps-2 pe-7 pl-2 text-xs font-medium transition-all disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 data-fixed:pe-2\",\n\t\t\t\t\t\t\t\t\tbadgeClassName\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tdata-fixed={option.fixed}\n\t\t\t\t\t\t\t\tdata-disabled={disabled || undefined}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\tclassName=\"text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute -inset-y-px -end-px flex size-7 items-center justify-center rounded-e-md border border-transparent p-0 outline-hidden transition-[color,box-shadow] outline-hidden focus-visible:ring-[3px]\"\n\t\t\t\t\t\t\t\t\tonKeyDown={(e) => {\n\t\t\t\t\t\t\t\t\t\tif (e.key === \"Enter\") {\n\t\t\t\t\t\t\t\t\t\t\thandleUnselect(option);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tonMouseDown={(e) => {\n\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tonClick={() => handleUnselect(option)}\n\t\t\t\t\t\t\t\t\taria-label=\"Remove\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<XIcon size={14} aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t\t{/* Avoid having the \"Search\" Icon */}\n\t\t\t\t\t<CommandPrimitive.Input\n\t\t\t\t\t\t{...inputProps}\n\t\t\t\t\t\tref={inputRef}\n\t\t\t\t\t\tvalue={inputValue}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tonValueChange={(value) => {\n\t\t\t\t\t\t\tsetInputValue(value);\n\t\t\t\t\t\t\tinputProps?.onValueChange?.(value);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonBlur={(event) => {\n\t\t\t\t\t\t\tif (!onScrollbar) {\n\t\t\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tinputProps?.onBlur?.(event);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonFocus={(event) => {\n\t\t\t\t\t\t\tsetOpen(true);\n\t\t\t\t\t\t\tif (triggerSearchOnFocus) {\n\t\t\t\t\t\t\t\tonSearch?.(debouncedSearchTerm);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tinputProps?.onFocus?.(event);\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tplaceholder={\n\t\t\t\t\t\t\thidePlaceholderWhenSelected && selected.length !== 0\n\t\t\t\t\t\t\t\t? \"\"\n\t\t\t\t\t\t\t\t: placeholder\n\t\t\t\t\t\t}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"placeholder:text-muted-foreground/70 flex-1 bg-transparent outline-hidden disabled:cursor-not-allowed\",\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"w-full\": hidePlaceholderWhenSelected,\n\t\t\t\t\t\t\t\t\"px-3 py-2\": selected.length === 0,\n\t\t\t\t\t\t\t\t\"ml-1\": selected.length !== 0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tinputProps?.className\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tsetSelected(selected.filter((s) => s.fixed));\n\t\t\t\t\t\t\tonChange?.(selected.filter((s) => s.fixed));\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-e-0 top-0 flex size-9 items-center justify-center rounded-md border border-transparent transition-[color,box-shadow] outline-hidden focus-visible:ring-[3px]\",\n\t\t\t\t\t\t\t(hideClearAllButton ||\n\t\t\t\t\t\t\t\tdisabled ||\n\t\t\t\t\t\t\t\tselected.length < 1 ||\n\t\t\t\t\t\t\t\tselected.filter((s) => s.fixed).length ===\n\t\t\t\t\t\t\t\t\tselected.length) &&\n\t\t\t\t\t\t\t\t\"hidden\"\n\t\t\t\t\t\t)}\n\t\t\t\t\t\taria-label=\"Clear all\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<XIcon size={16} aria-hidden=\"true\" />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className=\"relative\">\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"border-input absolute top-2 z-10 w-full overflow-hidden rounded-md border\",\n\t\t\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\t\t\t!open && \"hidden\"\n\t\t\t\t\t)}\n\t\t\t\t\tdata-state={open ? \"open\" : \"closed\"}\n\t\t\t\t>\n\t\t\t\t\t{open && (\n\t\t\t\t\t\t<CommandList\n\t\t\t\t\t\t\tclassName=\"bg-popover text-popover-foreground shadow-lg outline-hidden\"\n\t\t\t\t\t\t\tonMouseLeave={() => {\n\t\t\t\t\t\t\t\tsetOnScrollbar(false);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tonMouseEnter={() => {\n\t\t\t\t\t\t\t\tsetOnScrollbar(true);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tonMouseUp={() => {\n\t\t\t\t\t\t\t\tinputRef?.current?.focus();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{isLoading ? (\n\t\t\t\t\t\t\t\t<>{loadingIndicator}</>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t{EmptyItem()}\n\t\t\t\t\t\t\t\t\t{CreatableItem()}\n\t\t\t\t\t\t\t\t\t{!selectFirstItem && (\n\t\t\t\t\t\t\t\t\t\t<CommandItem value=\"-\" className=\"hidden\" />\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t{Object.entries(selectables).map(\n\t\t\t\t\t\t\t\t\t\t([key, dropdowns]) => (\n\t\t\t\t\t\t\t\t\t\t\t<CommandGroup\n\t\t\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\t\t\theading={key}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"h-full overflow-auto\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{dropdowns.map((option) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<CommandItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={option.value}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvalue={option.value}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdisabled={option.disable}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonMouseDown={(e) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonSelect={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tselected.length >=\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tmaxSelected\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonMaxSelected?.(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tselected.length\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetInputValue(\"\");\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst newOptions = [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...selected,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toption,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsetSelected(newOptions);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonChange?.(newOptions);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"cursor-pointer\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toption.disable &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pointer-events-none cursor-not-allowed opacity-50\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</CommandItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t\t\t</CommandGroup>\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</CommandList>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</Command>\n\t);\n};\n\nMultipleSelector.displayName = \"MultipleSelector\";\nexport default MultipleSelector;\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/command.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { SearchIcon } from \"lucide-react\";\n\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from \"./dialog\";\n\nfunction Command({\n\tclassName,\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive>) {\n\treturn (\n\t\t<CommandPrimitive\n\t\t\tdata-slot=\"command\"\n\t\t\tclassName={cn(\n\t\t\t\t\"bg-popover text-popover-foreground flex size-full flex-col overflow-hidden rounded-md\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nfunction CommandDialog({\n\ttitle = \"Command Palette\",\n\tdescription = \"Search for a command to run...\",\n\tchildren,\n\t...props\n}: React.ComponentProps<typeof Dialog> & {\n\ttitle?: string;\n\tdescription?: string;\n}) {\n\treturn (\n\t\t<Dialog {...props}>\n\t\t\t<DialogHeader className=\"sr-only\">\n\t\t\t\t<DialogTitle>{title}</DialogTitle>\n\t\t\t\t<DialogDescription>{description}</DialogDescription>\n\t\t\t</DialogHeader>\n\t\t\t<DialogContent className=\"overflow-hidden p-0 sm:max-w-lg [&>button:last-child]:hidden\">\n\t\t\t\t<Command className=\"**:[[cmdk-group-heading]]:text-muted-foreground max-h-svh data-[slot=command-input-wrapper]:**:h-12 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group]]:px-2 **:[[cmdk-input]]:h-12 **:[[cmdk-item]]:px-3 **:[[cmdk-item]]:py-2\">\n\t\t\t\t\t{children}\n\t\t\t\t</Command>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\nfunction CommandInput({\n\tclassName,\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive.Input>) {\n\treturn (\n\t\t<div\n\t\t\tclassName=\"border-input flex items-center border-b px-5\"\n\t\t\tcmdk-input-wrapper=\"\"\n\t\t>\n\t\t\t<SearchIcon size={20} className=\"text-muted-foreground/80 me-3\" />\n\t\t\t<CommandPrimitive.Input\n\t\t\t\tdata-slot=\"command-input-wrapper\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"placeholder:text-muted-foreground/70 flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nfunction CommandList({\n\tclassName,\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive.List>) {\n\treturn (\n\t\t<CommandPrimitive.List\n\t\t\tdata-slot=\"command-list\"\n\t\t\tclassName={cn(\n\t\t\t\t\"max-h-80 flex-1 overflow-x-hidden overflow-y-auto\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nfunction CommandEmpty({\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive.Empty>) {\n\treturn (\n\t\t<CommandPrimitive.Empty\n\t\t\tdata-slot=\"command-empty\"\n\t\t\tclassName=\"py-6 text-center text-sm\"\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nfunction CommandGroup({\n\tclassName,\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive.Group>) {\n\treturn (\n\t\t<CommandPrimitive.Group\n\t\t\tdata-slot=\"command-group\"\n\t\t\tclassName={cn(\n\t\t\t\t\"text-foreground **:[[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-2 **:[[cmdk-group-heading]]:px-3 **:[[cmdk-group-heading]]:py-2 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nfunction CommandSeparator({\n\tclassName,\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive.Separator>) {\n\treturn (\n\t\t<CommandPrimitive.Separator\n\t\t\tdata-slot=\"command-separator\"\n\t\t\tclassName={cn(\"bg-border -mx-1 h-px\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nfunction CommandItem({\n\tclassName,\n\t...props\n}: React.ComponentProps<typeof CommandPrimitive.Item>) {\n\treturn (\n\t\t<CommandPrimitive.Item\n\t\t\tdata-slot=\"command-item\"\n\t\t\tclassName={cn(\n\t\t\t\t\"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground relative flex cursor-default items-center gap-3 rounded-md px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nfunction CommandShortcut({\n\tclassName,\n\t...props\n}: React.ComponentProps<\"span\">) {\n\treturn (\n\t\t<kbd\n\t\t\tdata-slot=\"command-shortcut\"\n\t\t\tclassName={cn(\n\t\t\t\t\"bg-background text-muted-foreground/70 ms-auto -me-1 inline-flex h-5 max-h-full items-center rounded border px-1 font-[inherit] text-[0.625rem] font-medium\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport {\n\tCommand,\n\tCommandDialog,\n\tCommandEmpty,\n\tCommandGroup,\n\tCommandInput,\n\tCommandItem,\n\tCommandList,\n\tCommandSeparator,\n\tCommandShortcut,\n};\n",
      "type": "registry:ui"
    }
  ]
}