{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "date-range-picker",
  "title": "Date-range-picker",
  "description": "A date-range-picker component.",
  "dependencies": [
    "dayjs",
    "react-day-picker",
    "@hugeicons/react",
    "@hugeicons/core-free-icons"
  ],
  "registryDependencies": [
    "@cubby-ui/button",
    "@cubby-ui/calendar",
    "@cubby-ui/popover"
  ],
  "files": [
    {
      "path": "registry/default/date-range-picker/date-range-picker.tsx",
      "content": "import * as React from \"react\";\nimport dayjs from \"dayjs\";\nimport { Button } from \"@/registry/default/button/button\";\nimport { Calendar } from \"@/registry/default/calendar/calendar\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/registry/default/popover/popover\";\nimport { cn } from \"@/lib/utils\";\n\nimport type { DateRange } from \"react-day-picker\";\n\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport Calendar01Icon from \"@hugeicons/core-free-icons/Calendar01Icon\";\nimport UnfoldMoreIcon from \"@hugeicons/core-free-icons/UnfoldMoreIcon\";\nexport interface DateRangePickerProps {\n  value?: DateRange;\n  onSelect?: (range: DateRange | undefined) => void;\n  placeholder?: string;\n  className?: string;\n  disabled?: boolean;\n  format?: string;\n  numberOfMonths?: number;\n  fixedWeeks?: boolean;\n}\n\nexport function DateRangePicker({\n  value,\n  onSelect,\n  placeholder = \"Select date range\",\n  className,\n  disabled = false,\n  format = \"DD MMM YYYY\",\n  numberOfMonths = 1,\n  fixedWeeks = false,\n}: DateRangePickerProps) {\n  const [open, setOpen] = React.useState(false);\n  const [tempRange, setTempRange] = React.useState<DateRange | undefined>(\n    undefined,\n  );\n  const [hoverDate, setHoverDate] = React.useState<Date | undefined>(undefined);\n  const previousTempRangeRef = React.useRef<DateRange | undefined>(undefined);\n\n  React.useEffect(() => {\n    if (open) {\n      setTempRange(value);\n      previousTempRangeRef.current = value;\n      setHoverDate(undefined);\n    }\n  }, [open, value]);\n\n  const formatDateRange = () => {\n    if (!value?.from) return placeholder;\n    if (!value.to) return dayjs(value.from).format(format);\n    return `${dayjs(value.from).format(format)} - ${dayjs(value.to).format(format)}`;\n  };\n\n  const displayRange = React.useMemo(() => {\n    if (tempRange?.from && !tempRange?.to && hoverDate) {\n      const start = tempRange.from;\n      const end = hoverDate;\n      if (start.getTime() <= end.getTime()) {\n        return { from: start, to: end };\n      } else {\n        return { from: end, to: start };\n      }\n    }\n    return tempRange;\n  }, [tempRange, hoverDate]);\n\n  const handleSelect = (range: DateRange | undefined) => {\n    const prevRange = previousTempRangeRef.current;\n\n    setHoverDate(undefined);\n\n    if (!range?.from) {\n      return;\n    }\n\n    if (prevRange?.from && prevRange?.to) {\n      if (range?.from && range?.to) {\n        if (range.from.getTime() === range.to.getTime()) {\n          setTempRange({ from: range.from, to: undefined });\n          previousTempRangeRef.current = { from: range.from, to: undefined };\n          return;\n        } else if (\n          // Calendar extends an existing range instead of starting fresh —\n          // detect that and restart from the clicked date.\n          range.from.getTime() === prevRange.from.getTime() ||\n          range.to.getTime() === prevRange.to.getTime()\n        ) {\n          const clickedDate =\n            range.from.getTime() !== prevRange.from.getTime()\n              ? range.from\n              : range.to;\n          setTempRange({ from: clickedDate, to: undefined });\n          previousTempRangeRef.current = { from: clickedDate, to: undefined };\n          return;\n        }\n      }\n\n      // Clicking the same single-day range clears it and restarts selection.\n      if (range?.from && !range?.to) {\n        if (\n          prevRange.from.getTime() === prevRange.to.getTime() &&\n          range.from.getTime() === prevRange.from.getTime()\n        ) {\n          setTempRange({ from: range.from, to: undefined });\n          previousTempRangeRef.current = { from: range.from, to: undefined };\n          return;\n        }\n      }\n    }\n\n    if (range.from && !range.to && prevRange?.from && !prevRange?.to) {\n      if (range.from.getTime() === prevRange.from.getTime()) {\n        const singleDayRange = { from: range.from, to: range.from };\n        setTempRange(singleDayRange);\n        previousTempRangeRef.current = singleDayRange;\n        onSelect?.(singleDayRange);\n        setOpen(false);\n        return;\n      }\n    }\n\n    setTempRange(range);\n    previousTempRangeRef.current = range;\n\n    if (range?.from && range?.to) {\n      const normalizedRange = {\n        from:\n          range.from.getTime() <= range.to.getTime() ? range.from : range.to,\n        to: range.from.getTime() <= range.to.getTime() ? range.to : range.from,\n      };\n      onSelect?.(normalizedRange);\n      setOpen(false);\n    }\n  };\n\n  return (\n    <Popover open={open} onOpenChange={setOpen}>\n      <PopoverTrigger\n        render={(props) => (\n          <Button\n            {...props}\n            variant=\"outline\"\n            className={cn(\"w-[300px] justify-between\", className)}\n            disabled={disabled}\n          >\n            <span className=\"flex w-full items-center\">\n              <HugeiconsIcon\n                icon={Calendar01Icon}\n                className=\"mr-2 size-4\"\n                strokeWidth={2}\n              />\n              <span className={cn(!value?.from && \"text-muted-foreground\")}>\n                {formatDateRange()}\n              </span>\n            </span>\n            <HugeiconsIcon\n              icon={UnfoldMoreIcon}\n              className=\"ml-2 size-4 shrink-0 opacity-50\"\n              strokeWidth={2}\n            />\n          </Button>\n        )}\n      />\n      <PopoverContent\n        className=\"w-auto border-none p-0 outline-none\"\n        sideOffset={4}\n        arrow={false}\n        onMouseLeave={() => {\n          setHoverDate(undefined);\n        }}\n      >\n        <Calendar\n          className=\"border-0\"\n          mode=\"range\"\n          numberOfMonths={numberOfMonths}\n          showOutsideDays\n          fixedWeeks={fixedWeeks}\n          selected={displayRange}\n          onSelect={(range) => {\n            // Calendar auto-sets both dates on first click — convert to a single\n            // anchor date so the user can pick the end of the range normally.\n            if (\n              !tempRange?.from &&\n              range?.from &&\n              range?.to &&\n              range.from.getTime() === range.to.getTime()\n            ) {\n              setTempRange({ from: range.from, to: undefined });\n              previousTempRangeRef.current = {\n                from: range.from,\n                to: undefined,\n              };\n              return;\n            }\n\n            // With hover preview active, `range.to` is the hovered date; use it\n            // as the actual end date rather than relying on the preview state.\n            if (tempRange?.from && !tempRange?.to && hoverDate && range?.to) {\n              const actualRange = {\n                from:\n                  tempRange.from.getTime() <= range.to.getTime()\n                    ? tempRange.from\n                    : range.to,\n                to:\n                  tempRange.from.getTime() <= range.to.getTime()\n                    ? range.to\n                    : tempRange.from,\n              };\n              handleSelect(actualRange);\n            } else {\n              handleSelect(range);\n            }\n          }}\n          onDayClick={(date) => {\n            if (!tempRange?.from) {\n              setTempRange({ from: date, to: undefined });\n              previousTempRangeRef.current = { from: date, to: undefined };\n              return;\n            }\n\n            if (\n              tempRange?.from &&\n              !tempRange?.to &&\n              date.getTime() === tempRange.from.getTime()\n            ) {\n              handleSelect({ from: date, to: date });\n              return;\n            }\n\n            if (\n              tempRange?.from &&\n              tempRange?.to &&\n              tempRange.from.getTime() === tempRange.to.getTime() &&\n              date.getTime() === tempRange.from.getTime()\n            ) {\n              setTempRange({ from: date, to: undefined });\n              previousTempRangeRef.current = { from: date, to: undefined };\n              return;\n            }\n          }}\n          onDayMouseEnter={(date) => {\n            if (tempRange?.from && !tempRange?.to) {\n              setHoverDate(date);\n            }\n          }}\n          onDayMouseLeave={() => {\n            // Calendar handles its own mouse-leave; no action needed here.\n          }}\n        />\n      </PopoverContent>\n    </Popover>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/date-range-picker.tsx"
    }
  ],
  "type": "registry:ui"
}