{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "calendar",
  "type": "registry:ui",
  "title": "Calendar",
  "description": "Date selection grid built on react-day-picker and themed through tokens.",
  "dependencies": [
    "react-day-picker@^10.0.1"
  ],
  "registryDependencies": [
    "https://control-ui.dev/r/core.json"
  ],
  "files": [
    {
      "path": "src/registry/knob-contracts/calendar-knobs.ts",
      "target": "@components/control-ui/knob-contracts/calendar-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/calendar.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const calendarKnobs = [\n  \"--cui-calendar-day-radius\",\n  \"--cui-calendar-today-background\",\n  \"--cui-calendar-selected-background\",\n  \"--cui-calendar-selected-foreground\",\n  \"--cui-calendar-range-background\",\n] as const;\nexport type CalendarKnobStyle = Partial<Record<(typeof calendarKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/calendar.css",
      "target": "@components/control-ui/styles/recipes/calendar.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"calendar\"][data-slot=\"root\"]) {\n    --cui-calendar-day-radius: var(--radius-control);\n    --cui-calendar-today-background: var(--accent);\n    --cui-calendar-selected-background: var(--primary);\n    --cui-calendar-selected-foreground: var(--primary-foreground);\n    --cui-calendar-range-background: var(--accent);\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"caption-label\"]) {\n    color: var(--foreground);\n    font-size: var(--text-sm);\n    font-weight: 500;\n    line-height: var(--text-sm--line-height, 1.25rem);\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"weekday\"]) {\n    color: var(--muted-foreground);\n    font-size: 0.72rem;\n    font-weight: 400;\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"nav-button\"]) {\n    border-radius: var(--radius-control);\n    outline: none;\n    color: var(--muted-foreground);\n    transition-property: background-color, color, box-shadow;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"calendar\"][data-slot=\"nav-button\"]:hover) {\n      background-color: var(--accent);\n      color: var(--accent-foreground);\n    }\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"nav-button\"]:disabled) {\n    opacity: 0.4;\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"]) {\n    border-radius: var(--cui-calendar-day-radius);\n    outline: none;\n    color: var(--foreground);\n    font-size: var(--text-sm);\n    font-weight: 400;\n    line-height: 1;\n    transition-property: background-color, color, box-shadow;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"calendar\"][data-slot=\"day\"]:hover) {\n      background-color: var(--accent);\n      color: var(--accent-foreground);\n    }\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"]:disabled) {\n    opacity: 0.4;\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"][data-today]) {\n    background-color: var(--cui-calendar-today-background);\n    color: var(--accent-foreground);\n    font-weight: 500;\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"][data-selected-single]),\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"][data-range-start]),\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"][data-range-end]) {\n    background-color: var(--cui-calendar-selected-background);\n    color: var(--cui-calendar-selected-foreground);\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"][data-range-middle]) {\n    border-radius: 0;\n    background-color: var(--cui-calendar-range-background);\n    color: var(--accent-foreground);\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"][data-range-start]) {\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 0;\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day\"][data-range-end]) {\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"day-cell\"]) {\n    text-align: center;\n  }\n\n  :where([data-control-family=\"calendar\"][data-slot=\"month-grid\"]) {\n    border-collapse: collapse;\n  }\n}\n\n@property --cui-calendar-day-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-calendar-today-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-calendar-selected-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-calendar-selected-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-calendar-range-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/calendar.tsx",
      "target": "@components/control-ui/ui/calendar.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport { type ComponentProps, type CSSProperties, useEffect, useRef } from \"react\";\nimport {\n  CaptionLabel as CaptionLabelBase,\n  type ChevronProps,\n  Day as DayBase,\n  type DayButtonProps,\n  DayPicker,\n  Month as MonthBase,\n  MonthCaption as MonthCaptionBase,\n  MonthGrid as MonthGridBase,\n  Months as MonthsBase,\n  Nav as NavBase,\n  Weekday as WeekdayBase,\n} from \"react-day-picker\";\nimport type { CalendarKnobStyle } from \"@/components/control-ui/knob-contracts/calendar-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\n\n// react-day-picker v10 — Base UI ships no calendar, so this is one primitive reaching outside it.\n// CalendarProps stays here rather than contracts.ts, which every component installs, so plain Button install never pulls this import.\ntype CalendarPropsWithStyle<Props> = Props extends unknown ? Omit<Props, \"style\"> & { style?: CSSProperties & CalendarKnobStyle } : never;\n\nexport type CalendarProps = CalendarPropsWithStyle<ComponentProps<typeof DayPicker>>;\n\nconst dayButtonClasses = \"flex h-9 w-full min-w-9 items-center justify-center disabled:pointer-events-none\";\n\nconst navButtonClasses = \"inline-flex size-8 items-center justify-center disabled:pointer-events-none\";\n\nconst chevronPathByOrientation = {\n  left: \"M10 3 5.5 8 10 13\",\n  right: \"M6 3 10.5 8 6 13\",\n  up: \"M3 10 8 5.5 13 10\",\n  down: \"M3 6 8 10.5 13 6\",\n} satisfies Record<NonNullable<ChevronProps[\"orientation\"]>, string>;\n\nexport function Calendar({ className, showOutsideDays = true, style, ...props }: CalendarProps) {\n  return (\n    <div data-control-ui=\"calendar\" data-control-family=\"calendar\" data-slot=\"root\" className={cn(\"w-fit p-3\", className)} style={style}>\n      <DayPicker\n        showOutsideDays={showOutsideDays}\n        components={{\n          Chevron: CalendarChevron,\n          Months: CalendarMonths,\n          Month: CalendarMonth,\n          MonthCaption: CalendarMonthCaption,\n          CaptionLabel: CalendarCaptionLabel,\n          Nav: CalendarNav,\n          PreviousMonthButton: CalendarNavButton,\n          NextMonthButton: CalendarNavButton,\n          MonthGrid: CalendarMonthGrid,\n          Weekday: CalendarWeekday,\n          Day: CalendarDay,\n          DayButton: CalendarDayButton,\n        }}\n        {...props}\n      />\n    </div>\n  );\n}\n\n// `relative` belongs here, not on Month: library renders Nav as sibling of months, so this is closest ancestor its absolute buttons can pin to\nfunction CalendarMonths({ className, ...props }: ComponentProps<typeof MonthsBase>) {\n  return (\n    <MonthsBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"months\"\n      className={cn(\"relative flex flex-col gap-4 sm:flex-row\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarMonth({ className, ...props }: ComponentProps<typeof MonthBase>) {\n  return (\n    <MonthBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"month\"\n      className={cn(\"flex flex-col gap-3\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarMonthCaption({ className, ...props }: ComponentProps<typeof MonthCaptionBase>) {\n  return (\n    <MonthCaptionBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"month-caption\"\n      className={cn(\"flex h-9 items-center justify-center\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarCaptionLabel({ className, ...props }: ComponentProps<typeof CaptionLabelBase>) {\n  return (\n    <CaptionLabelBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"caption-label\"\n      className={cn(\"select-none\", className)}\n      {...props}\n    />\n  );\n}\n\n// matches MonthCaption row so buttons centre on month label\nfunction CalendarNav({ className, ...props }: ComponentProps<typeof NavBase>) {\n  return (\n    <NavBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"nav\"\n      className={cn(\"absolute inset-x-0 top-0 flex h-9 items-center justify-between\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarNavButton({ className, ...props }: ComponentProps<\"button\">) {\n  return (\n    <button\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"nav-button\"\n      className={cn(navButtonClasses, className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarMonthGrid({ className, ...props }: ComponentProps<typeof MonthGridBase>) {\n  return (\n    <MonthGridBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"month-grid\"\n      className={cn(\"mt-1 w-full\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarWeekday({ className, ...props }: ComponentProps<typeof WeekdayBase>) {\n  return (\n    <WeekdayBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"weekday\"\n      className={cn(\"pb-1.5\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarDay({ className, ...props }: ComponentProps<typeof DayBase>) {\n  return (\n    <DayBase\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"day-cell\"\n      className={cn(\"p-0 align-middle\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarDayButton({ day, modifiers, className, ...props }: DayButtonProps) {\n  const ref = useRef<HTMLButtonElement>(null);\n  useEffect(() => {\n    if (modifiers.focused) ref.current?.focus();\n  }, [modifiers.focused]);\n  // one-click range marks same day as both ends, which would flatten both sides and drop --radius-control entirely\n  const isSingleDayRange = Boolean(modifiers.range_start && modifiers.range_end);\n  const isRange = !isSingleDayRange && (modifiers.range_start || modifiers.range_middle || modifiers.range_end);\n  return (\n    <button\n      ref={ref}\n      type=\"button\"\n      data-control-ui=\"calendar\"\n      data-control-family=\"calendar\"\n      data-slot=\"day\"\n      data-today={modifiers.today ? true : undefined}\n      data-selected-single={modifiers.selected && !isRange ? true : undefined}\n      data-range-start={modifiers.range_start && !isSingleDayRange ? true : undefined}\n      data-range-middle={modifiers.range_middle ? true : undefined}\n      data-range-end={modifiers.range_end && !isSingleDayRange ? true : undefined}\n      className={cn(dayButtonClasses, className)}\n      {...props}\n    />\n  );\n}\n\nfunction CalendarChevron({ className, orientation }: ChevronProps) {\n  const path = chevronPathByOrientation[orientation ?? \"down\"];\n  return (\n    <svg\n      viewBox=\"0 0 16 16\"\n      className={cn(\"size-4\", className)}\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"1.5\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden=\"true\"\n    >\n      <path d={path} />\n    </svg>\n  );\n}\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/calendar.css\"": {}
  },
  "meta": {}
}
