@dashforge/tw 0.2.1-beta → 0.4.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 +257 -0
- package/CONSUMER-VALIDATION.md +130 -0
- package/PARITY.md +483 -0
- package/PERFORMANCE.md +169 -0
- package/dist/index.esm.js +801 -42
- package/dist/src/components/Accordion/Accordion.d.ts +21 -0
- package/dist/src/components/Accordion/Accordion.d.ts.map +1 -0
- package/dist/src/components/Accordion/accordion.types.d.ts +74 -0
- package/dist/src/components/Accordion/accordion.types.d.ts.map +1 -0
- package/dist/src/components/Accordion/accordion.variants.d.ts +58 -0
- package/dist/src/components/Accordion/accordion.variants.d.ts.map +1 -0
- package/dist/src/components/AppShell/AppShell.d.ts +14 -0
- package/dist/src/components/AppShell/AppShell.d.ts.map +1 -1
- package/dist/src/components/AppShell/appShell.variants.d.ts.map +1 -1
- package/dist/src/components/Autocomplete/Autocomplete.d.ts.map +1 -1
- package/dist/src/components/Autocomplete/autocomplete.variants.d.ts.map +1 -1
- package/dist/src/components/Breadcrumbs/breadcrumbs.variants.d.ts.map +1 -1
- package/dist/src/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/src/components/Dialog/Dialog.d.ts +17 -0
- package/dist/src/components/Dialog/Dialog.d.ts.map +1 -0
- package/dist/src/components/Dialog/dialog.types.d.ts +75 -0
- package/dist/src/components/Dialog/dialog.types.d.ts.map +1 -0
- package/dist/src/components/Dialog/dialog.variants.d.ts +80 -0
- package/dist/src/components/Dialog/dialog.variants.d.ts.map +1 -0
- package/dist/src/components/LeftNav/leftNav.variants.d.ts.map +1 -1
- package/dist/src/components/Popover/Popover.d.ts +15 -0
- package/dist/src/components/Popover/Popover.d.ts.map +1 -0
- package/dist/src/components/Popover/popover.types.d.ts +45 -0
- package/dist/src/components/Popover/popover.types.d.ts.map +1 -0
- package/dist/src/components/Popover/popover.variants.d.ts +34 -0
- package/dist/src/components/Popover/popover.variants.d.ts.map +1 -0
- package/dist/src/components/Snackbar/snackbar.variants.d.ts.map +1 -1
- package/dist/src/components/Switch/switch.variants.d.ts.map +1 -1
- package/dist/src/components/Tabs/Tabs.d.ts +15 -0
- package/dist/src/components/Tabs/Tabs.d.ts.map +1 -0
- package/dist/src/components/Tabs/tabs.types.d.ts +55 -0
- package/dist/src/components/Tabs/tabs.types.d.ts.map +1 -0
- package/dist/src/components/Tabs/tabs.variants.d.ts +82 -0
- package/dist/src/components/Tabs/tabs.variants.d.ts.map +1 -0
- package/dist/src/components/TextField/TextField.d.ts.map +1 -1
- package/dist/src/components/TextField/textField.types.d.ts +29 -3
- package/dist/src/components/TextField/textField.types.d.ts.map +1 -1
- package/dist/src/components/TextField/textField.variants.d.ts +6 -0
- package/dist/src/components/TextField/textField.variants.d.ts.map +1 -1
- package/dist/src/components/Tooltip/Tooltip.d.ts +29 -0
- package/dist/src/components/Tooltip/Tooltip.d.ts.map +1 -0
- package/dist/src/components/Tooltip/tooltip.types.d.ts +47 -0
- package/dist/src/components/Tooltip/tooltip.types.d.ts.map +1 -0
- package/dist/src/components/Tooltip/tooltip.variants.d.ts +34 -0
- package/dist/src/components/Tooltip/tooltip.variants.d.ts.map +1 -0
- package/dist/src/index.d.ts +16 -1
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/components/Accordion/Accordion.test.tsx +95 -0
- package/src/components/Accordion/Accordion.tsx +97 -0
- package/src/components/Accordion/accordion.types.ts +66 -0
- package/src/components/Accordion/accordion.variants.ts +30 -0
- package/src/components/AppShell/AppShell.tsx +126 -1
- package/src/components/AppShell/appShell.variants.ts +8 -2
- package/src/components/Autocomplete/Autocomplete.tsx +77 -4
- package/src/components/Autocomplete/autocomplete.variants.ts +6 -0
- package/src/components/Breadcrumbs/breadcrumbs.variants.ts +5 -0
- package/src/components/Checkbox/Checkbox.tsx +43 -9
- package/src/components/Dialog/Dialog.test.tsx +96 -0
- package/src/components/Dialog/Dialog.tsx +93 -0
- package/src/components/Dialog/dialog.types.ts +62 -0
- package/src/components/Dialog/dialog.variants.ts +62 -0
- package/src/components/LeftNav/leftNav.variants.ts +12 -1
- package/src/components/Popover/Popover.test.tsx +72 -0
- package/src/components/Popover/Popover.tsx +55 -0
- package/src/components/Popover/popover.types.ts +42 -0
- package/src/components/Popover/popover.variants.ts +18 -0
- package/src/components/Snackbar/snackbar.variants.ts +4 -2
- package/src/components/Switch/switch.variants.ts +6 -1
- package/src/components/Tabs/Tabs.test.tsx +74 -0
- package/src/components/Tabs/Tabs.tsx +66 -0
- package/src/components/Tabs/tabs.types.ts +49 -0
- package/src/components/Tabs/tabs.variants.ts +58 -0
- package/src/components/TextField/TextField.tsx +29 -0
- package/src/components/TextField/textField.types.ts +23 -3
- package/src/components/TextField/textField.variants.ts +18 -0
- package/src/components/Tooltip/Tooltip.test.tsx +73 -0
- package/src/components/Tooltip/Tooltip.tsx +70 -0
- package/src/components/Tooltip/tooltip.types.ts +44 -0
- package/src/components/Tooltip/tooltip.variants.ts +18 -0
- package/src/index.ts +40 -1
package/dist/index.esm.js
CHANGED
|
@@ -11,6 +11,11 @@ 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 * as RadixDialog from '@radix-ui/react-dialog';
|
|
15
|
+
import * as RadixTabs from '@radix-ui/react-tabs';
|
|
16
|
+
import * as RadixTooltip from '@radix-ui/react-tooltip';
|
|
17
|
+
import * as RadixPopover from '@radix-ui/react-popover';
|
|
18
|
+
import * as RadixAccordion from '@radix-ui/react-accordion';
|
|
14
19
|
|
|
15
20
|
function _extends() {
|
|
16
21
|
_extends = Object.assign || function assign(target) {
|
|
@@ -510,7 +515,24 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
510
515
|
'read-only:cursor-default'
|
|
511
516
|
],
|
|
512
517
|
helperText: 'mt-1 text-sm text-neutral-600',
|
|
513
|
-
errorText: 'mt-1 text-sm text-danger-600'
|
|
518
|
+
errorText: 'mt-1 text-sm text-danger-600',
|
|
519
|
+
/*
|
|
520
|
+
* `prefix` / `suffix` slot — inline adornment rendered before /
|
|
521
|
+
* after the input INSIDE the inputWrapper. `shrink-0` keeps the
|
|
522
|
+
* adornment width fixed so it doesn't compete for space with the
|
|
523
|
+
* input; `select-none` + `pointer-events-none` avoids
|
|
524
|
+
* accidentally stealing focus from the input on click (the
|
|
525
|
+
* inputWrapper handles focus via `focus-within`).
|
|
526
|
+
*/ prefix: [
|
|
527
|
+
'shrink-0 inline-flex items-center select-none pointer-events-none',
|
|
528
|
+
'text-neutral-500',
|
|
529
|
+
'mr-2'
|
|
530
|
+
],
|
|
531
|
+
suffix: [
|
|
532
|
+
'shrink-0 inline-flex items-center select-none pointer-events-none',
|
|
533
|
+
'text-neutral-500',
|
|
534
|
+
'ml-2'
|
|
535
|
+
]
|
|
514
536
|
},
|
|
515
537
|
variants: {
|
|
516
538
|
size: {
|
|
@@ -587,7 +609,7 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
587
609
|
* - `aria-describedby` links the input to the helper/error text node.
|
|
588
610
|
* - Required fields get the native `required` attribute + a visual `*`.
|
|
589
611
|
*/ function TextField(props) {
|
|
590
|
-
var _slotProps_root, _slotProps_label, _slotProps_requiredMark, _slotProps_inputWrapper, _slotProps_input, _slotProps_errorText, _slotProps_helperText;
|
|
612
|
+
var _slotProps_root, _slotProps_label, _slotProps_requiredMark, _slotProps_inputWrapper, _slotProps_prefix, _slotProps_input, _slotProps_suffix, _slotProps_errorText, _slotProps_helperText;
|
|
591
613
|
const { name, rules, visibleWhen, layout = 'stacked', size, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, type, onChange: userOnChange, onBlur: userOnBlur, value: userValue, defaultValue } = props, rest = _object_without_properties_loose(props, [
|
|
592
614
|
"name",
|
|
593
615
|
"rules",
|
|
@@ -717,25 +739,37 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
717
739
|
})
|
|
718
740
|
]
|
|
719
741
|
}),
|
|
720
|
-
|
|
742
|
+
jsxs("div", {
|
|
721
743
|
className: cn(v.inputWrapper(), slotProps == null ? void 0 : (_slotProps_inputWrapper = slotProps.inputWrapper) == null ? void 0 : _slotProps_inputWrapper.className),
|
|
722
|
-
children:
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
744
|
+
children: [
|
|
745
|
+
(slotProps == null ? void 0 : (_slotProps_prefix = slotProps.prefix) == null ? void 0 : _slotProps_prefix.children) !== undefined && jsx("span", {
|
|
746
|
+
"aria-hidden": "true",
|
|
747
|
+
className: cn(v.prefix(), slotProps.prefix.className),
|
|
748
|
+
children: slotProps.prefix.children
|
|
749
|
+
}),
|
|
750
|
+
jsx("input", _extends({}, rest, {
|
|
751
|
+
id: inputId,
|
|
752
|
+
name: name,
|
|
753
|
+
type: type != null ? type : 'text',
|
|
754
|
+
placeholder: placeholder,
|
|
755
|
+
value: isFormMode ? resolvedValue != null ? resolvedValue : '' : userValue,
|
|
756
|
+
defaultValue: !isFormMode && userValue === undefined ? defaultValue : undefined,
|
|
757
|
+
disabled: effectiveDisabled,
|
|
758
|
+
readOnly: effectiveReadOnly,
|
|
759
|
+
required: required,
|
|
760
|
+
"aria-invalid": resolvedError || undefined,
|
|
761
|
+
"aria-describedby": resolvedHelperText ? helperId : undefined,
|
|
762
|
+
onChange: handleChange,
|
|
763
|
+
onBlur: handleBlur,
|
|
764
|
+
ref: inputRef,
|
|
765
|
+
className: cn(v.input(), slotProps == null ? void 0 : (_slotProps_input = slotProps.input) == null ? void 0 : _slotProps_input.className)
|
|
766
|
+
})),
|
|
767
|
+
(slotProps == null ? void 0 : (_slotProps_suffix = slotProps.suffix) == null ? void 0 : _slotProps_suffix.children) !== undefined && jsx("span", {
|
|
768
|
+
"aria-hidden": "true",
|
|
769
|
+
className: cn(v.suffix(), slotProps.suffix.className),
|
|
770
|
+
children: slotProps.suffix.children
|
|
771
|
+
})
|
|
772
|
+
]
|
|
739
773
|
}),
|
|
740
774
|
resolvedHelperText && jsx("p", {
|
|
741
775
|
id: helperId,
|
|
@@ -811,8 +845,8 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
811
845
|
});
|
|
812
846
|
|
|
813
847
|
/**
|
|
814
|
-
* Inline checkmark SVG used by `Radix.Indicator
|
|
815
|
-
* `currentColor` so the parent's `text-white` propagates
|
|
848
|
+
* Inline checkmark SVG used by `Radix.Indicator` when fully checked.
|
|
849
|
+
* Stroke uses `currentColor` so the parent's `text-white` propagates.
|
|
816
850
|
*
|
|
817
851
|
* @internal
|
|
818
852
|
*/ function CheckIcon({ className }) {
|
|
@@ -830,6 +864,32 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
830
864
|
})
|
|
831
865
|
});
|
|
832
866
|
}
|
|
867
|
+
/**
|
|
868
|
+
* Inline dash SVG used by `Radix.Indicator` when the checkbox is in
|
|
869
|
+
* the `indeterminate` tri-state ("some, but not all, children
|
|
870
|
+
* selected" — the canonical "select all" partial state).
|
|
871
|
+
*
|
|
872
|
+
* Pre-0.2.2-beta the indicator rendered the CheckIcon for BOTH
|
|
873
|
+
* checked and indeterminate (Radix mounts the Indicator for either
|
|
874
|
+
* state). We now discriminate via the `data-state` attribute Radix
|
|
875
|
+
* sets on the Indicator element itself — see the parent `Indicator`
|
|
876
|
+
* rendering below for the CSS toggle.
|
|
877
|
+
*
|
|
878
|
+
* @internal
|
|
879
|
+
*/ function DashIcon({ className }) {
|
|
880
|
+
return jsx("svg", {
|
|
881
|
+
"aria-hidden": "true",
|
|
882
|
+
viewBox: "0 0 16 16",
|
|
883
|
+
fill: "none",
|
|
884
|
+
className: className,
|
|
885
|
+
children: jsx("path", {
|
|
886
|
+
d: "M3 8h10",
|
|
887
|
+
stroke: "currentColor",
|
|
888
|
+
strokeWidth: "2.5",
|
|
889
|
+
strokeLinecap: "round"
|
|
890
|
+
})
|
|
891
|
+
});
|
|
892
|
+
}
|
|
833
893
|
/**
|
|
834
894
|
* Dashforge TW Checkbox — bridge-integrated form control.
|
|
835
895
|
*
|
|
@@ -975,11 +1035,16 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
975
1035
|
onBlur: handleBlur,
|
|
976
1036
|
ref: registration == null ? void 0 : registration.ref,
|
|
977
1037
|
className: cn(v.control(), slotProps == null ? void 0 : (_slotProps_control = slotProps.control) == null ? void 0 : _slotProps_control.className),
|
|
978
|
-
children:
|
|
979
|
-
className: cn(v.indicator(), slotProps == null ? void 0 : (_slotProps_indicator = slotProps.indicator) == null ? void 0 : _slotProps_indicator.className),
|
|
980
|
-
children:
|
|
981
|
-
|
|
982
|
-
|
|
1038
|
+
children: jsxs(RadixCheckbox.Indicator, {
|
|
1039
|
+
className: cn(v.indicator(), 'group', slotProps == null ? void 0 : (_slotProps_indicator = slotProps.indicator) == null ? void 0 : _slotProps_indicator.className),
|
|
1040
|
+
children: [
|
|
1041
|
+
jsx(CheckIcon, {
|
|
1042
|
+
className: "h-full w-full group-data-[state=indeterminate]:hidden"
|
|
1043
|
+
}),
|
|
1044
|
+
jsx(DashIcon, {
|
|
1045
|
+
className: "h-full w-full group-data-[state=checked]:hidden"
|
|
1046
|
+
})
|
|
1047
|
+
]
|
|
983
1048
|
})
|
|
984
1049
|
})),
|
|
985
1050
|
jsxs("div", {
|
|
@@ -1024,7 +1089,12 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
1024
1089
|
],
|
|
1025
1090
|
thumb: [
|
|
1026
1091
|
'pointer-events-none inline-block rounded-full bg-white shadow ring-0',
|
|
1027
|
-
|
|
1092
|
+
// Slide animation gated on `prefers-reduced-motion: no-preference`
|
|
1093
|
+
// (WCAG 2.3.3). The thumb still moves between positions instantly
|
|
1094
|
+
// for users who request reduced motion — the data-state change
|
|
1095
|
+
// applies the translate-x rule unconditionally, only the smooth
|
|
1096
|
+
// transition between the two is suppressed.
|
|
1097
|
+
'transition-transform motion-reduce:transition-none',
|
|
1028
1098
|
'data-[state=unchecked]:translate-x-0'
|
|
1029
1099
|
],
|
|
1030
1100
|
label: 'select-none cursor-pointer text-neutral-900',
|
|
@@ -2414,7 +2484,13 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
2414
2484
|
'flex items-center justify-center shrink-0 px-2',
|
|
2415
2485
|
'text-neutral-600 hover:text-neutral-900',
|
|
2416
2486
|
'disabled:cursor-not-allowed disabled:opacity-40',
|
|
2417
|
-
'transition-colors'
|
|
2487
|
+
'transition-colors',
|
|
2488
|
+
// Chevron flip on open — targets the SVG child via the aria-
|
|
2489
|
+
// expanded state on the button itself (set by React). Smooth
|
|
2490
|
+
// rotate gated on prefers-reduced-motion (WCAG 2.3.3); the
|
|
2491
|
+
// 180° state still applies, just without the animated tween.
|
|
2492
|
+
'[&[aria-expanded=true]>svg]:rotate-180',
|
|
2493
|
+
'[&>svg]:transition-transform [&>svg]:duration-150 motion-reduce:[&>svg]:transition-none'
|
|
2418
2494
|
],
|
|
2419
2495
|
clearButton: [
|
|
2420
2496
|
'flex items-center justify-center shrink-0 px-2',
|
|
@@ -2507,6 +2583,52 @@ function _object_without_properties_loose(source, excluded) {
|
|
|
2507
2583
|
}
|
|
2508
2584
|
});
|
|
2509
2585
|
|
|
2586
|
+
/**
|
|
2587
|
+
* Inline SVG icons used by the Autocomplete chrome (chip remove, clear,
|
|
2588
|
+
* dropdown caret). Stroke uses `currentColor` so the parent's `text-*`
|
|
2589
|
+
* propagates — same pattern as Checkbox's CheckIcon.
|
|
2590
|
+
*
|
|
2591
|
+
* Why inline SVG (not lucide / heroicons / unicode glyphs):
|
|
2592
|
+
* - Zero icon-library dependency: keeps `@dashforge/tw` self-contained.
|
|
2593
|
+
* - Crisp at every size (the unicode `×` / `▾` glyphs we shipped pre-
|
|
2594
|
+
* 0.2.2 rendered as chunky font characters that looked unpolished
|
|
2595
|
+
* next to the rest of the design system).
|
|
2596
|
+
* - SVG scales with parent font-size cleanly via `width="1em" height="1em"`.
|
|
2597
|
+
*
|
|
2598
|
+
* @internal
|
|
2599
|
+
*/ function CloseIcon({ className }) {
|
|
2600
|
+
return jsx("svg", {
|
|
2601
|
+
"aria-hidden": "true",
|
|
2602
|
+
viewBox: "0 0 16 16",
|
|
2603
|
+
width: "1em",
|
|
2604
|
+
height: "1em",
|
|
2605
|
+
fill: "none",
|
|
2606
|
+
className: className,
|
|
2607
|
+
children: jsx("path", {
|
|
2608
|
+
d: "M4 4l8 8M12 4l-8 8",
|
|
2609
|
+
stroke: "currentColor",
|
|
2610
|
+
strokeWidth: "1.75",
|
|
2611
|
+
strokeLinecap: "round"
|
|
2612
|
+
})
|
|
2613
|
+
});
|
|
2614
|
+
}
|
|
2615
|
+
function ChevronDownIcon({ className }) {
|
|
2616
|
+
return jsx("svg", {
|
|
2617
|
+
"aria-hidden": "true",
|
|
2618
|
+
viewBox: "0 0 16 16",
|
|
2619
|
+
width: "1em",
|
|
2620
|
+
height: "1em",
|
|
2621
|
+
fill: "none",
|
|
2622
|
+
className: className,
|
|
2623
|
+
children: jsx("path", {
|
|
2624
|
+
d: "M4 6l4 4 4-4",
|
|
2625
|
+
stroke: "currentColor",
|
|
2626
|
+
strokeWidth: "1.75",
|
|
2627
|
+
strokeLinecap: "round",
|
|
2628
|
+
strokeLinejoin: "round"
|
|
2629
|
+
})
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2510
2632
|
/**
|
|
2511
2633
|
* Coerce a raw value (from bridge / props) into a canonical shape:
|
|
2512
2634
|
*
|
|
@@ -2813,7 +2935,15 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
2813
2935
|
if (next == null) {
|
|
2814
2936
|
setInputValue('');
|
|
2815
2937
|
} else {
|
|
2816
|
-
|
|
2938
|
+
// Look up the label in the EFFECTIVE option pool (static
|
|
2939
|
+
// `options` + async `asyncOptions` when `loadOptions` is
|
|
2940
|
+
// configured). Looking only at the static `options` here
|
|
2941
|
+
// means async-loaded picks never update the input — the
|
|
2942
|
+
// user sees their search query stick instead of the
|
|
2943
|
+
// selected label after click. Same lookup logic mirrored in
|
|
2944
|
+
// `displayInputValue` so the two paths can't drift.
|
|
2945
|
+
const pool = loadOptions && asyncOptions !== null ? asyncOptions : options;
|
|
2946
|
+
const found = pool.find((opt)=>getOptionValue(opt) === next);
|
|
2817
2947
|
const found_label = found ? labelAsString(found) : undefined;
|
|
2818
2948
|
if (found_label !== undefined) {
|
|
2819
2949
|
setInputValue(found_label);
|
|
@@ -2843,6 +2973,8 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
2843
2973
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2844
2974
|
[
|
|
2845
2975
|
options,
|
|
2976
|
+
asyncOptions,
|
|
2977
|
+
loadOptions,
|
|
2846
2978
|
isFormMode,
|
|
2847
2979
|
bridge,
|
|
2848
2980
|
name,
|
|
@@ -3189,7 +3321,7 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
3189
3321
|
"aria-label": `Remove ${labelText}`,
|
|
3190
3322
|
tabIndex: -1,
|
|
3191
3323
|
className: cn(v.chipRemove(), slotProps == null ? void 0 : (_slotProps_chipRemove = slotProps.chipRemove) == null ? void 0 : _slotProps_chipRemove.className),
|
|
3192
|
-
children:
|
|
3324
|
+
children: jsx(CloseIcon, {})
|
|
3193
3325
|
})
|
|
3194
3326
|
]
|
|
3195
3327
|
}, key);
|
|
@@ -3233,7 +3365,7 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
3233
3365
|
"aria-label": "Clear selection",
|
|
3234
3366
|
tabIndex: -1,
|
|
3235
3367
|
className: cn(v.clearButton(), slotProps == null ? void 0 : (_slotProps_clearButton = slotProps.clearButton) == null ? void 0 : _slotProps_clearButton.className),
|
|
3236
|
-
children:
|
|
3368
|
+
children: jsx(CloseIcon, {})
|
|
3237
3369
|
}),
|
|
3238
3370
|
jsx("button", {
|
|
3239
3371
|
type: "button",
|
|
@@ -3245,7 +3377,7 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
3245
3377
|
tabIndex: -1,
|
|
3246
3378
|
disabled: effectiveDisabled,
|
|
3247
3379
|
className: cn(v.trigger(), slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
|
|
3248
|
-
children:
|
|
3380
|
+
children: jsx(ChevronDownIcon, {})
|
|
3249
3381
|
}),
|
|
3250
3382
|
isOpen && jsx("ul", {
|
|
3251
3383
|
ref: listboxRef,
|
|
@@ -3643,7 +3775,12 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
3643
3775
|
'text-neutral-600 hover:text-primary-700',
|
|
3644
3776
|
'rounded-sm outline-none',
|
|
3645
3777
|
'focus-visible:ring-2 focus-visible:ring-primary-500/50',
|
|
3646
|
-
'transition-colors'
|
|
3778
|
+
'transition-colors',
|
|
3779
|
+
// Defensive `no-underline` — see the matching comment in
|
|
3780
|
+
// LeftNav itemLink slot. The Breadcrumbs root cause covers
|
|
3781
|
+
// TopBar too because Breadcrumbs is typically rendered in
|
|
3782
|
+
// TopBar's center slot.
|
|
3783
|
+
'no-underline hover:no-underline'
|
|
3647
3784
|
],
|
|
3648
3785
|
current: [
|
|
3649
3786
|
'inline-flex items-center gap-1 truncate',
|
|
@@ -3837,7 +3974,10 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
3837
3974
|
root: [
|
|
3838
3975
|
'flex flex-col h-full',
|
|
3839
3976
|
'bg-neutral-50 border-r border-neutral-200',
|
|
3840
|
-
|
|
3977
|
+
// Width transition (rail-mode toggle) — gated on
|
|
3978
|
+
// prefers-reduced-motion (WCAG 2.3.3). The new width still
|
|
3979
|
+
// applies, just without the animated tween.
|
|
3980
|
+
'transition-[width] duration-200 motion-reduce:transition-none motion-reduce:duration-0'
|
|
3841
3981
|
],
|
|
3842
3982
|
brand: [
|
|
3843
3983
|
'flex items-center gap-2 px-3 h-14 shrink-0',
|
|
@@ -3851,7 +3991,15 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
3851
3991
|
'outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50',
|
|
3852
3992
|
'transition-colors w-full',
|
|
3853
3993
|
'aria-disabled:opacity-50 aria-disabled:cursor-not-allowed',
|
|
3854
|
-
'aria-disabled:hover:bg-transparent'
|
|
3994
|
+
'aria-disabled:hover:bg-transparent',
|
|
3995
|
+
// Defensive `no-underline` — Tailwind's preflight removes the
|
|
3996
|
+
// default browser anchor underline globally, but environments
|
|
3997
|
+
// that DISABLE preflight (e.g. our docs-lab, where the tw
|
|
3998
|
+
// section coexists with MUI's chrome) get raw browser defaults
|
|
3999
|
+
// back. Without this, `<a>` items in the nav render underlined
|
|
4000
|
+
// in those contexts. Explicit `no-underline` + `hover:no-underline`
|
|
4001
|
+
// keeps the appearance consistent regardless of preflight state.
|
|
4002
|
+
'no-underline hover:no-underline'
|
|
3855
4003
|
],
|
|
3856
4004
|
itemActive: 'bg-primary-100 text-primary-900 font-medium',
|
|
3857
4005
|
itemIcon: 'shrink-0 w-5 h-5 flex items-center justify-center',
|
|
@@ -4259,14 +4407,20 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
4259
4407
|
nav: 'hidden md:flex shrink-0',
|
|
4260
4408
|
navMobile: [
|
|
4261
4409
|
'flex md:hidden fixed inset-y-0 left-0 z-40',
|
|
4262
|
-
|
|
4410
|
+
// Drawer slide-in is the most prominent motion in AppShell and
|
|
4411
|
+
// a clear WCAG 2.3.3 candidate. Gate the transition on
|
|
4412
|
+
// `prefers-reduced-motion: no-preference`; the data-driven
|
|
4413
|
+
// `-translate-x-full` / `translate-x-0` still applies, just
|
|
4414
|
+
// without the smooth slide.
|
|
4415
|
+
'transition-transform duration-200 ease-out motion-reduce:transition-none motion-reduce:duration-0',
|
|
4263
4416
|
'-translate-x-full'
|
|
4264
4417
|
],
|
|
4265
4418
|
main: 'flex-1 min-w-0 overflow-y-auto',
|
|
4266
4419
|
footer: 'shrink-0',
|
|
4267
4420
|
backdrop: [
|
|
4268
4421
|
'md:hidden fixed inset-0 z-30 bg-black/40',
|
|
4269
|
-
|
|
4422
|
+
// Backdrop opacity fade — micro motion, gated for consistency.
|
|
4423
|
+
'transition-opacity duration-200 motion-reduce:transition-none motion-reduce:duration-0',
|
|
4270
4424
|
'opacity-0 pointer-events-none'
|
|
4271
4425
|
]
|
|
4272
4426
|
},
|
|
@@ -4283,6 +4437,28 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
4283
4437
|
}
|
|
4284
4438
|
});
|
|
4285
4439
|
|
|
4440
|
+
/**
|
|
4441
|
+
* Query selector for natively-focusable elements + anything with an
|
|
4442
|
+
* explicit positive (or implicit `0`) tabindex. Used by the focus
|
|
4443
|
+
* trap to enumerate the drawer's interactive content.
|
|
4444
|
+
*
|
|
4445
|
+
* Notes:
|
|
4446
|
+
* - Excludes `[tabindex="-1"]` (intentionally non-tabbable).
|
|
4447
|
+
* - Excludes `:disabled` — the browser already skips them in tab
|
|
4448
|
+
* order; including them here would route focus to dead elements.
|
|
4449
|
+
* - `details > summary` is the standard way to get a focusable
|
|
4450
|
+
* `<details>` toggle.
|
|
4451
|
+
*
|
|
4452
|
+
* @internal
|
|
4453
|
+
*/ const FOCUSABLE_SELECTOR = [
|
|
4454
|
+
'a[href]',
|
|
4455
|
+
'button:not(:disabled)',
|
|
4456
|
+
'input:not(:disabled):not([type="hidden"])',
|
|
4457
|
+
'select:not(:disabled)',
|
|
4458
|
+
'textarea:not(:disabled)',
|
|
4459
|
+
'[tabindex]:not([tabindex="-1"]):not(:disabled)',
|
|
4460
|
+
'details > summary:first-of-type'
|
|
4461
|
+
].join(',');
|
|
4286
4462
|
/**
|
|
4287
4463
|
* Dashforge TW AppShell — top-level layout orchestrator.
|
|
4288
4464
|
*
|
|
@@ -4311,6 +4487,20 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
4311
4487
|
* - The mobile drawer + backdrop participate in the standard
|
|
4312
4488
|
* "click outside to close" pattern — `Escape` closes the drawer
|
|
4313
4489
|
* too (added via global keydown).
|
|
4490
|
+
* - **Focus trap** (WCAG 2.4.3) — when the mobile drawer opens:
|
|
4491
|
+
* 1. The previously-focused element is captured.
|
|
4492
|
+
* 2. Focus moves to the first focusable element inside the drawer.
|
|
4493
|
+
* 3. Tab / Shift+Tab wrap inside the drawer (cycle from
|
|
4494
|
+
* last → first and first → last) — Tab can never escape
|
|
4495
|
+
* to the page underneath while the drawer is open.
|
|
4496
|
+
* 4. On close, focus returns to the captured element (typically
|
|
4497
|
+
* the hamburger toggle the user pressed to open the drawer).
|
|
4498
|
+
* This pattern matches WAI-ARIA APG's modal dialog guidance even
|
|
4499
|
+
* though the drawer isn't strictly a dialog — same focus
|
|
4500
|
+
* management makes keyboard users' experience predictable.
|
|
4501
|
+
* - **`role="dialog"` + `aria-modal="true"`** are applied to the
|
|
4502
|
+
* drawer when open so screen readers announce it as a modal
|
|
4503
|
+
* overlay rather than just an aside.
|
|
4314
4504
|
*/ function AppShell(props) {
|
|
4315
4505
|
var _slotProps_root, _slotProps_header, _slotProps_nav, _slotProps_navMobile, _slotProps_backdrop, _slotProps_main, _slotProps_footer;
|
|
4316
4506
|
const { header, nav, footer, children, navOpen = false, onNavOpenChange, sx, slotProps } = props;
|
|
@@ -4340,6 +4530,80 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
4340
4530
|
navOpen,
|
|
4341
4531
|
onNavOpenChange
|
|
4342
4532
|
]);
|
|
4533
|
+
/*
|
|
4534
|
+
* Focus trap for the mobile drawer.
|
|
4535
|
+
*
|
|
4536
|
+
* Implementation:
|
|
4537
|
+
* - On open: capture the currently-focused element (`document.activeElement`)
|
|
4538
|
+
* so we can restore it on close. Then move focus to the first
|
|
4539
|
+
* focusable element inside the drawer.
|
|
4540
|
+
* - While open: a Tab/Shift+Tab keydown listener wraps focus inside
|
|
4541
|
+
* the drawer subtree (last → first on Tab from end, first → last
|
|
4542
|
+
* on Shift+Tab from start).
|
|
4543
|
+
* - On close: restore focus to the captured element.
|
|
4544
|
+
*
|
|
4545
|
+
* Hand-rolled (no `focus-trap-react` dep) — the logic is ~20 LOC and
|
|
4546
|
+
* scoped to a single drawer; adding a runtime dep felt like overkill.
|
|
4547
|
+
* If we ever need more sophisticated trap semantics (nested traps,
|
|
4548
|
+
* sentinel nodes, etc.) the dep is the right call.
|
|
4549
|
+
*/ const drawerRef = useRef(null);
|
|
4550
|
+
const restoreFocusRef = useRef(null);
|
|
4551
|
+
useEffect(()=>{
|
|
4552
|
+
if (!navOpen) return;
|
|
4553
|
+
// 1) Capture the element that had focus before the drawer opened.
|
|
4554
|
+
restoreFocusRef.current = document.activeElement;
|
|
4555
|
+
// 2) Move focus to the first focusable element inside the drawer.
|
|
4556
|
+
// Defer via rAF so the drawer DOM (slide-in animation start) has
|
|
4557
|
+
// settled and the elements are actually visible/focusable.
|
|
4558
|
+
const raf = requestAnimationFrame(()=>{
|
|
4559
|
+
const drawer = drawerRef.current;
|
|
4560
|
+
if (!drawer) return;
|
|
4561
|
+
const first = drawer.querySelector(FOCUSABLE_SELECTOR);
|
|
4562
|
+
first == null ? void 0 : first.focus();
|
|
4563
|
+
});
|
|
4564
|
+
// 3) Trap Tab / Shift+Tab inside the drawer.
|
|
4565
|
+
const onKeyDown = (event)=>{
|
|
4566
|
+
if (event.key !== 'Tab') return;
|
|
4567
|
+
const drawer = drawerRef.current;
|
|
4568
|
+
if (!drawer) return;
|
|
4569
|
+
const focusables = Array.from(drawer.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
4570
|
+
if (focusables.length === 0) {
|
|
4571
|
+
event.preventDefault();
|
|
4572
|
+
return;
|
|
4573
|
+
}
|
|
4574
|
+
const first = focusables[0];
|
|
4575
|
+
const last = focusables[focusables.length - 1];
|
|
4576
|
+
const active = document.activeElement;
|
|
4577
|
+
if (event.shiftKey) {
|
|
4578
|
+
// Shift+Tab on first → wrap to last.
|
|
4579
|
+
if (active === first || !drawer.contains(active)) {
|
|
4580
|
+
event.preventDefault();
|
|
4581
|
+
last.focus();
|
|
4582
|
+
}
|
|
4583
|
+
} else {
|
|
4584
|
+
// Tab on last → wrap to first.
|
|
4585
|
+
if (active === last || !drawer.contains(active)) {
|
|
4586
|
+
event.preventDefault();
|
|
4587
|
+
first.focus();
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
};
|
|
4591
|
+
document.addEventListener('keydown', onKeyDown);
|
|
4592
|
+
return ()=>{
|
|
4593
|
+
cancelAnimationFrame(raf);
|
|
4594
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
4595
|
+
// 4) Restore focus to the previously-focused element on close.
|
|
4596
|
+
// Guard against the element being removed from the DOM (rare
|
|
4597
|
+
// but possible if the consumer re-renders the page while the
|
|
4598
|
+
// drawer is open).
|
|
4599
|
+
const restore = restoreFocusRef.current;
|
|
4600
|
+
if (restore && document.body.contains(restore)) {
|
|
4601
|
+
restore.focus();
|
|
4602
|
+
}
|
|
4603
|
+
};
|
|
4604
|
+
}, [
|
|
4605
|
+
navOpen
|
|
4606
|
+
]);
|
|
4343
4607
|
return jsxs("div", {
|
|
4344
4608
|
className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root = slotProps.root) == null ? void 0 : _slotProps_root.className),
|
|
4345
4609
|
children: [
|
|
@@ -4357,8 +4621,15 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
|
|
|
4357
4621
|
children: nav
|
|
4358
4622
|
}),
|
|
4359
4623
|
jsx("aside", {
|
|
4624
|
+
ref: drawerRef,
|
|
4360
4625
|
className: cn(v.navMobile(), slotProps == null ? void 0 : (_slotProps_navMobile = slotProps.navMobile) == null ? void 0 : _slotProps_navMobile.className),
|
|
4361
4626
|
"aria-hidden": !navOpen,
|
|
4627
|
+
// When open, the drawer is a modal overlay — `dialog` +
|
|
4628
|
+
// `aria-modal="true"` so screen readers announce it as
|
|
4629
|
+
// such. When closed, drop both attributes (the aria-
|
|
4630
|
+
// hidden=true above already removes it from the AT tree).
|
|
4631
|
+
role: navOpen ? 'dialog' : undefined,
|
|
4632
|
+
"aria-modal": navOpen ? true : undefined,
|
|
4362
4633
|
children: nav
|
|
4363
4634
|
}),
|
|
4364
4635
|
jsx("div", {
|
|
@@ -4663,8 +4934,10 @@ const ConfirmContext = /*#__PURE__*/ createContext(null);
|
|
|
4663
4934
|
'rounded-lg border shadow-lg',
|
|
4664
4935
|
'text-sm bg-neutral-50 text-neutral-900',
|
|
4665
4936
|
// Subtle enter transition — opacity + translate, kept short so a
|
|
4666
|
-
// burst of snackbars feels snappy.
|
|
4667
|
-
|
|
4937
|
+
// burst of snackbars feels snappy. Gated on motion-reduce
|
|
4938
|
+
// (WCAG 2.3.3) — users who request reduced motion see snackbars
|
|
4939
|
+
// pop in instantly without the slide animation.
|
|
4940
|
+
'transition-all duration-200 motion-reduce:transition-none motion-reduce:duration-0',
|
|
4668
4941
|
'data-[state=entered]:opacity-100 data-[state=exited]:opacity-0'
|
|
4669
4942
|
],
|
|
4670
4943
|
icon: 'shrink-0 mt-0.5 w-5 h-5 inline-flex items-center justify-center',
|
|
@@ -6523,6 +6796,492 @@ AspectRatio.displayName = 'AspectRatio';
|
|
|
6523
6796
|
});
|
|
6524
6797
|
VisuallyHidden.displayName = 'VisuallyHidden';
|
|
6525
6798
|
|
|
6799
|
+
/**
|
|
6800
|
+
* `<Dialog>` variant recipe.
|
|
6801
|
+
*
|
|
6802
|
+
* Slots:
|
|
6803
|
+
* - `overlay` — backdrop (Radix's `DialogOverlay`)
|
|
6804
|
+
* - `content` — the dialog box itself
|
|
6805
|
+
* - `title` — heading at the top
|
|
6806
|
+
* - `description` — secondary text under the title
|
|
6807
|
+
* - `closeButton` — top-right `×` button
|
|
6808
|
+
* - `body` — main scrollable area
|
|
6809
|
+
* - `actions` — footer action bar
|
|
6810
|
+
*
|
|
6811
|
+
* Three sizes (`sm` / `md` / `lg`) drive the content max-width.
|
|
6812
|
+
* Motion is gated by `prefers-reduced-motion` so the slide-in
|
|
6813
|
+
* animation collapses to an instant appear on users that opt out.
|
|
6814
|
+
*/ const dialogVariants = tv({
|
|
6815
|
+
slots: {
|
|
6816
|
+
overlay: [
|
|
6817
|
+
'fixed inset-0 z-50 bg-neutral-950/60 backdrop-blur-sm',
|
|
6818
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0',
|
|
6819
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0',
|
|
6820
|
+
'motion-reduce:transition-none motion-reduce:duration-0'
|
|
6821
|
+
],
|
|
6822
|
+
content: [
|
|
6823
|
+
'fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2',
|
|
6824
|
+
'w-full bg-white dark:bg-neutral-900 rounded-lg shadow-xl',
|
|
6825
|
+
'border border-neutral-200 dark:border-neutral-800',
|
|
6826
|
+
'p-6 flex flex-col gap-4 max-h-[90vh]',
|
|
6827
|
+
'focus:outline-none',
|
|
6828
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
6829
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
|
6830
|
+
'motion-reduce:transition-none motion-reduce:duration-0'
|
|
6831
|
+
],
|
|
6832
|
+
title: 'text-lg font-semibold leading-tight text-neutral-900 dark:text-neutral-50',
|
|
6833
|
+
description: 'text-sm text-neutral-600 dark:text-neutral-400',
|
|
6834
|
+
closeButton: [
|
|
6835
|
+
'absolute top-4 right-4 inline-flex items-center justify-center',
|
|
6836
|
+
'h-8 w-8 rounded-md text-neutral-500 hover:text-neutral-900',
|
|
6837
|
+
'dark:text-neutral-400 dark:hover:text-neutral-50',
|
|
6838
|
+
'hover:bg-neutral-100 dark:hover:bg-neutral-800',
|
|
6839
|
+
'focus:outline-none focus:ring-2 focus:ring-primary-500',
|
|
6840
|
+
'transition-colors'
|
|
6841
|
+
],
|
|
6842
|
+
body: 'flex-1 overflow-y-auto',
|
|
6843
|
+
actions: 'flex justify-end gap-2 pt-2'
|
|
6844
|
+
},
|
|
6845
|
+
variants: {
|
|
6846
|
+
size: {
|
|
6847
|
+
sm: {
|
|
6848
|
+
content: 'max-w-sm'
|
|
6849
|
+
},
|
|
6850
|
+
md: {
|
|
6851
|
+
content: 'max-w-md'
|
|
6852
|
+
},
|
|
6853
|
+
lg: {
|
|
6854
|
+
content: 'max-w-2xl'
|
|
6855
|
+
}
|
|
6856
|
+
}
|
|
6857
|
+
},
|
|
6858
|
+
defaultVariants: {
|
|
6859
|
+
size: 'md'
|
|
6860
|
+
}
|
|
6861
|
+
});
|
|
6862
|
+
|
|
6863
|
+
/**
|
|
6864
|
+
* Dashforge TW `<Dialog>` — declarative modal dialog.
|
|
6865
|
+
*
|
|
6866
|
+
* Built on `@radix-ui/react-dialog`:
|
|
6867
|
+
* - APG dialog pattern out of the box (focus trap, restore focus on
|
|
6868
|
+
* close, Esc-to-close, `aria-modal`, `aria-labelledby`).
|
|
6869
|
+
* - Renders into a portal (no z-index hell).
|
|
6870
|
+
* - Scroll lock on `<body>` while open.
|
|
6871
|
+
*
|
|
6872
|
+
* Use the imperative `useDialog()` (export from this same module) if
|
|
6873
|
+
* you want a `confirm()`-style return value pattern (similar to
|
|
6874
|
+
* `useConfirm()` from `ConfirmDialog`). Use `<Dialog>` when you want
|
|
6875
|
+
* the control flow living in your component tree.
|
|
6876
|
+
*/ function Dialog(props) {
|
|
6877
|
+
var _slotProps_overlay, _slotProps_content, _slotProps_title, _slotProps_description, _slotProps_body, _slotProps_closeButton;
|
|
6878
|
+
const { open, onOpenChange, children, title, description, showCloseButton = true, disableBackdropClose = false, disableEscapeClose = false, size = 'md', sx, slotProps } = props;
|
|
6879
|
+
const v = dialogVariants({
|
|
6880
|
+
size
|
|
6881
|
+
});
|
|
6882
|
+
return jsx(RadixDialog.Root, {
|
|
6883
|
+
open: open,
|
|
6884
|
+
onOpenChange: onOpenChange,
|
|
6885
|
+
children: jsxs(RadixDialog.Portal, {
|
|
6886
|
+
children: [
|
|
6887
|
+
jsx(RadixDialog.Overlay, {
|
|
6888
|
+
className: cn(v.overlay(), slotProps == null ? void 0 : (_slotProps_overlay = slotProps.overlay) == null ? void 0 : _slotProps_overlay.className)
|
|
6889
|
+
}),
|
|
6890
|
+
jsxs(RadixDialog.Content, {
|
|
6891
|
+
className: cn(v.content(), sx, slotProps == null ? void 0 : (_slotProps_content = slotProps.content) == null ? void 0 : _slotProps_content.className),
|
|
6892
|
+
onPointerDownOutside: (event)=>{
|
|
6893
|
+
if (disableBackdropClose) event.preventDefault();
|
|
6894
|
+
},
|
|
6895
|
+
onEscapeKeyDown: (event)=>{
|
|
6896
|
+
if (disableEscapeClose) event.preventDefault();
|
|
6897
|
+
},
|
|
6898
|
+
children: [
|
|
6899
|
+
title != null && jsx(RadixDialog.Title, {
|
|
6900
|
+
className: cn(v.title(), slotProps == null ? void 0 : (_slotProps_title = slotProps.title) == null ? void 0 : _slotProps_title.className),
|
|
6901
|
+
children: title
|
|
6902
|
+
}),
|
|
6903
|
+
description != null && jsx(RadixDialog.Description, {
|
|
6904
|
+
className: cn(v.description(), slotProps == null ? void 0 : (_slotProps_description = slotProps.description) == null ? void 0 : _slotProps_description.className),
|
|
6905
|
+
children: description
|
|
6906
|
+
}),
|
|
6907
|
+
jsx("div", {
|
|
6908
|
+
className: cn(v.body(), slotProps == null ? void 0 : (_slotProps_body = slotProps.body) == null ? void 0 : _slotProps_body.className),
|
|
6909
|
+
children: children
|
|
6910
|
+
}),
|
|
6911
|
+
showCloseButton && jsx(RadixDialog.Close, {
|
|
6912
|
+
"aria-label": "Close",
|
|
6913
|
+
className: cn(v.closeButton(), slotProps == null ? void 0 : (_slotProps_closeButton = slotProps.closeButton) == null ? void 0 : _slotProps_closeButton.className),
|
|
6914
|
+
children: jsx("svg", {
|
|
6915
|
+
width: "1em",
|
|
6916
|
+
height: "1em",
|
|
6917
|
+
viewBox: "0 0 16 16",
|
|
6918
|
+
fill: "none",
|
|
6919
|
+
stroke: "currentColor",
|
|
6920
|
+
strokeWidth: "1.5",
|
|
6921
|
+
strokeLinecap: "round",
|
|
6922
|
+
strokeLinejoin: "round",
|
|
6923
|
+
"aria-hidden": "true",
|
|
6924
|
+
children: jsx("path", {
|
|
6925
|
+
d: "M4 4l8 8M12 4l-8 8"
|
|
6926
|
+
})
|
|
6927
|
+
})
|
|
6928
|
+
})
|
|
6929
|
+
]
|
|
6930
|
+
})
|
|
6931
|
+
]
|
|
6932
|
+
})
|
|
6933
|
+
});
|
|
6934
|
+
}
|
|
6935
|
+
|
|
6936
|
+
const tabsVariants = tv({
|
|
6937
|
+
slots: {
|
|
6938
|
+
root: 'flex',
|
|
6939
|
+
list: 'inline-flex items-center gap-1',
|
|
6940
|
+
trigger: [
|
|
6941
|
+
'inline-flex items-center justify-center whitespace-nowrap',
|
|
6942
|
+
'text-sm font-medium transition-colors',
|
|
6943
|
+
'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500',
|
|
6944
|
+
'disabled:opacity-50 disabled:pointer-events-none',
|
|
6945
|
+
'motion-reduce:transition-none'
|
|
6946
|
+
],
|
|
6947
|
+
content: [
|
|
6948
|
+
'mt-3 focus:outline-none',
|
|
6949
|
+
'data-[state=inactive]:hidden'
|
|
6950
|
+
]
|
|
6951
|
+
},
|
|
6952
|
+
variants: {
|
|
6953
|
+
variant: {
|
|
6954
|
+
underline: {
|
|
6955
|
+
list: 'border-b border-neutral-200 dark:border-neutral-800',
|
|
6956
|
+
trigger: [
|
|
6957
|
+
'px-3 py-2 border-b-2 border-transparent text-neutral-600 dark:text-neutral-400',
|
|
6958
|
+
'hover:text-neutral-900 dark:hover:text-neutral-50',
|
|
6959
|
+
'data-[state=active]:border-primary-500 data-[state=active]:text-primary-700',
|
|
6960
|
+
'dark:data-[state=active]:text-primary-400'
|
|
6961
|
+
]
|
|
6962
|
+
},
|
|
6963
|
+
pill: {
|
|
6964
|
+
list: 'rounded-lg bg-neutral-100 dark:bg-neutral-800 p-1',
|
|
6965
|
+
trigger: [
|
|
6966
|
+
'px-3 py-1.5 rounded-md text-neutral-600 dark:text-neutral-400',
|
|
6967
|
+
'hover:text-neutral-900 dark:hover:text-neutral-50',
|
|
6968
|
+
'data-[state=active]:bg-white dark:data-[state=active]:bg-neutral-900',
|
|
6969
|
+
'data-[state=active]:text-neutral-900 dark:data-[state=active]:text-neutral-50',
|
|
6970
|
+
'data-[state=active]:shadow-sm'
|
|
6971
|
+
]
|
|
6972
|
+
}
|
|
6973
|
+
},
|
|
6974
|
+
orientation: {
|
|
6975
|
+
horizontal: {
|
|
6976
|
+
root: 'flex-col',
|
|
6977
|
+
list: 'flex-row'
|
|
6978
|
+
},
|
|
6979
|
+
vertical: {
|
|
6980
|
+
root: 'flex-row gap-4',
|
|
6981
|
+
list: 'flex-col items-stretch'
|
|
6982
|
+
}
|
|
6983
|
+
}
|
|
6984
|
+
},
|
|
6985
|
+
defaultVariants: {
|
|
6986
|
+
variant: 'underline',
|
|
6987
|
+
orientation: 'horizontal'
|
|
6988
|
+
}
|
|
6989
|
+
});
|
|
6990
|
+
|
|
6991
|
+
/**
|
|
6992
|
+
* Dashforge TW `<Tabs>` — declarative tab navigation.
|
|
6993
|
+
*
|
|
6994
|
+
* Built on `@radix-ui/react-tabs`:
|
|
6995
|
+
* - APG tabs pattern (arrow-key navigation, automatic activation,
|
|
6996
|
+
* `role="tablist"` + `role="tab"` + `role="tabpanel"`).
|
|
6997
|
+
* - Controlled / uncontrolled (`value` / `defaultValue`).
|
|
6998
|
+
*
|
|
6999
|
+
* Two variant axes:
|
|
7000
|
+
* - `variant` — `underline` (default) | `pill`
|
|
7001
|
+
* - `orientation` — `horizontal` (default) | `vertical`
|
|
7002
|
+
*/ function Tabs(props) {
|
|
7003
|
+
var _items_, _slotProps_root, _slotProps_list;
|
|
7004
|
+
const { items, value, defaultValue, onValueChange, variant = 'underline', orientation = 'horizontal', sx, slotProps } = props;
|
|
7005
|
+
const v = tabsVariants({
|
|
7006
|
+
variant,
|
|
7007
|
+
orientation
|
|
7008
|
+
});
|
|
7009
|
+
const resolvedDefault = defaultValue != null ? defaultValue : (_items_ = items[0]) == null ? void 0 : _items_.value;
|
|
7010
|
+
return jsxs(RadixTabs.Root, {
|
|
7011
|
+
value: value,
|
|
7012
|
+
defaultValue: resolvedDefault,
|
|
7013
|
+
onValueChange: onValueChange,
|
|
7014
|
+
orientation: orientation,
|
|
7015
|
+
className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root = slotProps.root) == null ? void 0 : _slotProps_root.className),
|
|
7016
|
+
children: [
|
|
7017
|
+
jsx(RadixTabs.List, {
|
|
7018
|
+
className: cn(v.list(), slotProps == null ? void 0 : (_slotProps_list = slotProps.list) == null ? void 0 : _slotProps_list.className),
|
|
7019
|
+
children: items.map((item)=>{
|
|
7020
|
+
var _slotProps_trigger;
|
|
7021
|
+
return jsx(RadixTabs.Trigger, {
|
|
7022
|
+
value: item.value,
|
|
7023
|
+
disabled: item.disabled,
|
|
7024
|
+
className: cn(v.trigger(), slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
|
|
7025
|
+
children: item.label
|
|
7026
|
+
}, item.value);
|
|
7027
|
+
})
|
|
7028
|
+
}),
|
|
7029
|
+
items.map((item)=>{
|
|
7030
|
+
var _slotProps_content;
|
|
7031
|
+
return jsx(RadixTabs.Content, {
|
|
7032
|
+
value: item.value,
|
|
7033
|
+
className: cn(v.content(), slotProps == null ? void 0 : (_slotProps_content = slotProps.content) == null ? void 0 : _slotProps_content.className),
|
|
7034
|
+
children: item.content
|
|
7035
|
+
}, item.value);
|
|
7036
|
+
})
|
|
7037
|
+
]
|
|
7038
|
+
});
|
|
7039
|
+
}
|
|
7040
|
+
|
|
7041
|
+
const tooltipVariants = tv({
|
|
7042
|
+
slots: {
|
|
7043
|
+
content: [
|
|
7044
|
+
'z-50 max-w-xs rounded-md px-3 py-1.5 text-xs font-medium',
|
|
7045
|
+
'bg-neutral-900 text-neutral-50',
|
|
7046
|
+
'dark:bg-neutral-50 dark:text-neutral-900',
|
|
7047
|
+
'shadow-md',
|
|
7048
|
+
'data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95',
|
|
7049
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
|
7050
|
+
'motion-reduce:transition-none motion-reduce:duration-0'
|
|
7051
|
+
],
|
|
7052
|
+
arrow: 'fill-neutral-900 dark:fill-neutral-50'
|
|
7053
|
+
}
|
|
7054
|
+
});
|
|
7055
|
+
|
|
7056
|
+
/**
|
|
7057
|
+
* Dashforge TW `<Tooltip>` — hoverable / focusable tooltip.
|
|
7058
|
+
*
|
|
7059
|
+
* Built on `@radix-ui/react-tooltip`:
|
|
7060
|
+
* - APG tooltip pattern: `role="tooltip"`, `aria-describedby` wired
|
|
7061
|
+
* to the trigger automatically (Radix manages the id linkage).
|
|
7062
|
+
* - Shows on hover OR keyboard focus.
|
|
7063
|
+
* - Dismissed on Escape or pointer leave.
|
|
7064
|
+
*
|
|
7065
|
+
* Wrap any single React node — it becomes the trigger via Radix's
|
|
7066
|
+
* `asChild` slot. The trigger inherits `aria-describedby` so screen
|
|
7067
|
+
* readers announce the tooltip content along with the trigger.
|
|
7068
|
+
*
|
|
7069
|
+
* @example
|
|
7070
|
+
* ```tsx
|
|
7071
|
+
* <Tooltip content="Delete this item">
|
|
7072
|
+
* <Button variant="ghost">
|
|
7073
|
+
* <TrashIcon />
|
|
7074
|
+
* </Button>
|
|
7075
|
+
* </Tooltip>
|
|
7076
|
+
* ```
|
|
7077
|
+
*
|
|
7078
|
+
* Each consumer can also wrap the entire app once in
|
|
7079
|
+
* `<RadixTooltip.Provider>` to share delay/skip configuration; we
|
|
7080
|
+
* include a per-component provider here for ease-of-use.
|
|
7081
|
+
*/ function Tooltip(props) {
|
|
7082
|
+
var _slotProps_content, _slotProps_arrow;
|
|
7083
|
+
const { children, content, side = 'top', align = 'center', hideArrow = false, delayDuration = 200, open, onOpenChange, sideOffset = 4, slotProps } = props;
|
|
7084
|
+
const v = tooltipVariants();
|
|
7085
|
+
return jsx(RadixTooltip.Provider, {
|
|
7086
|
+
delayDuration: delayDuration,
|
|
7087
|
+
children: jsxs(RadixTooltip.Root, {
|
|
7088
|
+
open: open,
|
|
7089
|
+
onOpenChange: onOpenChange,
|
|
7090
|
+
children: [
|
|
7091
|
+
jsx(RadixTooltip.Trigger, {
|
|
7092
|
+
asChild: true,
|
|
7093
|
+
children: children
|
|
7094
|
+
}),
|
|
7095
|
+
jsx(RadixTooltip.Portal, {
|
|
7096
|
+
children: jsxs(RadixTooltip.Content, {
|
|
7097
|
+
side: side,
|
|
7098
|
+
align: align,
|
|
7099
|
+
sideOffset: sideOffset,
|
|
7100
|
+
className: cn(v.content(), slotProps == null ? void 0 : (_slotProps_content = slotProps.content) == null ? void 0 : _slotProps_content.className),
|
|
7101
|
+
children: [
|
|
7102
|
+
content,
|
|
7103
|
+
!hideArrow && jsx(RadixTooltip.Arrow, {
|
|
7104
|
+
className: cn(v.arrow(), slotProps == null ? void 0 : (_slotProps_arrow = slotProps.arrow) == null ? void 0 : _slotProps_arrow.className)
|
|
7105
|
+
})
|
|
7106
|
+
]
|
|
7107
|
+
})
|
|
7108
|
+
})
|
|
7109
|
+
]
|
|
7110
|
+
})
|
|
7111
|
+
});
|
|
7112
|
+
}
|
|
7113
|
+
|
|
7114
|
+
const popoverVariants = tv({
|
|
7115
|
+
slots: {
|
|
7116
|
+
content: [
|
|
7117
|
+
'z-50 rounded-md border border-neutral-200 dark:border-neutral-800',
|
|
7118
|
+
'bg-white dark:bg-neutral-900 p-4 shadow-lg',
|
|
7119
|
+
'text-sm text-neutral-900 dark:text-neutral-50',
|
|
7120
|
+
'focus:outline-none',
|
|
7121
|
+
'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
|
|
7122
|
+
'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
|
|
7123
|
+
'motion-reduce:transition-none motion-reduce:duration-0'
|
|
7124
|
+
],
|
|
7125
|
+
arrow: 'fill-white dark:fill-neutral-900'
|
|
7126
|
+
}
|
|
7127
|
+
});
|
|
7128
|
+
|
|
7129
|
+
/**
|
|
7130
|
+
* Dashforge TW `<Popover>` — clickable floating content panel.
|
|
7131
|
+
*
|
|
7132
|
+
* Built on `@radix-ui/react-popover`:
|
|
7133
|
+
* - Focus trap inside the popover (Tab cycles within).
|
|
7134
|
+
* - Outside-click + Escape dismiss.
|
|
7135
|
+
* - APG dialog-like semantics (`role="dialog"` on content).
|
|
7136
|
+
* - Portal-rendered.
|
|
7137
|
+
*
|
|
7138
|
+
* Use `<Popover>` for menus / pickers / settings panels with
|
|
7139
|
+
* interactive children. Use `<Tooltip>` for read-only hints.
|
|
7140
|
+
*/ function Popover(props) {
|
|
7141
|
+
var _slotProps_content, _slotProps_arrow;
|
|
7142
|
+
const { children, content, side = 'bottom', align = 'center', showArrow = false, open, onOpenChange, sideOffset = 8, width, slotProps } = props;
|
|
7143
|
+
const v = popoverVariants();
|
|
7144
|
+
return jsxs(RadixPopover.Root, {
|
|
7145
|
+
open: open,
|
|
7146
|
+
onOpenChange: onOpenChange,
|
|
7147
|
+
children: [
|
|
7148
|
+
jsx(RadixPopover.Trigger, {
|
|
7149
|
+
asChild: true,
|
|
7150
|
+
children: children
|
|
7151
|
+
}),
|
|
7152
|
+
jsx(RadixPopover.Portal, {
|
|
7153
|
+
children: jsxs(RadixPopover.Content, {
|
|
7154
|
+
side: side,
|
|
7155
|
+
align: align,
|
|
7156
|
+
sideOffset: sideOffset,
|
|
7157
|
+
style: width != null ? {
|
|
7158
|
+
width
|
|
7159
|
+
} : undefined,
|
|
7160
|
+
className: cn(v.content(), slotProps == null ? void 0 : (_slotProps_content = slotProps.content) == null ? void 0 : _slotProps_content.className),
|
|
7161
|
+
children: [
|
|
7162
|
+
content,
|
|
7163
|
+
showArrow && jsx(RadixPopover.Arrow, {
|
|
7164
|
+
className: cn(v.arrow(), slotProps == null ? void 0 : (_slotProps_arrow = slotProps.arrow) == null ? void 0 : _slotProps_arrow.className)
|
|
7165
|
+
})
|
|
7166
|
+
]
|
|
7167
|
+
})
|
|
7168
|
+
})
|
|
7169
|
+
]
|
|
7170
|
+
});
|
|
7171
|
+
}
|
|
7172
|
+
|
|
7173
|
+
const accordionVariants = tv({
|
|
7174
|
+
slots: {
|
|
7175
|
+
root: 'w-full',
|
|
7176
|
+
item: 'border-b border-neutral-200 dark:border-neutral-800',
|
|
7177
|
+
header: 'flex',
|
|
7178
|
+
trigger: [
|
|
7179
|
+
'flex flex-1 items-center justify-between py-3 text-left',
|
|
7180
|
+
'text-sm font-medium text-neutral-900 dark:text-neutral-50',
|
|
7181
|
+
'transition-all hover:underline',
|
|
7182
|
+
'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:rounded',
|
|
7183
|
+
'[&[data-state=open]>svg]:rotate-180',
|
|
7184
|
+
'disabled:opacity-50 disabled:pointer-events-none',
|
|
7185
|
+
'motion-reduce:transition-none'
|
|
7186
|
+
],
|
|
7187
|
+
content: [
|
|
7188
|
+
'overflow-hidden text-sm text-neutral-700 dark:text-neutral-300',
|
|
7189
|
+
'data-[state=open]:animate-accordion-down',
|
|
7190
|
+
'data-[state=closed]:animate-accordion-up',
|
|
7191
|
+
'motion-reduce:animate-none'
|
|
7192
|
+
],
|
|
7193
|
+
chevron: [
|
|
7194
|
+
'h-4 w-4 shrink-0 text-neutral-500 transition-transform duration-200',
|
|
7195
|
+
'motion-reduce:transition-none motion-reduce:duration-0'
|
|
7196
|
+
]
|
|
7197
|
+
}
|
|
7198
|
+
});
|
|
7199
|
+
|
|
7200
|
+
/**
|
|
7201
|
+
* Dashforge TW `<Accordion>` — collapsible section list.
|
|
7202
|
+
*
|
|
7203
|
+
* Built on `@radix-ui/react-accordion`:
|
|
7204
|
+
* - APG accordion pattern: `role="region"` on content, header
|
|
7205
|
+
* button with `aria-expanded` and `aria-controls` linked to
|
|
7206
|
+
* the panel.
|
|
7207
|
+
* - Keyboard support: Space / Enter toggle, ArrowDown / ArrowUp
|
|
7208
|
+
* move focus between triggers, Home / End to extremes.
|
|
7209
|
+
* - Two modes:
|
|
7210
|
+
* - `type="single"` — at most one section open at a time;
|
|
7211
|
+
* `collapsible` allows clicking the open section to close it
|
|
7212
|
+
* (default true).
|
|
7213
|
+
* - `type="multiple"` — multiple sections open simultaneously.
|
|
7214
|
+
*
|
|
7215
|
+
* The trigger renders a chevron that flips 180° via CSS
|
|
7216
|
+
* (`data-state=open` selector) — no React state, no JS animation.
|
|
7217
|
+
*/ function Accordion(props) {
|
|
7218
|
+
var _props_collapsible;
|
|
7219
|
+
var _slotProps_root;
|
|
7220
|
+
const v = accordionVariants();
|
|
7221
|
+
const { items, sx, slotProps } = props;
|
|
7222
|
+
const renderItems = (items, slotProps)=>items.map((item)=>{
|
|
7223
|
+
var _slotProps_item, _slotProps_header, _slotProps_trigger, _slotProps_chevron, _slotProps_content;
|
|
7224
|
+
return jsxs(RadixAccordion.Item, {
|
|
7225
|
+
value: item.value,
|
|
7226
|
+
disabled: item.disabled,
|
|
7227
|
+
className: cn(v.item(), slotProps == null ? void 0 : (_slotProps_item = slotProps.item) == null ? void 0 : _slotProps_item.className),
|
|
7228
|
+
children: [
|
|
7229
|
+
jsx(RadixAccordion.Header, {
|
|
7230
|
+
className: cn(v.header(), slotProps == null ? void 0 : (_slotProps_header = slotProps.header) == null ? void 0 : _slotProps_header.className),
|
|
7231
|
+
children: jsxs(RadixAccordion.Trigger, {
|
|
7232
|
+
className: cn(v.trigger(), slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
|
|
7233
|
+
children: [
|
|
7234
|
+
item.header,
|
|
7235
|
+
jsx("svg", {
|
|
7236
|
+
className: cn(v.chevron(), slotProps == null ? void 0 : (_slotProps_chevron = slotProps.chevron) == null ? void 0 : _slotProps_chevron.className),
|
|
7237
|
+
width: "1em",
|
|
7238
|
+
height: "1em",
|
|
7239
|
+
viewBox: "0 0 16 16",
|
|
7240
|
+
fill: "none",
|
|
7241
|
+
stroke: "currentColor",
|
|
7242
|
+
strokeWidth: "1.5",
|
|
7243
|
+
strokeLinecap: "round",
|
|
7244
|
+
strokeLinejoin: "round",
|
|
7245
|
+
"aria-hidden": "true",
|
|
7246
|
+
children: jsx("path", {
|
|
7247
|
+
d: "M4 6l4 4 4-4"
|
|
7248
|
+
})
|
|
7249
|
+
})
|
|
7250
|
+
]
|
|
7251
|
+
})
|
|
7252
|
+
}),
|
|
7253
|
+
jsx(RadixAccordion.Content, {
|
|
7254
|
+
className: cn(v.content(), slotProps == null ? void 0 : (_slotProps_content = slotProps.content) == null ? void 0 : _slotProps_content.className),
|
|
7255
|
+
children: jsx("div", {
|
|
7256
|
+
className: "pb-3 pt-0",
|
|
7257
|
+
children: item.content
|
|
7258
|
+
})
|
|
7259
|
+
})
|
|
7260
|
+
]
|
|
7261
|
+
}, item.value);
|
|
7262
|
+
});
|
|
7263
|
+
if (props.type === 'multiple') {
|
|
7264
|
+
var _slotProps_root1;
|
|
7265
|
+
return jsx(RadixAccordion.Root, {
|
|
7266
|
+
type: "multiple",
|
|
7267
|
+
value: props.value,
|
|
7268
|
+
defaultValue: props.defaultValue,
|
|
7269
|
+
onValueChange: props.onValueChange,
|
|
7270
|
+
className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root1 = slotProps.root) == null ? void 0 : _slotProps_root1.className),
|
|
7271
|
+
children: renderItems(items, slotProps)
|
|
7272
|
+
});
|
|
7273
|
+
}
|
|
7274
|
+
return jsx(RadixAccordion.Root, {
|
|
7275
|
+
type: "single",
|
|
7276
|
+
collapsible: (_props_collapsible = props.collapsible) != null ? _props_collapsible : true,
|
|
7277
|
+
value: props.value,
|
|
7278
|
+
defaultValue: props.defaultValue,
|
|
7279
|
+
onValueChange: props.onValueChange,
|
|
7280
|
+
className: cn(v.root(), sx, slotProps == null ? void 0 : (_slotProps_root = slotProps.root) == null ? void 0 : _slotProps_root.className),
|
|
7281
|
+
children: renderItems(items, slotProps)
|
|
7282
|
+
});
|
|
7283
|
+
}
|
|
7284
|
+
|
|
6526
7285
|
/**
|
|
6527
7286
|
* @dashforge/tw
|
|
6528
7287
|
*
|
|
@@ -6550,6 +7309,6 @@ VisuallyHidden.displayName = 'VisuallyHidden';
|
|
|
6550
7309
|
*/ // ───── Components ─────
|
|
6551
7310
|
/**
|
|
6552
7311
|
* Package version (synced with `package.json` at publish time).
|
|
6553
|
-
*/ const VERSION = '0.
|
|
7312
|
+
*/ const VERSION = '0.4.0-beta';
|
|
6554
7313
|
|
|
6555
|
-
export { AppShell, AspectRatio, Autocomplete, Box, Breadcrumbs, Button, Checkbox, ConfirmDialogProvider, Container, DateTimePicker, Divider, Grid, LeftNav, NumberField, OTPField, RadioGroup, SnackbarProvider, Stack, Switch, TextField, Textarea, TopBar, Typography, VERSION, VisuallyHidden, appShellVariants, autocompleteVariants, boxVariants, breadcrumbsVariants, buttonVariants, checkboxVariants, cn, confirmDialogVariants, containerVariants, dateTimePickerVariants, dividerLineVariants, dividerVariants, gridVariants, isoToInputValue, leftNavVariants, numberFieldVariants, otpFieldVariants, radioGroupVariants, snackbarVariants, stackVariants, switchVariants, textFieldVariants, textareaVariants, topBarVariants, typographyVariants, useAccessState, useConfirm, useSnackbar };
|
|
7314
|
+
export { Accordion, AppShell, AspectRatio, Autocomplete, Box, Breadcrumbs, Button, Checkbox, ConfirmDialogProvider, Container, DateTimePicker, Dialog, Divider, Grid, LeftNav, NumberField, OTPField, Popover, RadioGroup, SnackbarProvider, Stack, Switch, Tabs, TextField, Textarea, Tooltip, TopBar, Typography, VERSION, VisuallyHidden, accordionVariants, appShellVariants, autocompleteVariants, boxVariants, breadcrumbsVariants, buttonVariants, checkboxVariants, cn, confirmDialogVariants, containerVariants, dateTimePickerVariants, dialogVariants, dividerLineVariants, dividerVariants, gridVariants, isoToInputValue, leftNavVariants, numberFieldVariants, otpFieldVariants, popoverVariants, radioGroupVariants, snackbarVariants, stackVariants, switchVariants, tabsVariants, textFieldVariants, textareaVariants, tooltipVariants, topBarVariants, typographyVariants, useAccessState, useConfirm, useSnackbar };
|