{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "date-range-picker",
  "title": "Date Range Picker",
  "description": "A button showing a range of days, opening a two-month calendar with optional presets beside it.",
  "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",
    "https://constella.aayush.cv/r/calendar.json",
    "https://constella.aayush.cv/r/popover.json"
  ],
  "files": [
    {
      "path": "src/components/primitives/date-range-picker.tsx",
      "content": "\"use client\";\n\nimport { Calendar03Icon, Tick02Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport { useRef, useState } from \"react\";\nimport type { DateRange, PropsBase } from \"react-day-picker\";\n\nimport { Button } from \"@/components/primitives/button\";\nimport { Calendar } from \"@/components/primitives/calendar\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/primitives/popover\";\nimport {\n  controlIconSize,\n  stateStyles,\n  typeStyles,\n} from \"@/lib/constella/styles\";\nimport {\n  colors,\n  radii,\n  sizes,\n  space,\n  strokes,\n} from \"@/lib/constella/tokens.stylex\";\n\ninterface DayRange {\n  from: Date;\n  to: Date;\n}\n\ninterface DateRangePreset {\n  label: string;\n  range: DayRange;\n}\n\nconst styles = stylex.create({\n  // A menu's corner, so the presets read as one.\n  content: {\n    borderEndEndRadius: radii.lg,\n    borderEndStartRadius: radii.lg,\n    borderStartEndRadius: radii.lg,\n    borderStartStartRadius: radii.lg,\n    flexDirection: \"row\",\n    gap: 0,\n    paddingBlockEnd: 0,\n    paddingBlockStart: 0,\n    paddingInlineEnd: 0,\n    paddingInlineStart: 0,\n    width: \"auto\",\n  },\n  presets: {\n    borderInlineEndColor: colors.borderSubtle,\n    borderInlineEndStyle: \"solid\",\n    borderInlineEndWidth: strokes.border,\n    display: \"flex\",\n    flexDirection: \"column\",\n    minWidth: sizes.menu,\n    paddingBlockEnd: space.xxs,\n    paddingBlockStart: space.xxs,\n    paddingInlineEnd: space.xxs,\n    paddingInlineStart: space.xxs,\n  },\n  // A default menu's radio item, its tick on the end.\n  preset: {\n    alignItems: \"center\",\n    borderBlockEndWidth: 0,\n    borderBlockStartWidth: 0,\n    borderEndEndRadius: radii.md,\n    borderEndStartRadius: radii.md,\n    borderInlineEndWidth: 0,\n    borderInlineStartWidth: 0,\n    borderStartEndRadius: radii.md,\n    borderStartStartRadius: radii.md,\n    color: colors.textPrimary,\n    cursor: \"pointer\",\n    display: \"flex\",\n    gap: space.row,\n    justifyContent: \"space-between\",\n    minHeight: sizes.controlMd,\n    paddingInlineEnd: space.sm,\n    paddingInlineStart: space.sm,\n    textAlign: \"start\",\n  },\n  calendar: {\n    paddingBlockEnd: space.md,\n    paddingBlockStart: space.md,\n    paddingInlineEnd: space.md,\n    paddingInlineStart: space.md,\n  },\n});\n\nconst sameDay = (a: Date, b: Date) => a.toDateString() === b.toDateString();\nconst sameRange = (a: DayRange, b: DayRange) =>\n  sameDay(a.from, b.from) && sameDay(a.to, b.to);\n\n/** A button showing a day range, opening presets beside a two-month calendar; a pick closes it. */\nfunction DateRangePicker({\n  onValueChange,\n  presets,\n  value,\n  ...calendar\n}: Pick<\n  PropsBase,\n  | \"disabled\"\n  | \"endMonth\"\n  | \"locale\"\n  | \"startMonth\"\n  | \"timeZone\"\n  | \"weekStartsOn\"\n> & {\n  onValueChange: (range: DayRange) => void;\n  presets?: readonly DateRangePreset[];\n  value: DayRange;\n}) {\n  const [open, setOpen] = useState(false);\n  const popup = useRef<HTMLDivElement>(null);\n  // The first day picked, until a second one ends the range.\n  const [anchor, setAnchor] = useState<Date | null>(null);\n  const shown: DateRange =\n    anchor === null ? value : { from: anchor, to: anchor };\n\n  const pick = (range: DayRange) => {\n    onValueChange(range);\n    setAnchor(null);\n    setOpen(false);\n  };\n\n  return (\n    <Popover\n      onOpenChange={(next) => {\n        setOpen(next);\n        setAnchor(null);\n      }}\n      open={open}\n    >\n      <PopoverTrigger render={<Button />}>\n        <HugeiconsIcon\n          aria-hidden\n          data-icon=\"inline-start\"\n          icon={Calendar03Icon}\n          size={controlIconSize.default}\n          strokeWidth={Number(strokes.icon)}\n        />\n        {new Intl.DateTimeFormat(calendar.locale?.code ?? \"en-US\", {\n          timeZone: calendar.timeZone,\n          day: \"numeric\",\n          month: \"short\",\n          year: \"numeric\",\n        })\n          .formatRange(value.from, value.to)\n          // Node's ICU spaces the dash with thin spaces and browsers' with plain ones, so SSR would mismatch.\n          .replaceAll(\"\\u2009\", \" \")}\n      </PopoverTrigger>\n      <PopoverContent\n        align=\"start\"\n        // A pointer open focuses the popup, so no preset wears a ring it didn't earn.\n        initialFocus={(openType) => openType === \"keyboard\" || popup.current}\n        ref={popup}\n        sx={styles.content}\n      >\n        {presets === undefined ? null : (\n          <div {...stylex.props(styles.presets)}>\n            {presets.map((preset) => {\n              const active = sameRange(preset.range, value);\n              return (\n                <button\n                  aria-pressed={active}\n                  key={preset.label}\n                  onClick={() => {\n                    pick(preset.range);\n                  }}\n                  type=\"button\"\n                  {...stylex.props(\n                    typeStyles.textMd,\n                    styles.preset,\n                    stateStyles.ghost\n                  )}\n                >\n                  {preset.label}\n                  {active ? (\n                    <HugeiconsIcon\n                      aria-hidden\n                      icon={Tick02Icon}\n                      size={controlIconSize.default}\n                      strokeWidth={Number(strokes.icon)}\n                    />\n                  ) : null}\n                </button>\n              );\n            })}\n          </div>\n        )}\n        <Calendar\n          defaultMonth={value.to}\n          mode=\"range\"\n          numberOfMonths={2}\n          onSelect={(_range, day) => {\n            if (anchor === null) {\n              setAnchor(day);\n              return;\n            }\n            pick(\n              anchor <= day\n                ? { from: anchor, to: day }\n                : { from: day, to: anchor }\n            );\n          }}\n          selected={shown}\n          {...calendar}\n          sx={styles.calendar}\n        />\n      </PopoverContent>\n    </Popover>\n  );\n}\n\nexport { DateRangePicker };\nexport type { DateRangePreset, DayRange };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Usage: https://constella.aayush.cv/docs/components/date-range-picker/index.md",
  "type": "registry:ui"
}