{
  "name": "multiselect-form",
  "type": "registry:ui",
  "registryDependencies": [
    "command",
    "button",
    "form",
    "sonner"
  ],
  "files": [
    {
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport * as z from \"zod\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Form,\n  FormControl,\n  FormField,\n  FormItem,\n  FormMessage,\n} from \"@/components/ui/form\";\nimport MultipleSelector, { type Option } from \"@/registry/ui/multiselect\";\n\nconst characters: Option[] = [\n  {\n    value: \"szechuan-sauce\",\n    label: \"Szechuan Sauce\",\n  },\n  {\n    value: \"portal-gun\",\n    label: \"Portal Gun\",\n  },\n  {\n    value: \"plumbus\",\n    label: \"Plumbus\",\n  },\n  {\n    value: \"meeseeks-box\",\n    label: \"Meeseeks Box\",\n  },\n  {\n    value: \"microverse-battery\",\n    label: \"Microverse Battery (kinda unstable)\",\n  },\n  {\n    value: \"butter-robot\",\n    label: \"Butter Robot (What is my purpose?)\",\n  },\n  {\n    value: \"fleeb-juice\",\n    label: \"Fleeb Juice\",\n  },\n  {\n    value: \"gromflomite-disguise\",\n    label: \"Gromflomite Disguise\",\n  },\n];\n\nconst FormSchema = z.object({\n  items: z.array(z.string()).min(1, {\n    message:\n      \"Gotta pick at least one, Morty! You can't just have *nothing* from the multiverse!\",\n  }),\n});\n\ntype FormValues = z.infer<typeof FormSchema>;\n\nexport default function MultiSelectForm() {\n  const form = useForm<FormValues>({\n    resolver: zodResolver(FormSchema),\n    defaultValues: {\n      items: [],\n    },\n  });\n\n  function onSubmit(data: FormValues) {\n    console.log(\"Selected items:\", data);\n    toast.success(\"Alright, Morty! We got the stuff! Now let's get schwifty!\");\n  }\n\n  return (\n    <Form {...form}>\n      <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n        <FormField\n          control={form.control}\n          name=\"items\"\n          render={({ field }) => (\n            <FormItem className=\"w-full md:w-[400px]\">\n              <FormControl>\n                <MultipleSelector\n                  value={characters.filter((character) =>\n                    field.value.includes(character.value)\n                  )}\n                  options={characters}\n                  placeholder=\"Select items from Rick's garage\"\n                  commandProps={{\n                    label: \"Select items\",\n                  }}\n                  hideClearAllButton\n                  hidePlaceholderWhenSelected\n                  emptyIndicator={\n                    <p className=\"text-center text-sm\">\n                      No items found, Morty! Are you sure you're in the right\n                      dimension?\n                    </p>\n                  }\n                  onChange={(options) => {\n                    field.onChange(options.map((option) => option.value));\n                  }}\n                />\n              </FormControl>\n              <FormMessage />\n            </FormItem>\n          )}\n        />\n        <Button type=\"submit\">Get Schwifty!</Button>\n\n        <p\n          className=\"text-muted-foreground mt-2 text-xs\"\n          role=\"region\"\n          aria-live=\"polite\"\n        >\n          Built with{\" \"}\n          <a\n            className=\"hover:text-foreground underline\"\n            href=\"https://originui.com/select\"\n            target=\"_blank\"\n            rel=\"noopener nofollow\"\n          >\n            origin/ui\n          </a>\n        </p>\n      </form>\n    </Form>\n  );\n}\n",
      "path": "ui/multiselect-form.tsx",
      "target": "components/ui/multiselect-form.tsx"
    },
    {
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { XIcon } from \"lucide-react\";\nimport { forwardRef, useEffect } from \"react\";\nimport { Command as CommandPrimitive, useCommandState } from \"cmdk\";\n\nimport { cn } from \"@/lib/utils\";\nimport {\n  Command,\n  CommandGroup,\n  CommandItem,\n  CommandList,\n} from \"@/components/ui/command\";\n\nexport interface Option {\n  value: string;\n  label: string;\n  disable?: boolean;\n  /** fixed option that can't be removed. */\n  fixed?: boolean;\n  /** Group the options by providing key. */\n  [key: string]: string | boolean | undefined;\n}\n\ninterface GroupOption {\n  [key: string]: Option[];\n}\n\ninterface MultipleSelectorProps {\n  value?: Option[];\n  defaultOptions?: Option[];\n  /** manually controlled options */\n  options?: Option[];\n  placeholder?: string;\n  /** Loading component. */\n  loadingIndicator?: React.ReactNode;\n  /** Empty component. */\n  emptyIndicator?: React.ReactNode;\n  /** Debounce time for async search. Only work with `onSearch`. */\n  delay?: number;\n  /**\n   * Only work with `onSearch` prop. Trigger search when `onFocus`.\n   * For example, when user click on the input, it will trigger the search to get initial options.\n   **/\n  triggerSearchOnFocus?: boolean;\n  /** async search */\n  onSearch?: (value: string) => Promise<Option[]>;\n  /**\n   * sync search. This search will not showing loadingIndicator.\n   * The rest props are the same as async search.\n   * i.e.: creatable, groupBy, delay.\n   **/\n  onSearchSync?: (value: string) => Option[];\n  onChange?: (options: Option[]) => void;\n  /** Limit the maximum number of selected options. */\n  maxSelected?: number;\n  /** When the number of selected options exceeds the limit, the onMaxSelected will be called. */\n  onMaxSelected?: (maxLimit: number) => void;\n  /** Hide the placeholder when there are options selected. */\n  hidePlaceholderWhenSelected?: boolean;\n  disabled?: boolean;\n  /** Group the options base on provided key. */\n  groupBy?: string;\n  className?: string;\n  badgeClassName?: string;\n  /**\n   * First item selected is a default behavior by cmdk. That is why the default is true.\n   * This is a workaround solution by add a dummy item.\n   *\n   * @reference: https://github.com/pacocoursey/cmdk/issues/171\n   */\n  selectFirstItem?: boolean;\n  /** Allow user to create option when there is no option matched. */\n  creatable?: boolean;\n  /** Props of `Command` */\n  commandProps?: React.ComponentPropsWithoutRef<typeof Command>;\n  /** Props of `CommandInput` */\n  inputProps?: Omit<\n    React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>,\n    \"value\" | \"placeholder\" | \"disabled\"\n  >;\n  /** hide the clear all button. */\n  hideClearAllButton?: boolean;\n}\n\nexport interface MultipleSelectorRef {\n  selectedValue: Option[];\n  input: HTMLInputElement;\n  focus: () => void;\n  reset: () => void;\n}\n\nexport function useDebounce<T>(value: T, delay?: number): T {\n  const [debouncedValue, setDebouncedValue] = React.useState<T>(value);\n\n  useEffect(() => {\n    const timer = setTimeout(() => setDebouncedValue(value), delay || 500);\n\n    return () => {\n      clearTimeout(timer);\n    };\n  }, [value, delay]);\n\n  return debouncedValue;\n}\n\nfunction transToGroupOption(options: Option[], groupBy?: string) {\n  if (options.length === 0) {\n    return {};\n  }\n  if (!groupBy) {\n    return {\n      \"\": options,\n    };\n  }\n\n  const groupOption: GroupOption = {};\n  options.forEach((option) => {\n    const key = (option[groupBy] as string) || \"\";\n    if (!groupOption[key]) {\n      groupOption[key] = [];\n    }\n    groupOption[key].push(option);\n  });\n  return groupOption;\n}\n\nfunction removePickedOption(groupOption: GroupOption, picked: Option[]) {\n  const cloneOption = JSON.parse(JSON.stringify(groupOption)) as GroupOption;\n\n  for (const [key, value] of Object.entries(cloneOption)) {\n    cloneOption[key] = value.filter(\n      (val) => !picked.find((p) => p.value === val.value)\n    );\n  }\n  return cloneOption;\n}\n\nfunction isOptionsExist(groupOption: GroupOption, targetOption: Option[]) {\n  for (const [, value] of Object.entries(groupOption)) {\n    if (\n      value.some((option) => targetOption.find((p) => p.value === option.value))\n    ) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * The `CommandEmpty` of shadcn/ui will cause the cmdk empty not rendering correctly.\n * So we create one and copy the `Empty` implementation from `cmdk`.\n *\n * @reference: https://github.com/hsuanyi-chou/shadcn-ui-expansions/issues/34#issuecomment-1949561607\n **/\nconst CommandEmpty = forwardRef<\n  HTMLDivElement,\n  React.ComponentProps<typeof CommandPrimitive.Empty>\n>(({ className, ...props }, forwardedRef) => {\n  // @ts-ignore\n  const render = useCommandState((state) => state.filtered.count === 0);\n\n  if (!render) return null;\n\n  return (\n    <div\n      ref={forwardedRef}\n      className={cn(\"px-2 py-4 text-center text-sm\", className)}\n      cmdk-empty=\"\"\n      role=\"presentation\"\n      {...props}\n    />\n  );\n});\n\nCommandEmpty.displayName = \"CommandEmpty\";\n\nconst MultipleSelector = React.forwardRef<\n  MultipleSelectorRef,\n  MultipleSelectorProps\n>(\n  (\n    {\n      value,\n      onChange,\n      placeholder,\n      defaultOptions: arrayDefaultOptions = [],\n      options: arrayOptions,\n      delay,\n      onSearch,\n      onSearchSync,\n      loadingIndicator,\n      emptyIndicator,\n      maxSelected = Number.MAX_SAFE_INTEGER,\n      onMaxSelected,\n      hidePlaceholderWhenSelected,\n      disabled,\n      groupBy,\n      className,\n      badgeClassName,\n      selectFirstItem = true,\n      creatable = false,\n      triggerSearchOnFocus = false,\n      commandProps,\n      inputProps,\n      hideClearAllButton = false,\n    }: MultipleSelectorProps,\n    ref: React.Ref<MultipleSelectorRef>\n  ) => {\n    const inputRef = React.useRef<HTMLInputElement>(null);\n    const [open, setOpen] = React.useState(false);\n    const [onScrollbar, setOnScrollbar] = React.useState(false);\n    const [isLoading, setIsLoading] = React.useState(false);\n    const dropdownRef = React.useRef<HTMLDivElement>(null); // Added this\n\n    const [selected, setSelected] = React.useState<Option[]>(value || []);\n    const [options, setOptions] = React.useState<GroupOption>(\n      transToGroupOption(arrayDefaultOptions, groupBy)\n    );\n    const [inputValue, setInputValue] = React.useState(\"\");\n    const debouncedSearchTerm = useDebounce(inputValue, delay || 500);\n\n    React.useImperativeHandle(\n      ref,\n      () => ({\n        selectedValue: [...selected],\n        input: inputRef.current as HTMLInputElement,\n        focus: () => inputRef?.current?.focus(),\n        reset: () => setSelected([]),\n      }),\n      [selected]\n    );\n\n    const handleClickOutside = (event: MouseEvent | TouchEvent) => {\n      if (\n        dropdownRef.current &&\n        !dropdownRef.current.contains(event.target as Node) &&\n        inputRef.current &&\n        !inputRef.current.contains(event.target as Node)\n      ) {\n        setOpen(false);\n        inputRef.current.blur();\n      }\n    };\n\n    const handleUnselect = React.useCallback(\n      (option: Option) => {\n        const newOptions = selected.filter((s) => s.value !== option.value);\n        setSelected(newOptions);\n        onChange?.(newOptions);\n      },\n      [onChange, selected]\n    );\n\n    const handleKeyDown = React.useCallback(\n      (e: React.KeyboardEvent<HTMLDivElement>) => {\n        const input = inputRef.current;\n        if (input) {\n          if (e.key === \"Delete\" || e.key === \"Backspace\") {\n            if (input.value === \"\" && selected.length > 0) {\n              const lastSelectOption = selected[selected.length - 1];\n              // If last item is fixed, we should not remove it.\n              if (!lastSelectOption.fixed) {\n                handleUnselect(selected[selected.length - 1]);\n              }\n            }\n          }\n          // This is not a default behavior of the <input /> field\n          if (e.key === \"Escape\") {\n            input.blur();\n          }\n        }\n      },\n      [handleUnselect, selected]\n    );\n\n    useEffect(() => {\n      if (open) {\n        document.addEventListener(\"mousedown\", handleClickOutside);\n        document.addEventListener(\"touchend\", handleClickOutside);\n      } else {\n        document.removeEventListener(\"mousedown\", handleClickOutside);\n        document.removeEventListener(\"touchend\", handleClickOutside);\n      }\n\n      return () => {\n        document.removeEventListener(\"mousedown\", handleClickOutside);\n        document.removeEventListener(\"touchend\", handleClickOutside);\n      };\n    }, [open]);\n\n    useEffect(() => {\n      if (value) {\n        setSelected(value);\n      }\n    }, [value]);\n\n    useEffect(() => {\n      /** If `onSearch` is provided, do not trigger options updated. */\n      if (!arrayOptions || onSearch) {\n        return;\n      }\n      const newOption = transToGroupOption(arrayOptions || [], groupBy);\n      if (JSON.stringify(newOption) !== JSON.stringify(options)) {\n        setOptions(newOption);\n      }\n    }, [arrayDefaultOptions, arrayOptions, groupBy, onSearch, options]);\n\n    useEffect(() => {\n      /** sync search */\n\n      const doSearchSync = () => {\n        const res = onSearchSync?.(debouncedSearchTerm);\n        setOptions(transToGroupOption(res || [], groupBy));\n      };\n\n      const exec = async () => {\n        if (!onSearchSync || !open) return;\n\n        if (triggerSearchOnFocus) {\n          doSearchSync();\n        }\n\n        if (debouncedSearchTerm) {\n          doSearchSync();\n        }\n      };\n\n      void exec();\n      // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]);\n\n    useEffect(() => {\n      /** async search */\n\n      const doSearch = async () => {\n        setIsLoading(true);\n        const res = await onSearch?.(debouncedSearchTerm);\n        setOptions(transToGroupOption(res || [], groupBy));\n        setIsLoading(false);\n      };\n\n      const exec = async () => {\n        if (!onSearch || !open) return;\n\n        if (triggerSearchOnFocus) {\n          await doSearch();\n        }\n\n        if (debouncedSearchTerm) {\n          await doSearch();\n        }\n      };\n\n      void exec();\n      // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, [debouncedSearchTerm, groupBy, open, triggerSearchOnFocus]);\n\n    const CreatableItem = () => {\n      if (!creatable) return undefined;\n      if (\n        isOptionsExist(options, [{ value: inputValue, label: inputValue }]) ||\n        selected.find((s) => s.value === inputValue)\n      ) {\n        return undefined;\n      }\n\n      const Item = (\n        <CommandItem\n          value={inputValue}\n          className=\"cursor-pointer\"\n          // @ts-ignore\n          onMouseDown={(e) => {\n            e.preventDefault();\n            e.stopPropagation();\n          }}\n          onSelect={(value: string) => {\n            if (selected.length >= maxSelected) {\n              onMaxSelected?.(selected.length);\n              return;\n            }\n            setInputValue(\"\");\n            const newOptions = [...selected, { value, label: value }];\n            setSelected(newOptions);\n            onChange?.(newOptions);\n          }}\n        >\n          {`Create \"${inputValue}\"`}\n        </CommandItem>\n      );\n\n      // For normal creatable\n      if (!onSearch && inputValue.length > 0) {\n        return Item;\n      }\n\n      // For async search creatable. avoid showing creatable item before loading at first.\n      if (onSearch && debouncedSearchTerm.length > 0 && !isLoading) {\n        return Item;\n      }\n\n      return undefined;\n    };\n\n    const EmptyItem = React.useCallback(() => {\n      if (!emptyIndicator) return undefined;\n\n      // For async search that showing emptyIndicator\n      if (onSearch && !creatable && Object.keys(options).length === 0) {\n        return (\n          <CommandItem value=\"-\" disabled>\n            {emptyIndicator}\n          </CommandItem>\n        );\n      }\n\n      return <CommandEmpty>{emptyIndicator}</CommandEmpty>;\n    }, [creatable, emptyIndicator, onSearch, options]);\n\n    const selectables = React.useMemo<GroupOption>(\n      () => removePickedOption(options, selected),\n      [options, selected]\n    );\n\n    /** Avoid Creatable Selector freezing or lagging when paste a long string. */\n    const commandFilter = React.useCallback(() => {\n      if (commandProps?.filter) {\n        return commandProps.filter;\n      }\n\n      if (creatable) {\n        return (value: string, search: string) => {\n          return value.toLowerCase().includes(search.toLowerCase()) ? 1 : -1;\n        };\n      }\n      // Using default filter in `cmdk`. We don&lsquo;t have to provide it.\n      return undefined;\n    }, [creatable, commandProps?.filter]);\n\n    return (\n      <Command\n        ref={dropdownRef}\n        {...commandProps}\n        // @ts-ignore\n        onKeyDown={(e) => {\n          handleKeyDown(e);\n          commandProps?.onKeyDown?.(e);\n        }}\n        className={cn(\n          \"h-auto overflow-visible bg-transparent\",\n          commandProps?.className\n        )}\n        shouldFilter={\n          commandProps?.shouldFilter !== undefined\n            ? commandProps.shouldFilter\n            : !onSearch\n        } // When onSearch is provided, we don&lsquo;t want to filter the options. You can still override it.\n        filter={commandFilter()}\n      >\n        <div\n          className={cn(\n            \"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-none focus-within:ring-[3px] has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50\",\n            {\n              \"p-1\": selected.length !== 0,\n              \"cursor-text\": !disabled && selected.length !== 0,\n            },\n            !hideClearAllButton && \"pe-9\",\n            className\n          )}\n          onClick={() => {\n            if (disabled) return;\n            inputRef?.current?.focus();\n          }}\n        >\n          <div className=\"flex flex-wrap gap-1\">\n            {selected.map((option) => {\n              return (\n                <div\n                  key={option.value}\n                  className={cn(\n                    \"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                    badgeClassName\n                  )}\n                  data-fixed={option.fixed}\n                  data-disabled={disabled || undefined}\n                >\n                  {option.label}\n                  <button\n                    className=\"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-none focus-visible:ring-[3px]\"\n                    onKeyDown={(e) => {\n                      if (e.key === \"Enter\") {\n                        handleUnselect(option);\n                      }\n                    }}\n                    onMouseDown={(e) => {\n                      e.preventDefault();\n                      e.stopPropagation();\n                    }}\n                    onClick={() => handleUnselect(option)}\n                    aria-label=\"Remove\"\n                  >\n                    <XIcon size={14} aria-hidden=\"true\" />\n                  </button>\n                </div>\n              );\n            })}\n            {/* Avoid having the \"Search\" Icon */}\n            <CommandPrimitive.Input\n              {...inputProps}\n              ref={inputRef}\n              value={inputValue}\n              disabled={disabled}\n              // @ts-ignore\n              onValueChange={(value) => {\n                setInputValue(value);\n                inputProps?.onValueChange?.(value);\n              }}\n              // @ts-ignore\n              onBlur={(event) => {\n                if (!onScrollbar) {\n                  setOpen(false);\n                }\n                inputProps?.onBlur?.(event);\n              }}\n              // @ts-ignore\n              onFocus={(event) => {\n                setOpen(true);\n                if (triggerSearchOnFocus) {\n                  onSearch?.(debouncedSearchTerm);\n                }\n                inputProps?.onFocus?.(event);\n              }}\n              placeholder={\n                hidePlaceholderWhenSelected && selected.length !== 0\n                  ? \"\"\n                  : placeholder\n              }\n              className={cn(\n                \"placeholder:text-muted-foreground/70 flex-1 bg-transparent outline-hidden disabled:cursor-not-allowed\",\n                {\n                  \"w-full\": hidePlaceholderWhenSelected,\n                  \"px-3 py-2\": selected.length === 0,\n                  \"ml-1\": selected.length !== 0,\n                },\n                inputProps?.className\n              )}\n            />\n            <button\n              type=\"button\"\n              onClick={() => {\n                setSelected(selected.filter((s) => s.fixed));\n                onChange?.(selected.filter((s) => s.fixed));\n              }}\n              className={cn(\n                \"text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute end-0 top-0 flex size-9 items-center justify-center rounded-md border border-transparent transition-[color,box-shadow] outline-none focus-visible:ring-[3px]\",\n                (hideClearAllButton ||\n                  disabled ||\n                  selected.length < 1 ||\n                  selected.filter((s) => s.fixed).length === selected.length) &&\n                  \"hidden\"\n              )}\n              aria-label=\"Clear all\"\n            >\n              <XIcon size={16} aria-hidden=\"true\" />\n            </button>\n          </div>\n        </div>\n        <div className=\"relative\">\n          <div\n            className={cn(\n              \"border-input absolute top-2 z-10 w-full overflow-hidden rounded-md border\",\n              \"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              !open && \"hidden\"\n            )}\n            data-state={open ? \"open\" : \"closed\"}\n          >\n            {open && (\n              <CommandList\n                className=\"bg-popover text-popover-foreground shadow-lg outline-hidden\"\n                onMouseLeave={() => {\n                  setOnScrollbar(false);\n                }}\n                onMouseEnter={() => {\n                  setOnScrollbar(true);\n                }}\n                onMouseUp={() => {\n                  inputRef?.current?.focus();\n                }}\n              >\n                {isLoading ? (\n                  <>{loadingIndicator}</>\n                ) : (\n                  <>\n                    {EmptyItem()}\n                    {CreatableItem()}\n                    {!selectFirstItem && (\n                      <CommandItem value=\"-\" className=\"hidden\" />\n                    )}\n                    {Object.entries(selectables).map(([key, dropdowns]) => (\n                      <CommandGroup\n                        key={key}\n                        heading={key}\n                        className=\"h-full overflow-auto\"\n                      >\n                        <>\n                          {dropdowns.map((option) => {\n                            return (\n                              <CommandItem\n                                key={option.value}\n                                value={option.value}\n                                disabled={option.disable}\n                                // @ts-ignore\n                                onMouseDown={(e) => {\n                                  e.preventDefault();\n                                  e.stopPropagation();\n                                }}\n                                onSelect={() => {\n                                  if (selected.length >= maxSelected) {\n                                    onMaxSelected?.(selected.length);\n                                    return;\n                                  }\n                                  setInputValue(\"\");\n                                  const newOptions = [...selected, option];\n                                  setSelected(newOptions);\n                                  onChange?.(newOptions);\n                                }}\n                                className={cn(\n                                  \"cursor-pointer\",\n                                  option.disable &&\n                                    \"pointer-events-none cursor-not-allowed opacity-50\"\n                                )}\n                              >\n                                {option.label}\n                              </CommandItem>\n                            );\n                          })}\n                        </>\n                      </CommandGroup>\n                    ))}\n                  </>\n                )}\n              </CommandList>\n            )}\n          </div>\n        </div>\n      </Command>\n    );\n  }\n);\n\nMultipleSelector.displayName = \"MultipleSelector\";\nexport default MultipleSelector;\n",
      "path": "ui/multiselect.tsx",
      "target": "components/ui/multiselect.tsx"
    }
  ]
}