{"version":3,"sources":["../../../../components/ui/extension/multi-select.tsx"],"sourcesContent":["\"use client\";\nimport { Badge } from '../badge';\nimport { Command, CommandItem, CommandEmpty, CommandList } from '../command';\nimport { IconX, IconCheck } from '@tabler/icons-react';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport React, { type KeyboardEvent, createContext, forwardRef, useCallback, useContext, useState } from 'react';\n\nimport { cn } from '../../../utils/ui';\n\nexport type MultiSelectValue = {\n  value: string;\n  label: string;\n};\n\ninterface MultiSelectorProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive> {\n  values: MultiSelectValue[];\n  onValuesChange: (value: MultiSelectValue[]) => void;\n  loop?: boolean;\n  className?: string;\n  children?: React.ReactNode;\n  dir?: 'ltr' | 'rtl';\n}\n\ninterface MultiSelectContextProps {\n  value: MultiSelectValue[];\n  onValueChange: (value: any) => void;\n  open: boolean;\n  setOpen: (value: boolean) => void;\n  inputValue: string;\n  setInputValue: React.Dispatch<React.SetStateAction<string>>;\n  activeIndex: number;\n  setActiveIndex: React.Dispatch<React.SetStateAction<number>>;\n  ref: React.RefObject<HTMLInputElement | null>;\n}\n\nconst MultiSelectContext = createContext<MultiSelectContextProps | null>(null);\n\nconst useMultiSelect = () => {\n  const context = useContext(MultiSelectContext);\n  if (!context) {\n    throw new Error('useMultiSelect must be used within MultiSelectProvider');\n  }\n  return context;\n};\n\n/**\n * MultiSelect Docs: {@link: https://shadcn-extension.vercel.app/docs/multi-select}\n */\n\n// TODO : expose the visibility of the popup\n\nfunction searchForValue(source: MultiSelectValue[], value: MultiSelectValue) {\n  for (let i = 0; i < source.length; i++) {\n    if (source[i].value === value.value) {\n      return i;\n    }\n  }\n  return -1;\n}\n\nconst MultiSelector = ({\n  values: value,\n  onValuesChange: onValueChange,\n  loop = false,\n  className,\n  children,\n  dir,\n  ...props\n}: MultiSelectorProps) => {\n  const [inputValue, setInputValue] = useState('');\n  const [open, setOpen] = useState<boolean>(false);\n  const [activeIndex, setActiveIndex] = useState<number>(-1);\n  const inputRef = React.useRef<HTMLInputElement>(null);\n\n  const onValueChangeHandler = useCallback(\n    (val: MultiSelectValue) => {\n      const element = searchForValue(value, val);\n      if (element !== -1) {\n        onValueChange(value.filter((_, index) => index !== element));\n      } else {\n        onValueChange([...value, val]);\n      }\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [value],\n  );\n\n  const handleKeyDown = useCallback(\n    (e: KeyboardEvent<HTMLDivElement>) => {\n      e.stopPropagation();\n      const target = inputRef.current;\n\n      if (!target) return;\n\n      const selectionStart = target.selectionStart ?? 0;\n      const selectionEnd = target.selectionEnd ?? 0;\n\n      // If there's a selection, do nothing and let the default behavior take over\n      if (selectionStart !== selectionEnd) {\n        return;\n      }\n\n      const moveNext = () => {\n        const nextIndex = activeIndex + 1;\n        setActiveIndex(nextIndex > value.length - 1 ? (loop ? 0 : -1) : nextIndex);\n      };\n\n      const movePrev = () => {\n        const prevIndex = activeIndex - 1;\n        setActiveIndex(prevIndex < 0 ? value.length - 1 : prevIndex);\n      };\n\n      const moveCurrent = () => {\n        const newIndex = activeIndex - 1 <= 0 ? (value.length - 1 === 0 ? -1 : 0) : activeIndex - 1;\n        setActiveIndex(newIndex);\n      };\n\n      switch (e.key) {\n        case 'ArrowLeft':\n          if (dir === 'rtl') {\n            if (value.length > 0 && (activeIndex !== -1 || loop)) {\n              moveNext();\n            }\n          } else {\n            if (value.length > 0 && target.selectionStart === 0) {\n              movePrev();\n            }\n          }\n          break;\n\n        case 'ArrowRight':\n          if (dir === 'rtl') {\n            if (value.length > 0 && target.selectionStart === 0) {\n              movePrev();\n            }\n          } else {\n            if (value.length > 0 && (activeIndex !== -1 || loop)) {\n              moveNext();\n            }\n          }\n          break;\n\n        case 'Backspace':\n        case 'Delete':\n          if (value.length > 0) {\n            if (activeIndex !== -1 && activeIndex < value.length) {\n              onValueChangeHandler(value[activeIndex]);\n              moveCurrent();\n            } else {\n              if (target.selectionStart === 0) {\n                onValueChangeHandler(value[value.length - 1]);\n              }\n            }\n          }\n          break;\n\n        case 'Enter':\n          setOpen(true);\n          break;\n\n        case 'Escape':\n          if (activeIndex !== -1) {\n            setActiveIndex(-1);\n          } else if (open) {\n            setInputValue('');\n            setOpen(false);\n          }\n          break;\n      }\n    },\n    [value, activeIndex, loop],\n  );\n\n  return (\n    <MultiSelectContext.Provider\n      value={{\n        value,\n        onValueChange: onValueChangeHandler,\n        open,\n        setOpen,\n        inputValue,\n        setInputValue,\n        activeIndex,\n        setActiveIndex,\n        ref: inputRef,\n      }}\n    >\n      <Command\n        onKeyDown={handleKeyDown}\n        className={cn('overflow-visible bg-transparent flex flex-col space-y-2', className)}\n        dir={dir}\n        {...props}\n      >\n        {children}\n      </Command>\n    </MultiSelectContext.Provider>\n  );\n};\n\nconst MultiSelectorTrigger = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n  ({ className, children, ...props }, ref) => {\n    const { value, onValueChange, activeIndex } = useMultiSelect();\n\n    const mousePreventDefault = useCallback((e: React.MouseEvent) => {\n      e.preventDefault();\n      e.stopPropagation();\n    }, []);\n\n    return (\n      <div\n        ref={ref}\n        className={cn(\n          'flex flex-wrap gap-1 px-2 py-2 ring-1 ring-muted rounded-lg bg-background border rounded-sm',\n          {\n            'ring-1 focus-within:ring-ring': activeIndex === -1,\n          },\n          className,\n        )}\n        {...props}\n      >\n        {value.map((item, index) => (\n          <Badge\n            key={item.value}\n            className={cn(\n              'px-1.5 rounded-md flex items-center gap-1',\n              activeIndex === index && 'ring-2 ring-muted-foreground ',\n            )}\n            variant=\"secondary\"\n          >\n            <span className=\"text-xs\">{item.label}</span>\n\n            <button\n              aria-label={`Remove ${item} option`}\n              aria-roledescription=\"button to remove option\"\n              type=\"button\"\n              onMouseDown={mousePreventDefault}\n              onClick={() => onValueChange(item)}\n            >\n              <span className=\"sr-only\">Remove {item.label} option</span>\n\n              <IconX className=\"h-4 w-4 hover:stroke-destructive\" />\n            </button>\n          </Badge>\n        ))}\n        {children}\n      </div>\n    );\n  },\n);\n\nMultiSelectorTrigger.displayName = 'MultiSelectorTrigger';\n\nconst MultiSelectorInput = forwardRef<\n  React.ElementRef<typeof CommandPrimitive.Input>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(({ className, ...props }, ref) => {\n  const { setOpen, inputValue, setInputValue, activeIndex, setActiveIndex, ref: inputRef } = useMultiSelect();\n\n  return (\n    <CommandPrimitive.Input\n      {...props}\n      tabIndex={0}\n      ref={inputRef}\n      value={inputValue}\n      onValueChange={activeIndex === -1 ? setInputValue : undefined}\n      onBlur={() => {\n        setInputValue('');\n        setOpen(false);\n      }}\n      onFocus={() => setOpen(true)}\n      onClick={() => setActiveIndex(-1)}\n      className={cn(\n        'p-0 bg-transparent border-none outline-none focus:outline-none focus:ring-0 placeholder:text-muted-foreground flex-1 text-sm',\n        className,\n        activeIndex !== -1 && 'caret-transparent',\n      )}\n    />\n  );\n});\n\nMultiSelectorInput.displayName = 'MultiSelectorInput';\n\nconst MultiSelectorContent = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ children }, ref) => {\n  const { open } = useMultiSelect();\n  return (\n    <div ref={ref} className=\"relative\">\n      {open ? children : null}\n    </div>\n  );\n});\n\nMultiSelectorContent.displayName = 'MultiSelectorContent';\n\nconst MultiSelectorList = forwardRef<\n  React.ElementRef<typeof CommandPrimitive.List>,\n  React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>\n>(({ className, children }, ref) => {\n  return (\n    <CommandList\n      ref={ref}\n      className={cn(\n        'p-2 flex flex-col gap-2 rounded-md scrollbar-thin scrollbar-track-transparent transition-colors scrollbar-thumb-muted-foreground dark:scrollbar-thumb-muted scrollbar-thumb-rounded-lg w-full absolute bg-background shadow-md z-100 border border-muted top-0',\n        className,\n      )}\n    >\n      {children}\n\n      <CommandEmpty>\n        <span className=\"text-muted-foreground\">No results found</span>\n      </CommandEmpty>\n    </CommandList>\n  );\n});\n\nMultiSelectorList.displayName = 'MultiSelectorList';\n\nconst MultiSelectorItem = forwardRef<\n  React.ElementRef<typeof CommandPrimitive.Item>,\n  { value: string; label: string } & React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>\n>(({ className, value, label, children, ...props }, ref) => {\n  const { value: Options, onValueChange, setInputValue } = useMultiSelect();\n\n  const mousePreventDefault = useCallback((e: React.MouseEvent) => {\n    e.preventDefault();\n    e.stopPropagation();\n  }, []);\n\n  const isIncluded =\n    searchForValue(Options, {\n      value: value,\n      label: label,\n    }) !== -1;\n\n  return (\n    <CommandItem\n      ref={ref}\n      {...props}\n      onSelect={() => {\n        onValueChange({\n          value: value,\n          label: label,\n        });\n        setInputValue('');\n      }}\n      className={cn(\n        'rounded-md cursor-pointer px-2 py-1 transition-colors flex justify-between',\n        className,\n        isIncluded && 'opacity-50 cursor-default',\n        props.disabled && 'opacity-50 cursor-not-allowed',\n      )}\n      onMouseDown={mousePreventDefault}\n    >\n      {children}\n      {isIncluded && <IconCheck className=\"h-4 w-4\" />}\n    </CommandItem>\n  );\n});\n\nMultiSelectorItem.displayName = 'MultiSelectorItem';\n\nexport {\n  MultiSelector,\n  MultiSelectorTrigger,\n  MultiSelectorInput,\n  MultiSelectorContent,\n  MultiSelectorList,\n  MultiSelectorItem,\n};\n"],"mappings":"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","names":["_a","_b"]}