@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.
- package/CHANGELOG.md +31 -0
- package/dist/index.esm.js +1152 -336
- package/dist/src/components/DateRangePicker/DateRangePicker.d.ts +13 -0
- package/dist/src/components/DateRangePicker/DateRangePicker.d.ts.map +1 -0
- package/dist/src/components/DateRangePicker/dateRangePicker.types.d.ts +85 -0
- package/dist/src/components/DateRangePicker/dateRangePicker.types.d.ts.map +1 -0
- package/dist/src/components/DateRangePicker/dateRangePicker.variants.d.ts +183 -0
- package/dist/src/components/DateRangePicker/dateRangePicker.variants.d.ts.map +1 -0
- package/dist/src/components/DateTimePicker/DateTimePicker.d.ts +7 -43
- package/dist/src/components/DateTimePicker/DateTimePicker.d.ts.map +1 -1
- package/dist/src/components/DateTimePicker/dateTimePicker.types.d.ts +50 -55
- package/dist/src/components/DateTimePicker/dateTimePicker.types.d.ts.map +1 -1
- package/dist/src/components/DateTimePicker/dateTimePicker.variants.d.ts +36 -94
- package/dist/src/components/DateTimePicker/dateTimePicker.variants.d.ts.map +1 -1
- package/dist/src/components/TimePicker/TimePicker.d.ts +12 -0
- package/dist/src/components/TimePicker/TimePicker.d.ts.map +1 -0
- package/dist/src/components/TimePicker/timePicker.types.d.ts +80 -0
- package/dist/src/components/TimePicker/timePicker.types.d.ts.map +1 -0
- package/dist/src/components/TimePicker/timePicker.variants.d.ts +103 -0
- package/dist/src/components/TimePicker/timePicker.variants.d.ts.map +1 -0
- package/dist/src/index.d.ts +10 -4
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/components/DateRangePicker/DateRangePicker.test.tsx +92 -0
- package/src/components/DateRangePicker/DateRangePicker.tsx +510 -0
- package/src/components/DateRangePicker/dateRangePicker.types.ts +74 -0
- package/src/components/DateRangePicker/dateRangePicker.variants.ts +101 -0
- package/src/components/DateTimePicker/DateTimePicker.test.tsx +60 -186
- package/src/components/DateTimePicker/DateTimePicker.tsx +209 -181
- package/src/components/DateTimePicker/dateTimePicker.types.ts +50 -54
- package/src/components/DateTimePicker/dateTimePicker.variants.ts +22 -51
- package/src/components/TimePicker/TimePicker.test.tsx +65 -0
- package/src/components/TimePicker/TimePicker.tsx +274 -0
- package/src/components/TimePicker/timePicker.types.ts +69 -0
- package/src/components/TimePicker/timePicker.variants.ts +53 -0
- package/src/index.ts +28 -16
- 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$
|
|
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$
|
|
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.
|
|
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,
|
|
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 };
|