{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "select",
  "title": "Select",
  "description": "Select from the Get IT Done design system.",
  "dependencies": [
    "@radix-ui/react-select@^2.4.1",
    "lucide-react@^0.379.0"
  ],
  "registryDependencies": [
    "https://zero-design.itdone.de/r/input.json",
    "https://zero-design.itdone.de/r/labels-context.json",
    "https://zero-design.itdone.de/r/recipes.json",
    "https://zero-design.itdone.de/r/utils.json",
    "https://zero-design.itdone.de/r/theme.json"
  ],
  "files": [
    {
      "path": "registry/ui/select.tsx",
      "content": "'use client';\n\nimport * as SelectPrimitive from '@radix-ui/react-select';\nimport { Check, ChevronDown, Loader2 } from 'lucide-react';\nimport * as React from 'react';\n\nimport { fieldHaloZero, focusRingField, invalidRing, menuItem, menuItemZero, openRing, overlayMotion, overlaySurface, overlaySurfaceZero, transitionBase } from '@/lib/recipes';\nimport { cn } from '@/lib/utils';\nimport type { InputSize } from '@/components/ui/input';\nimport { usePreset } from '@/components/ui/labels-context';\n\n// Trigger heights share the Input scale: `xs` is the compact `--size-control-xs` height (28, 24 in zero), `sm`, `md` and `lg` follow the control tokens.\nconst TRIGGER_SIZE: Record<InputSize, string> = {\n  xs: 'h-control-xs px-control-px-sm py-0',\n  sm: 'h-control-sm px-control-px-sm py-0',\n  md: 'h-control-md px-control-px-sm py-0',\n  lg: 'h-control-lg px-control-px-sm py-0',\n};\n\nconst Select = SelectPrimitive.Root;\n\nconst SelectGroup = SelectPrimitive.Group;\n\nconst SelectValue = SelectPrimitive.Value;\n\n// Option density of the open list, set by SelectContent and read by the options.\nconst SelectDensityContext = React.createContext<'default' | 'touch'>('default');\n\nconst SelectTrigger = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Trigger>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & {\n    clamp?: boolean;\n    // Dense 32px trigger for inline rows. Default keeps the 40px trigger.\n    compact?: boolean;\n    // Trigger height, see Input `size`. Overrides `compact`. In the zero preset the default is `md`.\n    size?: InputSize;\n    // Chevron becomes a spinner and the trigger reports aria-busy.\n    loading?: boolean;\n    // `readonly` shows the value on the muted read-only surface and keeps the list closed.\n    appearance?: 'default' | 'readonly';\n    // Leading icon, Avatar or colour dot shown before the value (Figma Type icon / avatar / dot leading).\n    leading?: React.ReactNode;\n    // Success border (Figma Color=Success). Invalid still wins via aria-invalid.\n    success?: boolean;\n  }\n>(({ className, children, clamp = false, compact = false, size, loading = false, appearance = 'default', leading, success = false, onPointerDown, onKeyDown, ...props }, ref) => {\n  const zero = usePreset() === 'zero';\n  const effectiveSize = size ?? (zero ? (compact ? 'sm' : 'md') : undefined);\n  return (\n    <SelectPrimitive.Trigger\n      ref={ref}\n      aria-busy={loading || undefined}\n      aria-readonly={appearance === 'readonly' || undefined}\n      onPointerDown={(event) => {\n        if (appearance === 'readonly') {\n          event.preventDefault();\n          return;\n        }\n        onPointerDown?.(event);\n      }}\n      onKeyDown={(event) => {\n        if (appearance === 'readonly' && (event.key === 'Enter' || event.key === ' ' || event.key.startsWith('Arrow'))) {\n          event.preventDefault();\n          return;\n        }\n        onKeyDown?.(event);\n      }}\n      className={cn(\n        'flex',\n        'w-full',\n        'items-center',\n        'justify-between',\n        'gap-2',\n        'rounded-control',\n        'border',\n        'border-solid',\n        'border-input',\n        'bg-background',\n        'px-4',\n        // Same vertical rhythm as Input (py-2 + typography-input-text/leading-normal), so a Select\n        // and an Input in one form row are the same height.\n        'py-2',\n        'text-select-foreground-default',\n        'typography-input-text',\n        // Below sm the trigger text is at least 16px so iOS Safari does not zoom on focus.\n        'max-sm:text-[max(16px,var(--typo-input-text-size,1rem))]',\n        'leading-normal',\n        transitionBase,\n        // Hover: darker border + soft field shadow (no background tint).\n        'hover:border-border-bold',\n        'hover:shadow-field-hover',\n        !zero && focusRingField,\n        // Open state mirrors the focus look, independent of :focus-visible (pointer open).\n        !zero && openRing,\n        // Invalid state: driven by `aria-invalid` (set by <FormControl>); arbitrary-variant form\n        // because `aria-invalid` is not in Tailwind's built-in aria allow-list.\n        invalidRing,\n        '[&>span]:line-clamp-1',\n        'data-[placeholder]:text-text-subtle',\n        'disabled:cursor-not-allowed',\n        'disabled:opacity-disabled',\n        { 'text-clamp': clamp },\n        { 'leading-clamp': clamp },\n        zero && fieldHaloZero,\n        compact && !effectiveSize && 'h-8 px-3 py-1',\n        effectiveSize && TRIGGER_SIZE[effectiveSize],\n        appearance === 'readonly' && 'cursor-default bg-muted hover:border-input hover:shadow-none',\n        success && 'border-border-success',\n        className,\n      )}\n      {...props}\n    >\n      {leading ? (\n        <span aria-hidden=\"true\" data-select-leading=\"\" className=\"!flex h-icon-xs w-icon-xs shrink-0 items-center justify-center !overflow-visible text-icon-subtle\">\n          {leading}\n        </span>\n      ) : null}\n      {children}\n      {loading ? (\n        <Loader2 aria-hidden=\"true\" className=\"h-4 w-4 shrink-0 animate-spin text-muted-foreground motion-reduce:animate-none\" />\n      ) : (\n        <SelectPrimitive.Icon asChild>\n          <ChevronDown className={cn('shrink-0 text-muted-foreground', zero ? 'h-icon-xs w-icon-xs' : 'h-4 w-4')} />\n        </SelectPrimitive.Icon>\n      )}\n    </SelectPrimitive.Trigger>\n  );\n});\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName;\n\nconst SelectContent = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Content>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {\n    clamp?: boolean;\n    // `touch` makes the options 44px high (touch-target-lg) below the sm breakpoint. Default keeps the dense options.\n    density?: 'default' | 'touch';\n  }\n>(({ className, children, position = 'popper', clamp = false, density = 'default', ...props }, ref) => {\n  const zero = usePreset() === 'zero';\n  return (\n    <SelectPrimitive.Portal>\n      <SelectPrimitive.Content\n        ref={ref}\n        className={cn(\n          'relative',\n          'z-dropdown',\n          'min-w-[8rem]',\n          'overflow-hidden',\n          overlaySurface,\n          zero && overlaySurfaceZero,\n          'typography-input-text',\n          overlayMotion,\n          'data-[side=bottom]:slide-in-from-top-2',\n          'data-[side=left]:slide-in-from-right-2',\n          'data-[side=right]:slide-in-from-left-2',\n          'data-[side=top]:slide-in-from-bottom-2',\n          position === 'popper' && 'data-[side=bottom]:translate-y-1',\n          'data-[side=left]:-translate-x-1',\n          'data-[side=right]:translate-x-1',\n          'data-[side=top]:-translate-y-1',\n          { 'text-sm': !clamp },\n          { 'leading-lg': !clamp },\n          { 'text-clamp': clamp },\n          { 'leading-clamp': clamp },\n          className,\n        )}\n        position={position}\n        {...props}\n      >\n        <SelectPrimitive.Viewport\n          className={cn(\n            'p-1',\n            position === 'popper' && 'h-[var(--radix-select-trigger-height)]',\n            'w-full',\n            'min-w-[var(--radix-select-trigger-width)]',\n          )}\n        >\n          <SelectDensityContext.Provider value={density}>{children}</SelectDensityContext.Provider>\n        </SelectPrimitive.Viewport>\n      </SelectPrimitive.Content>\n    </SelectPrimitive.Portal>\n  );\n});\nSelectContent.displayName = SelectPrimitive.Content.displayName;\n\nconst SelectLabel = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Label>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> & { clamp?: boolean }\n>(({ className, clamp = false, ...props }, ref) => (\n  <SelectPrimitive.Label\n    ref={ref}\n    className={cn(\n      'py-[6px]',\n      'px-2',\n      'text-muted-foreground',\n      'typography-input-text',\n      { 'text-xs': !clamp },\n      { 'leading-lg': !clamp },\n      { 'text-clamp-small': clamp },\n      { 'leading-clamp-small': clamp },\n      className,\n    )}\n    {...props}\n  />\n));\nSelectLabel.displayName = SelectPrimitive.Label.displayName;\n\nconst SelectItem = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Item>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> & { clamp?: boolean }\n>(({ className, children, clamp = false, ...props }, ref) => {\n  const zero = usePreset() === 'zero';\n  const density = React.useContext(SelectDensityContext);\n  return (\n    <SelectPrimitive.Item\n      ref={ref}\n      className={cn(\n        zero ? menuItemZero : menuItem,\n        'w-full',\n        'pr-2',\n        density === 'touch' && 'max-sm:min-h-[var(--size-touch-target-lg)]',\n        { 'text-clamp': clamp },\n        { 'leading-clamp': clamp },\n        className,\n      )}\n      {...props}\n    >\n      <SelectPrimitive.ItemText className=\"flex-1\">{children}</SelectPrimitive.ItemText>\n      <span className={cn('flex', 'h-4', 'w-4', 'shrink-0', 'items-center', 'justify-center')}>\n        <SelectPrimitive.ItemIndicator>\n          <Check className=\"h-4 w-4\" />\n        </SelectPrimitive.ItemIndicator>\n      </span>\n    </SelectPrimitive.Item>\n  );\n});\nSelectItem.displayName = SelectPrimitive.Item.displayName;\n\nconst SelectSeparator = React.forwardRef<\n  React.ElementRef<typeof SelectPrimitive.Separator>,\n  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n  <SelectPrimitive.Separator\n    ref={ref}\n    className={cn('-mx-1', 'my-1', 'h-px', 'bg-border-subtle', className)}\n    {...props}\n  />\n));\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName;\n\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}