@joewinke/jatui 0.41.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CLAUDE.md +9 -3
  2. package/dist/components/AnimatedNumber.svelte +22 -4
  3. package/dist/components/BookingScheduler.svelte +412 -0
  4. package/dist/components/BookingScheduler.svelte.d.ts +66 -0
  5. package/dist/components/CalendarPicker.svelte +190 -205
  6. package/dist/components/CalendarPicker.svelte.d.ts +19 -1
  7. package/dist/components/DatePicker.svelte +419 -0
  8. package/dist/components/DatePicker.svelte.d.ts +44 -0
  9. package/dist/components/DateRangePicker.svelte +471 -5
  10. package/dist/components/DateRangePicker.svelte.d.ts +32 -3
  11. package/dist/components/EventCalendar.svelte +1324 -0
  12. package/dist/components/EventCalendar.svelte.d.ts +101 -0
  13. package/dist/components/TimeSlotPicker.svelte +174 -108
  14. package/dist/components/TimeSlotPicker.svelte.d.ts +27 -0
  15. package/dist/components/calendar/CalendarHeader.svelte +98 -0
  16. package/dist/components/calendar/CalendarHeader.svelte.d.ts +24 -0
  17. package/dist/components/calendar/MonthGrid.svelte +361 -0
  18. package/dist/components/calendar/MonthGrid.svelte.d.ts +55 -0
  19. package/dist/components/calendar/calendarGrid.d.ts +219 -0
  20. package/dist/components/calendar/calendarGrid.js +494 -0
  21. package/dist/components/calendar/createCalendarGrid.d.ts +25 -0
  22. package/dist/components/calendar/createCalendarGrid.js +57 -0
  23. package/dist/components/calendar/dayOverlap.d.ts +92 -0
  24. package/dist/components/calendar/dayOverlap.js +147 -0
  25. package/dist/components/calendar/eventCalendar.d.ts +75 -0
  26. package/dist/components/calendar/eventCalendar.js +187 -0
  27. package/dist/components/calendar/index.d.ts +32 -0
  28. package/dist/components/calendar/index.js +25 -0
  29. package/dist/components/calendar/monthPacking.d.ts +97 -0
  30. package/dist/components/calendar/monthPacking.js +254 -0
  31. package/dist/components/calendar/timeSlots.d.ts +57 -0
  32. package/dist/components/calendar/timeSlots.js +163 -0
  33. package/dist/index.d.ts +17 -0
  34. package/dist/index.js +11 -0
  35. package/dist/showcase/Globe.svelte +1 -1
  36. package/package.json +6 -1
@@ -2,16 +2,81 @@
2
2
  /**
3
3
  * DateRangePicker Component
4
4
  * DaisyUI dropdown for filtering by date range with quick presets
5
+ *
6
+ * Two modes (jatui-lfxyy):
7
+ * - `mode="presets"` (default, unchanged): the compact filter-bar dropdown —
8
+ * string presets (`selectedRange`) plus native From/To inputs.
9
+ * - `mode="calendar"`: a two-month range calendar with a preset sidebar,
10
+ * hover preview, typed start/end fields, an "N days selected" pill and
11
+ * Apply/Cancel. Binds `value: { start, end }` as `YYYY-MM-DD` strings
12
+ * (open ends are null). `onRangeChange` still fires in the legacy shape —
13
+ * `(presetId | 'custom', from?, to?)` — so a filter bar can switch modes
14
+ * without touching its handler.
5
15
  */
6
16
 
17
+ import { tick } from 'svelte';
7
18
  import { formatShortDate } from '../utils/dateFormatters';
19
+ import { floating, type Placement } from '../actions/floating';
20
+ import MonthGrid from './calendar/MonthGrid.svelte';
21
+ import CalendarHeader from './calendar/CalendarHeader.svelte';
22
+ import { createCalendarGrid } from './calendar/createCalendarGrid';
23
+ import {
24
+ calendarAccentStyle,
25
+ datePlaceholder,
26
+ defaultRangePresetsWithAll,
27
+ formatMonthYear,
28
+ formatRangeLabel,
29
+ formatTypedDate,
30
+ fromIsoRange,
31
+ makeIsDisabled,
32
+ matchPreset,
33
+ normalizeRange,
34
+ parseTypedDate,
35
+ pickRangeDate,
36
+ rangeDayCount,
37
+ resolvePreset,
38
+ resolveWeekStart,
39
+ toDay,
40
+ toIsoRange,
41
+ type DateRange,
42
+ type IsoDateRange,
43
+ type RangePreset,
44
+ type Weekday
45
+ } from './calendar/calendarGrid';
8
46
 
9
47
  interface Props {
10
- selectedRange: string; // 'today' | 'yesterday' | 'week' | 'month' | 'all' | 'custom'
48
+ selectedRange?: string; // 'today' | 'yesterday' | 'week' | 'month' | 'all' | 'custom'
11
49
  customFrom?: string | null; // ISO date for custom range
12
50
  customTo?: string | null; // ISO date for custom range
13
- onRangeChange: (range: string, from?: string, to?: string) => void;
51
+ onRangeChange?: (range: string, from?: string, to?: string) => void;
14
52
  compact?: boolean;
53
+ /** `presets` (default): the original dropdown. `calendar`: the range calendar. */
54
+ mode?: 'presets' | 'calendar';
55
+ /** Calendar mode: the committed range (bindable). */
56
+ value?: IsoDateRange;
57
+ /** Calendar mode: fires on commit with the range and the matching preset id (or null). */
58
+ onChange?: (range: IsoDateRange, presetId: string | null) => void;
59
+ /** Calendar mode: quick-select sidebar. Defaults to Today … Last year + All time. */
60
+ presets?: RangePreset[];
61
+ /** Calendar mode: month panels side by side (1 or 2). */
62
+ months?: 1 | 2;
63
+ /** Calendar mode: `apply` (default) holds the pick until Apply; `instant` commits on the second click. */
64
+ commit?: 'apply' | 'instant';
65
+ min?: string | Date | null;
66
+ max?: string | Date | null;
67
+ isDateEnabled?: (date: Date) => boolean;
68
+ weekStart?: Weekday | 'locale';
69
+ locale?: string;
70
+ /** Trigger text for an empty (all-time) range. */
71
+ placeholder?: string;
72
+ /** Accessible name for the trigger and dialog. */
73
+ label?: string;
74
+ /** Form field names for the two ends. */
75
+ nameStart?: string;
76
+ nameEnd?: string;
77
+ accentColor?: string;
78
+ placement?: Placement;
79
+ zIndex?: number;
15
80
  }
16
81
 
17
82
  let {
@@ -19,9 +84,156 @@
19
84
  customFrom = null,
20
85
  customTo = null,
21
86
  onRangeChange,
22
- compact = false
87
+ compact = false,
88
+ mode = 'presets',
89
+ value = $bindable({ start: null, end: null }),
90
+ onChange,
91
+ presets: presetsProp,
92
+ months = 2,
93
+ commit = 'apply',
94
+ min,
95
+ max,
96
+ isDateEnabled,
97
+ weekStart = 'locale',
98
+ locale,
99
+ placeholder = 'All time',
100
+ label = 'Date range',
101
+ nameStart,
102
+ nameEnd,
103
+ accentColor,
104
+ placement = 'bottom-end',
105
+ zIndex = 60
23
106
  }: Props = $props();
24
107
 
108
+ // ── Calendar mode ────────────────────────────────────────────────────────
109
+
110
+ const calPresets = $derived(presetsProp ?? defaultRangePresetsWithAll());
111
+ const firstDay = $derived(resolveWeekStart(weekStart, locale));
112
+ const minDay = $derived(toDay(min ?? null));
113
+ const maxDay = $derived(toDay(max ?? null));
114
+ const isDisabled = $derived(makeIsDisabled({ min: minDay, max: maxDay, isDateEnabled }));
115
+ const committedRange = $derived(fromIsoRange(value));
116
+ const activePresetId = $derived(matchPreset(value ?? { start: null, end: null }, calPresets));
117
+ const calLabel = $derived.by(() => {
118
+ const preset = calPresets.find((p) => p.id === activePresetId);
119
+ if (preset) return preset.label;
120
+ return formatRangeLabel(committedRange, locale) || placeholder;
121
+ });
122
+
123
+ let calOpen = $state(false);
124
+ let triggerEl = $state<HTMLButtonElement | null>(null);
125
+ let popEl = $state<HTMLDivElement | null>(null);
126
+ let pending = $state<DateRange>({ start: null, end: null });
127
+ let hover = $state<Date | null>(null);
128
+ const cal = createCalendarGrid({ min: () => minDay, max: () => maxDay, months: () => months });
129
+ let startText = $state('');
130
+ let endText = $state('');
131
+ let message = $state('');
132
+ let lastDismiss = 0;
133
+
134
+ /** The band to paint: the pending range, or the hover preview while the end is open. */
135
+ const shown = $derived<DateRange>(
136
+ pending.start && !pending.end && hover ? normalizeRange({ start: pending.start, end: hover }) : pending
137
+ );
138
+ const shownCount = $derived(rangeDayCount(shown));
139
+ const pendingPresetId = $derived(matchPreset(toIsoRange(pending), calPresets));
140
+
141
+ function syncTexts() {
142
+ startText = formatTypedDate(pending.start, locale);
143
+ endText = formatTypedDate(pending.end, locale);
144
+ }
145
+
146
+ async function openCalendar() {
147
+ pending = { ...committedRange };
148
+ hover = null;
149
+ message = '';
150
+ cal.reset(pending.start ?? pending.end);
151
+ syncTexts();
152
+ calOpen = true;
153
+ await tick();
154
+ popEl?.querySelector<HTMLElement>('.jatui-month-grid__day[tabindex="0"]')?.focus();
155
+ }
156
+
157
+ function closeCalendar() {
158
+ calOpen = false;
159
+ lastDismiss = performance.now();
160
+ }
161
+
162
+ function toggleCalendar() {
163
+ if (calOpen) return closeCalendar();
164
+ if (performance.now() - lastDismiss < 250) return;
165
+ void openCalendar();
166
+ }
167
+
168
+ function commitRange(range: DateRange) {
169
+ const iso = toIsoRange(normalizeRange(range));
170
+ const presetId = matchPreset(iso, calPresets);
171
+ value = iso;
172
+ onChange?.(iso, presetId);
173
+ onRangeChange?.(presetId ?? 'custom', iso.start ?? undefined, iso.end ?? undefined);
174
+ closeCalendar();
175
+ }
176
+
177
+ function pickDate(date: Date) {
178
+ pending = pickRangeDate(pending, date);
179
+ hover = null;
180
+ message = '';
181
+ syncTexts();
182
+ if (commit === 'instant' && pending.start && pending.end) commitRange(pending);
183
+ }
184
+
185
+ function choosePreset(preset: RangePreset) {
186
+ pending = fromIsoRange(resolvePreset(preset));
187
+ hover = null;
188
+ message = '';
189
+ syncTexts();
190
+ if (pending.start) cal.reset(pending.start);
191
+ if (commit === 'instant') commitRange(pending);
192
+ }
193
+
194
+ function handleFocusDate(date: Date) {
195
+ // Keyboard users get the same preview a pointer does.
196
+ if (pending.start && !pending.end) hover = date;
197
+ cal.focus(date);
198
+ }
199
+
200
+ function commitTypedEnd(which: 'start' | 'end') {
201
+ const text = which === 'start' ? startText : endText;
202
+ const current = formatTypedDate(pending[which], locale);
203
+ if (text.trim() === current) return;
204
+ if (!text.trim()) {
205
+ pending = { ...pending, [which]: null };
206
+ return;
207
+ }
208
+ const parsed = parseTypedDate(text, locale);
209
+ if (!parsed || isDisabled(parsed)) {
210
+ message = parsed ? 'That date is not available.' : `Couldn't read that date — use ${datePlaceholder(locale)}.`;
211
+ syncTexts();
212
+ return;
213
+ }
214
+ message = '';
215
+ pending = normalizeRange({ ...pending, [which]: parsed });
216
+ syncTexts();
217
+ handleFocusDate(parsed);
218
+ }
219
+
220
+ function typedKeydown(e: KeyboardEvent, which: 'start' | 'end') {
221
+ if (e.key === 'Enter') {
222
+ e.preventDefault();
223
+ commitTypedEnd(which);
224
+ } else if (e.key === 'Escape') {
225
+ const current = formatTypedDate(pending[which], locale);
226
+ const text = which === 'start' ? startText : endText;
227
+ if (text !== current) {
228
+ e.stopPropagation();
229
+ syncTexts();
230
+ message = '';
231
+ }
232
+ }
233
+ }
234
+
235
+ // ── Presets mode (original) ──────────────────────────────────────────────
236
+
25
237
  // Local state for custom date inputs
26
238
  // svelte-ignore state_referenced_locally
27
239
  let localFrom = $state(customFrom || '');
@@ -56,7 +268,7 @@
56
268
  showCustom = false;
57
269
  localFrom = '';
58
270
  localTo = '';
59
- onRangeChange(preset);
271
+ onRangeChange?.(preset);
60
272
 
61
273
  // Close dropdown
62
274
  if (document.activeElement instanceof HTMLElement) {
@@ -66,7 +278,7 @@
66
278
 
67
279
  function handleCustomApply() {
68
280
  if (localFrom || localTo) {
69
- onRangeChange('custom', localFrom || undefined, localTo || undefined);
281
+ onRangeChange?.('custom', localFrom || undefined, localTo || undefined);
70
282
 
71
283
  // Close dropdown
72
284
  if (document.activeElement instanceof HTMLElement) {
@@ -80,6 +292,141 @@
80
292
  }
81
293
  </script>
82
294
 
295
+ {#if mode === 'calendar'}
296
+ <button
297
+ bind:this={triggerEl}
298
+ type="button"
299
+ class="{compact ? 'px-2 py-1 text-[10px]' : 'px-2.5 py-1.5 text-xs'} rounded cursor-pointer transition-all flex items-center gap-1.5 font-mono tracking-wider whitespace-nowrap bg-base-200 border border-base-300 text-base-content/60"
300
+ aria-haspopup="dialog"
301
+ aria-expanded={calOpen}
302
+ aria-label="{label}: {calLabel}"
303
+ onclick={toggleCalendar}
304
+ >
305
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 text-primary" aria-hidden="true">
306
+ <path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5" />
307
+ </svg>
308
+ <span>{calLabel}</span>
309
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-3 h-3 text-base-content/50" aria-hidden="true">
310
+ <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
311
+ </svg>
312
+ </button>
313
+ {#if nameStart}<input type="hidden" name={nameStart} value={value?.start ?? ''} />{/if}
314
+ {#if nameEnd}<input type="hidden" name={nameEnd} value={value?.end ?? ''} />{/if}
315
+
316
+ {#if calOpen}
317
+ <div
318
+ bind:this={popEl}
319
+ role="dialog"
320
+ aria-label={label}
321
+ class="jatui-range bg-base-100 rounded-box border border-base-300"
322
+ style="z-index: {zIndex}; {calendarAccentStyle(accentColor)}"
323
+ data-calendar-root
324
+ use:floating={{ anchor: triggerEl, placement, offset: 6, onDismiss: closeCalendar }}
325
+ >
326
+ {#if calPresets.length > 0}
327
+ <div class="jatui-range__presets" role="group" aria-label="Quick ranges">
328
+ {#each calPresets as preset (preset.id)}
329
+ <button
330
+ type="button"
331
+ class="jatui-range__preset"
332
+ class:is-active={pendingPresetId === preset.id}
333
+ aria-pressed={pendingPresetId === preset.id}
334
+ onclick={() => choosePreset(preset)}
335
+ >
336
+ {preset.label}
337
+ </button>
338
+ {/each}
339
+ </div>
340
+ {/if}
341
+
342
+ <div class="jatui-range__main">
343
+ <div class="jatui-range__fields">
344
+ <label class="jatui-range__field">
345
+ <span>Start</span>
346
+ <input
347
+ type="text"
348
+ inputmode="numeric"
349
+ autocomplete="off"
350
+ dir="ltr"
351
+ class="input input-sm font-mono"
352
+ placeholder={datePlaceholder(locale)}
353
+ bind:value={startText}
354
+ onkeydown={(e) => typedKeydown(e, 'start')}
355
+ onblur={() => commitTypedEnd('start')}
356
+ />
357
+ </label>
358
+ <span class="jatui-range__dash" aria-hidden="true">–</span>
359
+ <label class="jatui-range__field">
360
+ <span>End</span>
361
+ <input
362
+ type="text"
363
+ inputmode="numeric"
364
+ autocomplete="off"
365
+ dir="ltr"
366
+ class="input input-sm font-mono"
367
+ placeholder={datePlaceholder(locale)}
368
+ bind:value={endText}
369
+ onkeydown={(e) => typedKeydown(e, 'end')}
370
+ onblur={() => commitTypedEnd('end')}
371
+ />
372
+ </label>
373
+ </div>
374
+ <p class="jatui-range__msg" role="status" aria-live="polite">{message}</p>
375
+
376
+ <div class="jatui-range__panels" class:is-two={months === 2}>
377
+ {#each cal.panels as m, i (m.getTime())}
378
+ <div class="jatui-range__panel">
379
+ <CalendarHeader
380
+ label={formatMonthYear(m, locale)}
381
+ onPrev={() => cal.shift(-1)}
382
+ onNext={() => cal.shift(1)}
383
+ canPrev={cal.canPrev}
384
+ canNext={cal.canNext}
385
+ hidePrev={i > 0}
386
+ hideNext={i < cal.panels.length - 1}
387
+ size="sm"
388
+ />
389
+ <MonthGrid
390
+ month={m}
391
+ focusedDate={cal.focusedDate}
392
+ weekStart={firstDay}
393
+ {locale}
394
+ range={shown}
395
+ {isDisabled}
396
+ min={minDay}
397
+ max={maxDay}
398
+ showOutsideDays={false}
399
+ fixedWeeks
400
+ size="sm"
401
+ onSelect={pickDate}
402
+ onFocusDate={handleFocusDate}
403
+ onHover={(d) => (hover = d)}
404
+ />
405
+ </div>
406
+ {/each}
407
+ </div>
408
+
409
+ <div class="jatui-range__footer">
410
+ <span class="jatui-range__count" aria-live="polite">
411
+ {#if shownCount > 0}
412
+ {shownCount} day{shownCount === 1 ? '' : 's'} selected
413
+ {:else if pending.start}
414
+ Pick an end date
415
+ {:else}
416
+ Any date
417
+ {/if}
418
+ </span>
419
+ <span class="jatui-range__actions">
420
+ <button type="button" class="btn btn-ghost btn-sm" onclick={closeCalendar}>Cancel</button>
421
+ {#if commit === 'apply'}
422
+ <button type="button" class="btn btn-primary btn-sm" onclick={() => commitRange(pending)}>Apply</button>
423
+ {/if}
424
+ </span>
425
+ </div>
426
+ </div>
427
+ </div>
428
+ {/if}
429
+ {:else}
83
430
  <!-- Date Range Picker -->
84
431
  <div class="dropdown dropdown-end">
85
432
  <!-- Trigger Button -->
@@ -192,3 +539,122 @@
192
539
  </div>
193
540
  </div>
194
541
  </div>
542
+ {/if}
543
+
544
+ <style>
545
+ .jatui-range {
546
+ display: flex;
547
+ gap: 0.75rem;
548
+ width: max-content;
549
+ max-width: calc(100vw - 1rem);
550
+ padding: 0.75rem;
551
+ }
552
+ .jatui-range__presets {
553
+ display: flex;
554
+ flex-direction: column;
555
+ gap: 2px;
556
+ min-width: 8rem;
557
+ padding-inline-end: 0.75rem;
558
+ border-inline-end: 1px solid var(--jatui-separator, var(--color-base-300));
559
+ }
560
+ .jatui-range__preset {
561
+ padding: 0.375rem 0.5rem;
562
+ border-radius: var(--radius-field, 0.375rem);
563
+ font-size: 0.8125rem;
564
+ text-align: start;
565
+ white-space: nowrap;
566
+ color: color-mix(in oklab, var(--color-base-content) 75%, transparent);
567
+ cursor: pointer;
568
+ }
569
+ .jatui-range__preset:hover {
570
+ background: var(--jatui-hover-bg, color-mix(in oklab, var(--color-base-content) 7%, transparent));
571
+ }
572
+ .jatui-range__preset.is-active {
573
+ background: var(--jatui-cal-band, var(--jatui-selection-bg, color-mix(in oklab, var(--color-primary) 14%, transparent)));
574
+ color: var(--color-base-content);
575
+ font-weight: 600;
576
+ }
577
+ .jatui-range__preset:focus-visible {
578
+ outline: var(--jatui-focus-ring-width, 2px) solid var(--jatui-focus-ring, var(--color-primary));
579
+ outline-offset: -2px;
580
+ }
581
+ .jatui-range__main {
582
+ display: flex;
583
+ flex-direction: column;
584
+ min-width: 0;
585
+ }
586
+ .jatui-range__fields {
587
+ display: flex;
588
+ align-items: flex-end;
589
+ gap: 0.5rem;
590
+ }
591
+ .jatui-range__field {
592
+ display: flex;
593
+ flex-direction: column;
594
+ gap: 0.125rem;
595
+ flex: 1;
596
+ font-size: 0.75rem;
597
+ color: color-mix(in oklab, var(--color-base-content) 55%, transparent);
598
+ }
599
+ .jatui-range__field input {
600
+ width: 100%;
601
+ min-width: 0;
602
+ }
603
+ .jatui-range__dash {
604
+ padding-block-end: 0.375rem;
605
+ color: color-mix(in oklab, var(--color-base-content) 45%, transparent);
606
+ }
607
+ .jatui-range__msg {
608
+ margin: 0.25rem 0 0;
609
+ font-size: 0.75rem;
610
+ color: var(--color-error);
611
+ }
612
+ .jatui-range__msg:empty {
613
+ margin: 0;
614
+ }
615
+ .jatui-range__panels {
616
+ display: grid;
617
+ gap: 1.25rem;
618
+ margin-block-start: 0.75rem;
619
+ }
620
+ .jatui-range__panels.is-two {
621
+ grid-template-columns: repeat(2, minmax(0, 1fr));
622
+ }
623
+ .jatui-range__footer {
624
+ display: flex;
625
+ align-items: center;
626
+ justify-content: space-between;
627
+ gap: 0.75rem;
628
+ margin-block-start: 0.5rem;
629
+ padding-block-start: 0.5rem;
630
+ border-block-start: 1px solid var(--jatui-separator, var(--color-base-300));
631
+ }
632
+ .jatui-range__count {
633
+ padding: 0.125rem 0.5rem;
634
+ border-radius: 9999px;
635
+ font-size: 0.75rem;
636
+ font-variant-numeric: tabular-nums;
637
+ background: var(--jatui-hover-bg, color-mix(in oklab, var(--color-base-content) 7%, transparent));
638
+ color: color-mix(in oklab, var(--color-base-content) 75%, transparent);
639
+ }
640
+ .jatui-range__actions {
641
+ display: inline-flex;
642
+ gap: 0.375rem;
643
+ }
644
+ @media (max-width: 40rem) {
645
+ .jatui-range {
646
+ flex-direction: column;
647
+ }
648
+ .jatui-range__presets {
649
+ flex-direction: row;
650
+ flex-wrap: wrap;
651
+ padding-inline-end: 0;
652
+ padding-block-end: 0.5rem;
653
+ border-inline-end: 0;
654
+ border-block-end: 1px solid var(--jatui-separator, var(--color-base-300));
655
+ }
656
+ .jatui-range__panels.is-two {
657
+ grid-template-columns: minmax(0, 1fr);
658
+ }
659
+ }
660
+ </style>
@@ -1,10 +1,39 @@
1
+ import { type Placement } from '../actions/floating';
2
+ import { type IsoDateRange, type RangePreset, type Weekday } from './calendar/calendarGrid';
1
3
  interface Props {
2
- selectedRange: string;
4
+ selectedRange?: string;
3
5
  customFrom?: string | null;
4
6
  customTo?: string | null;
5
- onRangeChange: (range: string, from?: string, to?: string) => void;
7
+ onRangeChange?: (range: string, from?: string, to?: string) => void;
6
8
  compact?: boolean;
9
+ /** `presets` (default): the original dropdown. `calendar`: the range calendar. */
10
+ mode?: 'presets' | 'calendar';
11
+ /** Calendar mode: the committed range (bindable). */
12
+ value?: IsoDateRange;
13
+ /** Calendar mode: fires on commit with the range and the matching preset id (or null). */
14
+ onChange?: (range: IsoDateRange, presetId: string | null) => void;
15
+ /** Calendar mode: quick-select sidebar. Defaults to Today … Last year + All time. */
16
+ presets?: RangePreset[];
17
+ /** Calendar mode: month panels side by side (1 or 2). */
18
+ months?: 1 | 2;
19
+ /** Calendar mode: `apply` (default) holds the pick until Apply; `instant` commits on the second click. */
20
+ commit?: 'apply' | 'instant';
21
+ min?: string | Date | null;
22
+ max?: string | Date | null;
23
+ isDateEnabled?: (date: Date) => boolean;
24
+ weekStart?: Weekday | 'locale';
25
+ locale?: string;
26
+ /** Trigger text for an empty (all-time) range. */
27
+ placeholder?: string;
28
+ /** Accessible name for the trigger and dialog. */
29
+ label?: string;
30
+ /** Form field names for the two ends. */
31
+ nameStart?: string;
32
+ nameEnd?: string;
33
+ accentColor?: string;
34
+ placement?: Placement;
35
+ zIndex?: number;
7
36
  }
8
- declare const DateRangePicker: import("svelte").Component<Props, {}, "">;
37
+ declare const DateRangePicker: import("svelte").Component<Props, {}, "value">;
9
38
  type DateRangePicker = ReturnType<typeof DateRangePicker>;
10
39
  export default DateRangePicker;