{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "dependencies": [
    "@base-ui/react@1.8.0"
  ],
  "description": "A listbox dropdown on Base UI: typeahead, focus return and a glass popover.",
  "docs": "Two steps after installing: import the copied stylesheet once at your app entry — it lands at `styles/liquefy-ui.css` — or `@import` it from your global CSS *before* `tailwindcss`, so Tailwind utilities keep winning over component styles. Then wrap the tree in `<LiquefyProvider>`, which is where every component reads its tokens from. Every copied file already carries its own 'use client' directive. Full documentation: https://liquefy-ui.com/#/docs/installation",
  "files": [
    {
      "content": "'use client'\n\nimport { Select } from '@base-ui/react/select'\nimport { forwardRef, useCallback, type ButtonHTMLAttributes, type ReactNode } from 'react'\nimport { CheckGlyph, ChevronDownGlyph } from '@/lib/internal-glyphs'\nimport { useLiquefyConfig, useLiquefyPortalContainer } from '@/lib/provider'\nimport { useLiquidStyles, type LiquidStyleProps } from '@/lib/styles-prop'\nimport { useLiquidGlass } from '@/hooks/use-liquid-glass'\n\n// What the hand-rolled listbox never had: typeahead, Home/End, PageUp/PageDown,\n// focus returning to the trigger, form integration through a hidden input, and a\n// popup that keeps itself on screen. All of that is Base UI's now. liquefy-ui\n// still owns the WebGL trigger and the glass popover.\n\nexport type LiquidSelectOption = {\n  disabled?: boolean\n  label: ReactNode\n  value: string\n}\n\nexport type LiquidSelectProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange' | 'value'> & LiquidStyleProps & {\n  defaultValue?: string\n  hint?: string\n  label?: string\n  /** Called when the popup opens or closes — a sheet holding the select needs to know. */\n  onOpenChange?: (open: boolean) => void\n  onValueChange?: (value: string) => void\n  options: LiquidSelectOption[]\n  placeholder?: string\n  value?: string\n}\n\nexport const LiquidSelect = forwardRef<HTMLButtonElement, LiquidSelectProps>(({\n  className,\n  defaultValue,\n  disabled,\n  hint,\n  label,\n  onOpenChange,\n  onValueChange,\n  options,\n  placeholder = 'Select…',\n  style,\n  styles,\n  value,\n  ...props\n}, forwardedRef) => {\n  const config = useLiquefyConfig()\n  const portalContainer = useLiquefyPortalContainer()\n\n  const [glassRef, canvasRef, pulse] = useLiquidGlass<HTMLButtonElement>(forwardedRef, {\n    bounce: 0.05,\n    disabled,\n    glow: config.glow,\n    intensity: config.intensity,\n    lens: config.lens && config.transparency,\n    lensStrength: config.refraction,\n    motion: config.motion,\n    ripple: config.ripple,\n    shimmer: config.shimmer,\n    sparkle: config.sparkle,\n    tilt: 2,\n    tint: config.tint,\n    webgl: config.webgl,\n    wobbliness: config.wobbliness,\n  })\n\n  const handleOpenChange = useCallback((open: boolean) => {\n    if (open) pulse(0.8)\n    onOpenChange?.(open)\n  }, [onOpenChange, pulse])\n\n  // The field wrapper is the layout box, so it owns className, style and styles.\n  const root = useLiquidStyles('lq-select', { className, style, styles })\n\n  return (\n    <div className={root.className} style={root.style}>\n      <Select.Root\n        defaultValue={defaultValue}\n        disabled={disabled}\n        // Lets Select.Value render the chosen option's label while the popup is shut.\n        items={options.map(({ label: optionLabel, value: optionValue }) => ({\n          label: optionLabel,\n          value: optionValue,\n        }))}\n        onOpenChange={handleOpenChange}\n        onValueChange={(next) => {\n          pulse(1)\n          if (next != null) onValueChange?.(String(next))\n        }}\n        value={value}\n      >\n        {label && <Select.Label className=\"lq-control-label\">{label}</Select.Label>}\n        <Select.Trigger className=\"lq-select__trigger\" ref={glassRef} {...props}>\n          {config.webgl && <canvas aria-hidden=\"true\" className=\"lq-surface__shader\" ref={canvasRef} />}\n          <Select.Value className=\"lq-select__value\" placeholder={placeholder} />\n          <Select.Icon className=\"lq-select__chevron\"><ChevronDownGlyph size={15} /></Select.Icon>\n        </Select.Trigger>\n        <Select.Portal container={portalContainer ?? undefined}>\n          <Select.Positioner\n            // false gives an ordinary dropdown under the trigger rather than Base\n            // UI's default of parking the selected row over it.\n            alignItemWithTrigger={false}\n            className=\"lq-select__positioner\"\n            sideOffset={7}\n          >\n            <Select.Popup className=\"lq-select__listbox lq-popover\">\n              {options.map((option) => (\n                <Select.Item\n                  className=\"lq-select__option\"\n                  disabled={option.disabled}\n                  key={option.value}\n                  value={option.value}\n                >\n                  <Select.ItemText>{option.label}</Select.ItemText>\n                  <Select.ItemIndicator><CheckGlyph size={14} /></Select.ItemIndicator>\n                </Select.Item>\n              ))}\n            </Select.Popup>\n          </Select.Positioner>\n        </Select.Portal>\n      </Select.Root>\n      {hint && <span className=\"lq-control-hint\">{hint}</span>}\n    </div>\n  )\n})\n\nLiquidSelect.displayName = 'LiquidSelect'\n",
      "path": "registry/liquid-select.tsx",
      "type": "registry:ui"
    }
  ],
  "name": "liquid-select",
  "registryDependencies": [
    "https://liquefy-ui.com/r/liquefy-ui.json",
    "https://liquefy-ui.com/r/internal-glyphs.json",
    "https://liquefy-ui.com/r/provider.json",
    "https://liquefy-ui.com/r/styles-prop.json",
    "https://liquefy-ui.com/r/use-liquid-glass.json"
  ],
  "title": "LiquidSelect",
  "type": "registry:ui"
}
