{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "date-range-picker",
  "title": "Date Range Picker",
  "description": "Date range picker with presets, two months, and Apply and Clear buttons.",
  "dependencies": [
    "date-fns",
    "lucide-react",
    "react-day-picker"
  ],
  "registryDependencies": [
    "@ikas/button",
    "@ikas/calendar",
    "@ikas/popover",
    "@ikas/utils"
  ],
  "files": [
    {
      "path": "registry/ikas/date-range-picker.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { endOfMonth, format, isSameDay, startOfDay, startOfMonth, subDays, subMonths } from \"date-fns\"\nimport { CalendarIcon } from \"lucide-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\"\n\ntype DateRangePreset = {\n  /** Text on the preset button. */\n  label: string\n  /** Builds the range from today's date when the preset is picked. */\n  range: (today: Date) => DateRange\n}\n\n/** Default presets: today, last 7 and 30 days, this month, last month. */\nconst dateRangePresets: DateRangePreset[] = [\n  { label: \"Bugün\", range: (today) => ({ from: today, to: today }) },\n  { label: \"Son 7 gün\", range: (today) => ({ from: subDays(today, 6), to: today }) },\n  { label: \"Son 30 gün\", range: (today) => ({ from: subDays(today, 29), to: today }) },\n  { label: \"Bu ay\", range: (today) => ({ from: startOfMonth(today), to: today }) },\n  {\n    label: \"Geçen ay\",\n    range: (today) => {\n      const month = subMonths(today, 1)\n      return { from: startOfMonth(month), to: endOfMonth(month) }\n    },\n  },\n]\n\ntype DateRangePickerProps = {\n  /** Applied range. Leave undefined with defaultValue for an uncontrolled picker. */\n  value?: DateRange\n  /** Initial range when uncontrolled. */\n  defaultValue?: DateRange\n  /** Called on Apply with the new range, or undefined after Clear. */\n  onValueChange?: (value: DateRange | undefined) => void\n  /** Quick ranges listed beside the calendar. Pass [] to hide the list. */\n  presets?: DateRangePreset[]\n  /** Earliest selectable day. */\n  minDate?: Date\n  /** Latest selectable day. */\n  maxDate?: Date\n  /** Disables the trigger. */\n  disabled?: boolean\n  /** Trigger text while no range is applied. */\n  placeholder?: string\n  /** date-fns format string for each end of the range. */\n  dateFormat?: string\n  /** Popover alignment against the trigger. */\n  align?: \"start\" | \"center\" | \"end\"\n  /** Classes for the trigger button. */\n  className?: string\n  /** Id of the trigger, for a FieldLabel htmlFor. */\n  id?: string\n  /** Marks the trigger invalid inside a Field. */\n  \"aria-invalid\"?: boolean\n}\n\nconst wideQuery = \"(min-width: 640px)\"\n\n/** Two months side by side from 640px up, one below. */\nfunction useWide() {\n  return React.useSyncExternalStore(\n    (onChange) => {\n      const media = window.matchMedia(wideQuery)\n      media.addEventListener(\"change\", onChange)\n      return () => media.removeEventListener(\"change\", onChange)\n    },\n    () => window.matchMedia(wideQuery).matches,\n    () => true\n  )\n}\n\nfunction sameRange(a: DateRange | undefined, b: DateRange | undefined) {\n  if (!a?.from || !b?.from) return false\n  return isSameDay(a.from, b.from) && isSameDay(a.to ?? a.from, b.to ?? b.from)\n}\n\n/**\n * Range picker in a popover: presets on the side, two months, and Apply / Clear.\n * The value changes only on Apply; closing the popover discards the draft.\n */\nfunction DateRangePicker({\n  value: valueProp,\n  defaultValue,\n  onValueChange,\n  presets = dateRangePresets,\n  minDate,\n  maxDate,\n  disabled = false,\n  placeholder = \"Tarih aralığı seçin\",\n  dateFormat = \"dd.MM.yyyy\",\n  align = \"start\",\n  className,\n  id,\n  \"aria-invalid\": ariaInvalid,\n}: DateRangePickerProps) {\n  const wide = useWide()\n  const [open, setOpen] = React.useState(false)\n  const [uncontrolled, setUncontrolled] = React.useState(defaultValue)\n  const value = valueProp !== undefined ? valueProp : uncontrolled\n  const [draft, setDraft] = React.useState<DateRange | undefined>(value)\n  const [month, setMonth] = React.useState<Date>()\n\n  /** First visible month, so the end of the range sits in the last month shown. */\n  function monthFor(range: DateRange | undefined) {\n    const end = range?.to ?? range?.from ?? new Date()\n    return wide ? subMonths(end, 1) : end\n  }\n\n  function onOpenChange(next: boolean) {\n    if (next) {\n      setDraft(value)\n      setMonth(monthFor(value))\n    }\n    setOpen(next)\n  }\n\n  function pickPreset(preset: DateRangePreset) {\n    const range = preset.range(startOfDay(new Date()))\n    setDraft(range)\n    setMonth(monthFor(range))\n  }\n\n  function apply() {\n    const next = draft?.from ? { from: draft.from, to: draft.to ?? draft.from } : undefined\n    setUncontrolled(next)\n    onValueChange?.(next)\n    setOpen(false)\n  }\n\n  function clear() {\n    setDraft(undefined)\n    setUncontrolled(undefined)\n    onValueChange?.(undefined)\n  }\n\n  const bounds = [minDate && { before: minDate }, maxDate && { after: maxDate }].filter((m) => m !== undefined)\n  const label = value?.from\n    ? value.to && !isSameDay(value.from, value.to)\n      ? `${format(value.from, dateFormat)} – ${format(value.to, dateFormat)}`\n      : format(value.from, dateFormat)\n    : placeholder\n\n  return (\n    <Popover open={open} onOpenChange={onOpenChange}>\n      <PopoverTrigger asChild>\n        <Button\n          id={id}\n          variant=\"outline\"\n          disabled={disabled}\n          aria-invalid={ariaInvalid}\n          data-empty={!value?.from || undefined}\n          className={cn(\"w-full justify-start font-normal data-empty:text-muted-foreground aria-invalid:ring-3 aria-invalid:ring-destructive/20 sm:w-auto\", className)}\n        >\n          <CalendarIcon data-icon=\"inline-start\" className=\"text-icon\" />\n          <span className=\"truncate tabular-nums\">{label}</span>\n        </Button>\n      </PopoverTrigger>\n      <PopoverContent align={align} collisionPadding={8} className=\"w-auto max-w-[calc(100vw-1rem)] gap-0 p-0\">\n        <div className=\"flex flex-col sm:flex-row\">\n          {presets.length > 0 && (\n            <div\n              role=\"group\"\n              aria-label=\"Hazır aralıklar\"\n              className=\"flex gap-1 overflow-x-auto border-b border-border p-2 [scrollbar-width:none] sm:min-w-32 sm:shrink-0 sm:flex-col sm:overflow-visible sm:border-r sm:border-b-0\"\n            >\n              {presets.map((preset) => {\n                const active = sameRange(draft, preset.range(startOfDay(new Date())))\n                return (\n                  <Button\n                    key={preset.label}\n                    variant=\"ghost\"\n                    size=\"sm\"\n                    aria-pressed={active}\n                    onClick={() => pickPreset(preset)}\n                    className=\"shrink-0 justify-start font-normal text-muted-foreground hover:text-foreground aria-pressed:bg-muted aria-pressed:font-medium aria-pressed:text-foreground\"\n                  >\n                    {preset.label}\n                  </Button>\n                )\n              })}\n            </div>\n          )}\n          <div className=\"flex flex-col\">\n            <div className=\"flex justify-center p-3\">\n              <Calendar\n                mode=\"range\"\n                selected={draft}\n                onSelect={setDraft}\n                month={month}\n                onMonthChange={setMonth}\n                numberOfMonths={wide ? 2 : 1}\n                // With two months the spill-over days would repeat the range.\n                showOutsideDays={!wide}\n                startMonth={minDate}\n                endMonth={maxDate}\n                disabled={bounds}\n              />\n            </div>\n            <div className=\"flex items-center justify-end gap-2 border-t border-border p-3\">\n              <Button variant=\"ghost\" size=\"sm\" onClick={clear} disabled={!draft?.from && !value?.from}>\n                Temizle\n              </Button>\n              <Button size=\"sm\" onClick={apply} disabled={!draft?.from}>\n                Uygula\n              </Button>\n            </div>\n          </div>\n        </div>\n      </PopoverContent>\n    </Popover>\n  )\n}\n\nexport { DateRangePicker, dateRangePresets, type DateRangePickerProps, type DateRangePreset }\n",
      "type": "registry:component",
      "target": "@components/ikas/date-range-picker.tsx"
    }
  ],
  "docs": "https://builders.ikas.com/tr/docs/app-development/ui-kit/components/date-range-picker",
  "categories": [
    "forms"
  ],
  "type": "registry:component"
}