{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "select",
  "title": "Select",
  "dependencies": [
    "@base-ui/react",
    "@phosphor-icons/react",
    "react-remove-scroll"
  ],
  "registryDependencies": [
    "https://ui.hotfix.jobs/r/recipes.json",
    "https://ui.hotfix.jobs/r/tokens.json",
    "https://ui.hotfix.jobs/r/use-media-query.json",
    "https://ui.hotfix.jobs/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/components/ui/select.tsx",
      "content": "\"use client\";\n\nimport { Select as SelectPrimitive } from \"@base-ui/react/select\";\nimport { CaretDown, Check } from \"@phosphor-icons/react/dist/ssr\";\nimport type * as React from \"react\";\nimport { RemoveScroll } from \"react-remove-scroll\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  itemRow,\n  mobilePopupBackdrop,\n  mobilePopupSurface,\n  popupSurface,\n  popupTriggerOpen,\n  selectionFocus,\n} from \"@/lib/recipes\";\nimport {\n  MOBILE_MEDIA_QUERY,\n  useMediaQuery,\n} from \"../hooks/use-media-query\";\n\nexport type SelectSize = \"sm\" | \"md\" | \"lg\";\nexport type SelectVariant = \"default\" | \"unstyled\";\n\nexport interface SelectProps\n  extends Omit<\n    React.ComponentProps<typeof SelectPrimitive.Root>,\n    \"value\" | \"defaultValue\" | \"onValueChange\" | \"items\"\n  > {\n  value?: string;\n  defaultValue?: string;\n  onValueChange?: (value: string) => void;\n  size?: SelectSize;\n  /** Removes trigger chrome when embedded in a composite surface. */\n  variant?: SelectVariant;\n  /** Content rendered at the start (icon, unit symbol). */\n  prefix?: React.ReactNode;\n  /** Content rendered at the end (before the chevron). */\n  suffix?: React.ReactNode;\n  /** Associates the trigger with a label. */\n  id?: string;\n  /** IDs of elements that describe the trigger. */\n  \"aria-describedby\"?: string;\n  /** Marks the trigger invalid. Pair with FieldError for its message. */\n  invalid?: boolean;\n  /** Placeholder text shown when no value is selected. */\n  placeholder?: string;\n  /** Class name applied to the trigger. */\n  className?: string;\n  /** Renders the trigger's selected-value display. Base UI's `Select.Value`\n   *  defaults to showing the raw `value` string, which surfaces ugly ids\n   *  (uuids, slugs) when the option label doesn't match the value. Pass a\n   *  mapper so consumers control the display without rebuilding the\n   *  trigger. Return `null` to fall through to the placeholder. */\n  renderValue?: (value: string) => React.ReactNode;\n}\n\nconst heightBySize: Record<SelectSize, string> = {\n  sm: \"h-6 text-small\",\n  md: \"h-8 text-small\",\n  lg: \"h-10 text-regular\",\n};\n\nconst leadingPad: Record<SelectSize, string> = {\n  sm: \"ps-3\",\n  md: \"ps-3\",\n  lg: \"ps-3.5\",\n};\n\nconst trailingPad: Record<SelectSize, string> = {\n  sm: \"pe-7\",\n  md: \"pe-8\",\n  lg: \"pe-9\",\n};\n\n/**\n * Rich select. Use `SelectItem` children; pair with `SelectGroup` / `SelectGroupLabel`\n * for optgroup semantics. For a searchable list, reach for `Combobox`.\n */\nexport function Select({\n  value,\n  defaultValue,\n  onValueChange,\n  size = \"md\",\n  variant = \"default\",\n  prefix,\n  suffix,\n  id,\n  \"aria-describedby\": ariaDescribedBy,\n  invalid,\n  placeholder,\n  disabled,\n  required,\n  className,\n  renderValue,\n  children,\n  modal,\n  ...props\n}: SelectProps): React.ReactElement {\n  const isMobile = useMediaQuery(MOBILE_MEDIA_QUERY);\n  const unstyled = variant === \"unstyled\";\n  const trigger = (\n    <SelectPrimitive.Trigger\n      id={id}\n      disabled={disabled}\n      aria-invalid={invalid || undefined}\n      aria-describedby={ariaDescribedBy}\n      data-slot=\"select\"\n      className={cn(\n        \"relative inline-flex w-full items-center overflow-hidden text-ink\",\n        !unstyled && \"rounded-[var(--radius-8)]\",\n        !unstyled && [\n          \"bg-fill-1 hover:bg-fill-2 focus-visible:bg-fill-2\",\n          popupTriggerOpen,\n          selectionFocus,\n          \"outline-none\",\n          \"transition-colors duration-[var(--duration-state)] ease-[var(--ease-standard)]\",\n        ],\n        \"group-data-[invalid]/field:[outline-style:solid] group-data-[invalid]/field:outline-[length:1px] group-data-[invalid]/field:outline-error\",\n        \"aria-invalid:[outline-style:solid] aria-invalid:outline-[length:1px] aria-invalid:outline-error\",\n        \"disabled:opacity-50 disabled:cursor-not-allowed\",\n        heightBySize[size],\n        prefix ? \"ps-0\" : leadingPad[size],\n        trailingPad[size],\n        className,\n      )}\n    >\n      {prefix && (\n        <span\n          className=\"pointer-events-none inline-flex shrink-0 items-center ps-3 pe-1.5 text-ink-muted [&_svg]:size-4\"\n          data-slot=\"select-prefix\"\n        >\n          {prefix}\n        </span>\n      )}\n      <SelectPrimitive.Value\n        placeholder={placeholder}\n        className=\"flex-1 truncate text-left\"\n        data-slot=\"select-value\"\n      >\n        {renderValue\n          ? (v: string) => {\n              const rendered = renderValue(v);\n              return rendered != null && rendered !== \"\"\n                ? rendered\n                : placeholder;\n            }\n          : undefined}\n      </SelectPrimitive.Value>\n      {suffix && (\n        <span\n          className=\"pointer-events-none inline-flex shrink-0 items-center ps-1.5 pe-1.5 text-ink-muted [&_svg]:size-4\"\n          data-slot=\"select-suffix\"\n        >\n          {suffix}\n        </span>\n      )}\n      <SelectPrimitive.Icon\n        className={cn(\n          \"pointer-events-none absolute top-1/2 -translate-y-1/2 text-ink-muted\",\n          size === \"sm\" ? \"right-2\" : size === \"lg\" ? \"right-3\" : \"right-2.5\",\n        )}\n      >\n        <CaretDown aria-hidden className=\"size-3.5\" />\n      </SelectPrimitive.Icon>\n    </SelectPrimitive.Trigger>\n  );\n\n  return (\n    <SelectPrimitive.Root\n      value={value}\n      defaultValue={defaultValue}\n      onValueChange={\n        onValueChange ? (next) => onValueChange(String(next ?? \"\")) : undefined\n      }\n      disabled={disabled}\n      required={required}\n      modal={isMobile ? true : modal}\n      {...props}\n    >\n      {trigger}\n      <SelectPopupSurface isMobile={isMobile}>{children}</SelectPopupSurface>\n    </SelectPrimitive.Root>\n  );\n}\n\n/* ---------------------------- Popup surface ---------------------------- */\n\nfunction SelectPopupSurface({\n  children,\n  isMobile,\n}: {\n  children: React.ReactNode;\n  isMobile: boolean;\n}): React.ReactElement {\n  if (isMobile) {\n    return (\n      <SelectPrimitive.Portal>\n        <RemoveScroll>\n          <SelectPrimitive.Backdrop\n            data-slot=\"select-backdrop\"\n            className={mobilePopupBackdrop}\n          />\n          <SelectPrimitive.Positioner\n            alignItemWithTrigger={false}\n            className=\"contents\"\n          >\n            <SelectPrimitive.Popup\n              data-slot=\"select-popup\"\n              data-mobile=\"true\"\n              className={cn(\n                mobilePopupSurface,\n                \"p-1\",\n              )}\n            >\n              <div className=\"min-h-0 flex-1 overflow-y-auto\">{children}</div>\n            </SelectPrimitive.Popup>\n          </SelectPrimitive.Positioner>\n        </RemoveScroll>\n      </SelectPrimitive.Portal>\n    );\n  }\n\n  return (\n    <SelectPrimitive.Portal>\n      <SelectPrimitive.Positioner\n        alignItemWithTrigger={false}\n        side=\"bottom\"\n        align=\"start\"\n        sideOffset={4}\n        className=\"z-50 outline-none\"\n      >\n        <SelectPrimitive.Popup\n          data-slot=\"select-popup\"\n          className={cn(\n            popupSurface,\n            \"min-w-[var(--anchor-width)] max-h-[var(--available-height)] overflow-y-auto p-1 outline-none\",\n            \"transition-[opacity,scale] duration-[var(--duration-state)] ease-[var(--ease-standard)]\",\n            \"data-starting-style:opacity-0 data-starting-style:scale-95\",\n            \"data-ending-style:opacity-0 data-ending-style:scale-95\",\n          )}\n        >\n          {children}\n        </SelectPrimitive.Popup>\n      </SelectPrimitive.Positioner>\n    </SelectPrimitive.Portal>\n  );\n}\n\n/* ------------------------------- Item ------------------------------- */\n\nexport interface SelectItemProps\n  extends React.ComponentProps<typeof SelectPrimitive.Item> {\n  value: string;\n}\n\nexport function SelectItem({\n  className,\n  children,\n  ...props\n}: SelectItemProps): React.ReactElement {\n  return (\n    <SelectPrimitive.Item\n      data-slot=\"select-item\"\n      className={cn(\n        itemRow.base,\n        itemRow.comfortable,\n        \"md:min-h-7 md:px-2 md:py-1.5 md:text-small\",\n        \"relative pe-8\",\n        className,\n      )}\n      {...props}\n    >\n      <SelectPrimitive.ItemText className=\"flex-1 truncate\">\n        {children}\n      </SelectPrimitive.ItemText>\n      <SelectPrimitive.ItemIndicator className=\"absolute right-2 top-1/2 -translate-y-1/2 text-ink-muted\">\n        <Check aria-hidden className=\"size-3.5\" />\n      </SelectPrimitive.ItemIndicator>\n    </SelectPrimitive.Item>\n  );\n}\n\n/* --------------------------- Group / Label -------------------------- */\n\nexport function SelectGroup(\n  props: React.ComponentProps<typeof SelectPrimitive.Group>,\n): React.ReactElement {\n  return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />;\n}\n\nexport function SelectGroupLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.GroupLabel>): React.ReactElement {\n  return (\n    <SelectPrimitive.GroupLabel\n      data-slot=\"select-group-label\"\n      className={cn(\n        \"px-2.5 pt-1.5 pb-1 text-micro text-ink-tertiary\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/* ---------------------------- Separator ----------------------------- */\n\nexport function SelectSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>): React.ReactElement {\n  return (\n    <SelectPrimitive.Separator\n      data-slot=\"select-separator\"\n      className={cn(\"-mx-1 my-1 h-px bg-hairline\", className)}\n      {...props}\n    />\n  );\n}\n\nexport { SelectPrimitive };\n",
      "type": "registry:ui",
      "target": "components/ui/select.tsx"
    }
  ],
  "type": "registry:ui"
}