{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "calendar",
  "title": "Calendar",
  "description": "A month grid for picking a day or a range, with the selection in the info color.",
  "dependencies": [
    "@hugeicons/core-free-icons",
    "@hugeicons/react",
    "@stylexjs/stylex",
    "react-day-picker"
  ],
  "registryDependencies": [
    "https://constella.aayush.cv/r/base.json",
    "https://constella.aayush.cv/r/button.json"
  ],
  "files": [
    {
      "path": "src/components/primitives/calendar.tsx",
      "content": "\"use client\";\n\nimport { ArrowLeft01Icon, ArrowRight01Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport { useEffect, useRef } from \"react\";\nimport type { ComponentProps } from \"react\";\nimport { DayPicker } from \"react-day-picker\";\nimport type { DayButton, DayPickerProps } from \"react-day-picker\";\n\nimport { buttonStyles } from \"@/components/primitives/button\";\nimport type { Sx } from \"@/lib/constella/styles\";\nimport {\n  controlIconSize,\n  stateStyles,\n  typeStyles,\n} from \"@/lib/constella/styles\";\nimport {\n  colors,\n  fontWeights,\n  opacities,\n  radii,\n  sizes,\n  space,\n  strokes,\n} from \"@/lib/constella/tokens.stylex\";\n\nconst styles = stylex.create({\n  root: {\n    width: \"fit-content\",\n  },\n  months: {\n    display: \"flex\",\n    gap: space.lg,\n    position: \"relative\",\n  },\n  month: {\n    display: \"flex\",\n    flexDirection: \"column\",\n    gap: space.sm,\n  },\n  // Over the captions, so its arrows sit beside the first and last month's names.\n  nav: {\n    alignItems: \"center\",\n    display: \"flex\",\n    height: sizes.controlMd,\n    insetBlockStart: 0,\n    insetInlineStart: 0,\n    insetInlineEnd: 0,\n    justifyContent: \"space-between\",\n    position: \"absolute\",\n    zIndex: 1,\n  },\n  navButton: {\n    // DayPicker marks an arrow past `startMonth`/`endMonth` aria-disabled, not disabled.\n    opacity: { default: 1, \":is([aria-disabled='true'])\": opacities.disabled },\n  },\n  caption: {\n    alignItems: \"center\",\n    display: \"flex\",\n    height: sizes.controlMd,\n    justifyContent: \"center\",\n    paddingInlineStart: sizes.controlMd,\n    paddingInlineEnd: sizes.controlMd,\n  },\n  captionLabel: {\n    fontWeight: fontWeights.medium,\n  },\n  grid: {\n    borderCollapse: \"collapse\",\n  },\n  row: {\n    display: \"flex\",\n  },\n  week: {\n    marginBlockStart: space.xxs,\n  },\n  weekday: {\n    alignItems: \"center\",\n    color: colors.textSecondary,\n    display: \"flex\",\n    fontWeight: fontWeights.regular,\n    height: sizes.controlMd,\n    justifyContent: \"center\",\n    width: sizes.controlMd,\n  },\n  day: {\n    height: sizes.controlMd,\n    paddingBlockStart: 0,\n    paddingBlockEnd: 0,\n    paddingInlineStart: 0,\n    paddingInlineEnd: 0,\n    width: sizes.controlMd,\n  },\n  rangeMiddle: {\n    backgroundColor: colors.infoSubtle,\n  },\n  // The fill runs on under the solid end, so the band reaches its edge.\n  rangeStart: {\n    backgroundColor: colors.infoSubtle,\n    borderEndStartRadius: radii.sm,\n    borderStartStartRadius: radii.sm,\n  },\n  rangeEnd: {\n    backgroundColor: colors.infoSubtle,\n    borderEndEndRadius: radii.sm,\n    borderStartEndRadius: radii.sm,\n  },\n  hidden: {\n    visibility: \"hidden\",\n  },\n  dayButton: {\n    alignItems: \"center\",\n    borderBlockStyle: \"none\",\n    borderInlineStyle: \"none\",\n    borderStartStartRadius: radii.sm,\n    borderStartEndRadius: radii.sm,\n    borderEndStartRadius: radii.sm,\n    borderEndEndRadius: radii.sm,\n    color: \"inherit\",\n    cursor: { default: \"pointer\", \":disabled\": \"default\" },\n    display: \"flex\",\n    fontVariantNumeric: \"tabular-nums\",\n    height: \"100%\",\n    justifyContent: \"center\",\n    paddingBlockStart: 0,\n    paddingBlockEnd: 0,\n    paddingInlineStart: 0,\n    paddingInlineEnd: 0,\n    width: \"100%\",\n  },\n  today: {\n    fontWeight: fontWeights.medium,\n  },\n  outside: {\n    color: colors.textMuted,\n  },\n  disabled: {\n    color: colors.textMuted,\n    opacity: opacities.disabled,\n  },\n  // These replace the ghost fill whole, hover and press included, so the band and the ends stay put.\n  inRange: {\n    backgroundColor: \"transparent\",\n  },\n  solid: {\n    backgroundColor: colors.infoSolid,\n    color: colors.infoOnSolid,\n  },\n  // An end square on the side the band continues from.\n  startEdge: {\n    borderEndEndRadius: 0,\n    borderStartEndRadius: 0,\n  },\n  endEdge: {\n    borderEndStartRadius: 0,\n    borderStartStartRadius: 0,\n  },\n});\n\nconst className = (...style: stylex.StyleXStyles[]) =>\n  stylex.props(...style).className ?? \"\";\n\nconst classNames = {\n  root: className(styles.root),\n  months: className(styles.months),\n  month: className(styles.month),\n  nav: className(styles.nav),\n  button_previous: className(\n    buttonStyles({ size: \"icon-sm\", variant: \"ghost\" }),\n    styles.navButton\n  ),\n  button_next: className(\n    buttonStyles({ size: \"icon-sm\", variant: \"ghost\" }),\n    styles.navButton\n  ),\n  month_caption: className(styles.caption),\n  caption_label: className(typeStyles.textSm, styles.captionLabel),\n  month_grid: className(styles.grid),\n  weekdays: className(styles.row),\n  weekday: className(typeStyles.captionLg, styles.weekday),\n  week: className(styles.row, styles.week),\n  day: className(typeStyles.textSm, styles.day),\n  range_start: className(styles.rangeStart),\n  range_middle: className(styles.rangeMiddle),\n  range_end: className(styles.rangeEnd),\n  hidden: className(styles.hidden),\n};\n\nfunction Chevron({ orientation }: { orientation?: string }) {\n  return (\n    <HugeiconsIcon\n      aria-hidden\n      icon={orientation === \"left\" ? ArrowLeft01Icon : ArrowRight01Icon}\n      size={controlIconSize.sm}\n      strokeWidth={Number(strokes.icon)}\n    />\n  );\n}\n\nfunction CalendarDayButton({\n  day: _day,\n  modifiers,\n  ...props\n}: ComponentProps<typeof DayButton>) {\n  const ref = useRef<HTMLButtonElement>(null);\n  // A custom day button takes over focus from DayPicker's own.\n  useEffect(() => {\n    if (modifiers.focused) {\n      ref.current?.focus();\n    }\n  }, [modifiers.focused]);\n\n  const {\n    range_end: end,\n    range_middle: middle,\n    range_start: start,\n  } = modifiers;\n  return (\n    <button\n      ref={ref}\n      type=\"button\"\n      {...props}\n      {...stylex.props(\n        styles.dayButton,\n        stateStyles.ghost,\n        modifiers.today && styles.today,\n        modifiers.outside && styles.outside,\n        modifiers.disabled && styles.disabled,\n        middle && styles.inRange,\n        (start || end || (modifiers.selected && !middle)) && styles.solid,\n        start && !end && styles.startEdge,\n        end && !start && styles.endEdge\n      )}\n    />\n  );\n}\n\n/** react-day-picker's DayPicker in Constella's look; every DayPicker prop passes through. */\nfunction Calendar({\n  showOutsideDays = false,\n  components,\n  sx,\n  ...props\n}: DayPickerProps & { sx?: Sx }) {\n  return (\n    <DayPicker\n      className={stylex.props(sx).className}\n      classNames={classNames}\n      components={{ Chevron, DayButton: CalendarDayButton, ...components }}\n      data-slot=\"calendar\"\n      showOutsideDays={showOutsideDays}\n      {...props}\n    />\n  );\n}\n\nexport { Calendar };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/calendar/index.md",
  "type": "registry:ui"
}