{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "range-calendar",
  "title": "Range Calendar",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendar.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  /** Selected range. `end` is undefined while the user has only picked the start. */\n  export interface DateRange {\n    start: Date\n    end: Date | undefined\n  }\n\n  /**\n   * React DayPicker-shaped range (`{ from, to }`) for the `selected`/`onSelect`\n   * aliases. Converts to/from the internal `{ start, end }` shape. Both use\n   * native `Date`, so conversion is a key rename plus midnight normalization.\n   */\n  export interface ReactDateRange {\n    from: Date | undefined\n    to?: Date | undefined\n  }\n\n  export interface CalendarDay {\n    date: Date\n    /** `y-m-d` key for focus management. */\n    key: string\n    dayNumber: number\n    outsideView: boolean\n    today: boolean\n    disabled: boolean\n    unavailable: boolean\n    selected: boolean\n    selectionStart: boolean\n    selectionEnd: boolean\n    highlighted: boolean\n    tabbable: boolean\n  }\n\n  export interface CalendarMonth {\n    key: string\n    label: string\n    weeks: CalendarDay[][]\n  }\n\n  /** Context shared with the range-calendar parts. Getters stay reactive in children. */\n  export interface RangeCalendarContext {\n    readonly months: CalendarMonth[]\n    readonly weekDays: string[]\n    readonly headingValue: string\n    readonly disabled: boolean\n    readonly readonly: boolean\n    readonly canPrev: boolean\n    readonly canNext: boolean\n    select: (day: CalendarDay) => void\n    hover: (day: CalendarDay | null) => void\n    prev: () => void\n    next: () => void\n    focusDay: (fromKey: string, deltaDays: number) => void\n    focusMonthStep: (fromKey: string, months: number) => void\n    weekEdge: (fromKey: string, toStart: boolean) => void\n  }\n\n  // Omit `children`: the snippet carries months/weekDays, which narrows the base `Snippet` type.\n  export interface RangeCalendarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {\n    /** The controlled range. Bindable. When both `value` and `selected` are set, `value` wins. */\n    value?: DateRange | undefined\n    /** Initial range for uncontrolled use. */\n    defaultValue?: DateRange | undefined\n    /** Called with the new range after every commit. */\n    onValueChange?: (value: DateRange) => void\n    /**\n     * React DayPicker-parity alias for `value`. Accepts `{ from, to }` and\n     * converts to internal `{ start, end }`. Bindable. Stays in sync with\n     * `value`: user selection updates both, and external updates to either\n     * sync the other.\n     */\n    selected?: ReactDateRange | undefined\n    /** React-parity alias for `onValueChange`. Fires with `{ from, to }` alongside `onValueChange`. */\n    onSelect?: (range: ReactDateRange | undefined) => void\n    /** Earliest selectable date. */\n    minValue?: Date\n    /** Latest selectable date. */\n    maxValue?: Date\n    /** When `true`, prevents the user from interacting with the calendar. */\n    disabled?: boolean\n    /** When `true`, dates cannot be selected but the calendar stays focusable. */\n    readonly?: boolean\n    /** Always render 6 week rows so the height never shifts month-to-month. */\n    fixedWeeks?: boolean\n    /** First day of the week: 0 = Sunday … 6 = Saturday. */\n    weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6\n    /** How many months to render side by side. */\n    numberOfMonths?: number\n    /** BCP 47 locale for month and weekday names. Defaults to the runtime locale. */\n    locale?: string\n    /** Initial visible month. Defaults to the start of `value`/`defaultValue`, else today. */\n    defaultPlaceholder?: Date\n    /** Extra predicate to disable individual dates. */\n    isDateDisabled?: (date: Date) => boolean\n    /** Extra predicate to mark individual dates unavailable. */\n    isDateUnavailable?: (date: Date) => boolean\n    children?: Snippet<[{ months: CalendarMonth[]; weekDays: string[] }]>\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { setContext, tick } from 'svelte'\n  import { cn } from '$lib/utils'\n  import RangeCalendarCell from './RangeCalendarCell.svelte'\n  import RangeCalendarCellTrigger from './RangeCalendarCellTrigger.svelte'\n  import RangeCalendarGrid from './RangeCalendarGrid.svelte'\n  import RangeCalendarGridBody from './RangeCalendarGridBody.svelte'\n  import RangeCalendarGridHead from './RangeCalendarGridHead.svelte'\n  import RangeCalendarGridRow from './RangeCalendarGridRow.svelte'\n  import RangeCalendarHeadCell from './RangeCalendarHeadCell.svelte'\n  import RangeCalendarHeader from './RangeCalendarHeader.svelte'\n  import RangeCalendarHeading from './RangeCalendarHeading.svelte'\n  import RangeCalendarNextButton from './RangeCalendarNextButton.svelte'\n  import RangeCalendarPrevButton from './RangeCalendarPrevButton.svelte'\n\n  let {\n    class: className,\n    value = $bindable(),\n    defaultValue = undefined,\n    onValueChange,\n    selected = $bindable(),\n    onSelect,\n    minValue = undefined,\n    maxValue = undefined,\n    disabled = false,\n    readonly = false,\n    fixedWeeks = false,\n    weekStartsOn = 0,\n    numberOfMonths = 1,\n    locale = undefined,\n    defaultPlaceholder = undefined,\n    isDateDisabled = undefined,\n    isDateUnavailable = undefined,\n    children,\n    ref = $bindable(null),\n    ...restProps\n  }: RangeCalendarProps = $props()\n\n  function atMidnight(d: Date): Date {\n    return new Date(d.getFullYear(), d.getMonth(), d.getDate())\n  }\n\n  function fromSelected(s: ReactDateRange | undefined): DateRange | undefined {\n    if (!s?.from) return undefined\n    return { start: atMidnight(s.from), end: s.to ? atMidnight(s.to) : undefined }\n  }\n\n  function toSelected(r: DateRange | undefined): ReactDateRange | undefined {\n    if (!r) return undefined\n    return { from: r.start, to: r.end }\n  }\n\n  function sameRange(a: DateRange | undefined, b: DateRange | undefined): boolean {\n    if (a == null || b == null) return a == null && b == null\n    return sameDay(a.start, b.start) && (a.end == null || b.end == null ? a.end == b.end : sameDay(a.end, b.end))\n  }\n\n  function sameSelected(a: ReactDateRange | undefined, b: ReactDateRange | undefined): boolean {\n    if (a == null || b == null) return a == null && b == null\n    const fromSame = a.from == null || b.from == null ? a.from == b.from : sameDay(a.from, b.from)\n    const toSame = a.to == null || b.to == null ? a.to == b.to : sameDay(a.to, b.to)\n    return fromSame && toSame\n  }\n\n  function dayKey(d: Date): string {\n    return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`\n  }\n\n  function sameDay(a: Date, b: Date): boolean {\n    return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate()\n  }\n\n  function compareDay(a: Date, b: Date): number {\n    const t = atMidnight(a).getTime() - atMidnight(b).getTime()\n    return t === 0 ? 0 : t < 0 ? -1 : 1\n  }\n\n  let root: HTMLDivElement | null = null\n  // Uncontrolled seed: initial `value`/`selected` win over `defaultValue` so a\n  // pre-selected controlled range shows its month on mount.\n  // svelte-ignore state_referenced_locally\n  let internal = $state<DateRange | undefined>(value ?? fromSelected(selected) ?? defaultValue)\n  let hoverKey = $state<string | null>(null)\n\n  // `value` wins when both aliases are set; `selected` converts `{ from, to }`.\n  const current = $derived(value ?? fromSelected(selected) ?? internal)\n\n  // Keep `value`/`selected` mirrors in sync on external updates (user selection\n  // syncs via `commit` below). Last-write-wins, with `value` winning when both\n  // change together. Guards prevent loops with `commit` (which updates all\n  // three together, detected as already-in-sync with `internal`).\n  let prevValue: DateRange | undefined = value\n  let prevSelected: ReactDateRange | undefined = selected\n  let didInitSync = false\n  $effect(() => {\n    const v = value\n    const s = selected\n    if (!didInitSync) {\n      didInitSync = true\n      prevValue = v\n      prevSelected = s\n      if (v !== undefined && s === undefined) {\n        const toSel = toSelected(v)\n        selected = toSel\n        prevSelected = toSel\n      } else if (s !== undefined && v === undefined) {\n        const conv = fromSelected(s)\n        value = conv\n        prevValue = conv\n      } else if (v !== undefined && s !== undefined) {\n        if (!sameRange(v, fromSelected(s))) {\n          const toSel = toSelected(v)\n          selected = toSel\n          prevSelected = toSel\n        }\n      }\n      return\n    }\n    const vChanged = !sameRange(v, prevValue)\n    const sChanged = !sameSelected(s, prevSelected)\n    if (!vChanged && !sChanged) return\n    if (vChanged && sChanged) {\n      if (sameRange(v, internal) && sameSelected(s, toSelected(v))) {\n        prevValue = v\n        prevSelected = s\n        return\n      }\n      if (v !== undefined) {\n        internal = v\n        const toSel = toSelected(v)\n        if (!sameSelected(s, toSel)) selected = toSel\n        prevValue = v\n        prevSelected = toSel\n      } else if (s !== undefined) {\n        internal = fromSelected(s)\n        prevValue = v\n        prevSelected = s\n      } else {\n        internal = undefined\n        prevValue = undefined\n        prevSelected = undefined\n      }\n    } else if (vChanged) {\n      internal = v\n      const toSel = toSelected(v)\n      if (!sameSelected(s, toSel)) selected = toSel\n      prevValue = v\n      prevSelected = toSel\n    } else {\n      const conv = fromSelected(s)\n      internal = conv\n      if (!sameRange(v, conv)) value = conv\n      prevValue = conv\n      prevSelected = s\n    }\n  })\n\n  // Visible month (first of the rendered run). Seeded from the placeholder,\n  // else the range start, else today — so a pre-selected value shows its month.\n  function initialVisible(): { y: number; m: number } {\n    const seed = defaultPlaceholder ?? current?.start ?? new Date()\n    return { y: seed.getFullYear(), m: seed.getMonth() }\n  }\n  // Uncontrolled seed: intentionally the initial placeholder/value only.\n  // svelte-ignore state_referenced_locally\n  let visible = $state(initialVisible())\n\n  $effect(() => {\n    ref = root\n  })\n\n  const today = $derived.by(() => {\n    const now = new Date()\n    return new Date(now.getFullYear(), now.getMonth(), now.getDate())\n  })\n\n  function isOutOfBounds(d: Date): boolean {\n    if (minValue && compareDay(d, minValue) < 0) return true\n    if (maxValue && compareDay(d, maxValue) > 0) return true\n    return false\n  }\n\n  const months = $derived.by((): CalendarMonth[] => {\n    const labelFmt = new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric' })\n    const range = current\n    const start = range?.start ? atMidnight(range.start) : null\n    const end = range?.end ? atMidnight(range.end) : null\n    const hoverDate = hoverKey\n      ? (() => {\n          const [y, m, d] = hoverKey.split('-').map(Number)\n          return new Date(y!, m!, d!)\n        })()\n      : null\n    const inProgress = start && !end && hoverDate && !sameDay(start, hoverDate)\n\n    const out: CalendarMonth[] = []\n    for (let i = 0; i < Math.max(1, numberOfMonths); i++) {\n      const first = new Date(visible.y, visible.m + i, 1)\n      const y = first.getFullYear()\n      const m = first.getMonth()\n      const dim = new Date(y, m + 1, 0).getDate()\n      const leading = (first.getDay() - weekStartsOn + 7) % 7\n      let total = leading + dim\n      const trailing = (7 - (total % 7)) % 7\n      total += trailing\n      if (fixedWeeks) total = 42\n\n      const days: CalendarDay[] = []\n      for (let c = 0; c < total; c++) {\n        const date = new Date(y, m, 1 - leading + c)\n        const key = dayKey(date)\n        const outsideView = date.getMonth() !== m\n        const isToday = sameDay(date, today)\n        const isDisabled = disabled || isOutOfBounds(date) || (isDateDisabled?.(date) ?? false)\n        const isUnavailable = isDateUnavailable?.(date) ?? false\n        const geStart = start ? compareDay(date, start) >= 0 : false\n        const leEnd = end ? compareDay(date, end) <= 0 : false\n        const isStart = start ? sameDay(date, start) : false\n        const isEnd = end ? sameDay(date, end) : false\n        const isSelected = end ? geStart && leEnd : isStart\n        let highlighted = false\n        if (inProgress && start && hoverDate) {\n          const lo = compareDay(start, hoverDate) <= 0 ? start : hoverDate\n          const hi = lo === start ? hoverDate : start\n          highlighted = compareDay(date, lo) > 0 && compareDay(date, hi) < 0\n        }\n        days.push({\n          date,\n          key,\n          dayNumber: date.getDate(),\n          outsideView,\n          today: isToday,\n          disabled: isDisabled,\n          unavailable: isUnavailable,\n          selected: isSelected,\n          selectionStart: isStart,\n          selectionEnd: isEnd,\n          highlighted,\n          tabbable: false,\n        })\n      }\n      const weeks: CalendarDay[][] = []\n      for (let w = 0; w < days.length; w += 7) weeks.push(days.slice(w, w + 7))\n      out.push({ key: `${y}-${m}`, label: labelFmt.format(first), weeks })\n    }\n\n    // One tabbable day across the whole run: range start, else today, else first enabled day.\n    const flat = out.flatMap((mo) => mo.weeks.flat())\n    const pick =\n      (start && flat.find((d) => sameDay(d.date, start) && !d.disabled)) ||\n      flat.find((d) => d.today && !d.disabled) ||\n      flat.find((d) => !d.disabled && !d.outsideView) ||\n      flat.find((d) => !d.disabled)\n    if (pick) pick.tabbable = true\n    return out\n  })\n\n  const weekDays = $derived.by(() => {\n    const fmt = new Intl.DateTimeFormat(locale, { weekday: 'narrow' })\n    // 2024-01-07 was a Sunday; walk a full week from there.\n    const names = Array.from({ length: 7 }, (_, i) => fmt.format(new Date(2024, 0, 7 + i)))\n    return [...names.slice(weekStartsOn), ...names.slice(0, weekStartsOn)]\n  })\n\n  const headingValue = $derived(months.map((mo) => mo.label).join(' – '))\n\n  const canPrev = $derived.by(() => {\n    if (!minValue) return true\n    const first = new Date(visible.y, visible.m, 1)\n    const minMonth = new Date(minValue.getFullYear(), minValue.getMonth(), 1)\n    return first > minMonth\n  })\n\n  const canNext = $derived.by(() => {\n    if (!maxValue) return true\n    const count = Math.max(1, numberOfMonths)\n    const last = new Date(visible.y, visible.m + count - 1, 1)\n    const maxMonth = new Date(maxValue.getFullYear(), maxValue.getMonth(), 1)\n    return last < maxMonth\n  })\n\n  function commit(next: DateRange) {\n    internal = next\n    value = next\n    const sel = toSelected(next)\n    selected = sel\n    onValueChange?.(next)\n    onSelect?.(sel)\n  }\n\n  function select(day: CalendarDay) {\n    if (disabled || readonly || day.disabled || day.unavailable) return\n    const d = atMidnight(day.date)\n    const range = current\n    if (!range?.start || range.end) {\n      commit({ start: d, end: undefined })\n    } else if (compareDay(d, range.start) < 0) {\n      commit({ start: d, end: atMidnight(range.start) })\n    } else {\n      commit({ start: atMidnight(range.start), end: d })\n    }\n  }\n\n  function hover(day: CalendarDay | null) {\n    hoverKey = day ? day.key : null\n  }\n\n  function prev() {\n    if (!canPrev) return\n    const d = new Date(visible.y, visible.m - 1, 1)\n    visible = { y: d.getFullYear(), m: d.getMonth() }\n  }\n\n  function next() {\n    if (!canNext) return\n    const d = new Date(visible.y, visible.m + 1, 1)\n    visible = { y: d.getFullYear(), m: d.getMonth() }\n  }\n\n  function focusKey(key: string) {\n    const target = root?.querySelector<HTMLButtonElement>(`[data-day=\"${key}\"]`)\n    target?.focus()\n  }\n\n  function parseKey(key: string): Date {\n    const [y, m, d] = key.split('-').map(Number)\n    return new Date(y!, m!, d!)\n  }\n\n  /** Move focus by whole days, shifting the visible window when leaving it. */\n  function focusDay(fromKey: string, deltaDays: number) {\n    const target = parseKey(fromKey)\n    target.setDate(target.getDate() + deltaDays)\n    const count = Math.max(1, numberOfMonths)\n    const firstVisible = new Date(visible.y, visible.m, 1)\n    const lastVisible = new Date(visible.y, visible.m + count, 0)\n    if (compareDay(target, firstVisible) < 0) {\n      visible = { y: target.getFullYear(), m: target.getMonth() }\n      tick().then(() => focusKey(dayKey(target)))\n    } else if (compareDay(target, lastVisible) > 0) {\n      visible = { y: target.getFullYear(), m: target.getMonth() - count + 1 }\n      tick().then(() => focusKey(dayKey(target)))\n    } else {\n      focusKey(dayKey(target))\n    }\n  }\n\n  /** Move focus by whole months (PageUp/PageDown), clamping the day number. */\n  function focusMonthStep(fromKey: string, step: number) {\n    const from = parseKey(fromKey)\n    const target = new Date(from.getFullYear(), from.getMonth() + step, 1)\n    const dim = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate()\n    target.setDate(Math.min(from.getDate(), dim))\n    visible = { y: target.getFullYear(), m: target.getMonth() }\n    tick().then(() => focusKey(dayKey(target)))\n  }\n\n  /** Move focus to the start/end of the focused week row (Home/End). */\n  function weekEdge(fromKey: string, toStart: boolean) {\n    const from = parseKey(fromKey)\n    const offset = (from.getDay() - weekStartsOn + 7) % 7\n    focusDay(fromKey, toStart ? -offset : 6 - offset)\n  }\n\n  setContext<RangeCalendarContext>('rangeCalendar', {\n    get months() {\n      return months\n    },\n    get weekDays() {\n      return weekDays\n    },\n    get headingValue() {\n      return headingValue\n    },\n    get disabled() {\n      return disabled\n    },\n    get readonly() {\n      return readonly\n    },\n    get canPrev() {\n      return canPrev\n    },\n    get canNext() {\n      return canNext\n    },\n    select,\n    hover,\n    prev,\n    next,\n    focusDay,\n    focusMonthStep,\n    weekEdge,\n  })\n</script>\n\n<div\n  bind:this={root}\n  data-uipkge=\"\"\n  data-slot=\"range-calendar\"\n  data-disabled={disabled || undefined}\n  class={cn('p-3', className)}\n  {...restProps}\n>\n  <RangeCalendarHeader>\n    <RangeCalendarHeading />\n\n    <div class=\"flex items-center gap-1\">\n      <RangeCalendarPrevButton />\n      <RangeCalendarNextButton />\n    </div>\n  </RangeCalendarHeader>\n\n  <div class=\"mt-4 flex flex-col gap-y-4 sm:flex-row sm:gap-x-4 sm:gap-y-0\">\n    {#each months as month (month.key)}\n      <RangeCalendarGrid label={month.label}>\n        <RangeCalendarGridHead>\n          <RangeCalendarGridRow>\n            {#each weekDays as day, di (di)}\n              <RangeCalendarHeadCell>\n                {day}\n              </RangeCalendarHeadCell>\n            {/each}\n          </RangeCalendarGridRow>\n        </RangeCalendarGridHead>\n        <RangeCalendarGridBody>\n          {#each month.weeks as week, index (index)}\n            <RangeCalendarGridRow class=\"mt-2 w-full\">\n              {#each week as weekDate (weekDate.key)}\n                <RangeCalendarCell>\n                  <RangeCalendarCellTrigger day={weekDate} />\n                </RangeCalendarCell>\n              {/each}\n            </RangeCalendarGridRow>\n          {/each}\n        </RangeCalendarGridBody>\n      </RangeCalendarGrid>\n    {/each}\n  </div>\n\n  {@render children?.({ months, weekDays })}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendar.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarCell.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface RangeCalendarCellProps extends HTMLAttributes<HTMLTableCellElement> {\n    children?: Snippet\n    ref?: HTMLTableCellElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: RangeCalendarCellProps = $props()\n</script>\n\n<td\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-cell\"\n  class={cn(\n    '[&:has([data-selected])]:bg-accent [&:has([data-highlighted])]:bg-accent relative p-0 text-center text-sm focus-within:relative focus-within:z-20 first:[&:has([data-selected])]:rounded-l-md last:[&:has([data-selected])]:rounded-r-md [&:has([data-selected][data-selection-end])]:rounded-r-md [&:has([data-selected][data-selection-start])]:rounded-l-md',\n    className,\n  )}\n  {...restProps}\n>\n  {@render children?.()}\n</td>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarCell.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarCellTrigger.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n  import type { CalendarDay, RangeCalendarContext } from './RangeCalendar.svelte'\n\n  // Omit `children`: the snippet carries the day, which narrows the base `Snippet` type.\n  export interface RangeCalendarCellTriggerProps extends Omit<HTMLButtonAttributes, 'children'> {\n    day: CalendarDay\n    children?: Snippet<[{ day: CalendarDay }]>\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { cn } from '$lib/utils'\n  import { buttonVariants } from '$lib/components/ui/button/button.variants'\n\n  let {\n    class: className,\n    day,\n    children,\n    disabled = undefined,\n    onclick: onclickProp,\n    onkeydown: onkeydownProp,\n    ref = $bindable(null),\n    ...restProps\n  }: RangeCalendarCellTriggerProps = $props()\n\n  const calendar = getContext<RangeCalendarContext | undefined>('rangeCalendar')\n  const effectiveDisabled = $derived(disabled ?? day.disabled ?? false)\n\n  function handleKeydown(event: KeyboardEvent) {\n    if (!calendar) return\n    if (event.key === 'ArrowRight') {\n      event.preventDefault()\n      calendar.focusDay(day.key, 1)\n    } else if (event.key === 'ArrowLeft') {\n      event.preventDefault()\n      calendar.focusDay(day.key, -1)\n    } else if (event.key === 'ArrowDown') {\n      event.preventDefault()\n      calendar.focusDay(day.key, 7)\n    } else if (event.key === 'ArrowUp') {\n      event.preventDefault()\n      calendar.focusDay(day.key, -7)\n    } else if (event.key === 'Home') {\n      event.preventDefault()\n      calendar.weekEdge(day.key, true)\n    } else if (event.key === 'End') {\n      event.preventDefault()\n      calendar.weekEdge(day.key, false)\n    } else if (event.key === 'PageUp') {\n      event.preventDefault()\n      calendar.focusMonthStep(day.key, event.shiftKey ? -12 : -1)\n    } else if (event.key === 'PageDown') {\n      event.preventDefault()\n      calendar.focusMonthStep(day.key, event.shiftKey ? 12 : 1)\n    }\n  }\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-trigger\"\n  data-day={day.key}\n  data-selected={day.selected || undefined}\n  data-selection-start={day.selectionStart || undefined}\n  data-selection-end={day.selectionEnd || undefined}\n  data-highlighted={day.highlighted || undefined}\n  data-today={day.today || undefined}\n  data-outside-view={day.outsideView || undefined}\n  data-unavailable={day.unavailable || undefined}\n  disabled={effectiveDisabled}\n  tabindex={day.tabbable ? 0 : -1}\n  aria-label={day.date.toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}\n  aria-pressed={day.selected || undefined}\n  class={cn(\n    buttonVariants({ variant: 'ghost' }),\n    'size-9 cursor-pointer p-0 font-normal transition-[color,background-color,transform,box-shadow] duration-150 data-[selected]:opacity-100',\n    '[&[data-today]:not([data-selected])]:bg-accent [&[data-today]:not([data-selected])]:text-accent-foreground',\n    // Selection Start / End — subtle pop\n    'data-[selection-start]:bg-primary data-[selection-start]:text-primary-foreground data-[selection-start]:hover:bg-primary data-[selection-start]:hover:text-primary-foreground data-[selection-start]:focus:bg-primary data-[selection-start]:focus:text-primary-foreground motion-safe:data-[selection-start]:animate-[calendar-day-pop_220ms_cubic-bezier(0.22,1.4,0.36,1)_both]',\n    'data-[selection-end]:bg-primary data-[selection-end]:text-primary-foreground data-[selection-end]:hover:bg-primary data-[selection-end]:hover:text-primary-foreground data-[selection-end]:focus:bg-primary data-[selection-end]:focus:text-primary-foreground motion-safe:data-[selection-end]:animate-[calendar-day-pop_220ms_cubic-bezier(0.22,1.4,0.36,1)_both]',\n    // Outside months\n    'data-[outside-view]:text-muted-foreground',\n    // Disabled\n    'data-[disabled]:text-muted-foreground data-[disabled]:opacity-50',\n    // Unavailable\n    'data-[unavailable]:text-destructive-foreground data-[unavailable]:line-through',\n    className,\n  )}\n  {...restProps}\n  onclick={(e) => {\n    calendar?.select(day)\n    onclickProp?.(e)\n  }}\n  onkeydown={(e) => {\n    handleKeydown(e)\n    onkeydownProp?.(e)\n  }}\n  onmouseenter={() => calendar?.hover(day)}\n  onmouseleave={() => calendar?.hover(null)}\n  onfocus={() => calendar?.hover(null)}\n>\n  {#if children}\n    {@render children({ day })}\n  {:else}\n    {day.dayNumber}\n  {/if}\n</button>\n\n<style>\n  @keyframes calendar-day-pop {\n    0% {\n      transform: scale(0.86);\n    }\n    70% {\n      transform: scale(1.06);\n    }\n    100% {\n      transform: scale(1);\n    }\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot='range-calendar-trigger'] {\n      animation: none !important;\n      transition: none !important;\n    }\n  }\n</style>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarCellTrigger.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarGrid.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface RangeCalendarGridProps extends HTMLAttributes<HTMLTableElement> {\n    /** Accessible month label, used as the table caption for screen readers. */\n    label?: string\n    children?: Snippet\n    ref?: HTMLTableElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let {\n    class: className,\n    label = undefined,\n    children,\n    ref = $bindable(null),\n    ...restProps\n  }: RangeCalendarGridProps = $props()\n</script>\n\n<table\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-grid\"\n  role=\"grid\"\n  aria-label={label}\n  class={cn('w-full border-collapse', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</table>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarGrid.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarGridBody.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface RangeCalendarGridBodyProps extends HTMLAttributes<HTMLTableSectionElement> {\n    children?: Snippet\n    ref?: HTMLTableSectionElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  let { children, ref = $bindable(null), ...restProps }: RangeCalendarGridBodyProps = $props()\n</script>\n\n<tbody bind:this={ref} data-uipkge=\"\" data-slot=\"range-calendar-grid-body\" {...restProps}>\n  {@render children?.()}\n</tbody>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarGridBody.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarGridHead.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface RangeCalendarGridHeadProps extends HTMLAttributes<HTMLTableSectionElement> {\n    children?: Snippet\n    ref?: HTMLTableSectionElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  let { children, ref = $bindable(null), ...restProps }: RangeCalendarGridHeadProps = $props()\n</script>\n\n<thead bind:this={ref} data-uipkge=\"\" data-slot=\"range-calendar-grid-head\" {...restProps}>\n  {@render children?.()}\n</thead>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarGridHead.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarGridRow.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface RangeCalendarGridRowProps extends HTMLAttributes<HTMLTableRowElement> {\n    children?: Snippet\n    ref?: HTMLTableRowElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: RangeCalendarGridRowProps = $props()\n</script>\n\n<tr bind:this={ref} data-uipkge=\"\" data-slot=\"range-calendar-grid-row\" class={cn('flex', className)} {...restProps}>\n  {@render children?.()}\n</tr>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarGridRow.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarHeadCell.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface RangeCalendarHeadCellProps extends HTMLAttributes<HTMLTableCellElement> {\n    children?: Snippet\n    ref?: HTMLTableCellElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: RangeCalendarHeadCellProps = $props()\n</script>\n\n<th\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-head-cell\"\n  scope=\"col\"\n  class={cn('text-muted-foreground w-8 rounded-md text-[0.8rem] font-normal', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</th>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarHeadCell.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarHeader.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface RangeCalendarHeaderProps extends HTMLAttributes<HTMLDivElement> {\n    children?: Snippet\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { cn } from '$lib/utils'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: RangeCalendarHeaderProps = $props()\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-header\"\n  class={cn('relative flex w-full items-center justify-center pt-1', className)}\n  {...restProps}\n>\n  {@render children?.()}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarHeader.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarHeading.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n  import type { RangeCalendarContext } from './RangeCalendar.svelte'\n\n  // Omit `children`: the snippet carries headingValue, which narrows the base `Snippet` type.\n  export interface RangeCalendarHeadingProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {\n    children?: Snippet<[{ headingValue: string }]>\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { cn } from '$lib/utils'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: RangeCalendarHeadingProps = $props()\n\n  const calendar = getContext<RangeCalendarContext | undefined>('rangeCalendar')\n  const headingValue = $derived(calendar?.headingValue ?? '')\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-heading\"\n  aria-live=\"polite\"\n  class={cn('text-sm font-medium', className)}\n  {...restProps}\n>\n  {#if children}\n    {@render children({ headingValue })}\n  {:else}\n    {headingValue}\n  {/if}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarHeading.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarNextButton.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n  import type { RangeCalendarContext } from './RangeCalendar.svelte'\n\n  export interface RangeCalendarNextButtonProps extends HTMLButtonAttributes {\n    children?: Snippet\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { ChevronRight } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n  import { buttonVariants } from '$lib/components/ui/button/button.variants'\n\n  let {\n    class: className,\n    children,\n    disabled = undefined,\n    onclick: onclickProp,\n    ref = $bindable(null),\n    ...restProps\n  }: RangeCalendarNextButtonProps = $props()\n\n  const calendar = getContext<RangeCalendarContext | undefined>('rangeCalendar')\n  const effectiveDisabled = $derived(disabled ?? (calendar ? calendar.disabled || !calendar.canNext : true))\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-next-button\"\n  aria-label=\"Next month\"\n  disabled={effectiveDisabled}\n  class={cn(\n    buttonVariants({ variant: 'outline' }),\n    'absolute right-1',\n    'size-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n    className,\n  )}\n  {...restProps}\n  onclick={(e) => {\n    calendar?.next()\n    onclickProp?.(e)\n  }}\n>\n  {#if children}\n    {@render children()}\n  {:else}\n    <ChevronRight class=\"size-4\" aria-hidden=\"true\" />\n  {/if}\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarNextButton.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/RangeCalendarPrevButton.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n  import type { RangeCalendarContext } from './RangeCalendar.svelte'\n\n  export interface RangeCalendarPrevButtonProps extends HTMLButtonAttributes {\n    children?: Snippet\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { ChevronLeft } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n  import { buttonVariants } from '$lib/components/ui/button/button.variants'\n\n  let {\n    class: className,\n    children,\n    disabled = undefined,\n    onclick: onclickProp,\n    ref = $bindable(null),\n    ...restProps\n  }: RangeCalendarPrevButtonProps = $props()\n\n  const calendar = getContext<RangeCalendarContext | undefined>('rangeCalendar')\n  const effectiveDisabled = $derived(disabled ?? (calendar ? calendar.disabled || !calendar.canPrev : true))\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  data-uipkge=\"\"\n  data-slot=\"range-calendar-prev-button\"\n  aria-label=\"Previous month\"\n  disabled={effectiveDisabled}\n  class={cn(\n    buttonVariants({ variant: 'outline' }),\n    'absolute left-1',\n    'size-7 bg-transparent p-0 opacity-50 hover:opacity-100',\n    className,\n  )}\n  {...restProps}\n  onclick={(e) => {\n    calendar?.prev()\n    onclickProp?.(e)\n  }}\n>\n  {#if children}\n    {@render children()}\n  {:else}\n    <ChevronLeft class=\"size-4\" aria-hidden=\"true\" />\n  {/if}\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/RangeCalendarPrevButton.svelte"
    },
    {
      "path": "packages/registry-svelte/components/range-calendar/index.ts",
      "content": "export {\n  default as RangeCalendar,\n  type CalendarDay,\n  type CalendarMonth,\n  type DateRange,\n  type ReactDateRange,\n  type RangeCalendarContext,\n  type RangeCalendarProps,\n} from './RangeCalendar.svelte'\nexport { default as RangeCalendarCell, type RangeCalendarCellProps } from './RangeCalendarCell.svelte'\nexport {\n  default as RangeCalendarCellTrigger,\n  type RangeCalendarCellTriggerProps,\n} from './RangeCalendarCellTrigger.svelte'\nexport { default as RangeCalendarGrid, type RangeCalendarGridProps } from './RangeCalendarGrid.svelte'\nexport { default as RangeCalendarGridBody, type RangeCalendarGridBodyProps } from './RangeCalendarGridBody.svelte'\nexport { default as RangeCalendarGridHead, type RangeCalendarGridHeadProps } from './RangeCalendarGridHead.svelte'\nexport { default as RangeCalendarGridRow, type RangeCalendarGridRowProps } from './RangeCalendarGridRow.svelte'\nexport { default as RangeCalendarHeadCell, type RangeCalendarHeadCellProps } from './RangeCalendarHeadCell.svelte'\nexport { default as RangeCalendarHeader, type RangeCalendarHeaderProps } from './RangeCalendarHeader.svelte'\nexport { default as RangeCalendarHeading, type RangeCalendarHeadingProps } from './RangeCalendarHeading.svelte'\nexport {\n  default as RangeCalendarNextButton,\n  type RangeCalendarNextButtonProps,\n} from './RangeCalendarNextButton.svelte'\nexport {\n  default as RangeCalendarPrevButton,\n  type RangeCalendarPrevButtonProps,\n} from './RangeCalendarPrevButton.svelte'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/range-calendar/index.ts"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/button.json"
  ],
  "description": "Inline from→to calendar grid. Click two dates; the range fills between. Plain-Date value API with min/max, disabled-date support, fixed weeks, and configurable week start.",
  "categories": [
    "date-time"
  ]
}