{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "multi-selector",
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "./components/ui/multi-selector.tsx",
      "content": "'use client';\nimport { Button } from '@/components/website/ui/button';\nimport {\n  Command,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n} from '@/components/website/ui/command';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/website/ui/popover';\nimport { cn } from '@/lib/utils';\nimport { CheckIcon, ChevronDown, XCircle, XIcon } from 'lucide-react';\nimport * as React from 'react';\n\n/**\n * Props for MultiSelect component\n */\ninterface MultiSelectProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  /**\n   * An array of option objects to be displayed in the multi-select component.\n   * Each option object has a label, value, and an optional icon.\n   */\n  options: {\n    /** The text to display for the option. */\n    label: string;\n    /** The unique value associated with the option. */\n    value: string;\n    /** Optional icon component to display alongside the option. */\n    icon?: React.ComponentType<{ className?: string }>;\n    disable?: boolean;\n  }[];\n\n  /**\n   * Callback function triggered when the selected values change.\n   * Receives an array of the new selected values.\n   */\n  onValueChange: (value: string[]) => void;\n\n  /** The default selected values when the component mounts. */\n  defaultValue?: string[];\n\n  /**\n   * Placeholder text to be displayed when no values are selected.\n   * Optional, defaults to \"Select options\".\n   */\n  placeholder?: string;\n\n  /**\n   * Animation duration in seconds for the visual effects (e.g., bouncing badges).\n   * Optional, defaults to 0 (no animation).\n   */\n  animation?: number;\n\n  /**\n   * Maximum number of items to display. Extra selected items will be summarized.\n   * Optional, defaults to 3.\n   */\n  maxCount?: number;\n\n  /**\n   * The modality of the popover. When set to true, interaction with outside elements\n   * will be disabled and only popover content will be visible to screen readers.\n   * Optional, defaults to false.\n   */\n  modalPopover?: boolean;\n\n  /**\n   * If true, renders the multi-select component as a child of another component.\n   * Optional, defaults to false.\n   */\n  asChild?: boolean;\n\n  /**\n   * Additional class names to apply custom styles to the multi-select component.\n   * Optional, can be used to add custom styles.\n   */\n  className?: string;\n  popoverClass?: string;\n  showall?: boolean;\n}\n\nexport const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(\n  (\n    {\n      options,\n      onValueChange,\n      defaultValue = [],\n      placeholder = 'Select options',\n      animation = 0,\n      maxCount = 3,\n      modalPopover = false,\n      asChild = false,\n      className,\n      popoverClass,\n      showall = false,\n      ...props\n    },\n    ref\n  ) => {\n    const [selectedValues, setSelectedValues] = React.useState<string[]>(defaultValue);\n    const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);\n\n    const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n      if (event.key === 'Enter') {\n        setIsPopoverOpen(true);\n      } else if (event.key === 'Backspace' && !event.currentTarget.value) {\n        const newSelectedValues = [...selectedValues];\n        newSelectedValues.pop();\n        setSelectedValues(newSelectedValues);\n        onValueChange(newSelectedValues);\n      }\n    };\n\n    const toggleOption = (option: string) => {\n      const newSelectedValues = selectedValues.includes(option)\n        ? selectedValues.filter((value) => value !== option)\n        : [...selectedValues, option];\n      setSelectedValues(newSelectedValues);\n      onValueChange(newSelectedValues);\n    };\n\n    const handleClear = () => {\n      setSelectedValues([]);\n      onValueChange([]);\n    };\n\n    const handleTogglePopover = () => {\n      setIsPopoverOpen((prev) => !prev);\n    };\n\n    const clearExtraOptions = () => {\n      const newSelectedValues = selectedValues.slice(0, maxCount);\n      setSelectedValues(newSelectedValues);\n      onValueChange(newSelectedValues);\n    };\n    const filteredOptions = options.filter((option) => !option.disable);\n    const toggleAll = () => {\n      if (selectedValues.length === filteredOptions.length) {\n        handleClear();\n      } else {\n        const allValues = filteredOptions.map((option) => option.value);\n        setSelectedValues(allValues);\n        onValueChange(allValues);\n      }\n    };\n\n    return (\n      <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal={modalPopover}>\n        <PopoverTrigger asChild>\n          <Button\n            ref={ref}\n            {...props}\n            onClick={handleTogglePopover}\n            className={cn(\n              'flex w-full p-1 rounded-md border min-h-10 h-auto items-center justify-between hover:bg-neutral-100 dark:bg-neutral-900 bg-neutral-50 dark:hover:bg-neutral-950',\n              className\n            )}\n          >\n            {selectedValues.length > 0 ? (\n              <div className='flex justify-between items-center w-full'>\n                <div className='flex flex-wrap items-center  gap-1 p-1'>\n                  {(showall ? selectedValues : selectedValues.slice(0, maxCount)).map((value) => {\n                    const option = options.find((o) => o.value === value);\n                    const IconComponent = option?.icon;\n                    return (\n                      <div\n                        key={value}\n                        className={cn(\n                          'inline-flex items-center rounded-lg px-2 py-1 text-xs font-semibold dark:bg-neutral-950 bg-neutral-200 text-primary'\n                        )}\n                      >\n                        {IconComponent && <IconComponent className='h-4 w-4 mr-2' />}\n                        {option?.label}\n                        <XCircle\n                          className='ml-2 h-4 w-4 cursor-pointer'\n                          onClick={(event) => {\n                            event.stopPropagation();\n                            toggleOption(value);\n                          }}\n                        />\n                      </div>\n                    );\n                  })}\n                  {!showall && selectedValues.length > maxCount && (\n                    <div\n                      className={cn(\n                        'bg-primary-foreground inline-flex items-center border px-2 py-0.5 rounded-lg text-foreground border-foreground/1 hover:bg-transparent'\n                      )}\n                      style={{ animationDuration: `${animation}s` }}\n                    >\n                      {`+ ${selectedValues.length - maxCount} more`}\n                      <XCircle\n                        className='ml-2 h-4 w-4 cursor-pointer'\n                        onClick={(event) => {\n                          event.stopPropagation();\n                          clearExtraOptions();\n                        }}\n                      />\n                    </div>\n                  )}\n                </div>\n                <div className='flex items-center justify-between'>\n                  <XIcon\n                    className='h-4 mx-2 cursor-pointer text-primary'\n                    onClick={(event) => {\n                      event.stopPropagation();\n                      handleClear();\n                    }}\n                  />\n                  {/* <Separator\n                    orientation=\"vertical\"\n                    className=\"flex min-h-6 h-full\"\n                  /> */}\n                  <ChevronDown className='h-4 mx-2 cursor-pointer text-primary' />\n                </div>\n              </div>\n            ) : (\n              <div className='flex items-center justify-between w-full mx-auto'>\n                <span className='text-sm text-muted-foreground mx-3'>{placeholder}</span>\n                <ChevronDown className='h-4 cursor-pointer text-muted-foreground mx-2' />\n              </div>\n            )}\n          </Button>\n        </PopoverTrigger>\n        <PopoverContent\n          className={cn('w-auto p-0', popoverClass)}\n          align='start'\n          onEscapeKeyDown={() => setIsPopoverOpen(false)}\n        >\n          <Command>\n            <CommandInput placeholder='Search...' onKeyDown={handleInputKeyDown} />\n            <CommandList>\n              <CommandEmpty>No results found.</CommandEmpty>\n              <CommandGroup>\n                <CommandItem key='all' onSelect={toggleAll} className='cursor-pointer'>\n                  <div\n                    className={cn(\n                      'mr-2 flex h-4 w-4 items-center justify-center rounded-xs border border-primary',\n                      selectedValues.length === filteredOptions.length\n                        ? 'bg-primary text-primary-foreground'\n                        : 'opacity-50 [&_svg]:invisible'\n                    )}\n                  >\n                    <CheckIcon className='h-4 w-4' />\n                  </div>\n                  <span>(Select All)</span>\n                </CommandItem>\n                {options.map((option) => {\n                  const isSelected = selectedValues.includes(option.value);\n                  const isDisabled = option.disable; // Check if option is disabled\n\n                  return (\n                    <CommandItem\n                      key={option.value}\n                      onSelect={() => !isDisabled && toggleOption(option.value)}\n                      className={cn(\n                        'cursor-pointer',\n                        isDisabled && 'opacity-50 cursor-not-allowed' // Disable styling\n                      )}\n                    >\n                      <div\n                        className={cn(\n                          'mr-2 flex h-4 w-4 items-center justify-center rounded-xs border border-primary',\n                          isSelected\n                            ? 'bg-primary text-primary-foreground'\n                            : 'opacity-50 [&_svg]:invisible'\n                        )}\n                      >\n                        {!isDisabled && <CheckIcon className='h-4 w-4' />}\n                      </div>\n                      {option.icon && (\n                        <option.icon\n                          className={cn('mr-2 h-4 w-4', isDisabled ? 'text-muted-foreground' : '')}\n                        />\n                      )}\n                      <span>{option.label}</span>\n                    </CommandItem>\n                  );\n                })}\n              </CommandGroup>\n              <CommandSeparator />\n              <CommandGroup>\n                <div className='flex items-center justify-between'>\n                  {selectedValues.length > 0 && (\n                    <>\n                      <CommandItem\n                        onSelect={handleClear}\n                        className='flex-1 justify-center cursor-pointer border-r'\n                      >\n                        Clear\n                      </CommandItem>\n                    </>\n                  )}\n                  <CommandItem\n                    onSelect={() => setIsPopoverOpen(false)}\n                    className='flex-1 justify-center cursor-pointer max-w-full'\n                  >\n                    Close\n                  </CommandItem>\n                </div>\n              </CommandGroup>\n            </CommandList>\n          </Command>\n        </PopoverContent>\n      </Popover>\n    );\n  }\n);\n\nMultiSelect.displayName = 'MultiSelect';\n",
      "type": "registry:component"
    },
    {
      "path": "./components/website/ui/button.tsx",
      "content": "import { Slot } from '@radix-ui/react-slot';\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\nconst buttonVariants = cva(\n  'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',\n  {\n    variants: {\n      variant: {\n        default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n        destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',\n        outline:\n          'border border-input dark:bg-neutral-800 bg-neutral-50 hover:bg-accent hover:text-accent-foreground',\n        secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n        ghost: 'hover:bg-accent hover:text-accent-foreground',\n        link: 'text-primary underline-offset-4 hover:underline',\n        uilayouts:\n          'dark:bg-zinc-900 bg-neutral-200 dark:text-white text-black border dark:border-neutral-800',\n      },\n      size: {\n        default: 'h-10 px-4 py-2',\n        sm: 'h-9 rounded-md px-3',\n        lg: 'h-11 rounded-md px-8',\n        icon: 'h-10 w-10',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      size: 'default',\n    },\n  }\n);\n\nexport interface ButtonProps\n  extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n    VariantProps<typeof buttonVariants> {\n  asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n  ({ className, variant, size, asChild = false, ...props }, ref) => {\n    const Comp = asChild ? Slot : 'button';\n    return (\n      <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />\n    );\n  }\n);\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n",
      "type": "registry:component"
    },
    {
      "path": "./components/website/ui/popover.tsx",
      "content": "'use client';\n\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\nimport * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\nconst Popover = PopoverPrimitive.Root;\n\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\nconst PopoverContent = React.forwardRef<\n  React.ElementRef<typeof PopoverPrimitive.Content>,\n  React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (\n  <PopoverPrimitive.Portal>\n    <PopoverPrimitive.Content\n      ref={ref}\n      align={align}\n      sideOffset={sideOffset}\n      className={cn(\n        'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n        className\n      )}\n      {...props}\n    />\n  </PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = PopoverPrimitive.Content.displayName;\n\nexport { Popover, PopoverContent, PopoverTrigger };\n",
      "type": "registry:component"
    },
    {
      "path": "./components/website/ui/command.tsx",
      "content": "'use client';\n\nimport { Dialog, DialogContent } from '@/components/website/ui/dialog';\nimport { cn } from '@/lib/utils';\nimport type { DialogProps } from '@radix-ui/react-dialog';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport { Search } from 'lucide-react';\nimport * as React from 'react';\n\nconst Command = React.forwardRef<\n  React.ElementRef<typeof CommandPrimitive>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive>\n>(({ className, ...props }, ref) => (\n  <CommandPrimitive\n    ref={ref}\n    className={cn(\n      'flex h-full w-full flex-col overflow-hidden rounded-md dark:bg-neutral-800 bg-neutral-50 text-popover-foreground',\n      className\n    )}\n    {...props}\n  />\n));\nCommand.displayName = CommandPrimitive.displayName;\n\ninterface CommandDialogProps extends DialogProps {}\n\nconst CommandDialog = ({ children, ...props }: CommandDialogProps) => {\n  return (\n    <Dialog {...props}>\n      <DialogContent className='overflow-hidden p-0'>\n        <Command className='[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5'>\n          {children}\n        </Command>\n      </DialogContent>\n    </Dialog>\n  );\n};\n\nconst CommandInput = React.forwardRef<\n  React.ElementRef<typeof CommandPrimitive.Input>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(({ className, ...props }, ref) => (\n  <div className='flex items-center border-b px-3' cmdk-input-wrapper=''>\n    <Search className='mr-2 h-4 w-4 shrink-0 opacity-50' />\n    <CommandPrimitive.Input\n      ref={ref}\n      className={cn(\n        'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',\n        className\n      )}\n      {...props}\n    />\n  </div>\n));\n\nCommandInput.displayName = CommandPrimitive.Input.displayName;\n\nconst CommandList = React.forwardRef<\n  React.ElementRef<typeof CommandPrimitive.List>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>\n>(({ className, ...props }, ref) => (\n  <CommandPrimitive.List\n    ref={ref}\n    className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}\n    {...props}\n  />\n));\n\nCommandList.displayName = CommandPrimitive.List.displayName;\n\nconst CommandEmpty = React.forwardRef<\n  React.ElementRef<typeof CommandPrimitive.Empty>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>\n>((props, ref) => (\n  <CommandPrimitive.Empty ref={ref} className='py-6 text-center text-sm' {...props} />\n));\n\nCommandEmpty.displayName = CommandPrimitive.Empty.displayName;\n\nconst CommandGroup = React.forwardRef<\n  React.ElementRef<typeof CommandPrimitive.Group>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>\n>(({ className, ...props }, ref) => (\n  <CommandPrimitive.Group\n    ref={ref}\n    className={cn(\n      'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',\n      className\n    )}\n    {...props}\n  />\n));\n\nCommandGroup.displayName = CommandPrimitive.Group.displayName;\n\nconst CommandSeparator = React.forwardRef<\n  React.ElementRef<typeof CommandPrimitive.Separator>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n  <CommandPrimitive.Separator\n    ref={ref}\n    className={cn('-mx-1 h-px bg-border', className)}\n    {...props}\n  />\n));\nCommandSeparator.displayName = CommandPrimitive.Separator.displayName;\n\nconst CommandItem = React.forwardRef<\n  React.ElementRef<typeof CommandPrimitive.Item>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>\n>(({ className, ...props }, ref) => (\n  <CommandPrimitive.Item\n    ref={ref}\n    className={cn(\n      'relative flex cursor-default select-none items-center rounded-xs px-2 py-1.5 text-sm outline-hidden dark:aria-selected:bg-neutral-950 aria-selected:bg-neutral-200 aria-selected:text-accent-foreground data-[disabled=\"true\"]:pointer-events-none data-[disabled=\"true\"]:opacity-50',\n      className\n    )}\n    {...props}\n  />\n));\n\nCommandItem.displayName = CommandPrimitive.Item.displayName;\n\nconst CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {\n  return (\n    <span\n      className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n      {...props}\n    />\n  );\n};\nCommandShortcut.displayName = 'CommandShortcut';\n\nexport {\n  Command,\n  CommandDialog,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n  CommandShortcut,\n};\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}