{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "calendar",
  "title": "Calendar",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A date grid for one day, several days or a range, with month and year selects, week numbers, disabled rules and range-end styling, on React DayPicker.",
  "dependencies": [
    "react-day-picker@^9",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/direction.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/calendar.tsx",
      "content": "// Ballmac UI: Calendar. https://ui.ballmac.com/components/calendar\n// Based on shadcn/ui Calendar (MIT, Copyright (c) 2023 shadcn) on React DayPicker (MIT, Copyright (c) Giampaolo Bellavite), restyled with a token-driven day grid, rounded range ends, styled month and year selects, and a footer slot.\n\"use client\";\n\nimport * as React from \"react\";\nimport { ChevronDown, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { DayPicker } from \"react-day-picker\";\nimport { useDirection } from \"@/lib/ballmac/direction\";\nimport { cn } from \"@/lib/utils\";\n\ntype CalendarProps = React.ComponentProps<typeof DayPicker> & {\n  /** Draw a border, padding and background around the calendar. Turn off inside a popover or card. */\n  bordered?: boolean;\n};\n\n/**\n * A date grid for picking one day, several days or a range (`mode=\"single\" | \"multiple\" | \"range\"`).\n * All React DayPicker props work: `selected`, `onSelect`, `disabled`, `fromDate`/`toDate`, `numberOfMonths`,\n * `captionLayout=\"dropdown\"` for month and year selects, `showWeekNumber`, and `locale`.\n * Arrow keys move between days, PageUp/PageDown change month, Home/End jump within the week.\n */\nfunction Calendar({\n  className,\n  classNames,\n  bordered = false,\n  showOutsideDays = true,\n  captionLayout = \"label\",\n  components,\n  ...props\n}: CalendarProps) {\n  const dir = useDirection(props.dir === \"rtl\" || props.dir === \"ltr\" ? props.dir : undefined);\n  return (\n    <DayPicker\n      dir={dir}\n      data-slot=\"calendar\"\n      showOutsideDays={showOutsideDays}\n      captionLayout={captionLayout}\n      className={cn(\n        \"group/calendar w-fit select-none [--cell-size:2.25rem]\",\n        bordered && \"rounded-xl border bg-card p-3 text-card-foreground shadow-xs\",\n        className,\n      )}\n      classNames={{\n        root: \"relative\",\n        months: \"relative flex flex-col gap-4 sm:flex-row\",\n        month: \"flex w-full flex-col gap-3\",\n        nav: \"absolute inset-x-0 top-0 z-10 flex h-(--cell-size) items-center justify-between\",\n        button_previous: navButton,\n        button_next: navButton,\n        month_caption: \"flex h-(--cell-size) items-center justify-center px-(--cell-size)\",\n        caption_label: cn(\n          \"text-sm font-semibold\",\n          captionLayout !== \"label\" &&\n            \"flex h-8 items-center gap-1 rounded-md pe-1 ps-2 text-sm font-medium [&>svg]:size-3.5 [&>svg]:text-muted-foreground\",\n        ),\n        dropdowns: \"flex h-(--cell-size) items-center justify-center gap-1.5 text-sm font-medium\",\n        dropdown_root:\n          \"relative rounded-md border border-input shadow-xs has-focus-visible:border-ring has-focus-visible:ring-[3px] has-focus-visible:ring-ring/50\",\n        dropdown: \"absolute inset-0 cursor-pointer opacity-0\",\n        months_dropdown: \"\",\n        years_dropdown: \"\",\n        month_grid: \"w-full border-collapse\",\n        weekdays: \"flex\",\n        weekday: \"flex-1 pb-1 text-center text-[0.75rem] font-medium text-muted-foreground\",\n        week: \"mt-1 flex w-full\",\n        week_number_header: \"w-(--cell-size)\",\n        week_number: \"w-(--cell-size) text-center text-xs text-muted-foreground\",\n        day: dayCell,\n        day_button: dayButton,\n        range_start: \"rounded-s-md bg-accent [&>button]:rounded-md\",\n        range_middle: \"rounded-none bg-accent [&>button]:!bg-transparent [&>button]:!text-accent-foreground [&>button]:hover:!bg-foreground/10\",\n        range_end: \"rounded-e-md bg-accent [&>button]:rounded-md\",\n        selected: \"[&>button]:bg-primary [&>button]:text-primary-foreground [&>button]:hover:bg-primary\",\n        today:\n          \"[&>button]:font-semibold [&:not([aria-selected=true])>button:not([data-range-middle])]:bg-accent [&:not([aria-selected=true])>button]:after:absolute [&:not([aria-selected=true])>button]:after:bottom-1 [&:not([aria-selected=true])>button]:after:left-1/2 [&:not([aria-selected=true])>button]:after:size-1 [&:not([aria-selected=true])>button]:after:-translate-x-1/2 [&:not([aria-selected=true])>button]:after:rounded-full [&:not([aria-selected=true])>button]:after:bg-primary\",\n        outside: \"text-muted-foreground aria-selected:text-muted-foreground\",\n        disabled: \"text-muted-foreground opacity-40 [&>button]:pointer-events-none\",\n        hidden: \"invisible\",\n        footer: \"mt-2 text-sm text-muted-foreground\",\n        ...classNames,\n      }}\n      components={{\n        Chevron: ({ orientation, className: c, ...rest }) => {\n          const Icon =\n            orientation === \"left\" ? ChevronLeft : orientation === \"right\" ? ChevronRight : ChevronDown;\n          return <Icon aria-hidden=\"true\" className={cn(\"size-4\", c)} {...(rest as object)} />;\n        },\n        ...components,\n      }}\n      {...props}\n    />\n  );\n}\n\nconst navButton =\n  \"inline-flex size-(--cell-size) items-center justify-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-disabled:pointer-events-none aria-disabled:opacity-40\";\nconst dayCell = \"group/day relative aspect-square h-(--cell-size) w-(--cell-size) flex-1 p-0 text-center text-sm\";\nconst dayButton =\n  \"relative flex size-full items-center justify-center rounded-md text-sm font-normal tabular-nums outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:z-10 focus-visible:ring-[3px] focus-visible:ring-ring/50 motion-reduce:transition-none\";\n\nexport { Calendar, type CalendarProps };\n",
      "type": "registry:ui",
      "target": "@components/ballmac/calendar.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "date",
      "calendar",
      "range",
      "day-picker"
    ],
    "version": "1.0.0",
    "updated": "2026-09-30",
    "ai": {
      "summary": "Use mode single, multiple or range with selected and onSelect. All DayPicker props work: disabled, numberOfMonths, captionLayout dropdown, locale.",
      "whenToUse": [
        "Choosing a date or range inside a card or popover",
        "Booking and scheduling",
        "Showing availability with disabled days"
      ],
      "whenNotToUse": [
        "A date field in a form; use date-picker",
        "Typing a range with inputs; use date-range-picker"
      ],
      "composesWith": [
        "popover",
        "date-picker",
        "button"
      ],
      "a11y": [
        {
          "keys": "Arrow keys",
          "action": "Move between days"
        },
        {
          "keys": "PageUp / PageDown",
          "action": "Previous or next month; with Shift, previous or next year"
        },
        {
          "keys": "Home / End",
          "action": "First or last day of the week"
        },
        {
          "keys": "Enter / Space",
          "action": "Selects the focused day"
        }
      ],
      "customization": [
        "mode: single | multiple | range",
        "captionLayout dropdown with startMonth and endMonth",
        "disabled rules and max selection",
        "bordered surface",
        "footer text"
      ]
    },
    "source": {
      "name": "shadcn/ui Calendar",
      "url": "https://github.com/shadcn-ui/ui",
      "license": "MIT",
      "copyright": "Copyright (c) 2023 shadcn",
      "modified": true
    },
    "examples": [
      "calendar-demo",
      "calendar-states"
    ],
    "url": "https://ui.ballmac.com/components/calendar"
  },
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}