{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "calendar",
  "title": "Calendar",
  "description": "Accessible date grid built on react-day-picker v9.",
  "dependencies": ["lucide-react", "react-day-picker"],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/glasswave/ui/calendar.tsx",
      "content": "\"use client\";\n\nimport \"react-day-picker/style.css\";\n\nimport { ChevronDown, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { DayPicker, getDefaultClassNames } from \"react-day-picker\";\nimport { cn } from \"@/lib/utils\";\n\nexport type CalendarProps = React.ComponentProps<typeof DayPicker>;\n\nexport function Calendar({\n  className,\n  classNames,\n  components,\n  captionLayout = \"dropdown\",\n  showOutsideDays = true,\n  startMonth,\n  endMonth,\n  style,\n  ...props\n}: CalendarProps) {\n  const defaults = getDefaultClassNames();\n\n  // The month/year dropdowns need a bounded range to list options. Default to a\n  // wide, generally-useful span; callers can still pass their own.\n  const fromMonth = startMonth ?? new Date(1925, 0);\n  const toMonth = endMonth ?? new Date(new Date().getFullYear() + 5, 11);\n\n  // Neutralize react-day-picker's blue accent at the source. These are set\n  // inline (highest priority) because rdp declares the same vars on `.rdp-root`\n  // with equal specificity, so a class would lose on load order. Values are\n  // theme-neutral, so they work in both light and dark.\n  const accentReset = {\n    \"--rdp-accent-color\": \"currentColor\",\n    \"--rdp-accent-background-color\": \"transparent\",\n    \"--rdp-selected-border\": \"0\",\n    \"--rdp-today-color\": \"inherit\",\n    // rdp defaults day cells to 44px via these vars, which beat our `w-9` on the\n    // day (same specificity, rdp loads later) while the weekday header has no\n    // width rule and stays 36px — so the columns drift apart. Pin every cell to\n    // 36px at the source so weekdays and days share one column pitch.\n    \"--rdp-day-width\": \"2.25rem\",\n    \"--rdp-day-height\": \"2.25rem\",\n    \"--rdp-day_button-width\": \"2.25rem\",\n    \"--rdp-day_button-height\": \"2.25rem\",\n    \"--rdp-day_button-border\": \"0\",\n  } as React.CSSProperties;\n\n  return (\n    <DayPicker\n      showOutsideDays={showOutsideDays}\n      captionLayout={captionLayout}\n      startMonth={fromMonth}\n      endMonth={toMonth}\n      style={{ ...accentReset, ...style }}\n      className={cn(\"w-fit p-3\", className)}\n      components={{\n        // rdp's default chevrons are sharp; lucide's have rounded line caps and\n        // we render them smaller for a softer nav. `down` is the dropdown caret.\n        Chevron: ({ orientation }) => {\n          const Icon =\n            orientation === \"left\"\n              ? ChevronLeft\n              : orientation === \"right\"\n                ? ChevronRight\n                : ChevronDown;\n          return <Icon className=\"size-4\" strokeWidth={2} />;\n        },\n        ...components,\n      }}\n      classNames={{\n        ...defaults,\n        months: cn(defaults.months, \"relative flex flex-col gap-4 sm:flex-row\"),\n        month: cn(defaults.month, \"flex flex-col gap-3\"),\n        month_caption: cn(\n          defaults.month_caption,\n          \"flex h-9 items-center justify-center\",\n        ),\n        caption_label: cn(\n          defaults.caption_label,\n          \"inline-flex items-center gap-0.5 text-sm font-medium tracking-tight\",\n        ),\n        // Month/year dropdown navigation: rdp lays a transparent native <select>\n        // over a visible label, so we just style the label to read as a button.\n        dropdowns: cn(defaults.dropdowns, \"flex items-center gap-1\"),\n        dropdown_root: cn(\n          defaults.dropdown_root,\n          \"relative inline-flex items-center rounded-full px-2.5 py-1 transition-colors hover:bg-black/[0.05] dark:hover:bg-white/10\",\n        ),\n        dropdown: cn(defaults.dropdown, \"cursor-pointer\"),\n        nav: cn(\n          defaults.nav,\n          \"absolute inset-x-0 top-0 flex h-9 items-center justify-between\",\n        ),\n        button_previous: cn(\n          defaults.button_previous,\n          \"inline-flex size-8 items-center justify-center rounded-full bg-transparent text-current/45 transition-colors hover:bg-black/[0.05] hover:text-current/80 dark:hover:bg-white/10\",\n        ),\n        button_next: cn(\n          defaults.button_next,\n          \"inline-flex size-8 items-center justify-center rounded-full bg-transparent text-current/45 transition-colors hover:bg-black/[0.05] hover:text-current/80 dark:hover:bg-white/10\",\n        ),\n        month_grid: cn(defaults.month_grid, \"border-collapse\"),\n        weekdays: cn(defaults.weekdays, \"flex\"),\n        weekday: cn(\n          defaults.weekday,\n          \"w-9 text-center text-[0.75rem] font-medium text-current/40\",\n        ),\n        week: cn(defaults.week, \"mt-1 flex w-full\"),\n        day: cn(defaults.day, \"size-9 p-0 text-center text-sm\"),\n        // No background transition on the day button: rdp swaps the selected\n        // modifier instantly, so a color transition leaves a \"ghost\" circle\n        // fading in/out as you move between dates. Focus uses focus-visible so a\n        // plain mouse click does not flash a ring.\n        // Explicit text-sm + font-normal here so the button never inherits\n        // rdp's `.rdp-selected { font-size: large; font-weight: bold }` from the\n        // cell — that inheritance is what made the digit jump/grow on select.\n        day_button: cn(\n          defaults.day_button,\n          \"mx-auto flex size-9 items-center justify-center rounded-full !text-sm !font-normal text-current outline-none hover:bg-black/[0.05] dark:hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-black/15 dark:focus-visible:ring-white/25 aria-selected:opacity-100\",\n        ),\n        // Selected = solid, glowing iOS-style pill. `!font-normal` so the digit\n        // stays the default weight even when the selected day is also `today`\n        // (which sets font-medium); `!bg`/`!text` so it beats the grey today\n        // circle.\n        selected: cn(\n          defaults.selected,\n          // Kill rdp's `.rdp-selected { font-size: large; font-weight: bold }`\n          // right on the cell where it is declared, so nothing can inherit it.\n          \"!text-sm !font-normal [&>button]:!text-sm [&>button]:!font-normal [&>button]:!bg-zinc-900 [&>button]:!text-white [&>button]:shadow-[0_4px_14px_rgba(0,0,0,0.30)] [&>button:hover]:!bg-zinc-900 dark:[&>button]:!bg-white dark:[&>button]:!text-zinc-900 dark:[&>button]:shadow-[0_4px_16px_rgba(255,255,255,0.20)] dark:[&>button:hover]:!bg-white\",\n        ),\n        // Today (when not selected) = subtle grey circle only. No weight change\n        // anywhere, so moving between days never reflows the digits.\n        today: cn(\n          defaults.today,\n          \"[&>button]:bg-black/[0.05] dark:[&>button]:bg-white/[0.10]\",\n        ),\n        outside: cn(\n          defaults.outside,\n          \"[&>button]:text-current/30 aria-selected:[&>button]:text-current/30\",\n        ),\n        disabled: cn(defaults.disabled, \"[&>button]:text-current/25\"),\n        hidden: cn(defaults.hidden, \"invisible\"),\n        ...classNames,\n      }}\n      {...props}\n    />\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}
