@dashforge/tw 0.9.1-beta → 0.10.0-beta

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 (37) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/index.esm.js +1152 -336
  3. package/dist/src/components/DateRangePicker/DateRangePicker.d.ts +13 -0
  4. package/dist/src/components/DateRangePicker/DateRangePicker.d.ts.map +1 -0
  5. package/dist/src/components/DateRangePicker/dateRangePicker.types.d.ts +85 -0
  6. package/dist/src/components/DateRangePicker/dateRangePicker.types.d.ts.map +1 -0
  7. package/dist/src/components/DateRangePicker/dateRangePicker.variants.d.ts +183 -0
  8. package/dist/src/components/DateRangePicker/dateRangePicker.variants.d.ts.map +1 -0
  9. package/dist/src/components/DateTimePicker/DateTimePicker.d.ts +7 -43
  10. package/dist/src/components/DateTimePicker/DateTimePicker.d.ts.map +1 -1
  11. package/dist/src/components/DateTimePicker/dateTimePicker.types.d.ts +50 -55
  12. package/dist/src/components/DateTimePicker/dateTimePicker.types.d.ts.map +1 -1
  13. package/dist/src/components/DateTimePicker/dateTimePicker.variants.d.ts +36 -94
  14. package/dist/src/components/DateTimePicker/dateTimePicker.variants.d.ts.map +1 -1
  15. package/dist/src/components/TimePicker/TimePicker.d.ts +12 -0
  16. package/dist/src/components/TimePicker/TimePicker.d.ts.map +1 -0
  17. package/dist/src/components/TimePicker/timePicker.types.d.ts +80 -0
  18. package/dist/src/components/TimePicker/timePicker.types.d.ts.map +1 -0
  19. package/dist/src/components/TimePicker/timePicker.variants.d.ts +103 -0
  20. package/dist/src/components/TimePicker/timePicker.variants.d.ts.map +1 -0
  21. package/dist/src/index.d.ts +10 -4
  22. package/dist/src/index.d.ts.map +1 -1
  23. package/package.json +4 -4
  24. package/src/components/DateRangePicker/DateRangePicker.test.tsx +92 -0
  25. package/src/components/DateRangePicker/DateRangePicker.tsx +510 -0
  26. package/src/components/DateRangePicker/dateRangePicker.types.ts +74 -0
  27. package/src/components/DateRangePicker/dateRangePicker.variants.ts +101 -0
  28. package/src/components/DateTimePicker/DateTimePicker.test.tsx +60 -186
  29. package/src/components/DateTimePicker/DateTimePicker.tsx +209 -181
  30. package/src/components/DateTimePicker/dateTimePicker.types.ts +50 -54
  31. package/src/components/DateTimePicker/dateTimePicker.variants.ts +22 -51
  32. package/src/components/TimePicker/TimePicker.test.tsx +65 -0
  33. package/src/components/TimePicker/TimePicker.tsx +274 -0
  34. package/src/components/TimePicker/timePicker.types.ts +69 -0
  35. package/src/components/TimePicker/timePicker.variants.ts +53 -0
  36. package/src/index.ts +28 -16
  37. package/src/components/DateTimePicker/DateTimePicker.perf.test.tsx +0 -153
package/dist/index.esm.js CHANGED
@@ -11,7 +11,7 @@ import { useDashFieldMeta } from '@dashforge/forms';
11
11
  import * as RadixCheckbox from '@radix-ui/react-checkbox';
12
12
  import * as RadixSwitch from '@radix-ui/react-switch';
13
13
  import * as RadixRadioGroup from '@radix-ui/react-radio-group';
14
- import { useCalendar, resolveCalendarKey, formatLongDate, parseISODate } from '@dashforge/calendar-core';
14
+ import { useCalendar, resolveCalendarKey, formatLongDate, parseISODate, formatTime, generateTimeOptions, timeStringToMinutes, getTodayISODate, useDateRange } from '@dashforge/calendar-core';
15
15
  import * as RadixPopover from '@radix-ui/react-popover';
16
16
  import * as RadixDialog from '@radix-ui/react-dialog';
17
17
  import * as RadixTabs from '@radix-ui/react-tabs';
@@ -3427,334 +3427,6 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
3427
3427
  });
3428
3428
  }
3429
3429
 
3430
- /**
3431
- * Tailwind-variants recipe for `<DateTimePicker>` with 6 slots.
3432
- *
3433
- * Styling mirrors `<TextField>` for layout / sizes / error states so
3434
- * the two field types compose visually in the same form.
3435
- *
3436
- * Native `<input type="date|time|datetime-local">` quirks handled here:
3437
- *
3438
- * - The browser-rendered placeholder mask (e.g., `mm/dd/yyyy`) is
3439
- * invisible on `bg-neutral-50` by default in some themes; we keep
3440
- * the same neutral palette and rely on the input's own contrast
3441
- * rules (no extra `::placeholder` styling — browsers don't honor it
3442
- * on these input types).
3443
- * - The native picker indicator (calendar / clock icon) is
3444
- * browser-supplied; we ensure it stays visible in dark mode via
3445
- * `color-scheme: light dark` on the input (set inline below).
3446
- */ const dateTimePickerVariants = tv({
3447
- slots: {
3448
- root: 'flex',
3449
- label: 'block text-sm font-medium text-neutral-900 mb-1',
3450
- requiredMark: 'text-danger-500 ml-0.5',
3451
- inputWrapper: [
3452
- 'relative flex items-center',
3453
- 'rounded-md border bg-neutral-50',
3454
- 'border-neutral-300',
3455
- 'transition-colors',
3456
- 'focus-within:border-primary-500 focus-within:ring-2 focus-within:ring-primary-500/30'
3457
- ],
3458
- input: [
3459
- 'block w-full bg-transparent outline-none',
3460
- 'text-neutral-900 placeholder:text-neutral-400',
3461
- 'disabled:cursor-not-allowed disabled:opacity-60',
3462
- 'read-only:cursor-default',
3463
- // `color-scheme` lets the native calendar / clock icon respect
3464
- // the dark mode (otherwise it stays light-themed against dark bg)
3465
- '[color-scheme:light_dark]'
3466
- ],
3467
- helperText: 'mt-1 text-sm text-neutral-600',
3468
- errorText: 'mt-1 text-sm text-danger-600'
3469
- },
3470
- variants: {
3471
- size: {
3472
- sm: {
3473
- inputWrapper: 'h-8 px-2',
3474
- input: 'text-sm'
3475
- },
3476
- md: {
3477
- inputWrapper: 'h-10 px-3',
3478
- input: 'text-base'
3479
- },
3480
- lg: {
3481
- inputWrapper: 'h-12 px-4',
3482
- input: 'text-lg'
3483
- }
3484
- },
3485
- layout: {
3486
- stacked: {
3487
- root: 'flex-col'
3488
- },
3489
- inline: {
3490
- root: 'flex-row items-start gap-3',
3491
- label: 'mb-0 pt-2 whitespace-nowrap shrink-0'
3492
- }
3493
- },
3494
- error: {
3495
- true: {
3496
- inputWrapper: 'border-danger-500 focus-within:border-danger-500 focus-within:ring-danger-500/30'
3497
- }
3498
- },
3499
- fullWidth: {
3500
- true: {
3501
- root: 'w-full',
3502
- inputWrapper: 'w-full'
3503
- }
3504
- },
3505
- disabled: {
3506
- true: {
3507
- inputWrapper: 'opacity-60 cursor-not-allowed bg-neutral-200'
3508
- }
3509
- }
3510
- },
3511
- defaultVariants: {
3512
- size: 'md',
3513
- layout: 'stacked',
3514
- error: false,
3515
- fullWidth: false,
3516
- disabled: false
3517
- }
3518
- });
3519
-
3520
- /**
3521
- * Resolve the native HTML input `type` for a given picker mode.
3522
- */ function inputTypeFor(mode) {
3523
- switch(mode){
3524
- case 'time':
3525
- return 'time';
3526
- case 'datetime':
3527
- return 'datetime-local';
3528
- case 'date':
3529
- default:
3530
- return 'date';
3531
- }
3532
- }
3533
- /**
3534
- * Coerce a stored/exposed value (ISO 8601-ish string or `null`/`undefined`)
3535
- * into the format the native input expects.
3536
- *
3537
- * Contract:
3538
- * - `date` → `YYYY-MM-DD`
3539
- * - `time` → `HH:mm` (or `HH:mm:ss` if seconds present)
3540
- * - `datetime` → `YYYY-MM-DDTHH:mm` (no timezone, datetime-local
3541
- * rejects `Z` / offset suffixes)
3542
- *
3543
- * The function is intentionally lenient:
3544
- * - Pass-through when the input already matches the expected shape.
3545
- * - Truncates a richer ISO string (e.g. `2026-05-16T10:23:45.000Z`)
3546
- * down to the mode-appropriate prefix.
3547
- * - Returns `''` for null / undefined / unparseable inputs (native
3548
- * inputs use `''` to represent "no value").
3549
- */ function isoToInputValue(mode, raw) {
3550
- if (raw == null || raw === '') return '';
3551
- // Fast path: already in the expected shape.
3552
- if (mode === 'date' && /^\d{4}-\d{2}-\d{2}$/.test(raw)) return raw;
3553
- if (mode === 'time' && /^\d{2}:\d{2}(:\d{2})?$/.test(raw)) return raw;
3554
- if (mode === 'datetime' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?$/.test(raw)) {
3555
- return raw;
3556
- }
3557
- // Slow path: parse via Date and re-format locally.
3558
- const d = new Date(raw);
3559
- if (isNaN(d.getTime())) return '';
3560
- const pad = (n)=>String(n).padStart(2, '0');
3561
- const yyyy = d.getFullYear();
3562
- const mm = pad(d.getMonth() + 1);
3563
- const dd = pad(d.getDate());
3564
- const hh = pad(d.getHours());
3565
- const mi = pad(d.getMinutes());
3566
- if (mode === 'date') return `${yyyy}-${mm}-${dd}`;
3567
- if (mode === 'time') return `${hh}:${mi}`;
3568
- return `${yyyy}-${mm}-${dd}T${hh}:${mi}`;
3569
- }
3570
- /**
3571
- * Take a native input string and return the canonical "stored" value:
3572
- * the same string for non-empty input, or `null` for empty (so the
3573
- * bridge / consumer never receives the ambiguous empty string).
3574
- */ function inputValueToStored(raw) {
3575
- return raw === '' ? null : raw;
3576
- }
3577
- /**
3578
- * Dashforge TW DateTimePicker — bridge-integrated native date/time input.
3579
- *
3580
- * Three modes (`mode` prop):
3581
- * - `date` — `<input type="date">` → `YYYY-MM-DD`
3582
- * - `time` — `<input type="time">` → `HH:mm` (`HH:mm:ss` with `step={1}`)
3583
- * - `datetime` — `<input type="datetime-local">` → `YYYY-MM-DDTHH:mm`
3584
- *
3585
- * **Why native inputs instead of React Aria `<DatePicker>`?**
3586
- *
3587
- * 1. Zero new deps (`@internationalized/date` would add ~30 KB).
3588
- * 2. Mirrors `@dashforge/ui/DateTimePicker` (MUI side) for API parity.
3589
- * 3. Native inputs are AAA-grade a11y out of the box — screen readers,
3590
- * keyboard nav, OS-provided calendar/clock UI.
3591
- * 4. Predictable state (no internal Aria state machine that fights
3592
- * controlled props — the F5-A lesson learned in `<Autocomplete>`).
3593
- *
3594
- * A richer custom-calendar version (range mode, locale awareness,
3595
- * custom popover styling) can land as F5-B-bis built on Aria
3596
- * `<DatePicker>` / `<Calendar>`.
3597
- *
3598
- * **A11y**:
3599
- * - `aria-invalid` driven by the resolved validation state.
3600
- * - `aria-describedby` links input ↔ helper/error.
3601
- * - Required fields get the native `required` attribute + a visual `*`.
3602
- * - `color-scheme: light dark` keeps the OS calendar icon readable
3603
- * in both color schemes.
3604
- */ function DateTimePicker(props) {
3605
- var _slotProps_root, _slotProps_label, _slotProps_requiredMark, _slotProps_inputWrapper, _slotProps_input, _slotProps_errorText, _slotProps_helperText;
3606
- const { name, rules, mode = 'date', visibleWhen, layout = 'stacked', size, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, min, max, step, value: explicitValue, defaultValue, onValueChange } = props;
3607
- // ───── Hooks (unconditional) ─────
3608
- const bridge = useContext(DashFormContext);
3609
- const isVisible = useEngineVisibility(bridge == null ? void 0 : bridge.engine, visibleWhen);
3610
- // Per-field reactive snapshot. Same pattern as <TextField> — re-renders
3611
- // this component when its OWN bridge value changes, but not when a
3612
- // sibling field changes (perf contract).
3613
- const fieldMeta = useDashFieldMeta(name);
3614
- const accessState = useAccessState(access);
3615
- const inputId = useId();
3616
- const helperId = `${inputId}-help`;
3617
- // StrictMode-safe unregister-on-unmount.
3618
- const unregisterRef = useRef({
3619
- bridge,
3620
- name
3621
- });
3622
- unregisterRef.current = {
3623
- bridge,
3624
- name
3625
- };
3626
- const isMountedRef = useRef(false);
3627
- useEffect(()=>{
3628
- isMountedRef.current = true;
3629
- return ()=>{
3630
- isMountedRef.current = false;
3631
- const { bridge: cap, name: capName } = unregisterRef.current;
3632
- queueMicrotask(()=>{
3633
- var _cap_unregister;
3634
- if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
3635
- });
3636
- };
3637
- }, []);
3638
- // ───── Derived ─────
3639
- const effectiveDisabled = Boolean(disabled) || accessState.disabled;
3640
- const effectiveReadOnly = accessState.readonly;
3641
- const isFormMode = Boolean(bridge == null ? void 0 : bridge.register);
3642
- let resolvedError = error;
3643
- let resolvedHelperText = helperText;
3644
- let registration = null;
3645
- let resolvedValue;
3646
- if (isFormMode && bridge) {
3647
- registration = bridge.register(name, rules);
3648
- const validation = resolveValidationState(name, bridge, error, helperText);
3649
- resolvedError = validation.error;
3650
- resolvedHelperText = validation.helperText;
3651
- if (explicitValue !== undefined) {
3652
- resolvedValue = explicitValue;
3653
- } else {
3654
- const bv = fieldMeta.value;
3655
- resolvedValue = bv == null ? null : String(bv);
3656
- }
3657
- } else if (explicitValue !== undefined) {
3658
- resolvedValue = explicitValue;
3659
- } else {
3660
- // Pure uncontrolled mode: defer to native input's defaultValue.
3661
- resolvedValue = undefined;
3662
- }
3663
- // Registration-supplied callback ref (RHF threads its own ref through
3664
- // here in form mode). Stable callback to keep React 19 happy.
3665
- const registrationRefFn = registration == null ? void 0 : registration.ref;
3666
- const inputRef = useCallback((instance)=>{
3667
- if (typeof registrationRefFn === 'function') {
3668
- registrationRefFn(instance);
3669
- }
3670
- }, [
3671
- registrationRefFn
3672
- ]);
3673
- // ───── Render-time guards (after all hooks) ─────
3674
- if (!isVisible) return null;
3675
- if (!accessState.visible) return null;
3676
- const v = dateTimePickerVariants({
3677
- size,
3678
- layout,
3679
- error: resolvedError,
3680
- fullWidth,
3681
- disabled: effectiveDisabled
3682
- });
3683
- const inputType = inputTypeFor(mode);
3684
- const nativeValue = resolvedValue === undefined ? undefined : isoToInputValue(mode, resolvedValue);
3685
- const nativeDefault = !isFormMode && explicitValue === undefined && defaultValue !== undefined ? isoToInputValue(mode, defaultValue) : undefined;
3686
- const nativeMin = min != null ? isoToInputValue(mode, min) : undefined;
3687
- const nativeMax = max != null ? isoToInputValue(mode, max) : undefined;
3688
- const handleChange = (event)=>{
3689
- const next = inputValueToStored(event.target.value);
3690
- if (isFormMode && bridge) {
3691
- var _registration_onChange;
3692
- bridge.setValue == null ? void 0 : bridge.setValue.call(bridge, name, next);
3693
- void (registration == null ? void 0 : (_registration_onChange = registration.onChange) == null ? void 0 : _registration_onChange.call(registration, {
3694
- target: {
3695
- name,
3696
- value: next != null ? next : ''
3697
- },
3698
- type: 'change'
3699
- }));
3700
- }
3701
- onValueChange == null ? void 0 : onValueChange(next);
3702
- };
3703
- const handleBlur = (event)=>{
3704
- if (isFormMode && bridge) {
3705
- var _registration_onBlur;
3706
- registration == null ? void 0 : (_registration_onBlur = registration.onBlur) == null ? void 0 : _registration_onBlur.call(registration, event);
3707
- }
3708
- };
3709
- return jsxs("div", {
3710
- className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root = slotProps.root) == null ? void 0 : _slotProps_root.className),
3711
- children: [
3712
- label && jsxs("label", {
3713
- htmlFor: inputId,
3714
- className: cn(v.label(), slotProps == null ? void 0 : (_slotProps_label = slotProps.label) == null ? void 0 : _slotProps_label.className),
3715
- children: [
3716
- label,
3717
- required && jsx("span", {
3718
- "aria-hidden": "true",
3719
- className: cn(v.requiredMark(), slotProps == null ? void 0 : (_slotProps_requiredMark = slotProps.requiredMark) == null ? void 0 : _slotProps_requiredMark.className),
3720
- children: "*"
3721
- })
3722
- ]
3723
- }),
3724
- jsx("div", {
3725
- className: cn(v.inputWrapper(), slotProps == null ? void 0 : (_slotProps_inputWrapper = slotProps.inputWrapper) == null ? void 0 : _slotProps_inputWrapper.className),
3726
- children: jsx("input", {
3727
- id: inputId,
3728
- ref: inputRef,
3729
- name: name,
3730
- type: inputType,
3731
- // Controlled in form / explicit-value mode; uncontrolled with
3732
- // `defaultValue` otherwise. Mirrors the TextField pattern.
3733
- value: nativeValue,
3734
- defaultValue: nativeDefault,
3735
- min: nativeMin,
3736
- max: nativeMax,
3737
- step: step,
3738
- placeholder: placeholder,
3739
- disabled: effectiveDisabled,
3740
- readOnly: effectiveReadOnly,
3741
- required: required,
3742
- "aria-invalid": resolvedError ? true : undefined,
3743
- "aria-describedby": resolvedHelperText ? helperId : undefined,
3744
- onChange: handleChange,
3745
- onBlur: handleBlur,
3746
- className: cn(v.input(), slotProps == null ? void 0 : (_slotProps_input = slotProps.input) == null ? void 0 : _slotProps_input.className)
3747
- })
3748
- }),
3749
- resolvedHelperText && jsx("p", {
3750
- id: helperId,
3751
- className: cn(resolvedError ? v.errorText() : v.helperText(), resolvedError ? slotProps == null ? void 0 : (_slotProps_errorText = slotProps.errorText) == null ? void 0 : _slotProps_errorText.className : slotProps == null ? void 0 : (_slotProps_helperText = slotProps.helperText) == null ? void 0 : _slotProps_helperText.className),
3752
- children: resolvedHelperText
3753
- })
3754
- ]
3755
- });
3756
- }
3757
-
3758
3430
  /**
3759
3431
  * Structural slots for `<Calendar>`.
3760
3432
  *
@@ -3820,7 +3492,7 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
3820
3492
  });
3821
3493
 
3822
3494
  // Inline 16×16 stroke chevrons — no icon dependency (tw convention).
3823
- function ChevronLeftIcon() {
3495
+ function ChevronLeftIcon$1() {
3824
3496
  return jsx("svg", {
3825
3497
  width: "1em",
3826
3498
  height: "1em",
@@ -3836,7 +3508,7 @@ function ChevronLeftIcon() {
3836
3508
  })
3837
3509
  });
3838
3510
  }
3839
- function ChevronRightIcon$1() {
3511
+ function ChevronRightIcon$2() {
3840
3512
  return jsx("svg", {
3841
3513
  width: "1em",
3842
3514
  height: "1em",
@@ -3955,7 +3627,7 @@ function ChevronRightIcon$1() {
3955
3627
  onClick: ()=>{
3956
3628
  calendar.goToPreviousMonth();
3957
3629
  },
3958
- children: jsx(ChevronLeftIcon, {})
3630
+ children: jsx(ChevronLeftIcon$1, {})
3959
3631
  }),
3960
3632
  jsx("span", {
3961
3633
  "aria-live": "polite",
@@ -3970,7 +3642,7 @@ function ChevronRightIcon$1() {
3970
3642
  onClick: ()=>{
3971
3643
  calendar.goToNextMonth();
3972
3644
  },
3973
- children: jsx(ChevronRightIcon$1, {})
3645
+ children: jsx(ChevronRightIcon$2, {})
3974
3646
  })
3975
3647
  ]
3976
3648
  }),
@@ -4143,7 +3815,7 @@ const popoverVariants = tv({
4143
3815
  });
4144
3816
 
4145
3817
  // Inline 16×16 stroke calendar glyph — no icon dependency (tw convention).
4146
- function CalendarIcon() {
3818
+ function CalendarIcon$2() {
4147
3819
  return jsxs("svg", {
4148
3820
  width: "1em",
4149
3821
  height: "1em",
@@ -4365,6 +4037,1150 @@ function CalendarIcon() {
4365
4037
  className: displayValue ? v.value() : v.placeholder(),
4366
4038
  children: displayValue || placeholder || 'Select a date'
4367
4039
  }),
4040
+ jsx("span", {
4041
+ className: v.icon(),
4042
+ children: jsx(CalendarIcon$2, {})
4043
+ })
4044
+ ]
4045
+ })
4046
+ }),
4047
+ resolvedHelperText && jsx("p", {
4048
+ id: helperId,
4049
+ className: cn(resolvedError ? v.errorText() : v.helperText(), resolvedError ? slotProps == null ? void 0 : (_slotProps_errorText = slotProps.errorText) == null ? void 0 : _slotProps_errorText.className : slotProps == null ? void 0 : (_slotProps_helperText = slotProps.helperText) == null ? void 0 : _slotProps_helperText.className),
4050
+ children: resolvedHelperText
4051
+ })
4052
+ ]
4053
+ });
4054
+ }
4055
+
4056
+ /**
4057
+ * Slots for `<TimePicker>` — a bridge-integrated time field whose trigger
4058
+ * is a `<button>` styled as an input, opening a time-list popover.
4059
+ *
4060
+ * Theme identity: bare neutral / brand token-backed classes only — no
4061
+ * `dark:` variants on the neutral palette (the preset CSS-var swap
4062
+ * auto-inverts). See `_shared/themeIdentity.test.ts`.
4063
+ */ const timePickerVariants = tv({
4064
+ slots: {
4065
+ root: 'flex flex-col',
4066
+ label: 'block text-sm font-medium text-neutral-900 mb-1',
4067
+ requiredMark: 'text-danger-500 ml-0.5',
4068
+ trigger: 'flex items-center gap-2 h-10 min-w-[10rem] rounded-md border border-neutral-300 bg-neutral-50 px-3 text-base text-neutral-900 cursor-pointer transition-colors hover:border-neutral-400 focus-visible:outline-none focus-visible:border-primary-500 focus-visible:ring-2 focus-visible:ring-primary-500/30 disabled:cursor-not-allowed disabled:opacity-60 disabled:bg-neutral-200',
4069
+ value: 'flex-1 truncate text-left',
4070
+ placeholder: 'flex-1 truncate text-left text-neutral-400',
4071
+ icon: 'shrink-0 text-[1rem] text-neutral-500',
4072
+ list: 'flex max-h-64 min-w-[8rem] flex-col gap-0.5 overflow-y-auto p-1',
4073
+ option: 'flex w-full cursor-pointer items-center rounded px-2.5 py-1.5 text-sm text-neutral-900 transition-colors hover:bg-neutral-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 aria-selected:bg-primary-600 aria-selected:text-white aria-selected:hover:bg-primary-600 aria-disabled:cursor-default aria-disabled:text-neutral-300 aria-disabled:opacity-60 aria-disabled:hover:bg-transparent',
4074
+ helperText: 'mt-1 text-sm text-neutral-600',
4075
+ errorText: 'mt-1 text-sm text-danger-600'
4076
+ },
4077
+ variants: {
4078
+ layout: {
4079
+ stacked: {},
4080
+ inline: {
4081
+ root: 'flex-row items-start gap-3',
4082
+ label: 'mb-0 pt-2.5 whitespace-nowrap shrink-0'
4083
+ }
4084
+ },
4085
+ error: {
4086
+ true: {
4087
+ trigger: 'border-danger-500 hover:border-danger-500 focus-visible:border-danger-500 focus-visible:ring-danger-500/30'
4088
+ }
4089
+ },
4090
+ fullWidth: {
4091
+ true: {
4092
+ root: 'w-full',
4093
+ trigger: 'w-full min-w-0'
4094
+ }
4095
+ }
4096
+ },
4097
+ defaultVariants: {
4098
+ layout: 'stacked',
4099
+ error: false,
4100
+ fullWidth: false
4101
+ }
4102
+ });
4103
+
4104
+ // Inline 16×16 stroke clock glyph — no icon dependency (tw convention).
4105
+ function ClockIcon() {
4106
+ return jsxs("svg", {
4107
+ width: "1em",
4108
+ height: "1em",
4109
+ viewBox: "0 0 16 16",
4110
+ fill: "none",
4111
+ "aria-hidden": "true",
4112
+ children: [
4113
+ jsx("circle", {
4114
+ cx: "8",
4115
+ cy: "8",
4116
+ r: "6",
4117
+ stroke: "currentColor",
4118
+ strokeWidth: "1.5"
4119
+ }),
4120
+ jsx("path", {
4121
+ d: "M8 4.5V8l2.4 1.4",
4122
+ stroke: "currentColor",
4123
+ strokeWidth: "1.5",
4124
+ strokeLinecap: "round",
4125
+ strokeLinejoin: "round"
4126
+ })
4127
+ ]
4128
+ });
4129
+ }
4130
+ /**
4131
+ * Dashforge TW `<TimePicker>` — a form-bound time-of-day field.
4132
+ *
4133
+ * A read-only trigger button paired with a time-list popover (Radix
4134
+ * Popover). Integrates with the Dashforge form bridge + RBAC.
4135
+ *
4136
+ * Storage contract: a canonical 24-hour `"HH:mm"` string, or `null` —
4137
+ * shared with the MUI `@dashforge/ui` `TimePicker`. `hour12` is display-only.
4138
+ */ function TimePicker(props) {
4139
+ var _timeStringToMinutes, _timeStringToMinutes1;
4140
+ var _slotProps_root, _slotProps_label, _slotProps_requiredMark, _slotProps_trigger, _slotProps_errorText, _slotProps_helperText;
4141
+ const { name, rules, label, helperText, error, required, disabled, placeholder, layout = 'stacked', visibleWhen, access, value: explicitValue, defaultValue, onChange, minTime, maxTime, stepMinutes, hour12 = false, fullWidth, sx, slotProps, testId } = props;
4142
+ const bridge = useContext(DashFormContext);
4143
+ const isVisible = useEngineVisibility(bridge == null ? void 0 : bridge.engine, visibleWhen);
4144
+ const fieldMeta = useDashFieldMeta(name);
4145
+ const accessState = useAccessState(access);
4146
+ const fieldId = useId();
4147
+ const helperId = `${fieldId}-help`;
4148
+ const [isOpen, setIsOpen] = useState(false);
4149
+ const [internalValue, setInternalValue] = useState(defaultValue != null ? defaultValue : null);
4150
+ const unregisterRef = useRef({
4151
+ bridge,
4152
+ name
4153
+ });
4154
+ unregisterRef.current = {
4155
+ bridge,
4156
+ name
4157
+ };
4158
+ const isMountedRef = useRef(false);
4159
+ useEffect(()=>{
4160
+ isMountedRef.current = true;
4161
+ return ()=>{
4162
+ isMountedRef.current = false;
4163
+ const { bridge: cap, name: capName } = unregisterRef.current;
4164
+ queueMicrotask(()=>{
4165
+ var _cap_unregister;
4166
+ if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
4167
+ });
4168
+ };
4169
+ }, []);
4170
+ const effectiveDisabled = Boolean(disabled) || accessState.disabled;
4171
+ const isInteractive = !effectiveDisabled && !accessState.readonly;
4172
+ const isFormMode = Boolean(bridge == null ? void 0 : bridge.register);
4173
+ let resolvedError = error;
4174
+ let resolvedHelperText = helperText;
4175
+ let registration = null;
4176
+ let resolvedValue;
4177
+ if (isFormMode && bridge) {
4178
+ registration = bridge.register(name, rules);
4179
+ const validation = resolveValidationState(name, bridge, error, helperText);
4180
+ resolvedError = validation.error;
4181
+ resolvedHelperText = validation.helperText;
4182
+ if (explicitValue !== undefined) {
4183
+ resolvedValue = explicitValue;
4184
+ } else {
4185
+ const bv = fieldMeta.value;
4186
+ resolvedValue = bv == null ? null : String(bv);
4187
+ }
4188
+ } else if (explicitValue !== undefined) {
4189
+ resolvedValue = explicitValue;
4190
+ } else {
4191
+ resolvedValue = internalValue;
4192
+ }
4193
+ const registrationRefFn = registration == null ? void 0 : registration.ref;
4194
+ const triggerRef = useCallback((instance)=>{
4195
+ if (typeof registrationRefFn === 'function') {
4196
+ registrationRefFn(instance);
4197
+ }
4198
+ }, [
4199
+ registrationRefFn
4200
+ ]);
4201
+ if (!isVisible) return null;
4202
+ if (!accessState.visible) return null;
4203
+ const v = timePickerVariants({
4204
+ layout,
4205
+ error: resolvedError,
4206
+ fullWidth
4207
+ });
4208
+ const displayValue = resolvedValue != null && resolvedValue !== '' ? formatTime(resolvedValue, {
4209
+ hour12
4210
+ }) : '';
4211
+ const options = generateTimeOptions(_extends({}, minTime !== undefined && {
4212
+ start: minTime
4213
+ }, maxTime !== undefined && {
4214
+ end: maxTime
4215
+ }, stepMinutes !== undefined && {
4216
+ stepMinutes
4217
+ }));
4218
+ const minMinutes = (_timeStringToMinutes = timeStringToMinutes(minTime != null ? minTime : '00:00')) != null ? _timeStringToMinutes : 0;
4219
+ const maxMinutes = (_timeStringToMinutes1 = timeStringToMinutes(maxTime != null ? maxTime : '23:59')) != null ? _timeStringToMinutes1 : 1439;
4220
+ const isTimeDisabled = (time)=>{
4221
+ const minutes = timeStringToMinutes(time);
4222
+ return minutes === null || minutes < minMinutes || minutes > maxMinutes;
4223
+ };
4224
+ const commitValue = (next)=>{
4225
+ if (isFormMode && bridge) {
4226
+ var _registration_onChange;
4227
+ bridge.setValue == null ? void 0 : bridge.setValue.call(bridge, name, next);
4228
+ void (registration == null ? void 0 : (_registration_onChange = registration.onChange) == null ? void 0 : _registration_onChange.call(registration, {
4229
+ target: {
4230
+ name,
4231
+ value: next != null ? next : ''
4232
+ },
4233
+ type: 'change'
4234
+ }));
4235
+ } else if (explicitValue === undefined) {
4236
+ setInternalValue(next);
4237
+ }
4238
+ onChange == null ? void 0 : onChange(next);
4239
+ };
4240
+ const markTouched = ()=>{
4241
+ if (isFormMode && bridge) {
4242
+ var _registration_onBlur;
4243
+ const committed = bridge.getValue(name);
4244
+ void (registration == null ? void 0 : (_registration_onBlur = registration.onBlur) == null ? void 0 : _registration_onBlur.call(registration, {
4245
+ target: {
4246
+ name,
4247
+ value: committed == null ? '' : String(committed)
4248
+ },
4249
+ type: 'blur'
4250
+ }));
4251
+ }
4252
+ };
4253
+ const handleOpenChange = (next)=>{
4254
+ if (next && !isInteractive) {
4255
+ return;
4256
+ }
4257
+ setIsOpen(next);
4258
+ if (!next) {
4259
+ markTouched();
4260
+ }
4261
+ };
4262
+ const handleSelect = (time)=>{
4263
+ if (isTimeDisabled(time)) {
4264
+ return;
4265
+ }
4266
+ commitValue(time);
4267
+ setIsOpen(false);
4268
+ markTouched();
4269
+ };
4270
+ return jsxs("div", {
4271
+ "data-testid": testId,
4272
+ className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root = slotProps.root) == null ? void 0 : _slotProps_root.className),
4273
+ children: [
4274
+ label && jsxs("label", {
4275
+ htmlFor: fieldId,
4276
+ className: cn(v.label(), slotProps == null ? void 0 : (_slotProps_label = slotProps.label) == null ? void 0 : _slotProps_label.className),
4277
+ children: [
4278
+ label,
4279
+ required && jsx("span", {
4280
+ "aria-hidden": "true",
4281
+ className: cn(v.requiredMark(), slotProps == null ? void 0 : (_slotProps_requiredMark = slotProps.requiredMark) == null ? void 0 : _slotProps_requiredMark.className),
4282
+ children: "*"
4283
+ })
4284
+ ]
4285
+ }),
4286
+ jsx(Popover, {
4287
+ open: isOpen,
4288
+ onOpenChange: handleOpenChange,
4289
+ side: "bottom",
4290
+ align: "start",
4291
+ content: jsx("div", {
4292
+ role: "listbox",
4293
+ "aria-label": "Time options",
4294
+ className: v.list(),
4295
+ children: options.map((time)=>jsx("button", {
4296
+ type: "button",
4297
+ role: "option",
4298
+ "aria-selected": time === resolvedValue,
4299
+ "aria-disabled": isTimeDisabled(time),
4300
+ className: v.option(),
4301
+ onClick: ()=>{
4302
+ handleSelect(time);
4303
+ },
4304
+ children: formatTime(time, {
4305
+ hour12
4306
+ })
4307
+ }, time))
4308
+ }),
4309
+ children: jsxs("button", {
4310
+ type: "button",
4311
+ id: fieldId,
4312
+ ref: triggerRef,
4313
+ disabled: effectiveDisabled,
4314
+ "aria-invalid": resolvedError ? true : undefined,
4315
+ "aria-describedby": resolvedHelperText ? helperId : undefined,
4316
+ className: cn(v.trigger(), slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
4317
+ children: [
4318
+ jsx("span", {
4319
+ className: displayValue ? v.value() : v.placeholder(),
4320
+ children: displayValue || placeholder || 'Select a time'
4321
+ }),
4322
+ jsx("span", {
4323
+ className: v.icon(),
4324
+ children: jsx(ClockIcon, {})
4325
+ })
4326
+ ]
4327
+ })
4328
+ }),
4329
+ resolvedHelperText && jsx("p", {
4330
+ id: helperId,
4331
+ className: cn(resolvedError ? v.errorText() : v.helperText(), resolvedError ? slotProps == null ? void 0 : (_slotProps_errorText = slotProps.errorText) == null ? void 0 : _slotProps_errorText.className : slotProps == null ? void 0 : (_slotProps_helperText = slotProps.helperText) == null ? void 0 : _slotProps_helperText.className),
4332
+ children: resolvedHelperText
4333
+ })
4334
+ ]
4335
+ });
4336
+ }
4337
+
4338
+ /**
4339
+ * Slots for `<DateTimePicker>` — a bridge-integrated date+time field whose
4340
+ * trigger is a `<button>` styled as an input, opening a popover that
4341
+ * combines a `<Calendar>` with a time list.
4342
+ *
4343
+ * Theme identity: bare neutral / brand token-backed classes only — no
4344
+ * `dark:` variants on the neutral palette (the preset CSS-var swap
4345
+ * auto-inverts). See `_shared/themeIdentity.test.ts`.
4346
+ */ const dateTimePickerVariants = tv({
4347
+ slots: {
4348
+ root: 'flex flex-col',
4349
+ label: 'block text-sm font-medium text-neutral-900 mb-1',
4350
+ requiredMark: 'text-danger-500 ml-0.5',
4351
+ trigger: 'flex items-center gap-2 h-10 min-w-[13rem] rounded-md border border-neutral-300 bg-neutral-50 px-3 text-base text-neutral-900 cursor-pointer transition-colors hover:border-neutral-400 focus-visible:outline-none focus-visible:border-primary-500 focus-visible:ring-2 focus-visible:ring-primary-500/30 disabled:cursor-not-allowed disabled:opacity-60 disabled:bg-neutral-200',
4352
+ value: 'flex-1 truncate text-left',
4353
+ placeholder: 'flex-1 truncate text-left text-neutral-400',
4354
+ icon: 'shrink-0 text-[1rem] text-neutral-500',
4355
+ panel: 'flex items-stretch',
4356
+ list: 'flex max-h-[19rem] min-w-[6.5rem] flex-col gap-0.5 overflow-y-auto border-l border-neutral-200 p-1',
4357
+ option: 'flex w-full cursor-pointer items-center rounded px-2.5 py-1.5 text-sm text-neutral-900 transition-colors hover:bg-neutral-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500 aria-selected:bg-primary-600 aria-selected:text-white aria-selected:hover:bg-primary-600',
4358
+ helperText: 'mt-1 text-sm text-neutral-600',
4359
+ errorText: 'mt-1 text-sm text-danger-600'
4360
+ },
4361
+ variants: {
4362
+ layout: {
4363
+ stacked: {},
4364
+ inline: {
4365
+ root: 'flex-row items-start gap-3',
4366
+ label: 'mb-0 pt-2.5 whitespace-nowrap shrink-0'
4367
+ }
4368
+ },
4369
+ error: {
4370
+ true: {
4371
+ trigger: 'border-danger-500 hover:border-danger-500 focus-visible:border-danger-500 focus-visible:ring-danger-500/30'
4372
+ }
4373
+ },
4374
+ fullWidth: {
4375
+ true: {
4376
+ root: 'w-full',
4377
+ trigger: 'w-full min-w-0'
4378
+ }
4379
+ }
4380
+ },
4381
+ defaultVariants: {
4382
+ layout: 'stacked',
4383
+ error: false,
4384
+ fullWidth: false
4385
+ }
4386
+ });
4387
+
4388
+ // Inline 16×16 stroke calendar glyph — no icon dependency (tw convention).
4389
+ function CalendarIcon$1() {
4390
+ return jsxs("svg", {
4391
+ width: "1em",
4392
+ height: "1em",
4393
+ viewBox: "0 0 16 16",
4394
+ fill: "none",
4395
+ "aria-hidden": "true",
4396
+ children: [
4397
+ jsx("rect", {
4398
+ x: "2.5",
4399
+ y: "3.5",
4400
+ width: "11",
4401
+ height: "10",
4402
+ rx: "1.5",
4403
+ stroke: "currentColor",
4404
+ strokeWidth: "1.5"
4405
+ }),
4406
+ jsx("path", {
4407
+ d: "M2.5 6.5h11M5.5 2v3M10.5 2v3",
4408
+ stroke: "currentColor",
4409
+ strokeWidth: "1.5",
4410
+ strokeLinecap: "round"
4411
+ })
4412
+ ]
4413
+ });
4414
+ }
4415
+ const DATETIME_PATTERN = /^(\d{4}-\d{2}-\d{2})T(\d{2}):(\d{2})/;
4416
+ /** Splits a stored `YYYY-MM-DDTHH:mm` value into its date and time parts. */ function splitDateTime(value) {
4417
+ if (value == null || value === '') {
4418
+ return {
4419
+ date: null,
4420
+ time: null
4421
+ };
4422
+ }
4423
+ const match = DATETIME_PATTERN.exec(value);
4424
+ if (match !== null) {
4425
+ var _match_, _match_1, _match_2;
4426
+ return {
4427
+ date: (_match_ = match[1]) != null ? _match_ : null,
4428
+ time: `${(_match_1 = match[2]) != null ? _match_1 : '00'}:${(_match_2 = match[3]) != null ? _match_2 : '00'}`
4429
+ };
4430
+ }
4431
+ return {
4432
+ date: parseISODate(value) !== null ? value : null,
4433
+ time: null
4434
+ };
4435
+ }
4436
+ /** Combines a date and a time into a `YYYY-MM-DDTHH:mm` value (or `null`). */ function joinDateTime(date, time) {
4437
+ if (date === null && time === null) {
4438
+ return null;
4439
+ }
4440
+ return `${date != null ? date : getTodayISODate()}T${time != null ? time : '00:00'}`;
4441
+ }
4442
+ /** Formats a stored datetime for the trigger display. */ function formatDateTime(value, locale, hour12) {
4443
+ const { date, time } = splitDateTime(value);
4444
+ const parts = [];
4445
+ if (date !== null) {
4446
+ const parsed = parseISODate(date);
4447
+ parts.push(parsed === null ? date : new Intl.DateTimeFormat(locale, {
4448
+ dateStyle: 'medium',
4449
+ timeZone: 'UTC'
4450
+ }).format(Date.UTC(parsed.year, parsed.month - 1, parsed.day)));
4451
+ }
4452
+ if (time !== null) {
4453
+ parts.push(formatTime(time, {
4454
+ hour12
4455
+ }));
4456
+ }
4457
+ return parts.join(', ');
4458
+ }
4459
+ /**
4460
+ * Dashforge TW `<DateTimePicker>` — a form-bound date + time field.
4461
+ *
4462
+ * A read-only trigger button paired with a popover combining a `<Calendar>`
4463
+ * and a time list (Radix Popover). Integrates with the Dashforge form
4464
+ * bridge + RBAC.
4465
+ *
4466
+ * Storage contract: a naive ISO datetime `"YYYY-MM-DDTHH:mm"` — no seconds,
4467
+ * no timezone. Shared with the MUI `@dashforge/ui` `DateTimePicker`.
4468
+ */ function DateTimePicker(props) {
4469
+ var _slotProps_root, _slotProps_label, _slotProps_requiredMark, _slotProps_trigger, _slotProps_errorText, _slotProps_helperText;
4470
+ const { name, rules, label, helperText, error, required, disabled, placeholder, layout = 'stacked', visibleWhen, access, value: explicitValue, defaultValue, onChange, minDate, maxDate, disabledDates, isDateDisabled, weekStartDay, locale, stepMinutes, hour12 = false, fullWidth, sx, slotProps, testId } = props;
4471
+ const bridge = useContext(DashFormContext);
4472
+ const isVisible = useEngineVisibility(bridge == null ? void 0 : bridge.engine, visibleWhen);
4473
+ const fieldMeta = useDashFieldMeta(name);
4474
+ const accessState = useAccessState(access);
4475
+ const fieldId = useId();
4476
+ const helperId = `${fieldId}-help`;
4477
+ const [isOpen, setIsOpen] = useState(false);
4478
+ const [internalValue, setInternalValue] = useState(defaultValue != null ? defaultValue : null);
4479
+ const unregisterRef = useRef({
4480
+ bridge,
4481
+ name
4482
+ });
4483
+ unregisterRef.current = {
4484
+ bridge,
4485
+ name
4486
+ };
4487
+ const isMountedRef = useRef(false);
4488
+ useEffect(()=>{
4489
+ isMountedRef.current = true;
4490
+ return ()=>{
4491
+ isMountedRef.current = false;
4492
+ const { bridge: cap, name: capName } = unregisterRef.current;
4493
+ queueMicrotask(()=>{
4494
+ var _cap_unregister;
4495
+ if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
4496
+ });
4497
+ };
4498
+ }, []);
4499
+ const effectiveDisabled = Boolean(disabled) || accessState.disabled;
4500
+ const isInteractive = !effectiveDisabled && !accessState.readonly;
4501
+ const isFormMode = Boolean(bridge == null ? void 0 : bridge.register);
4502
+ let resolvedError = error;
4503
+ let resolvedHelperText = helperText;
4504
+ let registration = null;
4505
+ let resolvedValue;
4506
+ if (isFormMode && bridge) {
4507
+ registration = bridge.register(name, rules);
4508
+ const validation = resolveValidationState(name, bridge, error, helperText);
4509
+ resolvedError = validation.error;
4510
+ resolvedHelperText = validation.helperText;
4511
+ if (explicitValue !== undefined) {
4512
+ resolvedValue = explicitValue;
4513
+ } else {
4514
+ const bv = fieldMeta.value;
4515
+ resolvedValue = bv == null ? null : String(bv);
4516
+ }
4517
+ } else if (explicitValue !== undefined) {
4518
+ resolvedValue = explicitValue;
4519
+ } else {
4520
+ resolvedValue = internalValue;
4521
+ }
4522
+ const registrationRefFn = registration == null ? void 0 : registration.ref;
4523
+ const triggerRef = useCallback((instance)=>{
4524
+ if (typeof registrationRefFn === 'function') {
4525
+ registrationRefFn(instance);
4526
+ }
4527
+ }, [
4528
+ registrationRefFn
4529
+ ]);
4530
+ if (!isVisible) return null;
4531
+ if (!accessState.visible) return null;
4532
+ const v = dateTimePickerVariants({
4533
+ layout,
4534
+ error: resolvedError,
4535
+ fullWidth
4536
+ });
4537
+ const resolvedLocale = locale != null ? locale : 'en-US';
4538
+ const { date, time } = splitDateTime(resolvedValue);
4539
+ const displayValue = formatDateTime(resolvedValue, resolvedLocale, hour12);
4540
+ const options = generateTimeOptions(_extends({}, stepMinutes !== undefined && {
4541
+ stepMinutes
4542
+ }));
4543
+ const commitValue = (next)=>{
4544
+ if (isFormMode && bridge) {
4545
+ var _registration_onChange;
4546
+ bridge.setValue == null ? void 0 : bridge.setValue.call(bridge, name, next);
4547
+ void (registration == null ? void 0 : (_registration_onChange = registration.onChange) == null ? void 0 : _registration_onChange.call(registration, {
4548
+ target: {
4549
+ name,
4550
+ value: next != null ? next : ''
4551
+ },
4552
+ type: 'change'
4553
+ }));
4554
+ } else if (explicitValue === undefined) {
4555
+ setInternalValue(next);
4556
+ }
4557
+ onChange == null ? void 0 : onChange(next);
4558
+ };
4559
+ const markTouched = ()=>{
4560
+ if (isFormMode && bridge) {
4561
+ var _registration_onBlur;
4562
+ const committed = bridge.getValue(name);
4563
+ void (registration == null ? void 0 : (_registration_onBlur = registration.onBlur) == null ? void 0 : _registration_onBlur.call(registration, {
4564
+ target: {
4565
+ name,
4566
+ value: committed == null ? '' : String(committed)
4567
+ },
4568
+ type: 'blur'
4569
+ }));
4570
+ }
4571
+ };
4572
+ const handleOpenChange = (next)=>{
4573
+ if (next && !isInteractive) {
4574
+ return;
4575
+ }
4576
+ setIsOpen(next);
4577
+ if (!next) {
4578
+ markTouched();
4579
+ }
4580
+ };
4581
+ // Picking a date keeps the popover open — the user still needs a time.
4582
+ const handleDateSelect = (nextDate)=>{
4583
+ commitValue(joinDateTime(nextDate, time));
4584
+ };
4585
+ // Picking a time completes the value and closes the popover.
4586
+ const handleTimeSelect = (nextTime)=>{
4587
+ commitValue(joinDateTime(date, nextTime));
4588
+ setIsOpen(false);
4589
+ markTouched();
4590
+ };
4591
+ return jsxs("div", {
4592
+ "data-testid": testId,
4593
+ className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root = slotProps.root) == null ? void 0 : _slotProps_root.className),
4594
+ children: [
4595
+ label && jsxs("label", {
4596
+ htmlFor: fieldId,
4597
+ className: cn(v.label(), slotProps == null ? void 0 : (_slotProps_label = slotProps.label) == null ? void 0 : _slotProps_label.className),
4598
+ children: [
4599
+ label,
4600
+ required && jsx("span", {
4601
+ "aria-hidden": "true",
4602
+ className: cn(v.requiredMark(), slotProps == null ? void 0 : (_slotProps_requiredMark = slotProps.requiredMark) == null ? void 0 : _slotProps_requiredMark.className),
4603
+ children: "*"
4604
+ })
4605
+ ]
4606
+ }),
4607
+ jsx(Popover, {
4608
+ open: isOpen,
4609
+ onOpenChange: handleOpenChange,
4610
+ side: "bottom",
4611
+ align: "start",
4612
+ content: jsxs("div", {
4613
+ className: v.panel(),
4614
+ children: [
4615
+ jsx(Calendar, {
4616
+ value: date,
4617
+ onChange: handleDateSelect,
4618
+ minDate: minDate,
4619
+ maxDate: maxDate,
4620
+ disabledDates: disabledDates,
4621
+ isDateDisabled: isDateDisabled,
4622
+ weekStartDay: weekStartDay,
4623
+ locale: locale,
4624
+ "aria-label": "Choose date",
4625
+ sx: "border-0 bg-transparent p-0"
4626
+ }),
4627
+ jsx("div", {
4628
+ role: "listbox",
4629
+ "aria-label": "Time options",
4630
+ className: v.list(),
4631
+ children: options.map((option)=>jsx("button", {
4632
+ type: "button",
4633
+ role: "option",
4634
+ "aria-selected": option === time,
4635
+ className: v.option(),
4636
+ onClick: ()=>{
4637
+ handleTimeSelect(option);
4638
+ },
4639
+ children: formatTime(option, {
4640
+ hour12
4641
+ })
4642
+ }, option))
4643
+ })
4644
+ ]
4645
+ }),
4646
+ children: jsxs("button", {
4647
+ type: "button",
4648
+ id: fieldId,
4649
+ ref: triggerRef,
4650
+ disabled: effectiveDisabled,
4651
+ "aria-invalid": resolvedError ? true : undefined,
4652
+ "aria-describedby": resolvedHelperText ? helperId : undefined,
4653
+ className: cn(v.trigger(), slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
4654
+ children: [
4655
+ jsx("span", {
4656
+ className: displayValue ? v.value() : v.placeholder(),
4657
+ children: displayValue || placeholder || 'Select date and time'
4658
+ }),
4659
+ jsx("span", {
4660
+ className: v.icon(),
4661
+ children: jsx(CalendarIcon$1, {})
4662
+ })
4663
+ ]
4664
+ })
4665
+ }),
4666
+ resolvedHelperText && jsx("p", {
4667
+ id: helperId,
4668
+ className: cn(resolvedError ? v.errorText() : v.helperText(), resolvedError ? slotProps == null ? void 0 : (_slotProps_errorText = slotProps.errorText) == null ? void 0 : _slotProps_errorText.className : slotProps == null ? void 0 : (_slotProps_helperText = slotProps.helperText) == null ? void 0 : _slotProps_helperText.className),
4669
+ children: resolvedHelperText
4670
+ })
4671
+ ]
4672
+ });
4673
+ }
4674
+
4675
+ /**
4676
+ * Slots for `<DateRangePicker>` — a bridge-integrated start/end date field
4677
+ * whose trigger is a `<button>` styled as an input, opening a dual-month
4678
+ * range calendar popover.
4679
+ *
4680
+ * Theme identity: bare neutral / brand token-backed classes only — no
4681
+ * `dark:` variants on the neutral palette (the preset CSS-var swap
4682
+ * auto-inverts). See `_shared/themeIdentity.test.ts`.
4683
+ */ const dateRangePickerVariants = tv({
4684
+ slots: {
4685
+ root: 'flex flex-col',
4686
+ label: 'block text-sm font-medium text-neutral-900 mb-1',
4687
+ requiredMark: 'text-danger-500 ml-0.5',
4688
+ trigger: 'flex items-center gap-2 h-10 min-w-[15rem] rounded-md border border-neutral-300 bg-neutral-50 px-3 text-base text-neutral-900 cursor-pointer transition-colors hover:border-neutral-400 focus-visible:outline-none focus-visible:border-primary-500 focus-visible:ring-2 focus-visible:ring-primary-500/30 disabled:cursor-not-allowed disabled:opacity-60 disabled:bg-neutral-200',
4689
+ value: 'flex-1 truncate text-left',
4690
+ placeholder: 'flex-1 truncate text-left text-neutral-400',
4691
+ icon: 'shrink-0 text-[1rem] text-neutral-500',
4692
+ panel: 'flex gap-3 p-3 select-none',
4693
+ month: 'flex flex-col gap-2',
4694
+ header: 'flex items-center justify-between gap-1',
4695
+ navButton: 'inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-[1rem] text-neutral-600 transition-colors hover:bg-neutral-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500',
4696
+ navSpacer: 'h-7 w-7 shrink-0',
4697
+ monthLabel: 'flex-1 text-center text-sm font-semibold text-neutral-900',
4698
+ grid: 'flex flex-col gap-1',
4699
+ weekdayRow: 'grid grid-cols-7 gap-1',
4700
+ weekday: 'flex h-8 items-center justify-center text-xs font-semibold text-neutral-500',
4701
+ weekRow: 'grid grid-cols-7 gap-1',
4702
+ helperText: 'mt-1 text-sm text-neutral-600',
4703
+ errorText: 'mt-1 text-sm text-danger-600'
4704
+ },
4705
+ variants: {
4706
+ layout: {
4707
+ stacked: {},
4708
+ inline: {
4709
+ root: 'flex-row items-start gap-3',
4710
+ label: 'mb-0 pt-2.5 whitespace-nowrap shrink-0'
4711
+ }
4712
+ },
4713
+ error: {
4714
+ true: {
4715
+ trigger: 'border-danger-500 hover:border-danger-500 focus-visible:border-danger-500 focus-visible:ring-danger-500/30'
4716
+ }
4717
+ },
4718
+ fullWidth: {
4719
+ true: {
4720
+ root: 'w-full',
4721
+ trigger: 'w-full min-w-0'
4722
+ }
4723
+ }
4724
+ },
4725
+ defaultVariants: {
4726
+ layout: 'stacked',
4727
+ error: false,
4728
+ fullWidth: false
4729
+ }
4730
+ });
4731
+ /**
4732
+ * Per-day-cell recipe for the range grid. `endpoint` (a committed start/end)
4733
+ * is the solid fill; `inBand` (inside the committed or previewed range) is
4734
+ * the light tint. Declared `inBand` before `endpoint` so an endpoint cell —
4735
+ * which is also in-band — resolves to the solid fill.
4736
+ */ const dateRangeDayVariants = tv({
4737
+ base: 'flex h-9 w-9 items-center justify-center rounded-md text-sm text-neutral-900 transition-colors hover:bg-neutral-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-500',
4738
+ variants: {
4739
+ inBand: {
4740
+ true: 'bg-primary-100 hover:bg-primary-100'
4741
+ },
4742
+ endpoint: {
4743
+ true: 'bg-primary-600 text-white hover:bg-primary-600'
4744
+ },
4745
+ siblingMonth: {
4746
+ true: 'text-neutral-400'
4747
+ },
4748
+ today: {
4749
+ true: 'font-bold ring-1 ring-inset ring-primary-400'
4750
+ },
4751
+ disabled: {
4752
+ true: 'cursor-default text-neutral-300 opacity-60 hover:bg-transparent'
4753
+ }
4754
+ },
4755
+ compoundVariants: [
4756
+ {
4757
+ endpoint: true,
4758
+ today: true,
4759
+ class: 'ring-0'
4760
+ },
4761
+ {
4762
+ endpoint: true,
4763
+ siblingMonth: true,
4764
+ class: 'text-white'
4765
+ }
4766
+ ],
4767
+ defaultVariants: {
4768
+ inBand: false,
4769
+ endpoint: false,
4770
+ siblingMonth: false,
4771
+ today: false,
4772
+ disabled: false
4773
+ }
4774
+ });
4775
+
4776
+ const EMPTY_RANGE = {
4777
+ start: null,
4778
+ end: null
4779
+ };
4780
+ function CalendarIcon() {
4781
+ return jsxs("svg", {
4782
+ width: "1em",
4783
+ height: "1em",
4784
+ viewBox: "0 0 16 16",
4785
+ fill: "none",
4786
+ "aria-hidden": "true",
4787
+ children: [
4788
+ jsx("rect", {
4789
+ x: "2.5",
4790
+ y: "3.5",
4791
+ width: "11",
4792
+ height: "10",
4793
+ rx: "1.5",
4794
+ stroke: "currentColor",
4795
+ strokeWidth: "1.5"
4796
+ }),
4797
+ jsx("path", {
4798
+ d: "M2.5 6.5h11M5.5 2v3M10.5 2v3",
4799
+ stroke: "currentColor",
4800
+ strokeWidth: "1.5",
4801
+ strokeLinecap: "round"
4802
+ })
4803
+ ]
4804
+ });
4805
+ }
4806
+ function ChevronLeftIcon() {
4807
+ return jsx("svg", {
4808
+ width: "1em",
4809
+ height: "1em",
4810
+ viewBox: "0 0 16 16",
4811
+ fill: "none",
4812
+ "aria-hidden": "true",
4813
+ children: jsx("path", {
4814
+ d: "M10 4 6 8l4 4",
4815
+ stroke: "currentColor",
4816
+ strokeWidth: "1.5",
4817
+ strokeLinecap: "round",
4818
+ strokeLinejoin: "round"
4819
+ })
4820
+ });
4821
+ }
4822
+ function ChevronRightIcon$1() {
4823
+ return jsx("svg", {
4824
+ width: "1em",
4825
+ height: "1em",
4826
+ viewBox: "0 0 16 16",
4827
+ fill: "none",
4828
+ "aria-hidden": "true",
4829
+ children: jsx("path", {
4830
+ d: "m6 4 4 4-4 4",
4831
+ stroke: "currentColor",
4832
+ strokeWidth: "1.5",
4833
+ strokeLinecap: "round",
4834
+ strokeLinejoin: "round"
4835
+ })
4836
+ });
4837
+ }
4838
+ /** Formats a stored ISO date for the trigger display (medium style). */ function formatEndpoint(iso, locale) {
4839
+ if (iso === null || iso === '') {
4840
+ return '';
4841
+ }
4842
+ const parts = parseISODate(iso);
4843
+ if (parts === null) {
4844
+ return iso;
4845
+ }
4846
+ return new Intl.DateTimeFormat(locale, {
4847
+ dateStyle: 'medium',
4848
+ timeZone: 'UTC'
4849
+ }).format(Date.UTC(parts.year, parts.month - 1, parts.day));
4850
+ }
4851
+ function formatRange(range, locale) {
4852
+ const start = formatEndpoint(range.start, locale);
4853
+ const end = formatEndpoint(range.end, locale);
4854
+ if (start === '') {
4855
+ return '';
4856
+ }
4857
+ return end === '' ? start : `${start} – ${end}`;
4858
+ }
4859
+ /** The dual-month range grid rendered inside the popover. */ function RangeCalendar(props) {
4860
+ const { value, onChange, minDate, maxDate, disabledDates, isDateDisabled, weekStartDay, locale } = props;
4861
+ const range = useDateRange(_extends({
4862
+ value,
4863
+ onChange,
4864
+ monthCount: 2
4865
+ }, minDate !== undefined && {
4866
+ minDate
4867
+ }, maxDate !== undefined && {
4868
+ maxDate
4869
+ }, disabledDates !== undefined && {
4870
+ disabledDates
4871
+ }, isDateDisabled !== undefined && {
4872
+ isDateDisabled
4873
+ }, weekStartDay !== undefined && {
4874
+ weekStartDay
4875
+ }, locale !== undefined && {
4876
+ locale
4877
+ }));
4878
+ const focusedCellRef = useRef(null);
4879
+ const shouldFocusRef = useRef(false);
4880
+ useEffect(()=>{
4881
+ if (shouldFocusRef.current && focusedCellRef.current) {
4882
+ focusedCellRef.current.focus({
4883
+ preventScroll: true
4884
+ });
4885
+ shouldFocusRef.current = false;
4886
+ }
4887
+ }, [
4888
+ range.focusedDate
4889
+ ]);
4890
+ const handleKeyDown = (event)=>{
4891
+ const action = resolveCalendarKey(event.key);
4892
+ if (action === null) {
4893
+ return;
4894
+ }
4895
+ event.preventDefault();
4896
+ shouldFocusRef.current = true;
4897
+ switch(action){
4898
+ case 'select':
4899
+ range.selectDate(range.focusedDate);
4900
+ break;
4901
+ case 'monthForward':
4902
+ range.goToNextMonth();
4903
+ break;
4904
+ case 'monthBackward':
4905
+ range.goToPreviousMonth();
4906
+ break;
4907
+ default:
4908
+ range.navigate(action);
4909
+ }
4910
+ };
4911
+ const v = dateRangePickerVariants();
4912
+ const resolvedLocale = locale != null ? locale : 'en-US';
4913
+ const lastIndex = range.months.length - 1;
4914
+ return jsx("div", {
4915
+ className: v.panel(),
4916
+ onMouseLeave: ()=>{
4917
+ range.hoverDate(null);
4918
+ },
4919
+ children: range.months.map((monthView, monthIndex)=>jsxs("div", {
4920
+ className: v.month(),
4921
+ children: [
4922
+ jsxs("div", {
4923
+ className: v.header(),
4924
+ children: [
4925
+ monthIndex === 0 ? jsx("button", {
4926
+ type: "button",
4927
+ className: v.navButton(),
4928
+ "aria-label": "Previous month",
4929
+ onClick: ()=>{
4930
+ range.goToPreviousMonth();
4931
+ },
4932
+ children: jsx(ChevronLeftIcon, {})
4933
+ }) : jsx("span", {
4934
+ className: v.navSpacer()
4935
+ }),
4936
+ jsx("span", {
4937
+ "aria-live": "polite",
4938
+ className: v.monthLabel(),
4939
+ children: monthView.monthLabel
4940
+ }),
4941
+ monthIndex === lastIndex ? jsx("button", {
4942
+ type: "button",
4943
+ className: v.navButton(),
4944
+ "aria-label": "Next month",
4945
+ onClick: ()=>{
4946
+ range.goToNextMonth();
4947
+ },
4948
+ children: jsx(ChevronRightIcon$1, {})
4949
+ }) : jsx("span", {
4950
+ className: v.navSpacer()
4951
+ })
4952
+ ]
4953
+ }),
4954
+ jsxs("div", {
4955
+ role: "grid",
4956
+ "aria-label": "Choose date range",
4957
+ onKeyDown: handleKeyDown,
4958
+ className: v.grid(),
4959
+ children: [
4960
+ jsx("div", {
4961
+ role: "row",
4962
+ className: v.weekdayRow(),
4963
+ children: range.weekdayNames.map((dayName, index)=>jsx("span", {
4964
+ role: "columnheader",
4965
+ className: v.weekday(),
4966
+ children: dayName
4967
+ }, `weekday-${String(index)}`))
4968
+ }),
4969
+ monthView.weeks.map((week)=>jsx("div", {
4970
+ role: "row",
4971
+ className: v.weekRow(),
4972
+ children: week.days.map((day)=>{
4973
+ const isActiveCell = day.iso === range.focusedDate;
4974
+ const endpoint = day.isRangeStart || day.isRangeEnd;
4975
+ const inBand = day.isInRange || day.isRangePreview;
4976
+ return jsx("span", {
4977
+ role: "gridcell",
4978
+ className: "flex",
4979
+ children: jsx("button", {
4980
+ type: "button",
4981
+ ref: isActiveCell ? focusedCellRef : null,
4982
+ tabIndex: isActiveCell ? 0 : -1,
4983
+ "aria-label": formatLongDate({
4984
+ year: day.year,
4985
+ month: day.month,
4986
+ day: day.day
4987
+ }, resolvedLocale),
4988
+ "aria-current": day.isToday ? 'date' : undefined,
4989
+ "aria-pressed": endpoint,
4990
+ "aria-disabled": day.isDisabled,
4991
+ onClick: ()=>{
4992
+ range.selectDate(day.iso);
4993
+ },
4994
+ onMouseEnter: ()=>{
4995
+ range.hoverDate(day.iso);
4996
+ },
4997
+ className: dateRangeDayVariants({
4998
+ inBand,
4999
+ endpoint,
5000
+ siblingMonth: day.isSiblingMonth,
5001
+ today: day.isToday,
5002
+ disabled: day.isDisabled
5003
+ }),
5004
+ children: day.day
5005
+ })
5006
+ }, day.iso);
5007
+ })
5008
+ }, week.key))
5009
+ ]
5010
+ })
5011
+ ]
5012
+ }, `${String(monthView.year)}-${String(monthView.month)}`))
5013
+ });
5014
+ }
5015
+ /**
5016
+ * Dashforge TW `<DateRangePicker>` — a form-bound start/end date field.
5017
+ *
5018
+ * A read-only trigger button paired with a dual-month range calendar popover
5019
+ * (Radix Popover), built on the headless `useDateRange` engine. Integrates
5020
+ * with the Dashforge form bridge + RBAC.
5021
+ *
5022
+ * Storage contract: a `{ start, end }` pair of ISO `YYYY-MM-DD` dates —
5023
+ * shared with the MUI `@dashforge/ui` `DateRangePicker`.
5024
+ */ function DateRangePicker(props) {
5025
+ var _slotProps_root, _slotProps_label, _slotProps_requiredMark, _slotProps_trigger, _slotProps_errorText, _slotProps_helperText;
5026
+ const { name, rules, label, helperText, error, required, disabled, placeholder, layout = 'stacked', visibleWhen, access, value: explicitValue, defaultValue, onChange, minDate, maxDate, disabledDates, isDateDisabled, weekStartDay, locale, fullWidth, sx, slotProps, testId } = props;
5027
+ const bridge = useContext(DashFormContext);
5028
+ const isVisible = useEngineVisibility(bridge == null ? void 0 : bridge.engine, visibleWhen);
5029
+ const fieldMeta = useDashFieldMeta(name);
5030
+ const accessState = useAccessState(access);
5031
+ const fieldId = useId();
5032
+ const helperId = `${fieldId}-help`;
5033
+ const [isOpen, setIsOpen] = useState(false);
5034
+ const [internalValue, setInternalValue] = useState(defaultValue != null ? defaultValue : EMPTY_RANGE);
5035
+ const unregisterRef = useRef({
5036
+ bridge,
5037
+ name
5038
+ });
5039
+ unregisterRef.current = {
5040
+ bridge,
5041
+ name
5042
+ };
5043
+ const isMountedRef = useRef(false);
5044
+ useEffect(()=>{
5045
+ isMountedRef.current = true;
5046
+ return ()=>{
5047
+ isMountedRef.current = false;
5048
+ const { bridge: cap, name: capName } = unregisterRef.current;
5049
+ queueMicrotask(()=>{
5050
+ var _cap_unregister;
5051
+ if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
5052
+ });
5053
+ };
5054
+ }, []);
5055
+ const effectiveDisabled = Boolean(disabled) || accessState.disabled;
5056
+ const isInteractive = !effectiveDisabled && !accessState.readonly;
5057
+ const isFormMode = Boolean(bridge == null ? void 0 : bridge.register);
5058
+ let resolvedError = error;
5059
+ let resolvedHelperText = helperText;
5060
+ let registration = null;
5061
+ let resolvedValue;
5062
+ if (isFormMode && bridge) {
5063
+ registration = bridge.register(name, rules);
5064
+ const validation = resolveValidationState(name, bridge, error, helperText);
5065
+ resolvedError = validation.error;
5066
+ resolvedHelperText = validation.helperText;
5067
+ if (explicitValue !== undefined) {
5068
+ resolvedValue = explicitValue;
5069
+ } else {
5070
+ const bv = fieldMeta.value;
5071
+ resolvedValue = bv != null ? bv : EMPTY_RANGE;
5072
+ }
5073
+ } else if (explicitValue !== undefined) {
5074
+ resolvedValue = explicitValue;
5075
+ } else {
5076
+ resolvedValue = internalValue;
5077
+ }
5078
+ const registrationRefFn = registration == null ? void 0 : registration.ref;
5079
+ const triggerRef = useCallback((instance)=>{
5080
+ if (typeof registrationRefFn === 'function') {
5081
+ registrationRefFn(instance);
5082
+ }
5083
+ }, [
5084
+ registrationRefFn
5085
+ ]);
5086
+ if (!isVisible) return null;
5087
+ if (!accessState.visible) return null;
5088
+ const v = dateRangePickerVariants({
5089
+ layout,
5090
+ error: resolvedError,
5091
+ fullWidth
5092
+ });
5093
+ const resolvedLocale = locale != null ? locale : 'en-US';
5094
+ const displayValue = formatRange(resolvedValue, resolvedLocale);
5095
+ const commitValue = (next)=>{
5096
+ if (isFormMode && bridge) {
5097
+ var _registration_onChange;
5098
+ bridge.setValue == null ? void 0 : bridge.setValue.call(bridge, name, next);
5099
+ void (registration == null ? void 0 : (_registration_onChange = registration.onChange) == null ? void 0 : _registration_onChange.call(registration, {
5100
+ target: {
5101
+ name,
5102
+ value: next
5103
+ },
5104
+ type: 'change'
5105
+ }));
5106
+ } else if (explicitValue === undefined) {
5107
+ setInternalValue(next);
5108
+ }
5109
+ onChange == null ? void 0 : onChange(next);
5110
+ };
5111
+ const markTouched = ()=>{
5112
+ if (isFormMode && bridge) {
5113
+ var _registration_onBlur;
5114
+ const committed = bridge.getValue(name);
5115
+ void (registration == null ? void 0 : (_registration_onBlur = registration.onBlur) == null ? void 0 : _registration_onBlur.call(registration, {
5116
+ target: {
5117
+ name,
5118
+ value: committed
5119
+ },
5120
+ type: 'blur'
5121
+ }));
5122
+ }
5123
+ };
5124
+ const handleOpenChange = (next)=>{
5125
+ if (next && !isInteractive) {
5126
+ return;
5127
+ }
5128
+ setIsOpen(next);
5129
+ if (!next) {
5130
+ markTouched();
5131
+ }
5132
+ };
5133
+ const handleRangeChange = (next)=>{
5134
+ commitValue(next);
5135
+ if (next.start !== null && next.end !== null) {
5136
+ setIsOpen(false);
5137
+ markTouched();
5138
+ }
5139
+ };
5140
+ return jsxs("div", {
5141
+ "data-testid": testId,
5142
+ className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root = slotProps.root) == null ? void 0 : _slotProps_root.className),
5143
+ children: [
5144
+ label && jsxs("label", {
5145
+ htmlFor: fieldId,
5146
+ className: cn(v.label(), slotProps == null ? void 0 : (_slotProps_label = slotProps.label) == null ? void 0 : _slotProps_label.className),
5147
+ children: [
5148
+ label,
5149
+ required && jsx("span", {
5150
+ "aria-hidden": "true",
5151
+ className: cn(v.requiredMark(), slotProps == null ? void 0 : (_slotProps_requiredMark = slotProps.requiredMark) == null ? void 0 : _slotProps_requiredMark.className),
5152
+ children: "*"
5153
+ })
5154
+ ]
5155
+ }),
5156
+ jsx(Popover, {
5157
+ open: isOpen,
5158
+ onOpenChange: handleOpenChange,
5159
+ side: "bottom",
5160
+ align: "start",
5161
+ content: jsx(RangeCalendar, {
5162
+ value: resolvedValue,
5163
+ onChange: handleRangeChange,
5164
+ minDate: minDate,
5165
+ maxDate: maxDate,
5166
+ disabledDates: disabledDates,
5167
+ isDateDisabled: isDateDisabled,
5168
+ weekStartDay: weekStartDay,
5169
+ locale: locale
5170
+ }),
5171
+ children: jsxs("button", {
5172
+ type: "button",
5173
+ id: fieldId,
5174
+ ref: triggerRef,
5175
+ disabled: effectiveDisabled,
5176
+ "aria-invalid": resolvedError ? true : undefined,
5177
+ "aria-describedby": resolvedHelperText ? helperId : undefined,
5178
+ className: cn(v.trigger(), slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
5179
+ children: [
5180
+ jsx("span", {
5181
+ className: displayValue ? v.value() : v.placeholder(),
5182
+ children: displayValue || placeholder || 'Select a date range'
5183
+ }),
4368
5184
  jsx("span", {
4369
5185
  className: v.icon(),
4370
5186
  children: jsx(CalendarIcon, {})
@@ -11979,6 +12795,6 @@ function SearchIcon(props) {
11979
12795
  */ // ───── Components ─────
11980
12796
  /**
11981
12797
  * Package version (synced with `package.json` at publish time).
11982
- */ const VERSION = '0.7.0-beta';
12798
+ */ const VERSION = '0.9.1-beta';
11983
12799
 
11984
- export { Accordion, AppShell, AspectRatio, Autocomplete, Box, Breadcrumbs, Button, Calendar, Checkbox, ConfirmDialogProvider, Container, DataGrid, DatePicker, DateTimePicker, Dialog, Divider, Grid, LeftNav, NumberField, OTPField, Pagination, Popover, RadioGroup, RenderButton, RenderChip, RenderText, RenderTwoLine, RowActionsMenu, Skeleton, SnackbarProvider, Stack, Switch, Table, Tabs, TextField, Textarea, Tooltip, TopBar, Typography, VERSION, VisuallyHidden, accordionVariants, appShellVariants, autocompleteVariants, boxVariants, breadcrumbsVariants, buttonVariants, calendarDayVariants, calendarVariants, checkboxVariants, cn, confirmDialogVariants, containerVariants, dataGridVariants, datePickerVariants, dateTimePickerVariants, dialogVariants, dividerLineVariants, dividerVariants, getNestedValue, gridVariants, isoToInputValue, leftNavVariants, numberFieldVariants, otpFieldVariants, paginationVariants, popoverVariants, radioGroupVariants, skeletonVariants, snackbarVariants, stackVariants, switchVariants, tableVariants, tabsVariants, textFieldVariants, textareaVariants, tooltipVariants, topBarVariants, typographyVariants, useAccessState, useConfirm, useSnackbar };
12800
+ export { Accordion, AppShell, AspectRatio, Autocomplete, Box, Breadcrumbs, Button, Calendar, Checkbox, ConfirmDialogProvider, Container, DataGrid, DatePicker, DateRangePicker, DateTimePicker, Dialog, Divider, Grid, LeftNav, NumberField, OTPField, Pagination, Popover, RadioGroup, RenderButton, RenderChip, RenderText, RenderTwoLine, RowActionsMenu, Skeleton, SnackbarProvider, Stack, Switch, Table, Tabs, TextField, Textarea, TimePicker, Tooltip, TopBar, Typography, VERSION, VisuallyHidden, accordionVariants, appShellVariants, autocompleteVariants, boxVariants, breadcrumbsVariants, buttonVariants, calendarDayVariants, calendarVariants, checkboxVariants, cn, confirmDialogVariants, containerVariants, dataGridVariants, datePickerVariants, dateRangeDayVariants, dateRangePickerVariants, dateTimePickerVariants, dialogVariants, dividerLineVariants, dividerVariants, getNestedValue, gridVariants, leftNavVariants, numberFieldVariants, otpFieldVariants, paginationVariants, popoverVariants, radioGroupVariants, skeletonVariants, snackbarVariants, stackVariants, switchVariants, tableVariants, tabsVariants, textFieldVariants, textareaVariants, timePickerVariants, tooltipVariants, topBarVariants, typographyVariants, useAccessState, useConfirm, useSnackbar };