{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "multi-select-1-lyra",
  "title": "Multi Select 1Lyra",
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "badge",
    "popover",
    "command"
  ],
  "files": [
    {
      "path": "src/registry/multi-select/lyra/MultiSelect1Lyra.jsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cva } from \"class-variance-authority\";\nimport { CheckIcon, XCircle, ChevronDown, XIcon } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport { Badge } from \"@/components/ui/badge\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport {\n  Command,\n  CommandEmpty,\n  CommandGroup,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n} from \"@/components/ui/command\";\n\nconst multiSelectVariants = cva(\n  \"m-1 transition ease-in-out duration-300 font-monouppercase tracking-wider rounded-none\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"border-[0.6px] border-white/20 text-white bg-neutral-900 hover:bg-neutral-800\",\n        secondary:\n          \"border-white/20 bg-neutral-800 text-white hover:bg-neutral-700\",\n        destructive:\n          \"border-transparent bg-red-900 text-white hover:bg-red-800\",\n        inverted: \"inverted\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n);\n\nexport const MultiSelect = React.forwardRef(\n  (\n    {\n      options,\n      value,\n      variant,\n      placeholder = \"SELECT OPTIONS\",\n      modalPopover = false,\n      asChild = false,\n      className,\n      wrap = true,\n      maxHeight = 200,\n      ...props\n    },\n    ref\n  ) => {\n    const [selectedValues, setSelectedValues] = React.useState(value ?? []);\n    const [maxCount, setMaxCount] = React.useState(null);\n    const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);\n    const triggerRef = React.useRef(null);\n    const [triggerWidth, setTriggerWidth] = React.useState(0);\n    const optionsRefs = React.useRef([]);\n    const [lineBreak, setLineBreak] = React.useState(true);\n    const badgeRef = React.useRef(null);\n    const crossRef = React.useRef(null);\n\n    const areAllSelected = options.every((opt) =>\n      selectedValues.includes(opt.value)\n    );\n\n    const handleSelectAll = () => {\n      const allValues = options.map((opt) => opt.value);\n      const currentlyAllSelected = options.every((opt) =>\n        selectedValues.includes(opt.value)\n      );\n\n      const newSelectedValues = currentlyAllSelected ? [] : allValues;\n      setSelectedValues(newSelectedValues);\n    };\n\n    React.useEffect(() => {\n      if (isPopoverOpen && triggerRef.current) {\n        setTriggerWidth(triggerRef.current.offsetWidth);\n      }\n    }, [isPopoverOpen]);\n\n    const toggleOption = (optionValue) => {\n      const isSelected = selectedValues.includes(optionValue);\n      let newSelectedValues;\n\n      if (isSelected) {\n        newSelectedValues = selectedValues.filter((val) => val !== optionValue);\n      } else {\n        newSelectedValues = [...selectedValues, optionValue];\n      }\n\n      setSelectedValues(newSelectedValues);\n    };\n\n    const handleClear = () => {\n      setSelectedValues([]);\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    };\n\n    React.useEffect(() => {\n      if (optionsRefs?.current.length === 0 || !triggerRef?.current) {\n        return;\n      }\n\n      const handleResize = () => {\n        let lastIndex = -1;\n\n        requestAnimationFrame(() => {\n          optionsRefs?.current.map((el, i) => {\n            if (\n              el?.getBoundingClientRect().right >\n              triggerRef.current?.getBoundingClientRect().right\n            ) {\n              setLineBreak(false);\n              if (lastIndex === -1) {\n                lastIndex = i;\n                setMaxCount(Math.max(1, i - 1));\n              }\n            }\n          });\n        });\n      };\n\n      handleResize();\n\n      window.addEventListener(\"resize\", handleResize);\n\n      return () => {\n        window.removeEventListener(\"resize\", handleResize);\n      };\n    }, [selectedValues]);\n\n    const combinedRef = (element) => {\n      triggerRef.current = element;\n      if (typeof ref === \"function\") {\n        ref(element);\n      } else if (ref) {\n        ref.current = element;\n      }\n    };\n\n    React.useEffect(() => {\n      if (!badgeRef?.current || !triggerRef?.current || !crossRef?.current) {\n        return;\n      }\n\n      if (\n        badgeRef.current.getBoundingClientRect().right +\n          crossRef.current.getBoundingClientRect().width >\n        triggerRef.current.getBoundingClientRect().right\n      ) {\n        setMaxCount((prev) => prev - 1);\n      }\n    }, [maxCount, wrap, lineBreak]);\n\n    return (\n      <div className=\"w-full relative\">\n        <Popover\n          open={isPopoverOpen}\n          onOpenChange={setIsPopoverOpen}\n          modal={modalPopover}\n        >\n          <PopoverTrigger asChild>\n            <Button\n              ref={combinedRef}\n              {...props}\n              onClick={handleTogglePopover}\n              className={cn(\n                \"flex w-full p-1 min-h-10 h-auto items-center justify-between hover:bg-white/5 [&_svg]:pointer-events-auto\",\n                \"rounded-none border-[0.6px] border-white/20 bg-black text-white font-mono uppercase tracking-wider\", // Lyra Specifics\n                className\n              )}\n            >\n              {selectedValues.length > 0 ? (\n                <div className=\"flex justify-between items-center w-full\">\n                  <div\n                    className={\n                      \"flex \" +\n                      (wrap ? \"flex-wrap \" : \"\") +\n                      \"items-center overflow-hidden\"\n                    }\n                  >\n                    {selectedValues\n                      .slice(0, maxCount ? maxCount : selectedValues.length)\n                      .map((value, index) => {\n                        const option = options.find((o) => o.value === value);\n                        const IconComponent = option?.icon;\n                        return (\n                          <div\n                            key={value}\n                            ref={(el) => (optionsRefs.current[index] = el)}\n                          >\n                            <Badge\n                              key={value}\n                              className={cn(multiSelectVariants({ variant }))}\n                            >\n                              {IconComponent && (\n                                <IconComponent className=\"h-4 w-4 mr-2\" />\n                              )}\n                              <div className=\"w-full max-w-[200px] overflow-hidden\">\n                                <span className=\"truncate block font-mono\">\n                                  {option?.label}\n                                </span>\n                              </div>\n                            </Badge>\n                          </div>\n                        );\n                      })}\n                    {!lineBreak &&\n                      !wrap &&\n                      selectedValues.length > maxCount && (\n                        <Badge\n                          ref={badgeRef}\n                          className={cn(\n                            \"bg-transparent text-white border-white/20 hover:bg-transparent rounded-none\",\n                            multiSelectVariants({ variant })\n                          )}\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                        </Badge>\n                      )}\n                  </div>\n                  <div className=\"flex items-center justify-between\">\n                    <XIcon\n                      ref={crossRef}\n                      className=\"h-4 mx-2 cursor-pointer text-white/50 hover:text-white\"\n                      onClick={(event) => {\n                        event.stopPropagation();\n                        handleClear();\n                      }}\n                    />\n                  </div>\n                </div>\n              ) : (\n                <div className=\"flex items-center justify-between w-full mx-auto\">\n                  <span className=\"text-sm text-neutral-500 mx-3 font-mono\">\n                    {placeholder}\n                  </span>\n                  <ChevronDown className=\"h-4 cursor-pointer text-white/50 mx-2\" />\n                </div>\n              )}\n            </Button>\n          </PopoverTrigger>\n          <PopoverContent\n            className=\"p-0 rounded-none border-[0.6px] border-white/20 bg-black\"\n            align=\"start\"\n            sideOffset={5}\n            onEscapeKeyDown={() => setIsPopoverOpen(false)}\n            style={{ width: triggerWidth > 0 ? `${triggerWidth}px ` : \"100%\" }}\n          >\n            <Command\n              className=\"w-full p-0 bg-black\"\n              onWheel={(e) => {\n                e.stopPropagation();\n              }}\n            >\n              <CommandList\n                className=\"w-full p-0 overflow-y-auto overflow-x-hidden scrollbar-thin scrollbar-thumb-neutral-800 scrollbar-track-transparent scroll-smooth\"\n                style={{\n                  maxHeight: `${maxHeight}px`,\n                  overscrollBehavior: \"contain\",\n                }}\n                onWheel={(e) => {\n                  const { currentTarget } = e;\n                  const isScrollable =\n                    currentTarget.scrollHeight > currentTarget.clientHeight;\n\n                  if (isScrollable) {\n                    const atTop = currentTarget.scrollTop === 0;\n                    const atBottom =\n                      currentTarget.scrollTop + currentTarget.clientHeight >=\n                      currentTarget.scrollHeight - 1;\n                    if (\n                      (e.deltaY < 0 && !atTop) ||\n                      (e.deltaY > 0 && !atBottom)\n                    ) {\n                      e.stopPropagation();\n                    }\n                  }\n                }}\n              >\n                <CommandEmpty className=\"py-6 text-center text-sm text-neutral-500 font-mono\">NO RESULTS.</CommandEmpty>\n                <CommandGroup className=\"w-full\">\n                  {!areAllSelected && (\n                    <CommandItem\n                      onMouseDown={(e) => {\n                        e.preventDefault();\n                        handleSelectAll();\n                      }}\n                      className=\"cursor-pointer w-full font-mono text-sm uppercase tracking-wider text-white hover:bg-white/10 aria-selected:bg-white/10 rounded-none\"\n                    >\n                      <div className=\"mr-2 flex h-4 w-4 items-center justify-center rounded-none border-[0.6px] border-white/40 bg-transparent\">\n                        <div className=\"h-2 w-2 rounded-none bg-transparent\" />\n                      </div>\n                      SELECT ALL\n                    </CommandItem>\n                  )}\n\n                  <CommandSeparator className=\"bg-white/10\" />\n\n                  {options.map((option) => {\n                    const isSelected = selectedValues.includes(option.value);\n                    return (\n                      <CommandItem\n                        key={option.value}\n                        onMouseDown={(e) => {\n                          e.preventDefault();\n                          toggleOption(option.value);\n                        }}\n                        className=\"cursor-pointer w-full font-mono text-sm uppercase tracking-wider text-white hover:bg-white/10 aria-selected:bg-white/10 rounded-none\"\n                      >\n                        <div\n                          className={cn(\n                            \"mr-2 flex h-4 w-4 items-center justify-center rounded-none border-[0.6px] border-white/40\",\n                            isSelected\n                              ? \"bg-white text-black border-white\"\n                              : \"opacity-50 [&_svg]:invisible\"\n                          )}\n                        >\n                          <CheckIcon\n                            className={cn(\n                              \"h-3 w-3\",\n                              isSelected ? \"text-black\" : \"\"\n                            )}\n                          />\n                        </div>\n                        {option.icon && (\n                          <option.icon className=\"mr-2 h-4 w-4 text-white\" />\n                        )}\n                        <span className=\"truncate\">{option?.label}</span>\n                      </CommandItem>\n                    );\n                  })}\n                </CommandGroup>\n              </CommandList>\n            </Command>\n          </PopoverContent>\n        </Popover>\n      </div>\n    );\n  }\n);\n\nMultiSelect.displayName = \"MultiSelect\";\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}