@mhmo91/schmancy 0.10.43 → 0.10.44
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.
- package/custom-elements.json +2 -2
- package/dist/agent/schmancy.agent.js +785 -779
- package/dist/agent/schmancy.agent.js.map +1 -1
- package/dist/agent/schmancy.manifest.json +1 -1
- package/dist/badge.cjs +1 -1
- package/dist/badge.js +1 -1
- package/dist/content-drawer.cjs +1 -1
- package/dist/content-drawer.js +1 -1
- package/dist/date-range-B2VN7cl_.cjs +138 -0
- package/dist/date-range-B2VN7cl_.cjs.map +1 -0
- package/dist/{date-range-D2NZU5Yg.js → date-range-CDF_5ju_.js} +63 -57
- package/dist/date-range-CDF_5ju_.js.map +1 -0
- package/dist/date-range.cjs +1 -1
- package/dist/date-range.js +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.js +1 -1
- package/dist/handover/agent-runtime-followups.md +1 -1
- package/dist/handover/agent-runtime-v1.md +3 -3
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/nav-drawer.cjs +1 -1
- package/dist/nav-drawer.js +1 -1
- package/dist/navigation-bar.cjs +1 -1
- package/dist/navigation-bar.js +1 -1
- package/dist/{src-DAtcPmCb.js → src-Bo-vvN6m.js} +1 -1
- package/dist/{src-DAtcPmCb.js.map → src-Bo-vvN6m.js.map} +1 -1
- package/dist/{src-DuRvYagm.cjs → src-MdpH1zth.cjs} +1 -1
- package/dist/{src-DuRvYagm.cjs.map → src-MdpH1zth.cjs.map} +1 -1
- package/dist/teleport.cjs +1 -1
- package/dist/teleport.js +1 -1
- package/package.json +1 -1
- package/src/form/fields/date-range/date-range-dialog.ts +14 -1
- package/src/form/fields/date-range/date-range.test.ts +218 -1
- package/src/form/fields/date-range/date-range.ts +42 -18
- package/types/src/form/fields/date-range/date-range.d.ts +4 -0
- package/dist/date-range-CVAWMdar.cjs +0 -138
- package/dist/date-range-CVAWMdar.cjs.map +0 -1
- package/dist/date-range-D2NZU5Yg.js.map +0 -1
|
@@ -273,7 +273,7 @@ describe('schmancy-date-range', () => {
|
|
|
273
273
|
// Exact shape: {start, end} — no preset field.
|
|
274
274
|
expect(detail.start).toBe('2026-06-01')
|
|
275
275
|
expect(detail.end).toBe('2026-06-15')
|
|
276
|
-
expect(Object.keys(detail).
|
|
276
|
+
expect(Object.keys(detail).toSorted()).toEqual(['end', 'start'])
|
|
277
277
|
|
|
278
278
|
// change must NOT have fired — provisional sweep is not a commit.
|
|
279
279
|
expect(changeReceived.length, 'change must not fire for provisional sweep').toBe(0)
|
|
@@ -380,4 +380,221 @@ describe('schmancy-date-range', () => {
|
|
|
380
380
|
await expectNoA11yViolations(host)
|
|
381
381
|
})
|
|
382
382
|
})
|
|
383
|
+
|
|
384
|
+
// -------------------------------------------------------------------------
|
|
385
|
+
describe('datetime-local', () => {
|
|
386
|
+
// Calendar pick → commits start-of-day / end-of-day YYYY-MM-DDTHH:mm
|
|
387
|
+
it('calendar pick commits start-of-day T00:00 and end-of-day T23:59', async () => {
|
|
388
|
+
const host = await mount('<schmancy-date-range name="dtw" type="datetime-local"></schmancy-date-range>')
|
|
389
|
+
const el = dr(host)
|
|
390
|
+
await el.updateComplete
|
|
391
|
+
|
|
392
|
+
// Open the picker.
|
|
393
|
+
const btn = el.shadowRoot!.querySelector('schmancy-button') as HTMLElement
|
|
394
|
+
document.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true, composed: true, clientX: 10, clientY: 10 }))
|
|
395
|
+
btn.click()
|
|
396
|
+
await el.updateComplete
|
|
397
|
+
await nextUpdate()
|
|
398
|
+
|
|
399
|
+
const dialog = await vi.waitFor(
|
|
400
|
+
() => {
|
|
401
|
+
for (const o of document.querySelectorAll('schmancy-overlay')) {
|
|
402
|
+
const d = o.shadowRoot?.querySelector('schmancy-date-range-dialog')
|
|
403
|
+
if (d) return d
|
|
404
|
+
}
|
|
405
|
+
throw new Error('dialog not mounted yet')
|
|
406
|
+
},
|
|
407
|
+
{ timeout: 2000 },
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
// Dispatch the calendar `change` event on the schmancy-calendar element inside
|
|
411
|
+
// the dialog's shadow root so it routes through handleCalendarChange, which is
|
|
412
|
+
// responsible for converting YYYY-MM-DD → YYYY-MM-DDTHH:mm when type="datetime-local".
|
|
413
|
+
const calendar = dialog.shadowRoot?.querySelector('schmancy-calendar')
|
|
414
|
+
expect(calendar, 'schmancy-calendar must be in the dialog shadow root').not.toBeNull()
|
|
415
|
+
|
|
416
|
+
const changeReceived: CustomEvent[] = []
|
|
417
|
+
el.addEventListener('change', (e) => changeReceived.push(e as CustomEvent))
|
|
418
|
+
|
|
419
|
+
calendar!.dispatchEvent(
|
|
420
|
+
new CustomEvent('change', {
|
|
421
|
+
detail: { value: null, start: '2026-06-10', end: '2026-06-20' },
|
|
422
|
+
bubbles: true,
|
|
423
|
+
composed: true,
|
|
424
|
+
}),
|
|
425
|
+
)
|
|
426
|
+
await el.updateComplete
|
|
427
|
+
|
|
428
|
+
expect(changeReceived.length, 'change must fire after calendar pick').toBeGreaterThan(0)
|
|
429
|
+
const detail = changeReceived[changeReceived.length - 1].detail as {
|
|
430
|
+
start: string | null
|
|
431
|
+
end: string | null
|
|
432
|
+
preset: string | null
|
|
433
|
+
}
|
|
434
|
+
expect(detail.start).toBe('2026-06-10T00:00')
|
|
435
|
+
expect(detail.end).toBe('2026-06-20T23:59')
|
|
436
|
+
expect(detail.preset).toBeNull()
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
// Typed path edits time without moving the date.
|
|
440
|
+
it('typed datetime-local input replaces time component without moving the date', async () => {
|
|
441
|
+
const host = await mount('<schmancy-date-range name="dtw" type="datetime-local"></schmancy-date-range>')
|
|
442
|
+
const el = dr(host)
|
|
443
|
+
el.start = '2026-06-10T00:00'
|
|
444
|
+
el.end = '2026-06-20T23:59'
|
|
445
|
+
await el.updateComplete
|
|
446
|
+
|
|
447
|
+
// Open the picker.
|
|
448
|
+
const btn = el.shadowRoot!.querySelector('schmancy-button') as HTMLElement
|
|
449
|
+
document.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true, composed: true, clientX: 10, clientY: 10 }))
|
|
450
|
+
btn.click()
|
|
451
|
+
await el.updateComplete
|
|
452
|
+
await nextUpdate()
|
|
453
|
+
|
|
454
|
+
const dialog = await vi.waitFor(
|
|
455
|
+
() => {
|
|
456
|
+
for (const o of document.querySelectorAll('schmancy-overlay')) {
|
|
457
|
+
const d = o.shadowRoot?.querySelector('schmancy-date-range-dialog')
|
|
458
|
+
if (d) return d
|
|
459
|
+
}
|
|
460
|
+
throw new Error('dialog not mounted yet')
|
|
461
|
+
},
|
|
462
|
+
{ timeout: 2000 },
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
// Simulate the typed From input changing the time (same date, different time).
|
|
466
|
+
// handleFromChange dispatches `calendar-change` directly with the full datetime
|
|
467
|
+
// value from the input, preserving the date part and replacing the time.
|
|
468
|
+
// We dispatch `calendar-change` at the dialog bridge seam (same approach used
|
|
469
|
+
// in the existing `input event` tests) to verify the contract end-to-end.
|
|
470
|
+
const changeReceived: CustomEvent[] = []
|
|
471
|
+
el.addEventListener('change', (e) => changeReceived.push(e as CustomEvent))
|
|
472
|
+
|
|
473
|
+
dialog.dispatchEvent(
|
|
474
|
+
new CustomEvent('calendar-change', {
|
|
475
|
+
// The typed input produces a full YYYY-MM-DDTHH:mm value; the dialog
|
|
476
|
+
// passes this through unchanged (no T-injection since it already has T).
|
|
477
|
+
detail: { start: '2026-06-10T09:30', end: '2026-06-20T23:59' },
|
|
478
|
+
bubbles: true,
|
|
479
|
+
composed: true,
|
|
480
|
+
}),
|
|
481
|
+
)
|
|
482
|
+
await el.updateComplete
|
|
483
|
+
|
|
484
|
+
expect(changeReceived.length).toBeGreaterThan(0)
|
|
485
|
+
const detail = changeReceived[changeReceived.length - 1].detail as {
|
|
486
|
+
start: string | null
|
|
487
|
+
end: string | null
|
|
488
|
+
}
|
|
489
|
+
// Date part preserved; time replaced.
|
|
490
|
+
expect(detail.start).toBe('2026-06-10T09:30')
|
|
491
|
+
expect(detail.end).toBe('2026-06-20T23:59')
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
// FormData carries YYYY-MM-DDTHH:mm ISO entries.
|
|
495
|
+
it('FormData ${name}.start and ${name}.end carry datetime ISO strings', async () => {
|
|
496
|
+
const host = await mount(
|
|
497
|
+
'<form><schmancy-date-range name="dtw" type="datetime-local"></schmancy-date-range></form>',
|
|
498
|
+
)
|
|
499
|
+
const form = host.querySelector('form') as HTMLFormElement
|
|
500
|
+
const el = dr(host)
|
|
501
|
+
el.start = '2026-06-10T09:30'
|
|
502
|
+
el.end = '2026-06-20T18:00'
|
|
503
|
+
await el.updateComplete
|
|
504
|
+
const fd = new FormData(form)
|
|
505
|
+
expect(fd.get('dtw.start')).toBe('2026-06-10T09:30')
|
|
506
|
+
expect(fd.get('dtw.end')).toBe('2026-06-20T18:00')
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
// Default presets are rebuilt with datetime format when type changes.
|
|
510
|
+
it('default presets use YYYY-MM-DDTHH:mm format when type="datetime-local"', async () => {
|
|
511
|
+
const host = await mount('<schmancy-date-range name="dtw"></schmancy-date-range>')
|
|
512
|
+
const el = dr(host)
|
|
513
|
+
// Initially type=date; presets are YYYY-MM-DD.
|
|
514
|
+
expect(el.presets[0].start).toMatch(/^\d{4}-\d{2}-\d{2}$/)
|
|
515
|
+
|
|
516
|
+
// Switch to datetime-local; presets should rebuild.
|
|
517
|
+
el.type = 'datetime-local'
|
|
518
|
+
await el.updateComplete
|
|
519
|
+
|
|
520
|
+
expect(el.presets[0].start).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/)
|
|
521
|
+
expect(el.presets[0].end).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/)
|
|
522
|
+
})
|
|
523
|
+
|
|
524
|
+
// usingDefaultPresets race: setting type + presets in the same willUpdate cycle
|
|
525
|
+
// must leave the consumer's presets intact (not overwritten by rebuilt defaults).
|
|
526
|
+
it('consumer presets survive when type and presets are set together', async () => {
|
|
527
|
+
const host = await mount('<schmancy-date-range name="dtw"></schmancy-date-range>')
|
|
528
|
+
const el = dr(host)
|
|
529
|
+
await el.updateComplete
|
|
530
|
+
|
|
531
|
+
const customPresets = [
|
|
532
|
+
{ id: 'q1', label: 'Q1 2026', start: '2026-01-01', end: '2026-03-31' },
|
|
533
|
+
{ id: 'q2', label: 'Q2 2026', start: '2026-04-01', end: '2026-06-30' },
|
|
534
|
+
]
|
|
535
|
+
|
|
536
|
+
// Set both type and presets in the same microtask so they arrive in one willUpdate.
|
|
537
|
+
el.type = 'datetime-local'
|
|
538
|
+
el.presets = customPresets
|
|
539
|
+
await el.updateComplete
|
|
540
|
+
|
|
541
|
+
// Consumer's presets must survive — not replaced by datetime-formatted defaults.
|
|
542
|
+
expect(el.presets).toHaveLength(2)
|
|
543
|
+
expect(el.presets[0].id).toBe('q1')
|
|
544
|
+
expect(el.presets[0].start).toBe('2026-01-01')
|
|
545
|
+
expect(el.presets[1].id).toBe('q2')
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
// Calendar pick in datetime mode — no double T insertion if already includes T.
|
|
549
|
+
it('dialog passes through already-formatted datetime values unchanged', async () => {
|
|
550
|
+
const host = await mount('<schmancy-date-range name="dtw" type="datetime-local"></schmancy-date-range>')
|
|
551
|
+
const el = dr(host)
|
|
552
|
+
el.start = '2026-06-10T00:00'
|
|
553
|
+
el.end = '2026-06-20T23:59'
|
|
554
|
+
await el.updateComplete
|
|
555
|
+
|
|
556
|
+
const btn = el.shadowRoot!.querySelector('schmancy-button') as HTMLElement
|
|
557
|
+
document.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true, composed: true, clientX: 10, clientY: 10 }))
|
|
558
|
+
btn.click()
|
|
559
|
+
await el.updateComplete
|
|
560
|
+
await nextUpdate()
|
|
561
|
+
|
|
562
|
+
const dialog = await vi.waitFor(
|
|
563
|
+
() => {
|
|
564
|
+
for (const o of document.querySelectorAll('schmancy-overlay')) {
|
|
565
|
+
const d = o.shadowRoot?.querySelector('schmancy-date-range-dialog')
|
|
566
|
+
if (d) return d
|
|
567
|
+
}
|
|
568
|
+
throw new Error('dialog not mounted yet')
|
|
569
|
+
},
|
|
570
|
+
{ timeout: 2000 },
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
const calendar = dialog.shadowRoot?.querySelector('schmancy-calendar')
|
|
574
|
+
expect(calendar, 'schmancy-calendar must be in the dialog shadow root').not.toBeNull()
|
|
575
|
+
|
|
576
|
+
const changeReceived: CustomEvent[] = []
|
|
577
|
+
el.addEventListener('change', (e) => changeReceived.push(e as CustomEvent))
|
|
578
|
+
|
|
579
|
+
// Dispatch calendar change with a value that already contains T — must NOT
|
|
580
|
+
// become 2026-06-10T00:00T00:00. The dialog's handleCalendarChange guards with
|
|
581
|
+
// `!start.includes('T')` so already-formatted values pass through unchanged.
|
|
582
|
+
calendar!.dispatchEvent(
|
|
583
|
+
new CustomEvent('change', {
|
|
584
|
+
detail: { value: null, start: '2026-06-10T00:00', end: '2026-06-20T23:59' },
|
|
585
|
+
bubbles: true,
|
|
586
|
+
composed: true,
|
|
587
|
+
}),
|
|
588
|
+
)
|
|
589
|
+
await el.updateComplete
|
|
590
|
+
|
|
591
|
+
expect(changeReceived.length).toBeGreaterThan(0)
|
|
592
|
+
const detail = changeReceived[changeReceived.length - 1].detail as {
|
|
593
|
+
start: string | null
|
|
594
|
+
end: string | null
|
|
595
|
+
}
|
|
596
|
+
expect(detail.start).toBe('2026-06-10T00:00')
|
|
597
|
+
expect(detail.end).toBe('2026-06-20T23:59')
|
|
598
|
+
})
|
|
599
|
+
})
|
|
383
600
|
})
|
|
@@ -28,55 +28,56 @@ dayjs.extend(quarterOfYear)
|
|
|
28
28
|
// Default built-in presets
|
|
29
29
|
// ---------------------------------------------------------------------------
|
|
30
30
|
|
|
31
|
-
function buildDefaultPresets(): DateRangeDialogPreset[] {
|
|
31
|
+
function buildDefaultPresets(type: 'date' | 'datetime-local' = 'date'): DateRangeDialogPreset[] {
|
|
32
|
+
const fmt = type === 'datetime-local' ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'
|
|
32
33
|
return [
|
|
33
34
|
{
|
|
34
35
|
id: 'today',
|
|
35
36
|
label: 'Today',
|
|
36
|
-
start: dayjs().startOf('day').format(
|
|
37
|
-
end: dayjs().endOf('day').format(
|
|
37
|
+
start: dayjs().startOf('day').format(fmt),
|
|
38
|
+
end: dayjs().endOf('day').format(fmt),
|
|
38
39
|
},
|
|
39
40
|
{
|
|
40
41
|
id: 'yesterday',
|
|
41
42
|
label: 'Yesterday',
|
|
42
|
-
start: dayjs().subtract(1, 'day').startOf('day').format(
|
|
43
|
-
end: dayjs().subtract(1, 'day').endOf('day').format(
|
|
43
|
+
start: dayjs().subtract(1, 'day').startOf('day').format(fmt),
|
|
44
|
+
end: dayjs().subtract(1, 'day').endOf('day').format(fmt),
|
|
44
45
|
},
|
|
45
46
|
{
|
|
46
47
|
id: 'last7',
|
|
47
48
|
label: 'Last 7 days',
|
|
48
|
-
start: dayjs().subtract(6, 'day').startOf('day').format(
|
|
49
|
-
end: dayjs().endOf('day').format(
|
|
49
|
+
start: dayjs().subtract(6, 'day').startOf('day').format(fmt),
|
|
50
|
+
end: dayjs().endOf('day').format(fmt),
|
|
50
51
|
},
|
|
51
52
|
{
|
|
52
53
|
id: 'last30',
|
|
53
54
|
label: 'Last 30 days',
|
|
54
|
-
start: dayjs().subtract(29, 'day').startOf('day').format(
|
|
55
|
-
end: dayjs().endOf('day').format(
|
|
55
|
+
start: dayjs().subtract(29, 'day').startOf('day').format(fmt),
|
|
56
|
+
end: dayjs().endOf('day').format(fmt),
|
|
56
57
|
},
|
|
57
58
|
{
|
|
58
59
|
id: 'thisWeek',
|
|
59
60
|
label: 'This week',
|
|
60
|
-
start: dayjs().startOf('week').format(
|
|
61
|
-
end: dayjs().endOf('week').format(
|
|
61
|
+
start: dayjs().startOf('week').format(fmt),
|
|
62
|
+
end: dayjs().endOf('week').format(fmt),
|
|
62
63
|
},
|
|
63
64
|
{
|
|
64
65
|
id: 'thisMonth',
|
|
65
66
|
label: 'This month',
|
|
66
|
-
start: dayjs().startOf('month').format(
|
|
67
|
-
end: dayjs().endOf('month').format(
|
|
67
|
+
start: dayjs().startOf('month').format(fmt),
|
|
68
|
+
end: dayjs().endOf('month').format(fmt),
|
|
68
69
|
},
|
|
69
70
|
{
|
|
70
71
|
id: 'lastMonth',
|
|
71
72
|
label: 'Last month',
|
|
72
|
-
start: dayjs().subtract(1, 'month').startOf('month').format(
|
|
73
|
-
end: dayjs().subtract(1, 'month').endOf('month').format(
|
|
73
|
+
start: dayjs().subtract(1, 'month').startOf('month').format(fmt),
|
|
74
|
+
end: dayjs().subtract(1, 'month').endOf('month').format(fmt),
|
|
74
75
|
},
|
|
75
76
|
{
|
|
76
77
|
id: 'thisYear',
|
|
77
78
|
label: 'This year',
|
|
78
|
-
start: dayjs().startOf('year').format(
|
|
79
|
-
end: dayjs().endOf('year').format(
|
|
79
|
+
start: dayjs().startOf('year').format(fmt),
|
|
80
|
+
end: dayjs().endOf('year').format(fmt),
|
|
80
81
|
},
|
|
81
82
|
]
|
|
82
83
|
}
|
|
@@ -121,7 +122,13 @@ export class SchmancyDateRange extends SchmancyFormField() {
|
|
|
121
122
|
@property() start: string | null = null
|
|
122
123
|
@property() end: string | null = null
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
/** Reference to the last array produced by buildDefaultPresets; used to detect consumer ownership. */
|
|
126
|
+
private defaultPresetsRef: DateRangeDialogPreset[] = buildDefaultPresets()
|
|
127
|
+
|
|
128
|
+
@property({ type: Array }) presets: DateRangeDialogPreset[] = this.defaultPresetsRef
|
|
129
|
+
|
|
130
|
+
/** True while the component holds the built-in default preset list (not user-supplied). */
|
|
131
|
+
private usingDefaultPresets = true
|
|
125
132
|
|
|
126
133
|
/** Selected preset id; null = custom range. Reflects to attribute. */
|
|
127
134
|
@property({ reflect: true }) preset: string | null = null
|
|
@@ -230,6 +237,23 @@ export class SchmancyDateRange extends SchmancyFormField() {
|
|
|
230
237
|
|
|
231
238
|
override willUpdate(changed: PropertyValues): void {
|
|
232
239
|
super.willUpdate(changed)
|
|
240
|
+
// Consumer ownership detection must run before the type-change rebuild so that
|
|
241
|
+
// when both `type` and `presets` arrive in the same willUpdate cycle (e.g. simultaneous
|
|
242
|
+
// attribute/property initialisation), the consumer's presets are not overwritten.
|
|
243
|
+
//
|
|
244
|
+
// A `presets` change signals consumer ownership when the incoming value is not the
|
|
245
|
+
// array reference produced by the internal default-builder (defaultPresetsRef).
|
|
246
|
+
// Since buildDefaultPresets always allocates a new array, defaultPresetsRef is the
|
|
247
|
+
// only reference that could match; any other reference came from the consumer.
|
|
248
|
+
if (changed.has('presets') && this.presets !== this.defaultPresetsRef) {
|
|
249
|
+
this.usingDefaultPresets = false
|
|
250
|
+
}
|
|
251
|
+
// Rebuild built-in presets when type changes, but only while the consumer has never
|
|
252
|
+
// supplied their own presets array.
|
|
253
|
+
if (changed.has('type') && this.usingDefaultPresets) {
|
|
254
|
+
this.defaultPresetsRef = buildDefaultPresets(this.type)
|
|
255
|
+
this.presets = this.defaultPresetsRef
|
|
256
|
+
}
|
|
233
257
|
if (changed.has('start') || changed.has('end') || changed.has('name') || changed.has('disabled')) {
|
|
234
258
|
if (this.name && !this.disabled) {
|
|
235
259
|
const fd = new FormData()
|
|
@@ -26,7 +26,11 @@ export declare class SchmancyDateRange extends SchmancyDateRange_base {
|
|
|
26
26
|
type: 'date' | 'datetime-local';
|
|
27
27
|
start: string | null;
|
|
28
28
|
end: string | null;
|
|
29
|
+
/** Reference to the last array produced by buildDefaultPresets; used to detect consumer ownership. */
|
|
30
|
+
private defaultPresetsRef;
|
|
29
31
|
presets: DateRangeDialogPreset[];
|
|
32
|
+
/** True while the component holds the built-in default preset list (not user-supplied). */
|
|
33
|
+
private usingDefaultPresets;
|
|
30
34
|
/** Selected preset id; null = custom range. Reflects to attribute. */
|
|
31
35
|
preset: string | null;
|
|
32
36
|
min?: string;
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
const e=require(`./chunk-CncqDLb2.cjs`),t=require(`./SchmancyElement-CeKrBW2j.cjs`),n=require(`./mixins-Cjn20BQH.cjs`),r=require(`./overlay.service-MMTiW2T3.cjs`),i=require(`./dayjs.min-CvRZTfam.cjs`);let a=require(`rxjs`),o=require(`lit/decorators.js`),s=require(`lit`),c=require(`lit/directives/if-defined.js`),l=require(`lit/directives/repeat.js`),u=require(`lit/directives/when.js`);var d=e.t((e,t)=>{var n=e,r=function(){"use strict";var e=`month`,t=`quarter`;return function(n,r){var i=r.prototype;i.quarter=function(e){return this.$utils().u(e)?Math.ceil((this.month()+1)/3):this.month(this.month()%3+3*(e-1))};var a=i.add;i.add=function(n,r){return n=Number(n),this.$utils().p(r)===t?this.add(3*n,e):a.bind(this)(n,r)};var o=i.startOf;i.startOf=function(n,r){var i=this.$utils(),a=!!i.u(r)||r;if(i.p(n)===t){var s=this.quarter()-1;return a?this.month(3*s).startOf(e).startOf(`day`):this.month(3*s+2).endOf(e).endOf(`day`)}return o.bind(this)(n,r)}}};typeof e==`object`&&t!==void 0?t.exports=r():typeof define==`function`&&define.amd?define(r):(n=typeof globalThis<`u`?globalThis:n||self).dayjs_plugin_quarterOfYear=r()}),f=e.r(d(),1),p=e.r(i.t(),1),m=class extends t.t{constructor(...e){super(...e),this.type=`date`,this.start=null,this.end=null,this.preset=null,this.presets=[]}static{this.styles=[s.css`
|
|
2
|
-
:host {
|
|
3
|
-
display: block;
|
|
4
|
-
}
|
|
5
|
-
`]}handleCalendarInput(e){e.stopPropagation(),this.dispatchEvent(new CustomEvent(`calendar-input`,{detail:{start:e.detail.start,end:e.detail.end},bubbles:!0,composed:!0}))}handleCalendarChange(e){e.stopPropagation(),this.dispatchEvent(new CustomEvent(`calendar-change`,{detail:{start:e.detail.start,end:e.detail.end},bubbles:!0,composed:!0}))}handlePresetClick(e){this.dispatchEvent(new CustomEvent(`preset-select`,{detail:e,bubbles:!0,composed:!0}))}handleFromChange(e){let t=e.target.value;if(!t)return;let n=t,r=this.end&&(0,p.default)(this.end).isBefore((0,p.default)(n))?n:this.end??null;this.dispatchEvent(new CustomEvent(`calendar-change`,{detail:{start:n,end:r},bubbles:!0,composed:!0}))}handleToChange(e){let t=e.target.value;t&&this.dispatchEvent(new CustomEvent(`calendar-change`,{detail:{start:this.start??null,end:t},bubbles:!0,composed:!0}))}render(){return s.html`
|
|
6
|
-
<div class="flex flex-col w-full" style="min-width:280px; max-width:360px">
|
|
7
|
-
<!-- Sticky chip quick-rail -->
|
|
8
|
-
<div
|
|
9
|
-
part="presets"
|
|
10
|
-
class="sticky top-0 z-20 bg-surface-default flex flex-wrap gap-2 p-3 border-b border-outline-variant/40"
|
|
11
|
-
>
|
|
12
|
-
${(0,u.when)(this.presets.length>0,()=>s.html`
|
|
13
|
-
${(0,l.repeat)(this.presets,e=>e.id,e=>s.html`
|
|
14
|
-
<schmancy-filter-chip
|
|
15
|
-
part="preset ${this.preset===e.id?`preset-selected`:``}"
|
|
16
|
-
.value=${e.id}
|
|
17
|
-
.selected=${this.preset===e.id}
|
|
18
|
-
title="${e.start} — ${e.end}"
|
|
19
|
-
@click=${()=>this.handlePresetClick(e)}
|
|
20
|
-
>
|
|
21
|
-
${e.label}
|
|
22
|
-
</schmancy-filter-chip>
|
|
23
|
-
`)}
|
|
24
|
-
`,()=>s.nothing)}
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<!-- Calendar (continuous-scroll range picker) -->
|
|
28
|
-
<div part="calendar" class="overflow-y-auto" style="max-height:320px">
|
|
29
|
-
<schmancy-calendar
|
|
30
|
-
mode="range"
|
|
31
|
-
.type=${this.type}
|
|
32
|
-
.start=${this.start}
|
|
33
|
-
.end=${this.end}
|
|
34
|
-
min=${(0,c.ifDefined)(this.min)}
|
|
35
|
-
max=${(0,c.ifDefined)(this.max)}
|
|
36
|
-
@input=${e=>this.handleCalendarInput(e)}
|
|
37
|
-
@change=${e=>this.handleCalendarChange(e)}
|
|
38
|
-
></schmancy-calendar>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<!-- Secondary typed-entry path -->
|
|
42
|
-
<div class="flex gap-2 p-3 border-t border-outline-variant/40 flex-wrap">
|
|
43
|
-
<div class="flex-1 min-w-30">
|
|
44
|
-
<schmancy-input
|
|
45
|
-
.type=${this.type}
|
|
46
|
-
.label=${`From`}
|
|
47
|
-
.value=${this.start??``}
|
|
48
|
-
min=${(0,c.ifDefined)(this.min)}
|
|
49
|
-
max=${(0,c.ifDefined)(this.max)}
|
|
50
|
-
@change=${this.handleFromChange}
|
|
51
|
-
></schmancy-input>
|
|
52
|
-
</div>
|
|
53
|
-
<div class="flex-1 min-w-30">
|
|
54
|
-
<schmancy-input
|
|
55
|
-
.type=${this.type}
|
|
56
|
-
.label=${`To`}
|
|
57
|
-
.value=${this.end??``}
|
|
58
|
-
min=${(0,c.ifDefined)(this.start??this.min)}
|
|
59
|
-
max=${(0,c.ifDefined)(this.max)}
|
|
60
|
-
@change=${this.handleToChange}
|
|
61
|
-
></schmancy-input>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
`}};t.u([(0,o.property)()],m.prototype,`type`,void 0),t.u([(0,o.property)()],m.prototype,`start`,void 0),t.u([(0,o.property)()],m.prototype,`end`,void 0),t.u([(0,o.property)()],m.prototype,`min`,void 0),t.u([(0,o.property)()],m.prototype,`max`,void 0),t.u([(0,o.property)()],m.prototype,`preset`,void 0),t.u([(0,o.property)({type:Array})],m.prototype,`presets`,void 0),m=t.u([(0,o.customElement)(`schmancy-date-range-dialog`)],m),p.default.extend(f.default);var h=class extends n.o(){constructor(...e){super(...e),this.type=`date`,this.start=null,this.end=null,this.presets=[{id:`today`,label:`Today`,start:(0,p.default)().startOf(`day`).format(`YYYY-MM-DD`),end:(0,p.default)().endOf(`day`).format(`YYYY-MM-DD`)},{id:`yesterday`,label:`Yesterday`,start:(0,p.default)().subtract(1,`day`).startOf(`day`).format(`YYYY-MM-DD`),end:(0,p.default)().subtract(1,`day`).endOf(`day`).format(`YYYY-MM-DD`)},{id:`last7`,label:`Last 7 days`,start:(0,p.default)().subtract(6,`day`).startOf(`day`).format(`YYYY-MM-DD`),end:(0,p.default)().endOf(`day`).format(`YYYY-MM-DD`)},{id:`last30`,label:`Last 30 days`,start:(0,p.default)().subtract(29,`day`).startOf(`day`).format(`YYYY-MM-DD`),end:(0,p.default)().endOf(`day`).format(`YYYY-MM-DD`)},{id:`thisWeek`,label:`This week`,start:(0,p.default)().startOf(`week`).format(`YYYY-MM-DD`),end:(0,p.default)().endOf(`week`).format(`YYYY-MM-DD`)},{id:`thisMonth`,label:`This month`,start:(0,p.default)().startOf(`month`).format(`YYYY-MM-DD`),end:(0,p.default)().endOf(`month`).format(`YYYY-MM-DD`)},{id:`lastMonth`,label:`Last month`,start:(0,p.default)().subtract(1,`month`).startOf(`month`).format(`YYYY-MM-DD`),end:(0,p.default)().subtract(1,`month`).endOf(`month`).format(`YYYY-MM-DD`)},{id:`thisYear`,label:`This year`,start:(0,p.default)().startOf(`year`).format(`YYYY-MM-DD`),end:(0,p.default)().endOf(`year`).format(`YYYY-MM-DD`)}],this.preset=null,this.placeholder=`Select date range`,this.clearable=!0,this.collapse=!1,this.open$=new a.Subject,this.close$=new a.Subject,this.announce$=new a.Subject,this.isOpen=!1,this.announceMessage=``,this.startDefault=null,this.endDefault=null,this.presetDefault=null}disconnectedCallback(){super.disconnectedCallback(),this.isOpen=!1}connectedCallback(){super.connectedCallback(),(0,a.merge)(this.open$.pipe((0,a.tap)(()=>{this.isOpen=!0}),(0,a.exhaustMap)(e=>r.o(()=>s.html`
|
|
66
|
-
<schmancy-date-range-dialog
|
|
67
|
-
.type=${this.type}
|
|
68
|
-
.start=${this.start}
|
|
69
|
-
.end=${this.end}
|
|
70
|
-
.min=${this.min}
|
|
71
|
-
.max=${this.max}
|
|
72
|
-
.preset=${this.preset}
|
|
73
|
-
.presets=${this.presets}
|
|
74
|
-
@calendar-input=${e=>{e.stopPropagation(),this.dispatchEvent(new CustomEvent(`input`,{detail:{start:e.detail.start,end:e.detail.end},bubbles:!0,composed:!0}))}}
|
|
75
|
-
@calendar-change=${e=>{e.stopPropagation(),this.commitRange(e.detail.start,e.detail.end,null),e.detail.start&&e.detail.end&&e.target?.dispatchEvent(new CustomEvent(`close`,{bubbles:!0,composed:!0}))}}
|
|
76
|
-
@preset-select=${e=>{e.stopPropagation(),this.commitRange(e.detail.start,e.detail.end,e.detail.id),e.target?.dispatchEvent(new CustomEvent(`close`,{bubbles:!0,composed:!0}))}}
|
|
77
|
-
></schmancy-date-range-dialog>
|
|
78
|
-
`,{anchor:e}).pipe((0,a.takeUntil)(this.close$),(0,a.finalize)(()=>{this.isOpen=!1})))),this.announce$.pipe((0,a.switchMap)(e=>(0,a.concat)((0,a.of)(e),(0,a.timer)(1500).pipe((0,a.map)(()=>``)))),(0,a.tap)(e=>{this.announceMessage=e})),(0,a.fromEvent)(document,`keydown`).pipe((0,a.tap)(e=>this.handleKeyDown(e)))).pipe((0,a.takeUntil)(this.disconnecting)).subscribe()}willUpdate(e){if(super.willUpdate(e),e.has(`start`)||e.has(`end`)||e.has(`name`)||e.has(`disabled`)){if(this.name&&!this.disabled){let e=new FormData;this.start&&e.append(`${this.name}.start`,this.start),this.end&&e.append(`${this.name}.end`,this.end),this.internals?.setFormValue(e.has(`${this.name}.start`)||e.has(`${this.name}.end`)?e:null)}else this.internals?.setFormValue(null);this.checkValidity()}e.has(`required`)&&this.checkValidity()}checkValidity(){if(this.disabled)return this.internals?.setValidity({}),!0;if(this.required&&(!this.start||!this.end)){let e=`Please select a complete date range.`;return this.internals?.setValidity({valueMissing:!0},e),this.shouldShowError()&&(this.error=!0,this.validationMessage=e),!1}if(this.start&&this.end&&this.end<this.start){let e=`End date must be on or after start date.`;return this.internals?.setValidity({customError:!0},e),this.shouldShowError()&&(this.error=!0,this.validationMessage=e),!1}return this.internals?.setValidity({}),this.shouldShowError()&&(this.error=!1,this.validationMessage=``),!0}toFormEntries(){if(!this.name||this.disabled)return[];let e=[];return this.start&&e.push([`${this.name}.start`,this.start]),this.end&&e.push([`${this.name}.end`,this.end]),e}get dirty(){return this.start!==this.startDefault||this.end!==this.endDefault}firstUpdated(e){super.firstUpdated(e),this.startDefault=this.start,this.endDefault=this.end,this.presetDefault=this.preset}resetForm(){this.start=this.startDefault,this.end=this.endDefault,this.preset=this.presetDefault,this.error=!1,this.validationMessage=``,this.touched=!1,this.submitted=!1,this.internals?.setValidity({})}commitRange(e,t,n){this.start=e,this.end=t,this.preset=n,this.announce$.next(`Date range: ${this.displayLabel()}`),this.emitChange({start:e,end:t,preset:n})}displayLabel(){if(this.preset){let e=this.presets.find(e=>e.id===this.preset);if(e)return e.label}return function(e,t,n,r){if(!e||!t)return r;let i=(0,p.default)(e),a=(0,p.default)(t);if(!i.isValid()||!a.isValid())return r;let o=n===`datetime-local`?i.format(` h:mm A`):``,s=n===`datetime-local`?a.format(` h:mm A`):``;return i.isSame(a,`day`)?`${i.format(`ddd, MMM D, YYYY`)}${o}`:i.isSame(a,`month`)&&i.isSame(a,`year`)?`${i.format(`ddd MMM D`)} - ${a.format(`ddd D, YYYY`)}${s}`:i.isSame(a,`year`)?`${i.format(`ddd MMM D`)} - ${a.format(`ddd MMM D, YYYY`)}${s}`:`${i.format(`ddd MMM D, YYYY`)}${o} - ${a.format(`ddd MMM D, YYYY`)}${s}`}(this.start??``,this.end??``,this.type,this.placeholder)}toggleDropdown(e){e.stopPropagation(),this.disabled||this.step!==void 0||(this.isOpen?this.close$.next():this.open$.next(e))}shiftDateRange(e,t){if(t.stopPropagation(),!this.start||!this.end)return;let n=(0,p.default)(this.start),r=(0,p.default)(this.end);if(!n.isValid()||!r.isValid())return;let i=this.type===`date`?`YYYY-MM-DD`:`YYYY-MM-DDTHH:mm`,a=e>0?1:-1,o=r.diff(n,`day`)+1,s,c;if(this.step!==void 0)typeof this.step==`number`?(s=a*this.step,c=`day`):this.step===`day`?(s=a*o,c=`day`):(s=a,c=this.step);else{let e=function(e,t){return{isFullMonth:e.date()===1&&t.isSame(e.endOf(`month`),`day`),isFullQuarter:e.isSame(e.startOf(`quarter`),`day`)&&t.isSame(t.endOf(`quarter`),`day`),isFullYear:e.isSame(e.startOf(`year`),`day`)&&t.isSame(t.endOf(`year`),`day`),isFullWeek:e.day()===0&&t.day()===6&&t.diff(e,`days`)===6}}(n,r);e.isFullYear?(s=a,c=`year`):e.isFullMonth?(s=a,c=`month`):e.isFullWeek?(s=a,c=`week`):(s=a*o,c=`day`)}let l=n.add(s,c),u=r.add(s,c);this.min&&l.isBefore((0,p.default)(this.min))||this.max&&u.isAfter((0,p.default)(this.max))||this.commitRange(l.format(i),u.format(i),null)}handleKeyDown(e){if(!this.start||!this.end||this.disabled)return;let t=e.target;if(t===this||this.contains(t))switch(e.key){case`PageUp`:this.shiftDateRange(-1,e),e.preventDefault();break;case`PageDown`:this.shiftDateRange(1,e),e.preventDefault();break;case`Home`:if(e.ctrlKey){let t=this.type===`date`?`YYYY-MM-DD`:`YYYY-MM-DDTHH:mm`,n=(0,p.default)(this.start),r=(0,p.default)(this.end),i=n.startOf(`month`);this.commitRange(i.format(t),i.add(r.diff(n,`day`),`day`).format(t),null),e.preventDefault()}break;case`End`:if(e.ctrlKey){let t=this.type===`date`?`YYYY-MM-DD`:`YYYY-MM-DDTHH:mm`,n=(0,p.default)(this.start),r=(0,p.default)(this.end),i=r.endOf(`month`);this.commitRange(i.subtract(r.diff(n,`day`),`day`).format(t),i.format(t),null),e.preventDefault()}}}canNavigateBackward(){return!this.start||!this.min||(0,p.default)(this.start).isAfter((0,p.default)(this.min))}canNavigateForward(){return!this.end||!this.max||(0,p.default)(this.end).isBefore((0,p.default)(this.max))}render(){let e=this.error&&!!this.validationMessage,t=e?` rounded outline outline-2 outline-error-default`:``,n=this.displayLabel();return s.html`
|
|
79
|
-
<div class="relative ${this.disabled?`opacity-60 pointer-events-none`:``}">
|
|
80
|
-
<!-- Screen reader announcements -->
|
|
81
|
-
<div class="sr-only" role="status" aria-live="polite" aria-atomic="true">${this.announceMessage}</div>
|
|
82
|
-
|
|
83
|
-
<!-- Collapsed: icon-only on narrow viewports when collapse=true -->
|
|
84
|
-
<schmancy-icon-button
|
|
85
|
-
class="${this.collapse?`lg:hidden`:`hidden`}${t}"
|
|
86
|
-
variant="outlined"
|
|
87
|
-
type="button"
|
|
88
|
-
aria-invalid=${e?`true`:`false`}
|
|
89
|
-
aria-label="Select date range. Current: ${n}"
|
|
90
|
-
@click=${e=>this.toggleDropdown(e)}
|
|
91
|
-
?disabled=${this.disabled}
|
|
92
|
-
>
|
|
93
|
-
date_range
|
|
94
|
-
</schmancy-icon-button>
|
|
95
|
-
|
|
96
|
-
<!-- Full trigger row: [← | range label | →] -->
|
|
97
|
-
<section
|
|
98
|
-
@click=${e=>e.stopPropagation()}
|
|
99
|
-
aria-invalid=${e?`true`:`false`}
|
|
100
|
-
class="${this.collapse?`hidden lg:flex`:`flex`}${t}"
|
|
101
|
-
>
|
|
102
|
-
<schmancy-icon-button
|
|
103
|
-
type="button"
|
|
104
|
-
aria-label="Previous ${this.preset??`date range`}"
|
|
105
|
-
@click=${e=>this.shiftDateRange(-1,e)}
|
|
106
|
-
?disabled=${this.disabled||!this.start||!this.end||!this.canNavigateBackward()}
|
|
107
|
-
>
|
|
108
|
-
arrow_left
|
|
109
|
-
</schmancy-icon-button>
|
|
110
|
-
|
|
111
|
-
<schmancy-button
|
|
112
|
-
class="w-max"
|
|
113
|
-
variant="outlined"
|
|
114
|
-
type="button"
|
|
115
|
-
aria-haspopup="dialog"
|
|
116
|
-
aria-expanded=${this.isOpen}
|
|
117
|
-
aria-label="Select date range. Current: ${n}"
|
|
118
|
-
aria-readonly="${this.step!==void 0}"
|
|
119
|
-
@click=${e=>this.toggleDropdown(e)}
|
|
120
|
-
?disabled=${this.disabled}
|
|
121
|
-
style="${this.step===void 0?``:`cursor:default;`}"
|
|
122
|
-
>
|
|
123
|
-
${n}
|
|
124
|
-
</schmancy-button>
|
|
125
|
-
|
|
126
|
-
<schmancy-icon-button
|
|
127
|
-
type="button"
|
|
128
|
-
aria-label="Next ${this.preset??`date range`}"
|
|
129
|
-
@click=${e=>this.shiftDateRange(1,e)}
|
|
130
|
-
?disabled=${this.disabled||!this.start||!this.end||!this.canNavigateForward()}
|
|
131
|
-
>
|
|
132
|
-
arrow_right
|
|
133
|
-
</schmancy-icon-button>
|
|
134
|
-
</section>
|
|
135
|
-
|
|
136
|
-
${e?s.html`<div role="alert" class="text-error-default text-sm mt-1">${this.validationMessage}</div>`:s.nothing}
|
|
137
|
-
</div>
|
|
138
|
-
`}};t.u([(0,o.property)()],h.prototype,`type`,void 0),t.u([(0,o.property)()],h.prototype,`start`,void 0),t.u([(0,o.property)()],h.prototype,`end`,void 0),t.u([(0,o.property)({type:Array})],h.prototype,`presets`,void 0),t.u([(0,o.property)({reflect:!0})],h.prototype,`preset`,void 0),t.u([(0,o.property)()],h.prototype,`min`,void 0),t.u([(0,o.property)()],h.prototype,`max`,void 0),t.u([(0,o.property)()],h.prototype,`placeholder`,void 0),t.u([(0,o.property)({type:Boolean})],h.prototype,`clearable`,void 0),t.u([(0,o.property)()],h.prototype,`step`,void 0),t.u([(0,o.property)({type:Boolean})],h.prototype,`collapse`,void 0),t.u([(0,o.state)()],h.prototype,`isOpen`,void 0),t.u([(0,o.state)()],h.prototype,`announceMessage`,void 0),h=t.u([(0,o.customElement)(`schmancy-date-range`)],h),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return h}});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"date-range-CVAWMdar.cjs","names":[],"sources":["../node_modules/dayjs/plugin/quarterOfYear.js","../src/form/fields/date-range/date-range-helpers.ts","../src/form/fields/date-range/date-range-dialog.ts","../src/form/fields/date-range/date-range.ts"],"sourcesContent":["!function(t,n){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=n():\"function\"==typeof define&&define.amd?define(n):(t=\"undefined\"!=typeof globalThis?globalThis:t||self).dayjs_plugin_quarterOfYear=n()}(this,(function(){\"use strict\";var t=\"month\",n=\"quarter\";return function(e,i){var r=i.prototype;r.quarter=function(t){return this.$utils().u(t)?Math.ceil((this.month()+1)/3):this.month(this.month()%3+3*(t-1))};var s=r.add;r.add=function(e,i){return e=Number(e),this.$utils().p(i)===n?this.add(3*e,t):s.bind(this)(e,i)};var u=r.startOf;r.startOf=function(e,i){var r=this.$utils(),s=!!r.u(i)||i;if(r.p(e)===n){var o=this.quarter()-1;return s?this.month(3*o).startOf(t).startOf(\"day\"):this.month(3*o+2).endOf(t).endOf(\"day\")}return u.bind(this)(e,i)}}}));","import dayjs from 'dayjs'\n\n/**\n * Format a date range into a human-readable string\n */\nexport function formatDateRange(\n\tfromValue: string,\n\ttoValue: string,\n\ttype: 'date' | 'datetime-local',\n\tplaceholder: string,\n): string {\n\tif (!fromValue || !toValue) {\n\t\treturn placeholder\n\t}\n\n\tconst fromDate = dayjs(fromValue)\n\tconst toDate = dayjs(toValue)\n\n\tif (!fromDate.isValid() || !toDate.isValid()) {\n\t\treturn placeholder\n\t}\n\n\t// Format times if needed (for datetime-local)\n\tconst fromTime = type === 'datetime-local' ? fromDate.format(' h:mm A') : ''\n\tconst toTime = type === 'datetime-local' ? toDate.format(' h:mm A') : ''\n\n\t// Check if same day\n\tif (fromDate.isSame(toDate, 'day')) {\n\t\treturn `${fromDate.format('ddd, MMM D, YYYY')}${fromTime}`\n\t}\n\n\t// Check if same month and year\n\tif (fromDate.isSame(toDate, 'month') && fromDate.isSame(toDate, 'year')) {\n\t\treturn `${fromDate.format('ddd MMM D')} - ${toDate.format('ddd D, YYYY')}${toTime}`\n\t}\n\n\t// Check if same year\n\tif (fromDate.isSame(toDate, 'year')) {\n\t\treturn `${fromDate.format('ddd MMM D')} - ${toDate.format('ddd MMM D, YYYY')}${toTime}`\n\t}\n\n\t// Different years\n\treturn `${fromDate.format('ddd MMM D, YYYY')}${fromTime} - ${toDate.format('ddd MMM D, YYYY')}${toTime}`\n}\n\n/**\n * Detect the type of date range (full month, full quarter, etc.)\n */\nexport interface DateRangeType {\n\tisFullMonth: boolean\n\tisFullQuarter: boolean\n\tisFullYear: boolean\n\tisFullWeek: boolean\n}\n\nexport function detectDateRangeType(fromDate: dayjs.Dayjs, toDate: dayjs.Dayjs): DateRangeType {\n\treturn {\n\t\tisFullMonth: fromDate.date() === 1 && toDate.isSame(fromDate.endOf('month'), 'day'),\n\t\tisFullQuarter: fromDate.isSame(fromDate.startOf('quarter'), 'day') && toDate.isSame(toDate.endOf('quarter'), 'day'),\n\t\tisFullYear: fromDate.isSame(fromDate.startOf('year'), 'day') && toDate.isSame(toDate.endOf('year'), 'day'),\n\t\tisFullWeek: fromDate.day() === 0 && toDate.day() === 6 && toDate.diff(fromDate, 'days') === 6,\n\t}\n}\n","import { SchmancyElement } from '@mixins/index'\nimport dayjs from 'dayjs'\nimport { css, html, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { when } from 'lit/directives/when.js'\nimport type { SchmancyCalendarChangeEvent, SchmancyCalendarInputEvent } from '../../../calendar/calendar'\n\nexport interface DateRangeDialogPreset {\n\tid: string\n\tlabel: string\n\tstart: string\n\tend: string\n}\n\n/**\n * Picker panel for `<schmancy-date-range>`.\n *\n * Layout: sticky chip quick-rail → continuous-scroll calendar → secondary typed path.\n * Emits composed events that `<schmancy-date-range>` bridges into its own\n * `input`/`change` events.\n *\n * @element schmancy-date-range-dialog\n * @fires calendar-input - Provisional sweep from the calendar { start, end }\n * @fires calendar-change - Committed endpoint from the calendar { start, end }\n * @fires preset-select - A chip was clicked { id, label, start, end }\n */\n@customElement('schmancy-date-range-dialog')\nexport class SchmancyDateRangeDialog extends SchmancyElement {\n\tstatic styles = [\n\t\tcss`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t}\n\t\t`,\n\t]\n\n\t@property() type: 'date' | 'datetime-local' = 'date'\n\t@property() start: string | null = null\n\t@property() end: string | null = null\n\t@property() min?: string\n\t@property() max?: string\n\t@property() preset: string | null = null\n\t@property({ type: Array }) presets: DateRangeDialogPreset[] = []\n\n\tprivate handleCalendarInput(e: SchmancyCalendarInputEvent) {\n\t\te.stopPropagation()\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('calendar-input', {\n\t\t\t\tdetail: { start: e.detail.start, end: e.detail.end },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate handleCalendarChange(e: SchmancyCalendarChangeEvent) {\n\t\te.stopPropagation()\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('calendar-change', {\n\t\t\t\tdetail: { start: e.detail.start, end: e.detail.end },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate handlePresetClick(p: DateRangeDialogPreset) {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('preset-select', {\n\t\t\t\tdetail: p,\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate handleFromChange(e: Event) {\n\t\tconst value = (e.target as HTMLInputElement).value\n\t\tif (!value) return\n\t\t// Swap if end is earlier than the new start\n\t\tconst newStart = value\n\t\tconst newEnd =\n\t\t\tthis.end && dayjs(this.end).isBefore(dayjs(newStart)) ? newStart : (this.end ?? null)\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('calendar-change', {\n\t\t\t\tdetail: { start: newStart, end: newEnd },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate handleToChange(e: Event) {\n\t\tconst value = (e.target as HTMLInputElement).value\n\t\tif (!value) return\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('calendar-change', {\n\t\t\t\tdetail: { start: this.start ?? null, end: value },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\trender() {\n\t\treturn html`\n\t\t\t<div class=\"flex flex-col w-full\" style=\"min-width:280px; max-width:360px\">\n\t\t\t\t<!-- Sticky chip quick-rail -->\n\t\t\t\t<div\n\t\t\t\t\tpart=\"presets\"\n\t\t\t\t\tclass=\"sticky top-0 z-20 bg-surface-default flex flex-wrap gap-2 p-3 border-b border-outline-variant/40\"\n\t\t\t\t>\n\t\t\t\t\t${when(\n\t\t\t\t\t\tthis.presets.length > 0,\n\t\t\t\t\t\t() => html`\n\t\t\t\t\t\t\t${repeat(\n\t\t\t\t\t\t\t\tthis.presets,\n\t\t\t\t\t\t\t\tp => p.id,\n\t\t\t\t\t\t\t\tp => html`\n\t\t\t\t\t\t\t\t\t<schmancy-filter-chip\n\t\t\t\t\t\t\t\t\t\tpart=\"preset ${this.preset === p.id ? 'preset-selected' : ''}\"\n\t\t\t\t\t\t\t\t\t\t.value=${p.id}\n\t\t\t\t\t\t\t\t\t\t.selected=${this.preset === p.id}\n\t\t\t\t\t\t\t\t\t\ttitle=\"${p.start} — ${p.end}\"\n\t\t\t\t\t\t\t\t\t\t@click=${() => this.handlePresetClick(p)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t${p.label}\n\t\t\t\t\t\t\t\t\t</schmancy-filter-chip>\n\t\t\t\t\t\t\t\t`,\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t`,\n\t\t\t\t\t\t() => nothing,\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Calendar (continuous-scroll range picker) -->\n\t\t\t\t<div part=\"calendar\" class=\"overflow-y-auto\" style=\"max-height:320px\">\n\t\t\t\t\t<schmancy-calendar\n\t\t\t\t\t\tmode=\"range\"\n\t\t\t\t\t\t.type=${this.type}\n\t\t\t\t\t\t.start=${this.start}\n\t\t\t\t\t\t.end=${this.end}\n\t\t\t\t\t\tmin=${ifDefined(this.min)}\n\t\t\t\t\t\tmax=${ifDefined(this.max)}\n\t\t\t\t\t\t@input=${(e: SchmancyCalendarInputEvent) => this.handleCalendarInput(e)}\n\t\t\t\t\t\t@change=${(e: SchmancyCalendarChangeEvent) => this.handleCalendarChange(e)}\n\t\t\t\t\t></schmancy-calendar>\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Secondary typed-entry path -->\n\t\t\t\t<div class=\"flex gap-2 p-3 border-t border-outline-variant/40 flex-wrap\">\n\t\t\t\t\t<div class=\"flex-1 min-w-30\">\n\t\t\t\t\t\t<schmancy-input\n\t\t\t\t\t\t\t.type=${this.type}\n\t\t\t\t\t\t\t.label=${'From'}\n\t\t\t\t\t\t\t.value=${this.start ?? ''}\n\t\t\t\t\t\t\tmin=${ifDefined(this.min)}\n\t\t\t\t\t\t\tmax=${ifDefined(this.max)}\n\t\t\t\t\t\t\t@change=${this.handleFromChange}\n\t\t\t\t\t\t></schmancy-input>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"flex-1 min-w-30\">\n\t\t\t\t\t\t<schmancy-input\n\t\t\t\t\t\t\t.type=${this.type}\n\t\t\t\t\t\t\t.label=${'To'}\n\t\t\t\t\t\t\t.value=${this.end ?? ''}\n\t\t\t\t\t\t\tmin=${ifDefined(this.start ?? this.min)}\n\t\t\t\t\t\t\tmax=${ifDefined(this.max)}\n\t\t\t\t\t\t\t@change=${this.handleToChange}\n\t\t\t\t\t\t></schmancy-input>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-date-range-dialog': SchmancyDateRangeDialog\n\t}\n}\n","import dayjs from 'dayjs'\nimport quarterOfYear from 'dayjs/plugin/quarterOfYear'\nimport { html, nothing, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport {\n\tconcat,\n\texhaustMap,\n\tfinalize,\n\tfromEvent,\n\tmap,\n\tmerge,\n\tof,\n\tSubject,\n\tswitchMap,\n\ttakeUntil,\n\ttap,\n\ttimer,\n} from 'rxjs'\nimport { SchmancyFormField } from '@mixins/index'\nimport { show } from '../../../overlay/overlay.service'\nimport { detectDateRangeType, formatDateRange } from './date-range-helpers'\nimport './date-range-dialog'\nimport type { DateRangeDialogPreset } from './date-range-dialog'\n\ndayjs.extend(quarterOfYear)\n\n// ---------------------------------------------------------------------------\n// Default built-in presets\n// ---------------------------------------------------------------------------\n\nfunction buildDefaultPresets(): DateRangeDialogPreset[] {\n\treturn [\n\t\t{\n\t\t\tid: 'today',\n\t\t\tlabel: 'Today',\n\t\t\tstart: dayjs().startOf('day').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().endOf('day').format('YYYY-MM-DD'),\n\t\t},\n\t\t{\n\t\t\tid: 'yesterday',\n\t\t\tlabel: 'Yesterday',\n\t\t\tstart: dayjs().subtract(1, 'day').startOf('day').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().subtract(1, 'day').endOf('day').format('YYYY-MM-DD'),\n\t\t},\n\t\t{\n\t\t\tid: 'last7',\n\t\t\tlabel: 'Last 7 days',\n\t\t\tstart: dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().endOf('day').format('YYYY-MM-DD'),\n\t\t},\n\t\t{\n\t\t\tid: 'last30',\n\t\t\tlabel: 'Last 30 days',\n\t\t\tstart: dayjs().subtract(29, 'day').startOf('day').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().endOf('day').format('YYYY-MM-DD'),\n\t\t},\n\t\t{\n\t\t\tid: 'thisWeek',\n\t\t\tlabel: 'This week',\n\t\t\tstart: dayjs().startOf('week').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().endOf('week').format('YYYY-MM-DD'),\n\t\t},\n\t\t{\n\t\t\tid: 'thisMonth',\n\t\t\tlabel: 'This month',\n\t\t\tstart: dayjs().startOf('month').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().endOf('month').format('YYYY-MM-DD'),\n\t\t},\n\t\t{\n\t\t\tid: 'lastMonth',\n\t\t\tlabel: 'Last month',\n\t\t\tstart: dayjs().subtract(1, 'month').startOf('month').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().subtract(1, 'month').endOf('month').format('YYYY-MM-DD'),\n\t\t},\n\t\t{\n\t\t\tid: 'thisYear',\n\t\t\tlabel: 'This year',\n\t\t\tstart: dayjs().startOf('year').format('YYYY-MM-DD'),\n\t\t\tend: dayjs().endOf('year').format('YYYY-MM-DD'),\n\t\t},\n\t]\n}\n\n// ---------------------------------------------------------------------------\n// Event types\n// ---------------------------------------------------------------------------\n\nexport type SchmancyDateRangeInputEvent = CustomEvent<{\n\tstart: string | null\n\tend: string | null\n}>\n\nexport type SchmancyDateRangeChangeEvent = CustomEvent<{\n\tstart: string | null\n\tend: string | null\n\tpreset: string | null\n}>\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * A date range selector composing `<schmancy-calendar mode=\"range\">` with a\n * sticky preset chip quick-rail and a secondary typed-entry path.\n *\n * Public API: flat ISO `start`/`end`, `preset` read-back, `presets` array.\n * FormData: `${name}.start` / `${name}.end` (empty endpoint omitted).\n *\n * @element schmancy-date-range\n * @fires input - Provisional sweep preview { start, end }\n * @fires change - Committed range change { start, end, preset }\n */\n@customElement('schmancy-date-range')\nexport class SchmancyDateRange extends SchmancyFormField() {\n\t// `name`, `disabled`, `required`, `error`, `validationMessage`, `id`,\n\t// `validateOn`, `touched`, `submitted`, `markTouched`, `markSubmitted`,\n\t// FACE wiring, FIELD_CONNECT_EVENT dispatch — all from the mixin.\n\n\t@property() type: 'date' | 'datetime-local' = 'date'\n\t@property() start: string | null = null\n\t@property() end: string | null = null\n\n\t@property({ type: Array }) presets: DateRangeDialogPreset[] = buildDefaultPresets()\n\n\t/** Selected preset id; null = custom range. Reflects to attribute. */\n\t@property({ reflect: true }) preset: string | null = null\n\n\t@property() min?: string\n\t@property() max?: string\n\t@property() placeholder = 'Select date range'\n\t@property({ type: Boolean }) clearable = true\n\t@property() step?: 'day' | 'week' | 'month' | 'year' | number\n\t/** Collapses to an icon-only button on narrow viewports. */\n\t@property({ type: Boolean }) collapse = false\n\n\t// Session subjects — ONE_PIPELINE_ONE_SUBSCRIBE in connectedCallback.\n\tprivate readonly open$ = new Subject<MouseEvent | undefined>()\n\tprivate readonly close$ = new Subject<void>()\n\tprivate readonly announce$ = new Subject<string>()\n\n\t@state() private isOpen = false\n\t@state() private announceMessage = ''\n\n\t// Default-capture for formResetCallback\n\tprivate startDefault: string | null = null\n\tprivate endDefault: string | null = null\n\tprivate presetDefault: string | null = null\n\n\toverride disconnectedCallback(): void {\n\t\tsuper.disconnectedCallback()\n\t\tthis.isOpen = false\n\t}\n\n\toverride connectedCallback(): void {\n\t\tsuper.connectedCallback()\n\n\t\t// One pipeline (rxjs ONE_PIPELINE_ONE_SUBSCRIBE).\n\t\tmerge(\n\t\t\t// Overlay session (rxjs SESSIONS_USE_HIGHER_ORDER_OBSERVABLES).\n\t\t\tthis.open$.pipe(\n\t\t\t\ttap(() => {\n\t\t\t\t\tthis.isOpen = true\n\t\t\t\t}),\n\t\t\t\texhaustMap(anchor =>\n\t\t\t\t\tshow(\n\t\t\t\t\t\t// Reactive factory — closed-over props read fresh on each mount.\n\t\t\t\t\t\t() => html`\n\t\t\t\t\t\t\t<schmancy-date-range-dialog\n\t\t\t\t\t\t\t\t.type=${this.type}\n\t\t\t\t\t\t\t\t.start=${this.start}\n\t\t\t\t\t\t\t\t.end=${this.end}\n\t\t\t\t\t\t\t\t.min=${this.min}\n\t\t\t\t\t\t\t\t.max=${this.max}\n\t\t\t\t\t\t\t\t.preset=${this.preset}\n\t\t\t\t\t\t\t\t.presets=${this.presets}\n\t\t\t\t\t\t\t\t@calendar-input=${(ev: CustomEvent<{ start: string | null; end: string | null }>) => {\n\t\t\t\t\t\t\t\t\tev.stopPropagation()\n\t\t\t\t\t\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\t\t\t\t\t\tnew CustomEvent('input', {\n\t\t\t\t\t\t\t\t\t\t\tdetail: { start: ev.detail.start, end: ev.detail.end },\n\t\t\t\t\t\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t@calendar-change=${(ev: CustomEvent<{ start: string | null; end: string | null }>) => {\n\t\t\t\t\t\t\t\t\tev.stopPropagation()\n\t\t\t\t\t\t\t\t\tthis.commitRange(ev.detail.start, ev.detail.end, null)\n\t\t\t\t\t\t\t\t\t// Two endpoints set → close overlay\n\t\t\t\t\t\t\t\t\tif (ev.detail.start && ev.detail.end) {\n\t\t\t\t\t\t\t\t\t\tev.target?.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t@preset-select=${(ev: CustomEvent<DateRangeDialogPreset>) => {\n\t\t\t\t\t\t\t\t\tev.stopPropagation()\n\t\t\t\t\t\t\t\t\tthis.commitRange(ev.detail.start, ev.detail.end, ev.detail.id)\n\t\t\t\t\t\t\t\t\tev.target?.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t></schmancy-date-range-dialog>\n\t\t\t\t\t\t`,\n\t\t\t\t\t\t{ anchor },\n\t\t\t\t\t).pipe(\n\t\t\t\t\t\ttakeUntil(this.close$),\n\t\t\t\t\t\tfinalize(() => {\n\t\t\t\t\t\t\tthis.isOpen = false\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\t\t// Screen-reader announcements.\n\t\t\tthis.announce$.pipe(\n\t\t\t\tswitchMap(message => concat(of(message), timer(1500).pipe(map(() => '')))),\n\t\t\t\ttap(message => {\n\t\t\t\t\tthis.announceMessage = message\n\t\t\t\t}),\n\t\t\t),\n\n\t\t\t// Document keyboard navigation.\n\t\t\tfromEvent<KeyboardEvent>(document, 'keydown').pipe(tap(ev => this.handleKeyDown(ev))),\n\t\t)\n\t\t\t.pipe(takeUntil(this.disconnecting))\n\t\t\t.subscribe()\n\t}\n\n\t// -------------------------------------------------------------------------\n\t// Mixin overrides — FormData, validity, dirty, reset\n\t// -------------------------------------------------------------------------\n\n\toverride willUpdate(changed: PropertyValues): void {\n\t\tsuper.willUpdate(changed)\n\t\tif (changed.has('start') || changed.has('end') || changed.has('name') || changed.has('disabled')) {\n\t\t\tif (this.name && !this.disabled) {\n\t\t\t\tconst fd = new FormData()\n\t\t\t\tif (this.start) fd.append(`${this.name}.start`, this.start)\n\t\t\t\tif (this.end) fd.append(`${this.name}.end`, this.end)\n\t\t\t\tthis.internals?.setFormValue(fd.has(`${this.name}.start`) || fd.has(`${this.name}.end`) ? fd : null)\n\t\t\t} else {\n\t\t\t\tthis.internals?.setFormValue(null)\n\t\t\t}\n\t\t\tthis.checkValidity()\n\t\t}\n\t\tif (changed.has('required')) {\n\t\t\tthis.checkValidity()\n\t\t}\n\t}\n\n\toverride checkValidity(): boolean {\n\t\tif (this.disabled) {\n\t\t\tthis.internals?.setValidity({})\n\t\t\treturn true\n\t\t}\n\t\tif (this.required && (!this.start || !this.end)) {\n\t\t\tconst msg = 'Please select a complete date range.'\n\t\t\tthis.internals?.setValidity({ valueMissing: true }, msg)\n\t\t\tif (this.shouldShowError()) {\n\t\t\t\tthis.error = true\n\t\t\t\tthis.validationMessage = msg\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t\tif (this.start && this.end && this.end < this.start) {\n\t\t\tconst msg = 'End date must be on or after start date.'\n\t\t\tthis.internals?.setValidity({ customError: true }, msg)\n\t\t\tif (this.shouldShowError()) {\n\t\t\t\tthis.error = true\n\t\t\t\tthis.validationMessage = msg\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t\tthis.internals?.setValidity({})\n\t\tif (this.shouldShowError()) {\n\t\t\tthis.error = false\n\t\t\tthis.validationMessage = ''\n\t\t}\n\t\treturn true\n\t}\n\n\toverride toFormEntries(): Array<[string, FormDataEntryValue]> {\n\t\tif (!this.name || this.disabled) return []\n\t\tconst entries: Array<[string, FormDataEntryValue]> = []\n\t\tif (this.start) entries.push([`${this.name}.start`, this.start])\n\t\tif (this.end) entries.push([`${this.name}.end`, this.end])\n\t\treturn entries\n\t}\n\n\toverride get dirty(): boolean {\n\t\treturn this.start !== this.startDefault || this.end !== this.endDefault\n\t}\n\n\toverride firstUpdated(changed: PropertyValues): void {\n\t\tsuper.firstUpdated(changed)\n\t\tthis.startDefault = this.start\n\t\tthis.endDefault = this.end\n\t\tthis.presetDefault = this.preset\n\t}\n\n\toverride resetForm(): void {\n\t\tthis.start = this.startDefault\n\t\tthis.end = this.endDefault\n\t\tthis.preset = this.presetDefault\n\t\tthis.error = false\n\t\tthis.validationMessage = ''\n\t\tthis.touched = false\n\t\tthis.submitted = false\n\t\tthis.internals?.setValidity({})\n\t}\n\n\t// -------------------------------------------------------------------------\n\t// Internal helpers\n\t// -------------------------------------------------------------------------\n\n\tprivate commitRange(start: string | null, end: string | null, presetId: string | null): void {\n\t\tthis.start = start\n\t\tthis.end = end\n\t\tthis.preset = presetId\n\t\tthis.announce$.next(`Date range: ${this.displayLabel()}`)\n\t\tthis.emitChange({ start, end, preset: presetId })\n\t}\n\n\tprivate displayLabel(): string {\n\t\tif (this.preset) {\n\t\t\tconst p = this.presets.find(x => x.id === this.preset)\n\t\t\tif (p) return p.label\n\t\t}\n\t\treturn formatDateRange(this.start ?? '', this.end ?? '', this.type, this.placeholder)\n\t}\n\n\tprivate toggleDropdown(e: MouseEvent) {\n\t\te.stopPropagation()\n\t\tif (this.disabled || this.step !== undefined) return\n\t\tif (this.isOpen) {\n\t\t\tthis.close$.next()\n\t\t} else {\n\t\t\tthis.open$.next(e)\n\t\t}\n\t}\n\n\tprivate shiftDateRange(direction: number, e: Event) {\n\t\te.stopPropagation()\n\t\tif (!this.start || !this.end) return\n\n\t\tconst fromDate = dayjs(this.start)\n\t\tconst toDate = dayjs(this.end)\n\t\tif (!fromDate.isValid() || !toDate.isValid()) return\n\n\t\tconst dateFormat = this.type === 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DDTHH:mm'\n\t\tconst dir = direction > 0 ? 1 : -1\n\t\tconst daysDiff = toDate.diff(fromDate, 'day') + 1\n\n\t\tlet amount: number\n\t\tlet unit: dayjs.ManipulateType\n\n\t\tif (this.step !== undefined) {\n\t\t\tif (typeof this.step === 'number') {\n\t\t\t\tamount = dir * this.step\n\t\t\t\tunit = 'day'\n\t\t\t} else if (this.step === 'day') {\n\t\t\t\tamount = dir * daysDiff\n\t\t\t\tunit = 'day'\n\t\t\t} else {\n\t\t\t\tamount = dir\n\t\t\t\tunit = this.step\n\t\t\t}\n\t\t} else {\n\t\t\tconst rangeType = detectDateRangeType(fromDate, toDate)\n\t\t\tif (rangeType.isFullYear) {\n\t\t\t\tamount = dir\n\t\t\t\tunit = 'year'\n\t\t\t} else if (rangeType.isFullMonth) {\n\t\t\t\tamount = dir\n\t\t\t\tunit = 'month'\n\t\t\t} else if (rangeType.isFullWeek) {\n\t\t\t\tamount = dir\n\t\t\t\tunit = 'week'\n\t\t\t} else {\n\t\t\t\tamount = dir * daysDiff\n\t\t\t\tunit = 'day'\n\t\t\t}\n\t\t}\n\n\t\tconst newFrom = fromDate.add(amount, unit)\n\t\tconst newTo = toDate.add(amount, unit)\n\n\t\tif (this.min && newFrom.isBefore(dayjs(this.min))) return\n\t\tif (this.max && newTo.isAfter(dayjs(this.max))) return\n\n\t\tthis.commitRange(newFrom.format(dateFormat), newTo.format(dateFormat), null)\n\t}\n\n\tprivate handleKeyDown(ev: KeyboardEvent) {\n\t\tif (!this.start || !this.end || this.disabled) return\n\t\tconst target = ev.target as Node | null\n\t\tif (target !== this && !this.contains(target)) return\n\n\t\tswitch (ev.key) {\n\t\t\tcase 'PageUp':\n\t\t\t\tthis.shiftDateRange(-1, ev)\n\t\t\t\tev.preventDefault()\n\t\t\t\tbreak\n\t\t\tcase 'PageDown':\n\t\t\t\tthis.shiftDateRange(1, ev)\n\t\t\t\tev.preventDefault()\n\t\t\t\tbreak\n\t\t\tcase 'Home':\n\t\t\t\tif (ev.ctrlKey) {\n\t\t\t\t\tconst fmt = this.type === 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DDTHH:mm'\n\t\t\t\t\tconst from = dayjs(this.start)\n\t\t\t\t\tconst to = dayjs(this.end)\n\t\t\t\t\tconst monthStart = from.startOf('month')\n\t\t\t\t\tthis.commitRange(\n\t\t\t\t\t\tmonthStart.format(fmt),\n\t\t\t\t\t\tmonthStart.add(to.diff(from, 'day'), 'day').format(fmt),\n\t\t\t\t\t\tnull,\n\t\t\t\t\t)\n\t\t\t\t\tev.preventDefault()\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 'End':\n\t\t\t\tif (ev.ctrlKey) {\n\t\t\t\t\tconst fmt = this.type === 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DDTHH:mm'\n\t\t\t\t\tconst from = dayjs(this.start)\n\t\t\t\t\tconst to = dayjs(this.end)\n\t\t\t\t\tconst monthEnd = to.endOf('month')\n\t\t\t\t\tthis.commitRange(\n\t\t\t\t\t\tmonthEnd.subtract(to.diff(from, 'day'), 'day').format(fmt),\n\t\t\t\t\t\tmonthEnd.format(fmt),\n\t\t\t\t\t\tnull,\n\t\t\t\t\t)\n\t\t\t\t\tev.preventDefault()\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\tprivate canNavigateBackward(): boolean {\n\t\tif (!this.start || !this.min) return true\n\t\treturn dayjs(this.start).isAfter(dayjs(this.min))\n\t}\n\n\tprivate canNavigateForward(): boolean {\n\t\tif (!this.end || !this.max) return true\n\t\treturn dayjs(this.end).isBefore(dayjs(this.max))\n\t}\n\n\t// -------------------------------------------------------------------------\n\t// Render\n\t// -------------------------------------------------------------------------\n\n\trender() {\n\t\tconst showError = this.error && !!this.validationMessage\n\t\tconst errorRing = showError ? ' rounded outline outline-2 outline-error-default' : ''\n\t\tconst label = this.displayLabel()\n\n\t\treturn html`\n\t\t\t<div class=\"relative ${this.disabled ? 'opacity-60 pointer-events-none' : ''}\">\n\t\t\t\t<!-- Screen reader announcements -->\n\t\t\t\t<div class=\"sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">${this.announceMessage}</div>\n\n\t\t\t\t<!-- Collapsed: icon-only on narrow viewports when collapse=true -->\n\t\t\t\t<schmancy-icon-button\n\t\t\t\t\tclass=\"${this.collapse ? 'lg:hidden' : 'hidden'}${errorRing}\"\n\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-invalid=${showError ? 'true' : 'false'}\n\t\t\t\t\taria-label=\"Select date range. Current: ${label}\"\n\t\t\t\t\t@click=${(e: MouseEvent) => this.toggleDropdown(e)}\n\t\t\t\t\t?disabled=${this.disabled}\n\t\t\t\t>\n\t\t\t\t\tdate_range\n\t\t\t\t</schmancy-icon-button>\n\n\t\t\t\t<!-- Full trigger row: [← | range label | →] -->\n\t\t\t\t<section\n\t\t\t\t\t@click=${(ev: Event) => ev.stopPropagation()}\n\t\t\t\t\taria-invalid=${showError ? 'true' : 'false'}\n\t\t\t\t\tclass=\"${this.collapse ? 'hidden lg:flex' : 'flex'}${errorRing}\"\n\t\t\t\t>\n\t\t\t\t\t<schmancy-icon-button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-label=\"Previous ${this.preset ?? 'date range'}\"\n\t\t\t\t\t\t@click=${(e: Event) => this.shiftDateRange(-1, e)}\n\t\t\t\t\t\t?disabled=${this.disabled || !this.start || !this.end || !this.canNavigateBackward()}\n\t\t\t\t\t>\n\t\t\t\t\t\tarrow_left\n\t\t\t\t\t</schmancy-icon-button>\n\n\t\t\t\t\t<schmancy-button\n\t\t\t\t\t\tclass=\"w-max\"\n\t\t\t\t\t\tvariant=\"outlined\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t\taria-expanded=${this.isOpen}\n\t\t\t\t\t\taria-label=\"Select date range. Current: ${label}\"\n\t\t\t\t\t\taria-readonly=\"${this.step !== undefined}\"\n\t\t\t\t\t\t@click=${(e: MouseEvent) => this.toggleDropdown(e)}\n\t\t\t\t\t\t?disabled=${this.disabled}\n\t\t\t\t\t\tstyle=\"${this.step !== undefined ? 'cursor:default;' : ''}\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${label}\n\t\t\t\t\t</schmancy-button>\n\n\t\t\t\t\t<schmancy-icon-button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-label=\"Next ${this.preset ?? 'date range'}\"\n\t\t\t\t\t\t@click=${(e: Event) => this.shiftDateRange(1, e)}\n\t\t\t\t\t\t?disabled=${this.disabled || !this.start || !this.end || !this.canNavigateForward()}\n\t\t\t\t\t>\n\t\t\t\t\t\tarrow_right\n\t\t\t\t\t</schmancy-icon-button>\n\t\t\t\t</section>\n\n\t\t\t\t${showError\n\t\t\t\t\t? html`<div role=\"alert\" class=\"text-error-default text-sm mt-1\">${this.validationMessage}</div>`\n\t\t\t\t\t: nothing}\n\t\t\t</div>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-date-range': SchmancyDateRange\n\t}\n}\n"],"x_google_ignoreList":[0],"mappings":"qZAAA,IAAU,EAAiN,EAA/M,EAA+M,UAAA,CAAmB,aAAa,IAAI,EAAE,QAAQ,EAAE,UAAU,OAAO,SAAS,EAAE,EAAA,CAAG,IAAI,EAAE,EAAE,UAAU,EAAE,QAAQ,SAAS,EAAA,CAAG,OAAO,KAAK,OAAA,EAAS,EAAE,CAAA,EAAG,KAAK,MAAM,KAAK,MAAA,EAAQ,GAAG,CAAA,EAAG,KAAK,MAAM,KAAK,MAAA,EAAQ,EAAE,GAAG,EAAE,EAAA,CAAG,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,SAAS,EAAE,EAAA,CAAG,MAAO,GAAE,OAAO,CAAA,EAAG,KAAK,OAAA,EAAS,EAAE,CAAA,IAAK,EAAE,KAAK,IAAI,EAAE,EAAE,CAAA,EAAG,EAAE,KAAK,IAAA,EAAM,EAAE,CAAA,CAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,SAAS,EAAE,EAAA,CAAG,IAAI,EAAE,KAAK,OAAA,EAAS,EAAA,CAAA,CAAI,EAAE,EAAE,CAAA,GAAI,EAAE,GAAG,EAAE,EAAE,CAAA,IAAK,EAAE,CAAC,IAAI,EAAE,KAAK,QAAA,EAAU,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,CAAA,EAAG,QAAQ,CAAA,EAAG,QAAQ,KAAA,EAAO,KAAK,MAAM,EAAE,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,MAAM,KAAA,CAAM,CAAC,OAAO,EAAE,KAAK,IAAA,EAAM,EAAE,CAAA,CAAE,CAAC,CAAC,EAAjvB,OAAiB,GAAjB,UAA8C,IAA7B,IAAS,GAA2B,EAAO,QAAQ,EAAA,EAAI,OAAmB,QAAnB,YAA2B,OAAO,IAAI,OAAO,CAAA,EAAA,CAAI,EAAE,OAAoB,WAApB,IAA+B,WAAW,GAAG,MAAM,2BAA2B,EAAA,CAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,EE6BjN,EAAA,cAAsC,EAAA,CAAA,CAAA,YAAA,GAAA,EAAA,CAAA,MAAA,GAAA,CAAA,EAAA,KAAA,KASE,OAAA,KAAA,MACX,KAAA,KAAA,IACF,KAAA,KAAA,OAGG,KAAA,KAAA,QAC0B,CAAA,CAAA,CAAA,OAAA,KAAA,OAd9C,CACf,EAAA,GAAG;;;;KAeJ,oBAA4B,EAAA,CAC3B,EAAE,gBAAA,EACF,KAAK,cACJ,IAAI,YAAY,iBAAkB,CACjC,OAAQ,CAAE,MAAO,EAAE,OAAO,MAAO,IAAK,EAAE,OAAO,GAAA,EAC/C,QAAA,CAAS,EACT,SAAA,CAAU,CAAA,CAAA,CAAA,CAGb,CAEA,qBAA6B,EAAA,CAC5B,EAAE,gBAAA,EACF,KAAK,cACJ,IAAI,YAAY,kBAAmB,CAClC,OAAQ,CAAE,MAAO,EAAE,OAAO,MAAO,IAAK,EAAE,OAAO,GAAA,EAC/C,QAAA,CAAS,EACT,SAAA,CAAU,CAAA,CAAA,CAAA,CAGb,CAEA,kBAA0B,EAAA,CACzB,KAAK,cACJ,IAAI,YAAY,gBAAiB,CAChC,OAAQ,EACR,QAAA,CAAS,EACT,SAAA,CAAU,CAAA,CAAA,CAAA,CAGb,CAEA,iBAAyB,EAAA,CACxB,IAAM,EAAS,EAAE,OAA4B,MAC7C,GAAA,CAAK,EAAO,OAEZ,IAAM,EAAW,EACX,EACL,KAAK,MAAA,EAAA,EAAA,SAAa,KAAK,GAAA,EAAK,UAAA,EAAA,EAAA,SAAe,CAAA,CAAA,EAAa,EAAY,KAAK,KAAO,KACjF,KAAK,cACJ,IAAI,YAAY,kBAAmB,CAClC,OAAQ,CAAE,MAAO,EAAU,IAAK,CAAA,EAChC,QAAA,CAAS,EACT,SAAA,CAAU,CAAA,CAAA,CAAA,CAGb,CAEA,eAAuB,EAAA,CACtB,IAAM,EAAS,EAAE,OAA4B,MACxC,GACL,KAAK,cACJ,IAAI,YAAY,kBAAmB,CAClC,OAAQ,CAAE,MAAO,KAAK,OAAS,KAAM,IAAK,CAAA,EAC1C,QAAA,CAAS,EACT,SAAA,CAAU,CAAA,CAAA,CAAA,CAGb,CAEA,QAAA,CACC,MAAO,GAAA,IAAI;;;;;;;kBAQP,KAAK,QAAQ,OAAS,MAChB,EAAA,IAAI;sBAER,KAAK,QACL,GAAK,EAAE,GACP,GAAK,EAAA,IAAI;;yBAEQ,KAAK,SAAW,EAAE,GAAK,kBAAoB,GAAA;mBACjD,EAAE,GAAA;sBACC,KAAK,SAAW,EAAE,GAAA;mBACrB,EAAE,MAAA,KAAW,EAAE,IAAA;uBACT,KAAK,kBAAkB,CAAA,EAAA;;YAEpC,EAAE,MAAA;;;YAKF,EAAA,OAAA,EAAA;;;;;;;cAQE,KAAK,KAAA;eACJ,KAAK,MAAA;aACP,KAAK,IAAA;4BACI,KAAK,GAAA,EAAA;4BACL,KAAK,GAAA,EAAA;eACX,GAAkC,KAAK,oBAAoB,CAAA,EAAA;gBAC1D,GAAmC,KAAK,qBAAqB,CAAA,EAAA;;;;;;;;eAQ/D,KAAK,KAAA;gBACJ,OAAA;gBACA,KAAK,OAAS,GAAA;6BACP,KAAK,GAAA,EAAA;6BACL,KAAK,GAAA,EAAA;iBACX,KAAK,iBAAA;;;;;eAKP,KAAK,KAAA;gBACJ,KAAA;gBACA,KAAK,KAAO,GAAA;6BACL,KAAK,OAAS,KAAK,GAAA,EAAA;6BACnB,KAAK,GAAA,EAAA;iBACX,KAAK,eAAA;;;;;GAMrB,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EA1IU,EAAA,UAAA,OAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,QAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,SAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UACA,CAAE,KAAM,KAAA,CAAA,CAAA,EAAO,EAAA,UAAA,UAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,eAhBX,4BAAA,CAAA,EAA4B,CAAA,ECJ3C,EAAA,QAAM,OAAO,EAAA,OAAA,EA0FN,IAAA,EAAA,cAAgC,EAAA,EAAA,CAAA,CAAA,YAAA,GAAA,EAAA,CAAA,MAAA,GAAA,CAAA,EAAA,KAAA,KAKQ,OAAA,KAAA,MACX,KAAA,KAAA,IACF,KAAA,KAAA,QA1F1B,CACN,CACC,GAAI,QACJ,MAAO,QACP,OAAA,EAAA,EAAA,SAAA,EAAe,QAAQ,KAAA,EAAO,OAAO,YAAA,EACrC,KAAA,EAAA,EAAA,SAAA,EAAa,MAAM,KAAA,EAAO,OAAO,YAAA,CAAA,EAElC,CACC,GAAI,YACJ,MAAO,YACP,OAAA,EAAA,EAAA,SAAA,EAAe,SAAS,EAAG,KAAA,EAAO,QAAQ,KAAA,EAAO,OAAO,YAAA,EACxD,KAAA,EAAA,EAAA,SAAA,EAAa,SAAS,EAAG,KAAA,EAAO,MAAM,KAAA,EAAO,OAAO,YAAA,CAAA,EAErD,CACC,GAAI,QACJ,MAAO,cACP,OAAA,EAAA,EAAA,SAAA,EAAe,SAAS,EAAG,KAAA,EAAO,QAAQ,KAAA,EAAO,OAAO,YAAA,EACxD,KAAA,EAAA,EAAA,SAAA,EAAa,MAAM,KAAA,EAAO,OAAO,YAAA,CAAA,EAElC,CACC,GAAI,SACJ,MAAO,eACP,OAAA,EAAA,EAAA,SAAA,EAAe,SAAS,GAAI,KAAA,EAAO,QAAQ,KAAA,EAAO,OAAO,YAAA,EACzD,KAAA,EAAA,EAAA,SAAA,EAAa,MAAM,KAAA,EAAO,OAAO,YAAA,CAAA,EAElC,CACC,GAAI,WACJ,MAAO,YACP,OAAA,EAAA,EAAA,SAAA,EAAe,QAAQ,MAAA,EAAQ,OAAO,YAAA,EACtC,KAAA,EAAA,EAAA,SAAA,EAAa,MAAM,MAAA,EAAQ,OAAO,YAAA,CAAA,EAEnC,CACC,GAAI,YACJ,MAAO,aACP,OAAA,EAAA,EAAA,SAAA,EAAe,QAAQ,OAAA,EAAS,OAAO,YAAA,EACvC,KAAA,EAAA,EAAA,SAAA,EAAa,MAAM,OAAA,EAAS,OAAO,YAAA,CAAA,EAEpC,CACC,GAAI,YACJ,MAAO,aACP,OAAA,EAAA,EAAA,SAAA,EAAe,SAAS,EAAG,OAAA,EAAS,QAAQ,OAAA,EAAS,OAAO,YAAA,EAC5D,KAAA,EAAA,EAAA,SAAA,EAAa,SAAS,EAAG,OAAA,EAAS,MAAM,OAAA,EAAS,OAAO,YAAA,CAAA,EAEzD,CACC,GAAI,WACJ,MAAO,YACP,OAAA,EAAA,EAAA,SAAA,EAAe,QAAQ,MAAA,EAAQ,OAAO,YAAA,EACtC,KAAA,EAAA,EAAA,SAAA,EAAa,MAAM,MAAA,EAAQ,OAAO,YAAA,CAAA,CAAA,EAAA,KAAA,OAgDiB,KAAA,KAAA,YAI3B,oBAAA,KAAA,UAAA,CACe,EAAA,KAAA,SAAA,CAGD,EAAA,KAAA,MAGf,IAAI,EAAA,QAAA,KAAA,OACH,IAAI,EAAA,QAAA,KAAA,UACD,IAAI,EAAA,QAAA,KAAA,OAAA,CAEP,EAAA,KAAA,gBACS,GAAA,KAAA,aAGG,KAAA,KAAA,WACF,KAAA,KAAA,cACG,IAAA,CAEvC,sBAAA,CACC,MAAM,qBAAA,EACN,KAAK,OAAA,CAAS,CACf,CAEA,mBAAA,CACC,MAAM,kBAAA,GAGN,EAAA,EAAA,OAEC,KAAK,MAAM,MAAA,EAAA,EAAA,SAAA,CAET,KAAK,OAAA,CAAS,CAAA,CAAA,GACd,EAAA,EAAA,YACU,GACV,EAAA,MAEO,EAAA,IAAI;;gBAEA,KAAK,KAAA;iBACJ,KAAK,MAAA;eACP,KAAK,IAAA;eACL,KAAK,IAAA;eACL,KAAK,IAAA;kBACF,KAAK,OAAA;mBACJ,KAAK,QAAA;0BACG,GAAA,CAClB,EAAG,gBAAA,EACH,KAAK,cACJ,IAAI,YAAY,QAAS,CACxB,OAAQ,CAAE,MAAO,EAAG,OAAO,MAAO,IAAK,EAAG,OAAO,GAAA,EACjD,QAAA,CAAS,EACT,SAAA,CAAU,CAAA,CAAA,CAAA,CAAA,EAAA;2BAIO,GAAA,CACnB,EAAG,gBAAA,EACH,KAAK,YAAY,EAAG,OAAO,MAAO,EAAG,OAAO,IAAK,IAAA,EAE7C,EAAG,OAAO,OAAS,EAAG,OAAO,KAChC,EAAG,QAAQ,cAAc,IAAI,YAAY,QAAS,CAAE,QAAA,CAAS,EAAM,SAAA,CAAU,CAAA,CAAA,CAAA,CAAA,EAAA;yBAG7D,GAAA,CACjB,EAAG,gBAAA,EACH,KAAK,YAAY,EAAG,OAAO,MAAO,EAAG,OAAO,IAAK,EAAG,OAAO,EAAA,EAC3D,EAAG,QAAQ,cAAc,IAAI,YAAY,QAAS,CAAE,QAAA,CAAS,EAAM,SAAA,CAAU,CAAA,CAAA,CAAA,CAAA,EAAA;;QAIhF,CAAE,OAAA,CAAA,CAAA,EACD,MAAA,EAAA,EAAA,WACS,KAAK,MAAA,GAAM,EAAA,EAAA,cAAA,CAEpB,KAAK,OAAA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,EAOlB,KAAK,UAAU,MAAA,EAAA,EAAA,WACJ,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,IAAqB,CAAA,GAAO,EAAA,EAAA,OAAS,IAAA,EAAM,MAAA,EAAA,EAAA,SAAe,EAAA,CAAA,CAAA,CAAA,GAAK,EAAA,EAAA,KACrE,GAAA,CACH,KAAK,gBAAkB,CAAA,CAAA,CAAA,GAEzB,EAAA,EAAA,WAGyB,SAAU,SAAA,EAAW,MAAA,EAAA,EAAA,KAAS,GAAM,KAAK,cAAc,CAAA,CAAA,CAAA,CAAA,EAE/E,MAAA,EAAA,EAAA,WAAe,KAAK,aAAA,CAAA,EACpB,UAAA,CACH,CAMA,WAAoB,EAAA,CAEnB,GADA,MAAM,WAAW,CAAA,EACb,EAAQ,IAAI,OAAA,GAAY,EAAQ,IAAI,KAAA,GAAU,EAAQ,IAAI,MAAA,GAAW,EAAQ,IAAI,UAAA,EAAa,CACjG,GAAI,KAAK,MAAA,CAAS,KAAK,SAAU,CAChC,IAAM,EAAK,IAAI,SACX,KAAK,OAAO,EAAG,OAAO,GAAG,KAAK,KAAA,QAAc,KAAK,KAAA,EACjD,KAAK,KAAK,EAAG,OAAO,GAAG,KAAK,KAAA,MAAY,KAAK,GAAA,EACjD,KAAK,WAAW,aAAa,EAAG,IAAI,GAAG,KAAK,KAAA,OAAA,GAAiB,EAAG,IAAI,GAAG,KAAK,KAAA,KAAA,EAAc,EAAK,IAAA,CAChG,MACC,KAAK,WAAW,aAAa,IAAA,EAE9B,KAAK,cAAA,CACN,CACI,EAAQ,IAAI,UAAA,GACf,KAAK,cAAA,CAEP,CAEA,eAAA,CACC,GAAI,KAAK,SAER,OADA,KAAK,WAAW,YAAY,CAAC,CAAA,EAAA,CACtB,EAER,GAAI,KAAK,WAAA,CAAc,KAAK,OAAA,CAAU,KAAK,KAAM,CAChD,IAAM,EAAM,uCAMZ,OALA,KAAK,WAAW,YAAY,CAAE,aAAA,CAAc,CAAA,EAAQ,CAAA,EAChD,KAAK,gBAAA,IACR,KAAK,MAAA,CAAQ,EACb,KAAK,kBAAoB,GAAA,CAEnB,CACR,CACA,GAAI,KAAK,OAAS,KAAK,KAAO,KAAK,IAAM,KAAK,MAAO,CACpD,IAAM,EAAM,2CAMZ,OALA,KAAK,WAAW,YAAY,CAAE,YAAA,CAAa,CAAA,EAAQ,CAAA,EAC/C,KAAK,gBAAA,IACR,KAAK,MAAA,CAAQ,EACb,KAAK,kBAAoB,GAAA,CAEnB,CACR,CAMA,OALA,KAAK,WAAW,YAAY,CAAC,CAAA,EACzB,KAAK,gBAAA,IACR,KAAK,MAAA,CAAQ,EACb,KAAK,kBAAoB,IAAA,CAEnB,CACR,CAEA,eAAA,CACC,GAAA,CAAK,KAAK,MAAQ,KAAK,SAAU,MAAO,CAAA,EACxC,IAAM,EAA+C,CAAA,EAGrD,OAFI,KAAK,OAAO,EAAQ,KAAK,CAAC,GAAG,KAAK,KAAA,QAAc,KAAK,KAAA,CAAA,EACrD,KAAK,KAAK,EAAQ,KAAK,CAAC,GAAG,KAAK,KAAA,MAAY,KAAK,GAAA,CAAA,EAC9C,CACR,CAEA,IAAA,OAAa,CACZ,OAAO,KAAK,QAAU,KAAK,cAAgB,KAAK,MAAQ,KAAK,UAC9D,CAEA,aAAsB,EAAA,CACrB,MAAM,aAAa,CAAA,EACnB,KAAK,aAAe,KAAK,MACzB,KAAK,WAAa,KAAK,IACvB,KAAK,cAAgB,KAAK,MAC3B,CAEA,WAAA,CACC,KAAK,MAAQ,KAAK,aAClB,KAAK,IAAM,KAAK,WAChB,KAAK,OAAS,KAAK,cACnB,KAAK,MAAA,CAAQ,EACb,KAAK,kBAAoB,GACzB,KAAK,QAAA,CAAU,EACf,KAAK,UAAA,CAAY,EACjB,KAAK,WAAW,YAAY,CAAC,CAAA,CAC9B,CAMA,YAAoB,EAAsB,EAAoB,EAAA,CAC7D,KAAK,MAAQ,EACb,KAAK,IAAM,EACX,KAAK,OAAS,EACd,KAAK,UAAU,KAAK,eAAe,KAAK,aAAA,GAAA,EACxC,KAAK,WAAW,CAAE,MAAA,EAAO,IAAA,EAAK,OAAQ,CAAA,CAAA,CACvC,CAEA,cAAA,CACC,GAAI,KAAK,OAAQ,CAChB,IAAM,EAAI,KAAK,QAAQ,KAAK,GAAK,EAAE,KAAO,KAAK,MAAA,EAC/C,GAAI,EAAG,OAAO,EAAE,KACjB,CACA,OFjUF,SAAA,EAAA,EAAA,EAAA,EAAA,CAAA,GAAA,CAAA,GAAA,CAAA,EAAA,OAAA,EAAA,IAAA,GAAA,EAAA,EAAA,SAAA,CAAA,EAAA,GAAA,EAAA,EAAA,SAAA,CAAA,EAAA,GAAA,CAAA,EAAA,QAAA,GAAA,CAAA,EAAA,QAAA,EAAA,OAAA,EAAA,IAAA,EAAA,IAAA,iBAAA,EAAA,OAAA,SAAA,EAAA,GAAA,EAAA,IAAA,iBAAA,EAAA,OAAA,SAAA,EAAA,GAAA,OAAA,EAAA,OAAA,EAAA,KAAA,EAAA,GAAA,EAAA,OAAA,kBAAA,IAAA,IAAA,EAAA,OAAA,EAAA,OAAA,GAAA,EAAA,OAAA,EAAA,MAAA,EAAA,GAAA,EAAA,OAAA,WAAA,EAAA,KAAA,EAAA,OAAA,aAAA,IAAA,IAAA,EAAA,OAAA,EAAA,MAAA,EAAA,GAAA,EAAA,OAAA,WAAA,EAAA,KAAA,EAAA,OAAA,iBAAA,IAAA,IAAA,GAAA,EAAA,OAAA,iBAAA,IAAA,EAAA,KAAA,EAAA,OAAA,iBAAA,IAAA,GAsCA,EE2RyB,KAAK,OAAS,GAAI,KAAK,KAAO,GAAI,KAAK,KAAM,KAAK,WAAA,CAC1E,CAEA,eAAuB,EAAA,CACtB,EAAE,gBAAA,EACE,KAAK,UAAY,KAAK,OAAjB,IAA0B,KAC/B,KAAK,OACR,KAAK,OAAO,KAAA,EAEZ,KAAK,MAAM,KAAK,CAAA,EAElB,CAEA,eAAuB,EAAmB,EAAA,CAEzC,GADA,EAAE,gBAAA,EAAA,CACG,KAAK,OAAA,CAAU,KAAK,IAAK,OAE9B,IAAM,GAAA,EAAA,EAAA,SAAiB,KAAK,KAAA,EACtB,GAAA,EAAA,EAAA,SAAe,KAAK,GAAA,EAC1B,GAAA,CAAK,EAAS,QAAA,GAAA,CAAc,EAAO,QAAA,EAAW,OAE9C,IAAM,EAAa,KAAK,OAAS,OAAS,aAAe,mBACnD,EAAM,EAAY,EAAI,EAAA,GACtB,EAAW,EAAO,KAAK,EAAU,KAAA,EAAS,EAE5C,EACA,EAEJ,GAAI,KAAK,OAAT,IAAkB,GACQ,OAAd,KAAK,MAAS,UACxB,EAAS,EAAM,KAAK,KACpB,EAAO,OACG,KAAK,OAAS,OACxB,EAAS,EAAM,EACf,EAAO,QAEP,EAAS,EACT,EAAO,KAAK,UAEP,CACN,IAAM,EFvTT,SAAA,EAAA,EAAA,CAAA,MAAA,CAAA,YAAA,EAAA,KAAA,IAAA,GAAA,EAAA,OAAA,EAAA,MAAA,OAAA,EAAA,KAAA,EAAA,cAAA,EAAA,OAAA,EAAA,QAAA,SAAA,EAAA,KAAA,GAAA,EAAA,OAAA,EAAA,MAAA,SAAA,EAAA,KAAA,EAAA,WAAA,EAAA,OAAA,EAAA,QAAA,MAAA,EAAA,KAAA,GAAA,EAAA,OAAA,EAAA,MAAA,MAAA,EAAA,KAAA,EAAA,WAAA,EAAA,IAAA,IAAA,GAAA,EAAA,IAAA,IAAA,GAAA,EAAA,KAAA,EAAA,MAAA,IAAA,CAAA,CAOA,EEgTyC,EAAU,CAAA,EAC5C,EAAU,YACb,EAAS,EACT,EAAO,QACG,EAAU,aACpB,EAAS,EACT,EAAO,SACG,EAAU,YACpB,EAAS,EACT,EAAO,SAEP,EAAS,EAAM,EACf,EAAO,MAET,CAEA,IAAM,EAAU,EAAS,IAAI,EAAQ,CAAA,EAC/B,EAAQ,EAAO,IAAI,EAAQ,CAAA,EAE7B,KAAK,KAAO,EAAQ,UAAA,EAAA,EAAA,SAAe,KAAK,GAAA,CAAA,GACxC,KAAK,KAAO,EAAM,SAAA,EAAA,EAAA,SAAc,KAAK,GAAA,CAAA,GAEzC,KAAK,YAAY,EAAQ,OAAO,CAAA,EAAa,EAAM,OAAO,CAAA,EAAa,IAAA,CACxE,CAEA,cAAsB,EAAA,CACrB,GAAA,CAAK,KAAK,OAAA,CAAU,KAAK,KAAO,KAAK,SAAU,OAC/C,IAAM,EAAS,EAAG,OAClB,GAAI,IAAW,MAAS,KAAK,SAAS,CAAA,EAEtC,OAAQ,EAAG,IAAX,CACC,IAAK,SACJ,KAAK,eAAA,GAAmB,CAAA,EACxB,EAAG,eAAA,EACH,MACD,IAAK,WACJ,KAAK,eAAe,EAAG,CAAA,EACvB,EAAG,eAAA,EACH,MACD,IAAK,OACJ,GAAI,EAAG,QAAS,CACf,IAAM,EAAM,KAAK,OAAS,OAAS,aAAe,mBAC5C,GAAA,EAAA,EAAA,SAAa,KAAK,KAAA,EAClB,GAAA,EAAA,EAAA,SAAW,KAAK,GAAA,EAChB,EAAa,EAAK,QAAQ,OAAA,EAChC,KAAK,YACJ,EAAW,OAAO,CAAA,EAClB,EAAW,IAAI,EAAG,KAAK,EAAM,KAAA,EAAQ,KAAA,EAAO,OAAO,CAAA,EACnD,IAAA,EAED,EAAG,eAAA,CACJ,CACA,MACD,IAAK,MACJ,GAAI,EAAG,QAAS,CACf,IAAM,EAAM,KAAK,OAAS,OAAS,aAAe,mBAC5C,GAAA,EAAA,EAAA,SAAa,KAAK,KAAA,EAClB,GAAA,EAAA,EAAA,SAAW,KAAK,GAAA,EAChB,EAAW,EAAG,MAAM,OAAA,EAC1B,KAAK,YACJ,EAAS,SAAS,EAAG,KAAK,EAAM,KAAA,EAAQ,KAAA,EAAO,OAAO,CAAA,EACtD,EAAS,OAAO,CAAA,EAChB,IAAA,EAED,EAAG,eAAA,CACJ,CAAA,CAGH,CAEA,qBAAA,CACC,MAAA,CAAK,KAAK,OAAA,CAAU,KAAK,MACzB,EAAA,EAAA,SAAa,KAAK,KAAA,EAAO,SAAA,EAAA,EAAA,SAAc,KAAK,GAAA,CAAA,CAC7C,CAEA,oBAAA,CACC,MAAA,CAAK,KAAK,KAAA,CAAQ,KAAK,MACvB,EAAA,EAAA,SAAa,KAAK,GAAA,EAAK,UAAA,EAAA,EAAA,SAAe,KAAK,GAAA,CAAA,CAC5C,CAMA,QAAA,CACC,IAAM,EAAY,KAAK,OAAA,CAAA,CAAW,KAAK,kBACjC,EAAY,EAAY,mDAAqD,GAC7E,EAAQ,KAAK,aAAA,EAEnB,MAAO,GAAA,IAAI;0BACa,KAAK,SAAW,iCAAmC,GAAA;;+EAEE,KAAK,gBAAA;;;;cAItE,KAAK,SAAW,YAAc,WAAW,EAAA;;;oBAGnC,EAAY,OAAS,QAAA;+CACM,EAAA;cAChC,GAAkB,KAAK,eAAe,CAAA,EAAA;iBACpC,KAAK,SAAA;;;;;;;cAOP,GAAc,EAAG,gBAAA,EAAA;oBACZ,EAAY,OAAS,QAAA;cAC3B,KAAK,SAAW,iBAAmB,SAAS,EAAA;;;;6BAI7B,KAAK,QAAU,aAAA;eAC5B,GAAa,KAAK,eAAA,GAAmB,CAAA,EAAA;kBACnC,KAAK,UAAA,CAAa,KAAK,OAAA,CAAU,KAAK,KAAA,CAAQ,KAAK,oBAAA,EAAA;;;;;;;;;;sBAU/C,KAAK,OAAA;gDACqB,EAAA;uBACzB,KAAK,WAAS,GAAT;eACZ,GAAkB,KAAK,eAAe,CAAA,EAAA;kBACpC,KAAK,SAAA;eACR,KAAK,WAAS,GAAgC,GAApB,kBAAoB;;QAErD,EAAA;;;;;yBAKiB,KAAK,QAAU,aAAA;eACxB,GAAa,KAAK,eAAe,EAAG,CAAA,EAAA;kBAClC,KAAK,UAAA,CAAa,KAAK,OAAA,CAAU,KAAK,KAAA,CAAQ,KAAK,mBAAA,EAAA;;;;;;MAM/D,EACC,EAAA,IAAI,6DAA6D,KAAK,kBAAA,QACtE,EAAA,QAAA;;GAGN,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EA/YU,EAAA,UAAA,OAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,QAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAEA,CAAE,KAAM,KAAA,CAAA,CAAA,EAAO,EAAA,UAAA,UAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAGf,CAAE,QAAA,CAAS,CAAA,CAAA,CAAA,EAAM,EAAA,UAAA,SAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EAEjB,EAAA,UAAA,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,MAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACA,EAAA,UAAA,cAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UACA,CAAE,KAAM,OAAA,CAAA,CAAA,EAAS,EAAA,UAAA,YAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAAA,CAAA,EACjB,EAAA,UAAA,OAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAEA,CAAE,KAAM,OAAA,CAAA,CAAA,EAAS,EAAA,UAAA,WAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,OAAA,CAAA,EAOpB,EAAA,UAAA,SAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,OAAA,CAAA,EACA,EAAA,UAAA,kBAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,eA7BO,qBAAA,CAAA,EAAqB,CAAA,EAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,CAAA,CAAA,CAAA,EAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,CAAA,CAAA,CAAA"}
|