{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "time-picker",
  "type": "registry:ui",
  "description": "Popover-based time picker with 12h/24h format and scrollable columns",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "button",
    "popover",
    "scroll-area"
  ],
  "files": [
    {
      "path": "registry/default/ui/time-picker.tsx",
      "content": "import * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport { Clock } from 'lucide-react'\nimport { Button } from '@/components/ui/button'\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from '@/components/ui/popover'\nimport { ScrollArea } from '@/components/ui/scroll-area'\n\nexport interface TimePickerProps {\n  value?: Date\n  defaultValue?: Date\n  onChange?: (date: Date | undefined) => void\n  format?: '12h' | '24h'\n  minuteStep?: 1 | 5 | 10 | 15 | 30\n  showSeconds?: boolean\n  minTime?: Date\n  maxTime?: Date\n  disabled?: boolean\n  placeholder?: string\n  className?: string\n}\n\nconst TimePicker = React.forwardRef<HTMLButtonElement, TimePickerProps>(\n  (\n    {\n      value: controlledValue,\n      defaultValue,\n      onChange,\n      format = '12h',\n      minuteStep = 1,\n      showSeconds = false,\n      minTime,\n      maxTime,\n      disabled = false,\n      placeholder = 'Select time',\n      className,\n    },\n    ref\n  ) => {\n    const [open, setOpen] = React.useState(false)\n    const [uncontrolledValue, setUncontrolledValue] = React.useState<Date | undefined>(defaultValue)\n\n    const isControlled = controlledValue !== undefined\n    const selectedTime = isControlled ? controlledValue : uncontrolledValue\n\n    const hours = format === '12h' ? 12 : 24\n    const hoursArray = Array.from({ length: hours }, (_, i) => (format === '12h' ? i + 1 : i))\n    const minutesArray = Array.from({ length: 60 / minuteStep }, (_, i) => i * minuteStep)\n    const secondsArray = Array.from({ length: 60 }, (_, i) => i)\n\n    const getHour = (date: Date) => {\n      const h = date.getHours()\n      if (format === '12h') {\n        return h === 0 ? 12 : h > 12 ? h - 12 : h\n      }\n      return h\n    }\n\n    const getPeriod = (date: Date) => {\n      return date.getHours() >= 12 ? 'PM' : 'AM'\n    }\n\n    const selectedHour = selectedTime ? getHour(selectedTime) : null\n    const selectedMinute = selectedTime ? selectedTime.getMinutes() : null\n    const selectedSecond = selectedTime ? selectedTime.getSeconds() : null\n    const selectedPeriod = selectedTime ? getPeriod(selectedTime) : 'AM'\n\n    const updateTime = (\n      hour?: number,\n      minute?: number,\n      second?: number,\n      period?: 'AM' | 'PM'\n    ) => {\n      const newDate = new Date(selectedTime || new Date())\n\n      if (hour !== undefined) {\n        let h = hour\n        if (format === '12h') {\n          const currentPeriod = period ?? selectedPeriod\n          if (currentPeriod === 'PM' && hour !== 12) h = hour + 12\n          else if (currentPeriod === 'AM' && hour === 12) h = 0\n        }\n        newDate.setHours(h)\n      }\n\n      if (minute !== undefined) {\n        newDate.setMinutes(minute)\n      }\n\n      if (second !== undefined) {\n        newDate.setSeconds(second)\n      }\n\n      if (period !== undefined && hour === undefined && selectedTime) {\n        let h = selectedTime.getHours()\n        if (period === 'PM' && h < 12) h += 12\n        else if (period === 'AM' && h >= 12) h -= 12\n        newDate.setHours(h)\n      }\n\n      // Check min/max time\n      if (minTime) {\n        const minMinutes = minTime.getHours() * 60 + minTime.getMinutes()\n        const newMinutes = newDate.getHours() * 60 + newDate.getMinutes()\n        if (newMinutes < minMinutes) return\n      }\n\n      if (maxTime) {\n        const maxMinutes = maxTime.getHours() * 60 + maxTime.getMinutes()\n        const newMinutes = newDate.getHours() * 60 + newDate.getMinutes()\n        if (newMinutes > maxMinutes) return\n      }\n\n      if (!isControlled) {\n        setUncontrolledValue(newDate)\n      }\n      onChange?.(newDate)\n    }\n\n    const formatDisplayTime = (date: Date) => {\n      const h = getHour(date)\n      const m = date.getMinutes().toString().padStart(2, '0')\n      const s = date.getSeconds().toString().padStart(2, '0')\n      const period = format === '12h' ? ` ${getPeriod(date)}` : ''\n      const hourStr = format === '12h' ? h.toString() : h.toString().padStart(2, '0')\n\n      if (showSeconds) {\n        return `${hourStr}:${m}:${s}${period}`\n      }\n      return `${hourStr}:${m}${period}`\n    }\n\n    const isTimeDisabled = (hour: number, minute: number) => {\n      let h = hour\n      if (format === '12h') {\n        if (selectedPeriod === 'PM' && hour !== 12) h = hour + 12\n        else if (selectedPeriod === 'AM' && hour === 12) h = 0\n      }\n\n      const timeMinutes = h * 60 + minute\n\n      if (minTime) {\n        const minMinutes = minTime.getHours() * 60 + minTime.getMinutes()\n        if (timeMinutes < minMinutes) return true\n      }\n\n      if (maxTime) {\n        const maxMinutes = maxTime.getHours() * 60 + maxTime.getMinutes()\n        if (timeMinutes > maxMinutes) return true\n      }\n\n      return false\n    }\n\n    // Calculate number of columns for responsive width\n    const columnCount = 2 + (showSeconds ? 1 : 0) + (format === '12h' ? 1 : 0)\n\n    return (\n      <Popover open={open} onOpenChange={setOpen}>\n        <PopoverTrigger asChild>\n          <Button\n            ref={ref}\n            variant=\"outline\"\n            disabled={disabled}\n            className={cn(\n              'w-[180px] justify-start text-left font-normal',\n              !selectedTime && 'text-muted-foreground',\n              className\n            )}\n          >\n            <Clock className=\"mr-2 h-4 w-4 shrink-0\" />\n            <span className=\"truncate\">\n              {selectedTime ? formatDisplayTime(selectedTime) : placeholder}\n            </span>\n          </Button>\n        </PopoverTrigger>\n        <PopoverContent\n          className={cn(\n            'w-auto p-0 overflow-hidden',\n            'animate-in fade-in-0 zoom-in-95 duration-200'\n          )}\n          align=\"start\"\n          sideOffset={4}\n        >\n          <div\n            className={cn(\n              'flex',\n              // Responsive: stack on very small screens\n              'max-w-[calc(100vw-2rem)]'\n            )}\n            style={{\n              // Dynamic width based on column count\n              minWidth: `${columnCount * 60}px`,\n            }}\n          >\n            {/* Hours column */}\n            <div className=\"flex-1 min-w-[60px] border-r-3 border-foreground\">\n              <div className=\"px-2 py-2 text-center text-xs font-bold uppercase tracking-wide text-muted-foreground border-b-3 border-foreground bg-muted/30\">\n                Hour\n              </div>\n              <ScrollArea className=\"h-[200px]\">\n                <div className=\"p-1\">\n                  {hoursArray.map((hour) => (\n                    <button\n                      key={hour}\n                      type=\"button\"\n                      onClick={() => updateTime(hour)}\n                      className={cn(\n                        'w-full px-2 py-1.5 text-center text-sm',\n                        'transition-all duration-150 ease-out',\n                        'hover:bg-muted hover:scale-105',\n                        'focus:outline-none focus:bg-muted',\n                        selectedHour === hour && 'bg-primary text-primary-foreground shadow-[2px_2px_0px_hsl(var(--shadow-color))] scale-105',\n                        isTimeDisabled(hour, selectedMinute ?? 0) && 'opacity-50 cursor-not-allowed hover:scale-100'\n                      )}\n                    >\n                      {format === '12h' ? hour : hour.toString().padStart(2, '0')}\n                    </button>\n                  ))}\n                </div>\n              </ScrollArea>\n            </div>\n\n            {/* Minutes column */}\n            <div className={cn(\n              'flex-1 min-w-[60px]',\n              (showSeconds || format === '12h') && 'border-r-3 border-foreground'\n            )}>\n              <div className=\"px-2 py-2 text-center text-xs font-bold uppercase tracking-wide text-muted-foreground border-b-3 border-foreground bg-muted/30\">\n                Min\n              </div>\n              <ScrollArea className=\"h-[200px]\">\n                <div className=\"p-1\">\n                  {minutesArray.map((minute) => (\n                    <button\n                      key={minute}\n                      type=\"button\"\n                      onClick={() => updateTime(undefined, minute)}\n                      className={cn(\n                        'w-full px-2 py-1.5 text-center text-sm',\n                        'transition-all duration-150 ease-out',\n                        'hover:bg-muted hover:scale-105',\n                        'focus:outline-none focus:bg-muted',\n                        selectedMinute === minute && 'bg-primary text-primary-foreground shadow-[2px_2px_0px_hsl(var(--shadow-color))] scale-105'\n                      )}\n                    >\n                      {minute.toString().padStart(2, '0')}\n                    </button>\n                  ))}\n                </div>\n              </ScrollArea>\n            </div>\n\n            {/* Seconds column */}\n            {showSeconds && (\n              <div className={cn(\n                'flex-1 min-w-[60px]',\n                format === '12h' && 'border-r-3 border-foreground'\n              )}>\n                <div className=\"px-2 py-2 text-center text-xs font-bold uppercase tracking-wide text-muted-foreground border-b-3 border-foreground bg-muted/30\">\n                  Sec\n                </div>\n                <ScrollArea className=\"h-[200px]\">\n                  <div className=\"p-1\">\n                    {secondsArray.map((second) => (\n                      <button\n                        key={second}\n                        type=\"button\"\n                        onClick={() => updateTime(undefined, undefined, second)}\n                        className={cn(\n                          'w-full px-2 py-1.5 text-center text-sm',\n                          'transition-all duration-150 ease-out',\n                          'hover:bg-muted hover:scale-105',\n                          'focus:outline-none focus:bg-muted',\n                          selectedSecond === second && 'bg-primary text-primary-foreground shadow-[2px_2px_0px_hsl(var(--shadow-color))] scale-105'\n                        )}\n                      >\n                        {second.toString().padStart(2, '0')}\n                      </button>\n                    ))}\n                  </div>\n                </ScrollArea>\n              </div>\n            )}\n\n            {/* AM/PM column */}\n            {format === '12h' && (\n              <div className=\"flex-1 min-w-[50px]\">\n                <div className=\"px-2 py-2 text-center text-xs font-bold uppercase tracking-wide text-muted-foreground border-b-3 border-foreground bg-muted/30\">\n                  <span className=\"hidden sm:inline\">Period</span>\n                  <span className=\"sm:hidden\">AP</span>\n                </div>\n                <div className=\"p-1 space-y-1\">\n                  {(['AM', 'PM'] as const).map((period) => (\n                    <button\n                      key={period}\n                      type=\"button\"\n                      onClick={() => updateTime(undefined, undefined, undefined, period)}\n                      className={cn(\n                        'w-full px-2 py-3 text-center text-sm font-bold',\n                        'transition-all duration-150 ease-out',\n                        'hover:bg-muted hover:scale-105',\n                        'focus:outline-none focus:bg-muted',\n                        selectedPeriod === period && 'bg-primary text-primary-foreground shadow-[2px_2px_0px_hsl(var(--shadow-color))] scale-105'\n                      )}\n                    >\n                      {period}\n                    </button>\n                  ))}\n                </div>\n              </div>\n            )}\n          </div>\n        </PopoverContent>\n      </Popover>\n    )\n  }\n)\nTimePicker.displayName = 'TimePicker'\n\nexport { TimePicker }\n",
      "type": "registry:ui",
      "target": "components/ui/time-picker.tsx"
    }
  ]
}