{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "date-range-picker", "title": "Date Range Picker", "description": "Popover-anchored calendar for choosing an optional from/to range.", "registryDependencies": [ "askyourpolicy/ss-registry/stitch-base", "askyourpolicy/ss-registry/button", "askyourpolicy/ss-registry/calendar", "askyourpolicy/ss-registry/popover" ], "files": [ { "path": "src/components/ui/date-range-picker.tsx", "content": "\"use client\";\n\nimport * as React from \"react\";\nimport type { DateRange } from \"react-day-picker\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport { Calendar } from \"@/components/ui/calendar\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/ui/popover\";\nimport { CalendarBlankIcon } from \"@phosphor-icons/react\";\n\ntype DateRangePickerProps = {\n align?: React.ComponentProps[\"align\"];\n className?: string;\n clearLabel?: string;\n disabled?: boolean;\n disabledDays?: React.ComponentProps[\"disabled\"];\n doneLabel?: string;\n endMonth?: Date;\n id?: string;\n locale?: string;\n months?: number;\n onValueChange: (value: DateRange | undefined) => void;\n placeholder?: string;\n startMonth?: Date;\n value: DateRange | undefined;\n};\n\nfunction DateRangePicker({\n align = \"start\",\n className,\n clearLabel = \"Clear\",\n disabled,\n disabledDays,\n doneLabel = \"Done\",\n endMonth,\n id,\n locale,\n months = 2,\n onValueChange,\n placeholder = \"Any date\",\n startMonth,\n value,\n}: DateRangePickerProps) {\n const [open, setOpen] = React.useState(false);\n const label = formatDateRange(value, locale);\n\n return (\n \n \n }\n >\n \n {label ?? placeholder}\n \n \n \n {/* The first click already yields a one-day range, so closing on a \"complete\" range would\n shut the calendar before the end date could be picked. Closing stays manual. */}\n
\n onValueChange(undefined)}\n size=\"sm\"\n variant=\"ghost\"\n >\n {clearLabel}\n \n \n
\n \n
\n );\n}\n\n// Intl renders a range in the shortest form the locale allows, collapsing a shared month or year.\nfunction formatDateRange(value: DateRange | undefined, locale?: string) {\n if (!value?.from) return null;\n const formatter = new Intl.DateTimeFormat(locale, {\n day: \"numeric\",\n month: \"short\",\n year: \"numeric\",\n });\n return value.to ? formatter.formatRange(value.from, value.to) : formatter.format(value.from);\n}\n\nexport { DateRangePicker, formatDateRange };\nexport type { DateRangePickerProps };\n", "type": "registry:ui" } ], "docs": "Controlled: pass value plus onValueChange and leave value undefined for an empty range. The trigger label is built with Intl.DateTimeFormat.formatRange, so a shared month or year collapses automatically. Space the surrounding field with gap rather than space-y: Base UI mounts focus guards beside the open trigger, and sibling-margin spacing then adds a margin that resizes the field as the popover opens.", "type": "registry:ui" }