{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "calendar",
  "title": "Calendar",
  "description": "Date grid with day, month and decade views and full keyboard support.",
  "dependencies": ["lucide-react"],
  "registryDependencies": [
    "https://indiacn.in/r/theme.json",
    "https://indiacn.in/r/typography.json"
  ],
  "files": [
    {
      "path": "components/ui/calendar.tsx",
      "content": "'use client';\n\nimport { ChevronDown, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';\nimport { KeyboardEvent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Label1, Label2 } from '@/components/ui/typography';\nimport { cn } from '@/lib/utils';\n\n/*\n * UX4G calendar: four views off one surface — a single month, two months side\n * by side for ranges, a year of months, and a decade of years.\n *\n * Measured from the kit at 1:1 — today is a 1px #613af5 outline, the selected\n * day is filled #613af5, a range fills #faefff (primary-50), and the card\n * carries a shadow rather than a border.\n *\n * Two deliberate departures. The kit's day cells are 24px on a 41px pitch;\n * these are 36px on a 37px pitch, so the footprint is unchanged but the target\n * clears WCAG 2.5.8 comfortably. And in the two-month view the kit repeats the\n * full arrow set under both headers; here the back arrows sit on the first\n * month and the forward arrows on the last, because two controls that move the\n * same window read as four different destinations to a screen reader.\n */\nconst WEEKDAY_LABELS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] as const;\n\nconst MONTH_LABELS = [\n  'Jan',\n  'Feb',\n  'Mar',\n  'Apr',\n  'May',\n  'Jun',\n  'Jul',\n  'Aug',\n  'Sep',\n  'Oct',\n  'Nov',\n  'Dec',\n] as const;\n\nconst MONTH_LABELS_LONG = [\n  'January',\n  'February',\n  'March',\n  'April',\n  'May',\n  'June',\n  'July',\n  'August',\n  'September',\n  'October',\n  'November',\n  'December',\n] as const;\n\nconst DAYS_IN_GRID = 42;\n\n/** Midnight on the given day, so comparisons ignore the clock. */\nfunction startOfDay(date: Date) {\n  return new Date(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\n/** Shifts by whole days, rolling over month and year boundaries. */\nfunction addDays(date: Date, amount: number) {\n  return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount);\n}\n\n/** Shifts by whole months, landing on the first of the target month. */\nfunction addMonths(date: Date, amount: number) {\n  return new Date(date.getFullYear(), date.getMonth() + amount, 1);\n}\n\n/** True when both dates fall on the same calendar day. */\nfunction isSameDay(a?: Date | null, b?: Date | null) {\n  return (\n    !!a &&\n    !!b &&\n    a.getFullYear() === b.getFullYear() &&\n    a.getMonth() === b.getMonth() &&\n    a.getDate() === b.getDate()\n  );\n}\n\n/** True when both dates fall in the same calendar month. */\nfunction isSameMonth(a: Date, b: Date) {\n  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();\n}\n\n/** Stable key for a day, used to address the cell refs. */\nfunction dayKey(date: Date) {\n  return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;\n}\n\n/** The six weeks that cover a month, including the days either side of it. */\nfunction monthMatrix(month: Date, weekStartsOn: number) {\n  const first = new Date(month.getFullYear(), month.getMonth(), 1);\n  const offset = (first.getDay() - weekStartsOn + 7) % 7;\n  const start = addDays(first, -offset);\n\n  return Array.from({ length: DAYS_IN_GRID }, (_, index) => addDays(start, index));\n}\n\n/** Weekday names rotated so the configured first day of the week leads. */\nfunction weekdayLabels(weekStartsOn: number) {\n  return Array.from({ length: 7 }, (_, index) => WEEKDAY_LABELS[(weekStartsOn + index) % 7]);\n}\n\n/** Long-form label used in the day cell's accessible name. */\nfunction describeDay(date: Date) {\n  return `${date.getDate()} ${MONTH_LABELS_LONG[date.getMonth()]} ${date.getFullYear()}`;\n}\n\ninterface IDateRange {\n  from: Date | null;\n  to: Date | null;\n}\n\ntype TCalendarView = 'day' | 'month' | 'year';\n\nconst CELL_BASE =\n  'focus-visible:shadow-focus-primary flex size-9 cursor-pointer items-center justify-center rounded-md border border-transparent text-sm transition-colors focus-visible:outline-none disabled:pointer-events-none';\n\ninterface ICalendarNavProps {\n  label: ReactNode;\n  onStepBack: () => void;\n  onStepForward: () => void;\n  onJumpBack: () => void;\n  onJumpForward: () => void;\n  stepBackLabel: string;\n  stepForwardLabel: string;\n  jumpBackLabel: string;\n  jumpForwardLabel: string;\n  showStep?: boolean;\n  showBack?: boolean;\n  showForward?: boolean;\n}\n\n/**\n * The arrow row above a grid.\n *\n * `showBack` / `showForward` let the two-month view put the back arrows on the\n * first header and the forward arrows on the last without duplicating them.\n */\nfunction CalendarNav({\n  label,\n  onStepBack,\n  onStepForward,\n  onJumpBack,\n  onJumpForward,\n  stepBackLabel,\n  stepForwardLabel,\n  jumpBackLabel,\n  jumpForwardLabel,\n  showStep = true,\n  showBack = true,\n  showForward = true,\n}: ICalendarNavProps) {\n  /*\n   * Both arrow groups reserve the same width whether or not they render\n   * anything. Without it the two-month view, which shows the back arrows only\n   * on the first month, pushed each month's label 30px off the centre of its\n   * own grid.\n   */\n  return (\n    <div className='flex h-8 items-center gap-2'>\n      <div className='flex w-15 items-center justify-start gap-1'>\n        {showBack && (\n          <CalendarNavButton onClick={onJumpBack} label={jumpBackLabel}>\n            <ChevronsLeft aria-hidden />\n          </CalendarNavButton>\n        )}\n        {showBack && showStep && (\n          <CalendarNavButton onClick={onStepBack} label={stepBackLabel}>\n            <ChevronLeft aria-hidden />\n          </CalendarNavButton>\n        )}\n      </div>\n      <Label1 className='text-neutral flex-1 text-center'>{label}</Label1>\n      <div className='flex w-15 items-center justify-end gap-1'>\n        {showForward && showStep && (\n          <CalendarNavButton onClick={onStepForward} label={stepForwardLabel}>\n            <ChevronRight aria-hidden />\n          </CalendarNavButton>\n        )}\n        {showForward && (\n          <CalendarNavButton onClick={onJumpForward} label={jumpForwardLabel}>\n            <ChevronsRight aria-hidden />\n          </CalendarNavButton>\n        )}\n      </div>\n    </div>\n  );\n}\n\n/** One arrow. Always carries a text label, since the glyph is decorative. */\nfunction CalendarNavButton({\n  onClick,\n  label,\n  children,\n}: {\n  onClick: () => void;\n  label: string;\n  children: ReactNode;\n}) {\n  return (\n    <button\n      type='button'\n      onClick={onClick}\n      aria-label={label}\n      className='focus-visible:shadow-focus-primary hover:bg-primary-50 hover:text-primary-800 flex size-7 cursor-pointer items-center justify-center rounded-md text-neutral-600 transition-colors focus-visible:outline-none [&>svg]:size-4'\n    >\n      {children}\n    </button>\n  );\n}\n\ninterface ICalendarDayProps {\n  date: Date;\n  label: string;\n  outside: boolean;\n  disabled: boolean;\n  selected: boolean;\n  today: boolean;\n  inRange: boolean;\n  focused: boolean;\n  onSelect: (date: Date) => void;\n  registerRef: (key: string, node: HTMLButtonElement | null) => void;\n}\n\n/** A single day. Split out so its click and ref callbacks stay stable. */\nfunction CalendarDay({\n  date,\n  label,\n  outside,\n  disabled,\n  selected,\n  today,\n  inRange,\n  focused,\n  onSelect,\n  registerRef,\n}: ICalendarDayProps) {\n  const handleClick = useCallback(() => onSelect(date), [onSelect, date]);\n  const handleRef = useCallback(\n    (node: HTMLButtonElement | null) => registerRef(dayKey(date), node),\n    [registerRef, date],\n  );\n\n  return (\n    <button\n      ref={handleRef}\n      type='button'\n      role='gridcell'\n      aria-label={label}\n      aria-selected={selected}\n      aria-current={today ? 'date' : undefined}\n      aria-disabled={disabled || undefined}\n      disabled={disabled}\n      tabIndex={focused ? 0 : -1}\n      onClick={handleClick}\n      className={cn(\n        CELL_BASE,\n        'text-neutral hover:bg-primary-50 hover:text-primary-800',\n        outside && 'text-neutral-400',\n        inRange && !selected && 'bg-primary-50 text-primary-800 hover:bg-primary-100',\n        today && !selected && 'border-primary text-primary',\n        selected &&\n          'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground',\n        disabled &&\n          'cursor-not-allowed text-neutral-400 hover:bg-transparent hover:text-neutral-400',\n      )}\n    >\n      {date.getDate()}\n    </button>\n  );\n}\n\ninterface ICalendarMonthProps {\n  month: Date;\n  weekStartsOn: number;\n  today: Date;\n  focusedDate: Date;\n  selected: Date | null;\n  range: IDateRange | null;\n  fixedWeeks: boolean;\n  onSelect: (date: Date) => void;\n  registerRef: (key: string, node: HTMLButtonElement | null) => void;\n  min?: Date;\n  max?: Date;\n}\n\n/** One month's day grid, with its weekday header row. */\nfunction CalendarMonth({\n  month,\n  weekStartsOn,\n  today,\n  focusedDate,\n  selected,\n  range,\n  min,\n  max,\n  fixedWeeks,\n  onSelect,\n  registerRef,\n}: ICalendarMonthProps) {\n  const labels = useMemo(() => weekdayLabels(weekStartsOn), [weekStartsOn]);\n  const days = useMemo(() => {\n    const all = monthMatrix(month, weekStartsOn);\n    if (fixedWeeks) return all;\n    const lastWeek = all.slice(35);\n\n    return lastWeek.every(day => !isSameMonth(day, month)) ? all.slice(0, 35) : all;\n  }, [month, weekStartsOn, fixedWeeks]);\n\n  const rangeFrom = range?.from ? startOfDay(range.from) : null;\n  const rangeTo = range?.to ? startOfDay(range.to) : null;\n\n  return (\n    <div className='flex flex-col gap-1'>\n      <div role='row' className='grid w-full grid-cols-7 justify-items-center'>\n        {labels.map(label => (\n          <Label2\n            key={label}\n            role='columnheader'\n            className='text-neutral flex size-9 items-center justify-center'\n          >\n            {label}\n          </Label2>\n        ))}\n      </div>\n      <div className='grid w-full grid-cols-7 justify-items-center gap-y-1'>\n        {days.map(day => {\n          const outside = !isSameMonth(day, month);\n          const beforeMin = !!min && day < startOfDay(min);\n          const afterMax = !!max && day > startOfDay(max);\n          const isEdge = isSameDay(day, rangeFrom) || isSameDay(day, rangeTo);\n          const inRange = !!rangeFrom && !!rangeTo && day >= rangeFrom && day <= rangeTo && !isEdge;\n\n          return (\n            <CalendarDay\n              key={dayKey(day)}\n              date={day}\n              label={describeDay(day)}\n              outside={outside}\n              disabled={beforeMin || afterMax || outside}\n              selected={isSameDay(day, selected) || isEdge}\n              today={isSameDay(day, today)}\n              inRange={inRange}\n              focused={isSameDay(day, focusedDate)}\n              onSelect={onSelect}\n              registerRef={registerRef}\n            />\n          );\n        })}\n      </div>\n    </div>\n  );\n}\n\n/** One month name in the year view, or one year in the decade view. */\nfunction CalendarChoice({\n  value,\n  label,\n  selected,\n  muted,\n  onSelect,\n}: {\n  value: number;\n  label: string;\n  selected: boolean;\n  muted: boolean;\n  onSelect: (value: number) => void;\n}) {\n  const handleClick = useCallback(() => onSelect(value), [onSelect, value]);\n\n  return (\n    <button\n      type='button'\n      onClick={handleClick}\n      aria-pressed={selected}\n      className={cn(\n        CELL_BASE,\n        // Figma's selected pill measures 60x24 in a 300px card; 72x36 keeps the\n        // proportion while clearing the minimum target size.\n        'h-9 w-18',\n        muted ? 'text-neutral-400' : 'text-neutral hover:bg-primary-50 hover:text-primary-800',\n        selected &&\n          'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground',\n      )}\n    >\n      {label}\n    </button>\n  );\n}\n\ninterface ICalendarProps {\n  /** Selected day in single-select mode. */\n  value?: Date | null;\n  onValueChange?: (date: Date) => void;\n  /** Selected span in range mode. Providing this switches the calendar to ranges. */\n  range?: IDateRange;\n  onRangeChange?: (range: IDateRange) => void;\n  /** Months shown side by side. Two is the kit's range layout. */\n  months?: 1 | 2;\n  /** Which grid opens first. Month and year views drill down into days. */\n  defaultView?: TCalendarView;\n  /** Shows the month and year selects plus the Month/Year view toggle. */\n  showViewControls?: boolean;\n  /**\n   * Always render six week rows. Off by default: a trailing week made\n   * entirely of next month's days is noise, and the kit never shows one.\n   */\n  fixedWeeks?: boolean;\n  weekStartsOn?: 0 | 1;\n  min?: Date;\n  max?: Date;\n  /** Anchors \"today\" and the initial view. Pass a fixed date in tests. */\n  referenceDate?: Date;\n  className?: string;\n}\n\n/**\n * Date grid with day, month and year views.\n *\n * Keyboard support follows the ARIA grid pattern: arrows move a day at a time,\n * Home and End jump to the ends of the week, PageUp and PageDown change month,\n * and only the focused cell is tabbable so the grid is a single tab stop.\n */\nfunction Calendar({\n  value = null,\n  onValueChange,\n  range,\n  onRangeChange,\n  months = 1,\n  defaultView = 'day',\n  showViewControls = false,\n  fixedWeeks = false,\n  weekStartsOn = 1,\n  min,\n  max,\n  referenceDate,\n  className,\n}: ICalendarProps) {\n  const today = useMemo(() => startOfDay(referenceDate ?? new Date()), [referenceDate]);\n  const [view, setView] = useState<TCalendarView>(defaultView);\n  const [viewMonth, setViewMonth] = useState(() =>\n    addMonths(value ?? range?.from ?? referenceDate ?? new Date(), 0),\n  );\n  const [focusedDate, setFocusedDate] = useState(() => value ?? range?.from ?? today);\n  const cells = useRef(new Map<string, HTMLButtonElement>());\n  const pendingFocus = useRef(false);\n\n  const registerRef = useCallback((key: string, node: HTMLButtonElement | null) => {\n    if (node) cells.current.set(key, node);\n    else cells.current.delete(key);\n  }, []);\n\n  useEffect(() => {\n    if (!pendingFocus.current) return;\n    pendingFocus.current = false;\n    cells.current.get(dayKey(focusedDate))?.focus();\n  }, [focusedDate]);\n\n  const moveFocus = useCallback((next: Date) => {\n    pendingFocus.current = true;\n    setFocusedDate(next);\n    setViewMonth(current => (isSameMonth(next, current) ? current : addMonths(next, 0)));\n  }, []);\n\n  const handleSelect = useCallback(\n    (date: Date) => {\n      setFocusedDate(date);\n      if (range && onRangeChange) {\n        const open = range.from && !range.to;\n        if (open && range.from && date >= range.from) onRangeChange({ from: range.from, to: date });\n        else onRangeChange({ from: date, to: null });\n\n        return;\n      }\n      onValueChange?.(date);\n    },\n    [range, onRangeChange, onValueChange],\n  );\n\n  const handleKeyDown = useCallback(\n    (event: KeyboardEvent<HTMLDivElement>) => {\n      const moves: Record<string, number> = {\n        ArrowLeft: -1,\n        ArrowRight: 1,\n        ArrowUp: -7,\n        ArrowDown: 7,\n      };\n      if (event.key in moves) {\n        event.preventDefault();\n        moveFocus(addDays(focusedDate, moves[event.key]));\n\n        return;\n      }\n      if (event.key === 'Home' || event.key === 'End') {\n        event.preventDefault();\n        const offset = (focusedDate.getDay() - weekStartsOn + 7) % 7;\n        moveFocus(addDays(focusedDate, event.key === 'Home' ? -offset : 6 - offset));\n\n        return;\n      }\n      if (event.key === 'PageUp' || event.key === 'PageDown') {\n        event.preventDefault();\n        const step = event.key === 'PageUp' ? -1 : 1;\n        const shifted = addMonths(focusedDate, event.shiftKey ? step * 12 : step);\n        const lastDay = new Date(shifted.getFullYear(), shifted.getMonth() + 1, 0).getDate();\n        moveFocus(\n          new Date(\n            shifted.getFullYear(),\n            shifted.getMonth(),\n            Math.min(focusedDate.getDate(), lastDay),\n          ),\n        );\n      }\n    },\n    [focusedDate, moveFocus, weekStartsOn],\n  );\n\n  const stepMonth = useCallback((amount: number) => {\n    setViewMonth(current => addMonths(current, amount));\n  }, []);\n  const stepBack = useCallback(() => stepMonth(-1), [stepMonth]);\n  const stepForward = useCallback(() => stepMonth(1), [stepMonth]);\n  const jumpBack = useCallback(() => stepMonth(-12), [stepMonth]);\n  const jumpForward = useCallback(() => stepMonth(12), [stepMonth]);\n\n  const pickMonth = useCallback((month: number) => {\n    setViewMonth(current => new Date(current.getFullYear(), month, 1));\n    setView('day');\n  }, []);\n  const pickYear = useCallback((year: number) => {\n    setViewMonth(current => new Date(year, current.getMonth(), 1));\n    setView('month');\n  }, []);\n  const openMonthView = useCallback(\n    () => setView(current => (current === 'month' ? 'day' : 'month')),\n    [],\n  );\n  const openYearView = useCallback(\n    () => setView(current => (current === 'year' ? 'day' : 'year')),\n    [],\n  );\n\n  const handleMonthSelect = useCallback(\n    (event: React.ChangeEvent<HTMLSelectElement>) => pickMonth(Number(event.target.value)),\n    [pickMonth],\n  );\n  const handleYearSelect = useCallback((event: React.ChangeEvent<HTMLSelectElement>) => {\n    const year = Number(event.target.value);\n    setViewMonth(current => new Date(year, current.getMonth(), 1));\n  }, []);\n\n  const years = useMemo(() => {\n    const first = min ? min.getFullYear() : today.getFullYear() - 100;\n    const last = max ? max.getFullYear() : today.getFullYear() + 10;\n\n    return Array.from({ length: last - first + 1 }, (_, index) => first + index);\n  }, [min, max, today]);\n\n  const decadeStart = Math.floor(viewMonth.getFullYear() / 10) * 10;\n  const shownMonths = useMemo(\n    () => Array.from({ length: months }, (_, index) => addMonths(viewMonth, index)),\n    [months, viewMonth],\n  );\n\n  return (\n    <div\n      className={cn(\n        'bg-neutral-0 inline-flex flex-col gap-4 rounded-lg p-5 shadow-md',\n        // Every view holds the same width, so drilling from days to months to\n        // years does not resize the card under the pointer. 252px is seven\n        // 36px day columns; the select header needs 280.\n        showViewControls ? 'min-w-[320px]' : 'min-w-[292px]',\n        className,\n      )}\n    >\n      {view === 'day' && showViewControls && (\n        <div className='flex items-center gap-2'>\n          {/* Year first, then month, as the kit orders them. */}\n          <CalendarSelect\n            value={viewMonth.getFullYear()}\n            onChange={handleYearSelect}\n            label='Year'\n            options={years.map(year => ({ value: year, label: String(year) }))}\n          />\n          <CalendarSelect\n            value={viewMonth.getMonth()}\n            onChange={handleMonthSelect}\n            label='Month'\n            options={MONTH_LABELS.map((label, index) => ({ value: index, label }))}\n          />\n          <div className='ml-auto flex overflow-hidden rounded-md border border-neutral-200 [&>*+*]:border-l [&>*+*]:border-neutral-200'>\n            <CalendarViewToggle label='Month' onClick={openMonthView} />\n            <CalendarViewToggle label='Year' onClick={openYearView} />\n          </div>\n        </div>\n      )}\n\n      {view === 'day' && (\n        <div\n          role='grid'\n          aria-label='Calendar'\n          onKeyDown={handleKeyDown}\n          className='flex w-full flex-wrap gap-6'\n        >\n          {shownMonths.map((month, index) => (\n            <div key={month.toISOString()} className='flex flex-1 flex-col gap-2'>\n              {/* The kit's one-month card navigates by select, not by arrow.\n                  Showing both stacks two ways to do the same thing. */}\n              {!showViewControls && (\n                <CalendarNav\n                  label={`${MONTH_LABELS[month.getMonth()]} ${month.getFullYear()}`}\n                  onStepBack={stepBack}\n                  onStepForward={stepForward}\n                  onJumpBack={jumpBack}\n                  onJumpForward={jumpForward}\n                  stepBackLabel='Previous month'\n                  stepForwardLabel='Next month'\n                  jumpBackLabel='Previous year'\n                  jumpForwardLabel='Next year'\n                  showBack={index === 0}\n                  showForward={index === shownMonths.length - 1}\n                />\n              )}\n              <CalendarMonth\n                month={month}\n                weekStartsOn={weekStartsOn}\n                today={today}\n                focusedDate={focusedDate}\n                selected={value}\n                range={range ?? null}\n                min={min}\n                max={max}\n                fixedWeeks={fixedWeeks}\n                onSelect={handleSelect}\n                registerRef={registerRef}\n              />\n            </div>\n          ))}\n        </div>\n      )}\n\n      {view === 'month' && (\n        <div className='flex w-full flex-col gap-3'>\n          <CalendarNav\n            label={String(viewMonth.getFullYear())}\n            onStepBack={stepBack}\n            onStepForward={stepForward}\n            onJumpBack={jumpBack}\n            onJumpForward={jumpForward}\n            stepBackLabel='Previous month'\n            stepForwardLabel='Next month'\n            jumpBackLabel='Previous year'\n            jumpForwardLabel='Next year'\n            showStep={false}\n          />\n          <div className='grid grid-cols-3 justify-items-center gap-y-2'>\n            {MONTH_LABELS.map((label, index) => (\n              <CalendarChoice\n                key={label}\n                value={index}\n                label={label}\n                selected={viewMonth.getMonth() === index}\n                muted={false}\n                onSelect={pickMonth}\n              />\n            ))}\n          </div>\n        </div>\n      )}\n\n      {view === 'year' && (\n        <div className='flex w-full flex-col gap-3'>\n          <CalendarNav\n            label={`${decadeStart}-${decadeStart + 9}`}\n            onStepBack={stepBack}\n            onStepForward={stepForward}\n            onJumpBack={jumpBack}\n            onJumpForward={jumpForward}\n            stepBackLabel='Previous year'\n            stepForwardLabel='Next year'\n            jumpBackLabel='Previous decade'\n            jumpForwardLabel='Next decade'\n            showStep={false}\n          />\n          <div className='grid grid-cols-3 justify-items-center gap-y-2'>\n            {Array.from({ length: 12 }, (_, index) => decadeStart - 1 + index).map(year => (\n              <CalendarChoice\n                key={year}\n                value={year}\n                label={String(year)}\n                selected={viewMonth.getFullYear() === year}\n                muted={year < decadeStart || year > decadeStart + 9}\n                onSelect={pickYear}\n              />\n            ))}\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\n/** Month or year select in the day header. Native, so it works on touch. */\nfunction CalendarSelect({\n  value,\n  onChange,\n  label,\n  options,\n}: {\n  value: number;\n  onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;\n  label: string;\n  options: { value: number; label: string }[];\n}) {\n  return (\n    <div className='relative'>\n      <select\n        value={value}\n        onChange={onChange}\n        aria-label={label}\n        className='bg-neutral-0 text-neutral focus-visible:shadow-focus-primary hover:border-primary h-8 cursor-pointer appearance-none rounded-md border border-neutral-200 pr-7 pl-2.5 text-sm transition-colors focus-visible:outline-none'\n      >\n        {options.map(option => (\n          <option key={option.value} value={option.value}>\n            {option.label}\n          </option>\n        ))}\n      </select>\n      <ChevronDown\n        className='pointer-events-none absolute top-1/2 right-2 size-4 -translate-y-1/2 text-neutral-600'\n        aria-hidden\n      />\n    </div>\n  );\n}\n\n/**\n * One half of the Month/Year toggle.\n *\n * These open the month and decade grids. The kit paints one of them filled,\n * but nothing is selected while the day grid is showing, so neither is marked\n * pressed here — the fill would claim a state that does not exist.\n */\nfunction CalendarViewToggle({ label, onClick }: { label: string; onClick: () => void }) {\n  return (\n    <button\n      type='button'\n      onClick={onClick}\n      className='focus-visible:shadow-focus-primary text-neutral hover:bg-primary-50 hover:text-primary-800 h-8 cursor-pointer px-3 text-sm transition-colors focus-visible:outline-none'\n    >\n      {label}\n    </button>\n  );\n}\n\nexport type { IDateRange, TCalendarView };\n\nexport { Calendar, addDays, addMonths, isSameDay, startOfDay, MONTH_LABELS, MONTH_LABELS_LONG };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}
