@thangnqdev/ui 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +54 -206
- package/dist/bento/index.cjs.map +1 -1
- package/dist/bento/index.js +2 -2
- package/dist/bento/styles.css +2 -46
- package/dist/buttons/index.cjs +111 -18
- package/dist/buttons/index.cjs.map +1 -1
- package/dist/buttons/index.d.cts +1 -1
- package/dist/buttons/index.d.ts +1 -1
- package/dist/buttons/index.js +3 -3
- package/dist/buttons/styles.css +2 -6
- package/dist/{chunk-4S6L5V7X.js → chunk-2YJBW4E2.js} +2 -2
- package/dist/chunk-2YJBW4E2.js.map +1 -0
- package/dist/{chunk-F5Q7BTMH.js → chunk-4CRFNALF.js} +1011 -556
- package/dist/chunk-4CRFNALF.js.map +1 -0
- package/dist/{chunk-LWFRUJRU.js → chunk-4MS6ZHFQ.js} +225 -41
- package/dist/chunk-4MS6ZHFQ.js.map +1 -0
- package/dist/{chunk-2OXZK6IP.js → chunk-77KTYOMQ.js} +3 -3
- package/dist/chunk-77KTYOMQ.js.map +1 -0
- package/dist/{chunk-IABPUCAQ.js → chunk-ADO3SVUA.js} +2 -2
- package/dist/chunk-ADO3SVUA.js.map +1 -0
- package/dist/{chunk-GXI2H5XA.js → chunk-D7FB3TCA.js} +3 -3
- package/dist/chunk-D7FB3TCA.js.map +1 -0
- package/dist/chunk-DSEL7ELZ.js +314 -0
- package/dist/chunk-DSEL7ELZ.js.map +1 -0
- package/dist/{chunk-KJRBRTQE.js → chunk-EXFR2BFJ.js} +37 -28
- package/dist/chunk-EXFR2BFJ.js.map +1 -0
- package/dist/{chunk-PF4ZHGVW.js → chunk-GXWB6BSY.js} +116 -23
- package/dist/chunk-GXWB6BSY.js.map +1 -0
- package/dist/{chunk-66VWUJEI.js → chunk-I2FQBMVW.js} +3 -3
- package/dist/chunk-I2FQBMVW.js.map +1 -0
- package/dist/{chunk-EU2LPUYP.js → chunk-I5O2WCGF.js} +3 -3
- package/dist/chunk-I5O2WCGF.js.map +1 -0
- package/dist/{chunk-ATYGDTMK.js → chunk-ME4XILG5.js} +5 -5
- package/dist/chunk-ME4XILG5.js.map +1 -0
- package/dist/{chunk-5FZ6ZFII.js → chunk-PC5SZFZC.js} +373 -150
- package/dist/chunk-PC5SZFZC.js.map +1 -0
- package/dist/{chunk-C4SUXMI3.js → chunk-S6XJMYME.js} +3 -3
- package/dist/chunk-S6XJMYME.js.map +1 -0
- package/dist/{chunk-A7P3O5Z5.js → chunk-V52JOSDF.js} +3 -3
- package/dist/chunk-V52JOSDF.js.map +1 -0
- package/dist/{chunk-NFVONJUK.js → chunk-W5WNWTQC.js} +455 -211
- package/dist/chunk-W5WNWTQC.js.map +1 -0
- package/dist/{chunk-WAFHC4DQ.js → chunk-YJ64RI7J.js} +3 -3
- package/dist/chunk-YJ64RI7J.js.map +1 -0
- package/dist/chunk-YOCGBORV.js +155 -0
- package/dist/chunk-YOCGBORV.js.map +1 -0
- package/dist/chunk-ZEDXARXW.js +96 -0
- package/dist/chunk-ZEDXARXW.js.map +1 -0
- package/dist/components.css +2 -0
- package/dist/core/index.cjs +33 -24
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/styles.css +2 -134
- package/dist/data-display/index.cjs +770 -247
- package/dist/data-display/index.cjs.map +1 -1
- package/dist/data-display/index.d.cts +1 -1
- package/dist/data-display/index.d.ts +1 -1
- package/dist/data-display/index.js +5 -4
- package/dist/data-display/styles.css +2 -4
- package/dist/feedback/index.cjs.map +1 -1
- package/dist/feedback/index.js +2 -2
- package/dist/feedback/styles.css +2 -4
- package/dist/forms/index.cjs +1211 -459
- package/dist/forms/index.cjs.map +1 -1
- package/dist/forms/index.d.cts +1 -1
- package/dist/forms/index.d.ts +1 -1
- package/dist/forms/index.js +8 -8
- package/dist/forms/styles.css +2 -6
- package/dist/glass/index.cjs.map +1 -1
- package/dist/glass/index.js +2 -2
- package/dist/glass/styles.css +2 -81
- package/dist/{index-D6fE7w-b.d.cts → index-BGt_hecO.d.cts} +1 -0
- package/dist/{index-D6fE7w-b.d.ts → index-BGt_hecO.d.ts} +1 -0
- package/dist/{index-DzcWh1Hs.d.cts → index-BtDvpZCf.d.cts} +7 -0
- package/dist/{index-DzcWh1Hs.d.ts → index-BtDvpZCf.d.ts} +7 -0
- package/dist/{index-Cle6QzQl.d.ts → index-COX1sBUN.d.ts} +27 -3
- package/dist/{index-BkRqGNG1.d.ts → index-Cg8MuP7u.d.cts} +40 -13
- package/dist/{index-BkRqGNG1.d.cts → index-Cg8MuP7u.d.ts} +40 -13
- package/dist/{index-CenuF_P2.d.ts → index-DHkPRTvE.d.cts} +39 -8
- package/dist/{index-CenuF_P2.d.cts → index-DHkPRTvE.d.ts} +39 -8
- package/dist/{index-TyK-Ldpy.d.cts → index-Du_oht9k.d.cts} +27 -3
- package/dist/index.cjs +2481 -917
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +19 -19
- package/dist/layout/index.cjs.map +1 -1
- package/dist/layout/index.js +2 -2
- package/dist/layout/styles.css +2 -8
- package/dist/navigation/index.cjs +288 -48
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +1 -1
- package/dist/navigation/index.d.ts +1 -1
- package/dist/navigation/index.js +6 -6
- package/dist/navigation/styles.css +2 -4
- package/dist/overlays/index.cjs +566 -229
- package/dist/overlays/index.cjs.map +1 -1
- package/dist/overlays/index.d.cts +1 -1
- package/dist/overlays/index.d.ts +1 -1
- package/dist/overlays/index.js +7 -7
- package/dist/overlays/styles.css +2 -8
- package/dist/reset.css +45 -0
- package/dist/styles.css +1 -1
- package/dist/tokens.css +11 -0
- package/dist/typography/index.cjs.map +1 -1
- package/dist/typography/index.js +4 -4
- package/dist/typography/styles.css +2 -5
- package/llms.txt +211 -113
- package/package.json +160 -116
- package/src/bento/BentoCard.tsx +140 -140
- package/src/bento/BentoGrid.tsx +50 -50
- package/src/bento/index.ts +2 -2
- package/src/bento/tokens.css +46 -46
- package/src/buttons/Button.tsx +104 -104
- package/src/buttons/ButtonGroup.tsx +43 -43
- package/src/buttons/IconButton.tsx +79 -79
- package/src/buttons/SplitButton.tsx +186 -86
- package/src/buttons/ToggleButton.tsx +157 -157
- package/src/buttons/index.ts +5 -5
- package/src/buttons/tokens.css +6 -6
- package/src/core/ThemeProvider.tsx +135 -123
- package/src/core/index.ts +2 -2
- package/src/core/tokens.css +134 -134
- package/src/data-display/Accordion.tsx +147 -147
- package/src/data-display/Avatar.tsx +134 -134
- package/src/data-display/Card.tsx +112 -112
- package/src/data-display/Chip.tsx +74 -74
- package/src/data-display/DataTablePro.tsx +299 -121
- package/src/data-display/StatCard.tsx +60 -60
- package/src/data-display/Table.tsx +74 -74
- package/src/data-display/Timeline.tsx +62 -62
- package/src/data-display/TreeView.tsx +243 -104
- package/src/data-display/tokens.css +4 -4
- package/src/feedback/Alert.tsx +80 -80
- package/src/feedback/EmptyState.tsx +45 -45
- package/src/feedback/Skeleton.tsx +66 -66
- package/src/feedback/Spinner.tsx +65 -65
- package/src/feedback/index.ts +5 -5
- package/src/feedback/tokens.css +4 -4
- package/src/forms/Checkbox.tsx +149 -69
- package/src/forms/CheckboxGroup.tsx +76 -29
- package/src/forms/Combobox.tsx +172 -28
- package/src/forms/DatePicker.tsx +385 -81
- package/src/forms/FileUpload.tsx +51 -7
- package/src/forms/FormField.tsx +115 -115
- package/src/forms/Input.tsx +151 -151
- package/src/forms/NumberInput.tsx +34 -20
- package/src/forms/PasswordInput.tsx +35 -35
- package/src/forms/PinInput.tsx +139 -125
- package/src/forms/Radio.tsx +142 -142
- package/src/forms/RangeSlider.tsx +237 -111
- package/src/forms/SearchInput.tsx +34 -34
- package/src/forms/Select.tsx +103 -103
- package/src/forms/Slider.tsx +85 -85
- package/src/forms/Textarea.tsx +114 -114
- package/src/forms/tokens.css +6 -6
- package/src/glass/GlassButton.tsx +59 -59
- package/src/glass/GlassCard.tsx +71 -71
- package/src/glass/index.ts +3 -3
- package/src/glass/tokens.css +81 -81
- package/src/index.ts +26 -26
- package/src/layout/AspectRatio.tsx +39 -39
- package/src/layout/Container.tsx +53 -53
- package/src/layout/Divider.tsx +61 -61
- package/src/layout/Flex.tsx +79 -79
- package/src/layout/Grid.tsx +124 -124
- package/src/layout/PageLayout.tsx +59 -59
- package/src/layout/Section.tsx +47 -47
- package/src/layout/Spacer.tsx +30 -30
- package/src/layout/Stack.tsx +88 -88
- package/src/layout/tokens.css +8 -8
- package/src/navigation/Breadcrumb.tsx +73 -73
- package/src/navigation/CommandPalette.tsx +142 -142
- package/src/navigation/DropdownMenu.tsx +244 -160
- package/src/navigation/Pagination.tsx +114 -114
- package/src/navigation/Stepper.tsx +93 -93
- package/src/navigation/Tabs.tsx +265 -133
- package/src/navigation/index.ts +6 -6
- package/src/navigation/tokens.css +4 -4
- package/src/overlays/AlertDialog.tsx +63 -54
- package/src/overlays/BottomSheet.tsx +30 -10
- package/src/overlays/ContextMenu.tsx +51 -9
- package/src/overlays/Drawer.tsx +160 -145
- package/src/overlays/FocusTrap.tsx +122 -49
- package/src/overlays/Modal.tsx +296 -219
- package/src/overlays/Popover.tsx +55 -25
- package/src/overlays/Portal.tsx +23 -23
- package/src/overlays/Toast.tsx +175 -137
- package/src/overlays/Tooltip.tsx +125 -100
- package/src/overlays/tokens.css +8 -8
- package/src/registry/components.ts +1368 -0
- package/src/styles/components.css +39 -0
- package/src/styles/index.css +2 -93
- package/src/styles/reset.css +45 -0
- package/src/styles/tokens.css +11 -2
- package/src/typography/Blockquote.tsx +32 -32
- package/src/typography/Code.tsx +89 -89
- package/src/typography/Heading.tsx +56 -56
- package/src/typography/Kbd.tsx +25 -25
- package/src/typography/Label.tsx +47 -47
- package/src/typography/Link.tsx +56 -56
- package/src/typography/Text.tsx +62 -62
- package/src/typography/index.ts +7 -7
- package/src/typography/tokens.css +5 -5
- package/src/utils/cn.ts +6 -6
- package/src/utils/scroll-lock.ts +19 -0
- package/src/utils/useControllableState.ts +54 -0
- package/ui-contract.json +192 -35
- package/dist/chunk-2OXZK6IP.js.map +0 -1
- package/dist/chunk-4S6L5V7X.js.map +0 -1
- package/dist/chunk-5FZ6ZFII.js.map +0 -1
- package/dist/chunk-66VWUJEI.js.map +0 -1
- package/dist/chunk-A7P3O5Z5.js.map +0 -1
- package/dist/chunk-ATYGDTMK.js.map +0 -1
- package/dist/chunk-C4SUXMI3.js.map +0 -1
- package/dist/chunk-EU2LPUYP.js.map +0 -1
- package/dist/chunk-F5Q7BTMH.js.map +0 -1
- package/dist/chunk-GXI2H5XA.js.map +0 -1
- package/dist/chunk-H3LCNPMC.js +0 -101
- package/dist/chunk-H3LCNPMC.js.map +0 -1
- package/dist/chunk-IABPUCAQ.js.map +0 -1
- package/dist/chunk-KJRBRTQE.js.map +0 -1
- package/dist/chunk-LBUBXUYQ.js +0 -40
- package/dist/chunk-LBUBXUYQ.js.map +0 -1
- package/dist/chunk-LWFRUJRU.js.map +0 -1
- package/dist/chunk-NFVONJUK.js.map +0 -1
- package/dist/chunk-PF4ZHGVW.js.map +0 -1
- package/dist/chunk-WAFHC4DQ.js.map +0 -1
- package/dist/chunk-X76KBH4Y.js +0 -71
- package/dist/chunk-X76KBH4Y.js.map +0 -1
package/dist/overlays/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React8 = require('react');
|
|
4
4
|
var reactDom = require('react-dom');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var classVarianceAuthority = require('class-variance-authority');
|
|
@@ -8,10 +8,14 @@ var lucideReact = require('lucide-react');
|
|
|
8
8
|
var clsx = require('clsx');
|
|
9
9
|
var tailwindMerge = require('tailwind-merge');
|
|
10
10
|
|
|
11
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
|
|
13
|
+
var React8__default = /*#__PURE__*/_interopDefault(React8);
|
|
14
|
+
|
|
11
15
|
// src/overlays/Portal.tsx
|
|
12
16
|
function Portal({ children, container }) {
|
|
13
|
-
const [mounted, setMounted] =
|
|
14
|
-
|
|
17
|
+
const [mounted, setMounted] = React8.useState(false);
|
|
18
|
+
React8.useEffect(() => {
|
|
15
19
|
setMounted(true);
|
|
16
20
|
return () => setMounted(false);
|
|
17
21
|
}, []);
|
|
@@ -20,44 +24,119 @@ function Portal({ children, container }) {
|
|
|
20
24
|
if (!target) return null;
|
|
21
25
|
return reactDom.createPortal(children, target);
|
|
22
26
|
}
|
|
23
|
-
var FOCUSABLE_SELECTOR =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
var FOCUSABLE_SELECTOR = [
|
|
28
|
+
"a[href]",
|
|
29
|
+
"button:not([disabled])",
|
|
30
|
+
"textarea:not([disabled])",
|
|
31
|
+
"input:not([disabled])",
|
|
32
|
+
"select:not([disabled])",
|
|
33
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
34
|
+
'[contenteditable="true"]'
|
|
35
|
+
].join(", ");
|
|
36
|
+
var trapStack = [];
|
|
37
|
+
function FocusTrap({
|
|
38
|
+
children,
|
|
39
|
+
active = true,
|
|
40
|
+
autoFocus = true,
|
|
41
|
+
restoreFocus = true
|
|
42
|
+
}) {
|
|
43
|
+
const rootRef = React8.useRef(null);
|
|
44
|
+
const previousActiveElementRef = React8.useRef(null);
|
|
45
|
+
React8.useEffect(() => {
|
|
27
46
|
if (!active) return;
|
|
47
|
+
if (typeof document !== "undefined") {
|
|
48
|
+
previousActiveElementRef.current = document.activeElement;
|
|
49
|
+
}
|
|
28
50
|
const root = rootRef.current;
|
|
29
51
|
if (!root) return;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
trapStack.push(root);
|
|
53
|
+
if (autoFocus) {
|
|
54
|
+
const timer = setTimeout(() => {
|
|
55
|
+
const focusable = root.querySelectorAll(FOCUSABLE_SELECTOR);
|
|
56
|
+
if (focusable.length > 0) {
|
|
57
|
+
focusable[0].focus();
|
|
58
|
+
} else if (typeof root.focus === "function") {
|
|
59
|
+
root.focus();
|
|
60
|
+
}
|
|
61
|
+
}, 0);
|
|
62
|
+
return () => clearTimeout(timer);
|
|
35
63
|
}
|
|
64
|
+
return () => {
|
|
65
|
+
const idx = trapStack.indexOf(root);
|
|
66
|
+
if (idx !== -1) trapStack.splice(idx, 1);
|
|
67
|
+
};
|
|
68
|
+
}, [active, autoFocus]);
|
|
69
|
+
React8.useEffect(() => {
|
|
70
|
+
if (!active) return;
|
|
36
71
|
const handleKeyDown = (e) => {
|
|
37
72
|
if (e.key !== "Tab") return;
|
|
73
|
+
const root = rootRef.current;
|
|
74
|
+
if (!root) return;
|
|
75
|
+
if (trapStack.length > 0 && trapStack[trapStack.length - 1] !== root) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const focusable = Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR)).filter(
|
|
79
|
+
(el) => el.offsetParent !== null || el.getClientRects().length > 0
|
|
80
|
+
);
|
|
81
|
+
if (focusable.length === 0) {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
root.focus();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const first = focusable[0];
|
|
87
|
+
const last = focusable[focusable.length - 1];
|
|
38
88
|
if (e.shiftKey) {
|
|
39
|
-
if (document.activeElement === first) {
|
|
89
|
+
if (document.activeElement === first || !root.contains(document.activeElement)) {
|
|
40
90
|
e.preventDefault();
|
|
41
|
-
last
|
|
91
|
+
last.focus();
|
|
42
92
|
}
|
|
43
93
|
} else {
|
|
44
|
-
if (document.activeElement === last) {
|
|
94
|
+
if (document.activeElement === last || !root.contains(document.activeElement)) {
|
|
45
95
|
e.preventDefault();
|
|
46
|
-
first
|
|
96
|
+
first.focus();
|
|
47
97
|
}
|
|
48
98
|
}
|
|
49
99
|
};
|
|
50
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
51
|
-
return () =>
|
|
52
|
-
|
|
53
|
-
|
|
100
|
+
window.addEventListener("keydown", handleKeyDown, true);
|
|
101
|
+
return () => {
|
|
102
|
+
window.removeEventListener("keydown", handleKeyDown, true);
|
|
103
|
+
const root = rootRef.current;
|
|
104
|
+
if (root) {
|
|
105
|
+
const idx = trapStack.indexOf(root);
|
|
106
|
+
if (idx !== -1) trapStack.splice(idx, 1);
|
|
107
|
+
}
|
|
108
|
+
if (restoreFocus && previousActiveElementRef.current && typeof previousActiveElementRef.current.focus === "function") {
|
|
109
|
+
previousActiveElementRef.current.focus();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}, [active, restoreFocus]);
|
|
113
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: rootRef, tabIndex: -1, className: "contents", style: { outline: "none" }, children });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/utils/scroll-lock.ts
|
|
117
|
+
var lockCount = 0;
|
|
118
|
+
var previousOverflow = "";
|
|
119
|
+
function lockBodyScroll() {
|
|
120
|
+
if (typeof document === "undefined") return;
|
|
121
|
+
if (lockCount === 0) {
|
|
122
|
+
previousOverflow = document.body.style.overflow;
|
|
123
|
+
document.body.style.overflow = "hidden";
|
|
124
|
+
}
|
|
125
|
+
lockCount++;
|
|
126
|
+
}
|
|
127
|
+
function unlockBodyScroll() {
|
|
128
|
+
if (typeof document === "undefined") return;
|
|
129
|
+
lockCount = Math.max(0, lockCount - 1);
|
|
130
|
+
if (lockCount === 0) {
|
|
131
|
+
document.body.style.overflow = previousOverflow;
|
|
132
|
+
}
|
|
54
133
|
}
|
|
55
134
|
function cn(...inputs) {
|
|
56
135
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
57
136
|
}
|
|
58
|
-
var ModalContext =
|
|
137
|
+
var ModalContext = React8.createContext(null);
|
|
59
138
|
function useModal() {
|
|
60
|
-
const context =
|
|
139
|
+
const context = React8.useContext(ModalContext);
|
|
61
140
|
if (!context) {
|
|
62
141
|
throw new Error("Modal compound components must be used within a <Modal />");
|
|
63
142
|
}
|
|
@@ -68,35 +147,78 @@ function Modal({
|
|
|
68
147
|
onClose,
|
|
69
148
|
children,
|
|
70
149
|
closeOnEsc = true,
|
|
71
|
-
closeOnOverlayClick = true
|
|
150
|
+
closeOnOverlayClick = true,
|
|
151
|
+
role = "dialog",
|
|
152
|
+
"aria-label": ariaLabel,
|
|
153
|
+
"aria-labelledby": customLabelledBy,
|
|
154
|
+
"aria-describedby": customDescribedBy
|
|
72
155
|
}) {
|
|
73
|
-
|
|
156
|
+
const generatedId = React8.useId();
|
|
157
|
+
const titleId = customLabelledBy || `modal-title-${generatedId}`;
|
|
158
|
+
const descriptionId = customDescribedBy || `modal-desc-${generatedId}`;
|
|
159
|
+
const [mountedTitleId, setMountedTitleId] = React8.useState(null);
|
|
160
|
+
const [mountedDescId, setMountedDescId] = React8.useState(null);
|
|
161
|
+
const registerTitle = React8.useCallback(
|
|
162
|
+
(id) => {
|
|
163
|
+
const activeId = id || titleId;
|
|
164
|
+
setMountedTitleId(activeId);
|
|
165
|
+
return () => setMountedTitleId(null);
|
|
166
|
+
},
|
|
167
|
+
[titleId]
|
|
168
|
+
);
|
|
169
|
+
const registerDescription = React8.useCallback(
|
|
170
|
+
(id) => {
|
|
171
|
+
const activeId = id || descriptionId;
|
|
172
|
+
setMountedDescId(activeId);
|
|
173
|
+
return () => setMountedDescId(null);
|
|
174
|
+
},
|
|
175
|
+
[descriptionId]
|
|
176
|
+
);
|
|
177
|
+
React8.useEffect(() => {
|
|
74
178
|
if (!isOpen) return;
|
|
179
|
+
lockBodyScroll();
|
|
75
180
|
const handleKeyDown = (e) => {
|
|
76
181
|
if (closeOnEsc && e.key === "Escape") {
|
|
77
182
|
onClose();
|
|
78
183
|
}
|
|
79
184
|
};
|
|
80
|
-
const originalOverflow = document.body.style.overflow;
|
|
81
|
-
document.body.style.overflow = "hidden";
|
|
82
185
|
window.addEventListener("keydown", handleKeyDown);
|
|
83
186
|
return () => {
|
|
84
187
|
window.removeEventListener("keydown", handleKeyDown);
|
|
85
|
-
|
|
188
|
+
unlockBodyScroll();
|
|
86
189
|
};
|
|
87
190
|
}, [isOpen, closeOnEsc, onClose]);
|
|
88
191
|
if (!isOpen) return null;
|
|
89
|
-
|
|
90
|
-
|
|
192
|
+
const resolvedLabelledBy = customLabelledBy || (ariaLabel ? void 0 : mountedTitleId || void 0);
|
|
193
|
+
const resolvedDescribedBy = customDescribedBy || (mountedDescId || void 0);
|
|
194
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
195
|
+
ModalContext.Provider,
|
|
91
196
|
{
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
197
|
+
value: {
|
|
198
|
+
isOpen,
|
|
199
|
+
onClose,
|
|
200
|
+
closeOnOverlayClick,
|
|
201
|
+
titleId,
|
|
202
|
+
descriptionId,
|
|
203
|
+
registerTitle,
|
|
204
|
+
registerDescription
|
|
205
|
+
},
|
|
206
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(FocusTrap, { active: isOpen, restoreFocus: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6",
|
|
210
|
+
role,
|
|
211
|
+
"aria-modal": "true",
|
|
212
|
+
"aria-label": ariaLabel,
|
|
213
|
+
"aria-labelledby": resolvedLabelledBy,
|
|
214
|
+
"aria-describedby": resolvedDescribedBy,
|
|
215
|
+
children
|
|
216
|
+
}
|
|
217
|
+
) })
|
|
96
218
|
}
|
|
97
|
-
) })
|
|
219
|
+
) });
|
|
98
220
|
}
|
|
99
|
-
var ModalOverlay =
|
|
221
|
+
var ModalOverlay = React8.forwardRef(
|
|
100
222
|
({ className, onClick, ...props }, ref) => {
|
|
101
223
|
const { onClose, closeOnOverlayClick } = useModal();
|
|
102
224
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -136,7 +258,7 @@ var modalContentVariants = classVarianceAuthority.cva(
|
|
|
136
258
|
}
|
|
137
259
|
}
|
|
138
260
|
);
|
|
139
|
-
var ModalContent =
|
|
261
|
+
var ModalContent = React8.forwardRef(
|
|
140
262
|
({ className, size, children, ...props }, ref) => {
|
|
141
263
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
142
264
|
"div",
|
|
@@ -150,37 +272,65 @@ var ModalContent = react.forwardRef(
|
|
|
150
272
|
}
|
|
151
273
|
);
|
|
152
274
|
ModalContent.displayName = "ModalContent";
|
|
153
|
-
var ModalHeader =
|
|
275
|
+
var ModalHeader = React8.forwardRef(
|
|
154
276
|
({ className, children, ...props }, ref) => {
|
|
155
277
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col space-y-1.5 mb-4", className), ...props, children });
|
|
156
278
|
}
|
|
157
279
|
);
|
|
158
280
|
ModalHeader.displayName = "ModalHeader";
|
|
159
|
-
var ModalTitle =
|
|
160
|
-
({ className, children, ...props }, ref) => {
|
|
161
|
-
|
|
281
|
+
var ModalTitle = React8.forwardRef(
|
|
282
|
+
({ className, children, id, ...props }, ref) => {
|
|
283
|
+
const { titleId, registerTitle } = useModal();
|
|
284
|
+
const activeId = id || titleId;
|
|
285
|
+
React8.useEffect(() => {
|
|
286
|
+
return registerTitle(activeId);
|
|
287
|
+
}, [registerTitle, activeId]);
|
|
288
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
289
|
+
"h2",
|
|
290
|
+
{
|
|
291
|
+
ref,
|
|
292
|
+
id: activeId,
|
|
293
|
+
className: cn("text-lg sm:text-xl font-bold tracking-tight text-[var(--ui-text-primary)]", className),
|
|
294
|
+
...props,
|
|
295
|
+
children
|
|
296
|
+
}
|
|
297
|
+
);
|
|
162
298
|
}
|
|
163
299
|
);
|
|
164
300
|
ModalTitle.displayName = "ModalTitle";
|
|
165
|
-
var ModalDescription =
|
|
166
|
-
({ className, children, ...props }, ref) => {
|
|
167
|
-
|
|
301
|
+
var ModalDescription = React8.forwardRef(
|
|
302
|
+
({ className, children, id, ...props }, ref) => {
|
|
303
|
+
const { descriptionId, registerDescription } = useModal();
|
|
304
|
+
const activeId = id || descriptionId;
|
|
305
|
+
React8.useEffect(() => {
|
|
306
|
+
return registerDescription(activeId);
|
|
307
|
+
}, [registerDescription, activeId]);
|
|
308
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
309
|
+
"p",
|
|
310
|
+
{
|
|
311
|
+
ref,
|
|
312
|
+
id: activeId,
|
|
313
|
+
className: cn("text-sm text-[var(--ui-text-muted)]", className),
|
|
314
|
+
...props,
|
|
315
|
+
children
|
|
316
|
+
}
|
|
317
|
+
);
|
|
168
318
|
}
|
|
169
319
|
);
|
|
170
320
|
ModalDescription.displayName = "ModalDescription";
|
|
171
|
-
var ModalBody =
|
|
321
|
+
var ModalBody = React8.forwardRef(
|
|
172
322
|
({ className, children, ...props }, ref) => {
|
|
173
323
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("py-2", className), ...props, children });
|
|
174
324
|
}
|
|
175
325
|
);
|
|
176
326
|
ModalBody.displayName = "ModalBody";
|
|
177
|
-
var ModalFooter =
|
|
327
|
+
var ModalFooter = React8.forwardRef(
|
|
178
328
|
({ className, children, ...props }, ref) => {
|
|
179
329
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex items-center justify-end gap-3 mt-6 pt-4 border-t border-[var(--ui-border-subtle)]", className), ...props, children });
|
|
180
330
|
}
|
|
181
331
|
);
|
|
182
332
|
ModalFooter.displayName = "ModalFooter";
|
|
183
|
-
var ModalCloseButton =
|
|
333
|
+
var ModalCloseButton = React8.forwardRef(
|
|
184
334
|
({ className, onClick, ...props }, ref) => {
|
|
185
335
|
const { onClose } = useModal();
|
|
186
336
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -194,7 +344,7 @@ var ModalCloseButton = react.forwardRef(
|
|
|
194
344
|
},
|
|
195
345
|
"aria-label": "Close dialog",
|
|
196
346
|
className: cn(
|
|
197
|
-
"absolute top-4 right-4 p-1.5 rounded-full text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)] transition-colors",
|
|
347
|
+
"absolute top-4 right-4 p-1.5 rounded-full text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)] transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
|
|
198
348
|
className
|
|
199
349
|
),
|
|
200
350
|
...props,
|
|
@@ -236,7 +386,7 @@ var buttonVariants = classVarianceAuthority.cva(
|
|
|
236
386
|
}
|
|
237
387
|
}
|
|
238
388
|
);
|
|
239
|
-
var Button =
|
|
389
|
+
var Button = React8.forwardRef(
|
|
240
390
|
({
|
|
241
391
|
className,
|
|
242
392
|
variant,
|
|
@@ -289,35 +439,46 @@ function AlertDialog({
|
|
|
289
439
|
confirmText = "Confirm",
|
|
290
440
|
cancelText = "Cancel",
|
|
291
441
|
variant = "danger",
|
|
292
|
-
isLoading = false
|
|
442
|
+
isLoading = false,
|
|
443
|
+
closeOnOverlayClick = false
|
|
293
444
|
}) {
|
|
294
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
/* @__PURE__ */ jsxRuntime.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
onClick:
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
445
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
446
|
+
Modal,
|
|
447
|
+
{
|
|
448
|
+
isOpen,
|
|
449
|
+
onClose,
|
|
450
|
+
role: "alertdialog",
|
|
451
|
+
closeOnOverlayClick,
|
|
452
|
+
children: [
|
|
453
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalOverlay, {}),
|
|
454
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { size: "sm", children: [
|
|
455
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalCloseButton, {}),
|
|
456
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
|
|
457
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: title }),
|
|
458
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalDescription, { children: description })
|
|
459
|
+
] }),
|
|
460
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ModalFooter, { children: [
|
|
461
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", size: "sm", onClick: onClose, disabled: isLoading, autoFocus: true, children: cancelText }),
|
|
462
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
463
|
+
Button,
|
|
464
|
+
{
|
|
465
|
+
variant: variant === "danger" ? "danger" : "primary",
|
|
466
|
+
size: "sm",
|
|
467
|
+
loading: isLoading,
|
|
468
|
+
onClick: onConfirm,
|
|
469
|
+
children: confirmText
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
] })
|
|
473
|
+
] })
|
|
474
|
+
]
|
|
475
|
+
}
|
|
476
|
+
);
|
|
317
477
|
}
|
|
318
|
-
|
|
478
|
+
AlertDialog.displayName = "AlertDialog";
|
|
479
|
+
var DrawerContext = React8.createContext(null);
|
|
319
480
|
function useDrawer() {
|
|
320
|
-
const context =
|
|
481
|
+
const context = React8.useContext(DrawerContext);
|
|
321
482
|
if (!context) {
|
|
322
483
|
throw new Error("Drawer compound components must be used within a <Drawer />");
|
|
323
484
|
}
|
|
@@ -344,54 +505,68 @@ function Drawer({
|
|
|
344
505
|
onClose,
|
|
345
506
|
placement = "right",
|
|
346
507
|
children,
|
|
347
|
-
closeOnEsc = true
|
|
508
|
+
closeOnEsc = true,
|
|
509
|
+
"aria-label": ariaLabel,
|
|
510
|
+
"aria-labelledby": customLabelledBy
|
|
348
511
|
}) {
|
|
349
|
-
|
|
512
|
+
const generatedId = React8.useId();
|
|
513
|
+
const titleId = customLabelledBy || `drawer-title-${generatedId}`;
|
|
514
|
+
React8.useEffect(() => {
|
|
350
515
|
if (!isOpen) return;
|
|
516
|
+
lockBodyScroll();
|
|
351
517
|
const handleKeyDown = (e) => {
|
|
352
518
|
if (closeOnEsc && e.key === "Escape") {
|
|
353
519
|
onClose();
|
|
354
520
|
}
|
|
355
521
|
};
|
|
356
|
-
const originalOverflow = document.body.style.overflow;
|
|
357
|
-
document.body.style.overflow = "hidden";
|
|
358
522
|
window.addEventListener("keydown", handleKeyDown);
|
|
359
523
|
return () => {
|
|
360
524
|
window.removeEventListener("keydown", handleKeyDown);
|
|
361
|
-
|
|
525
|
+
unlockBodyScroll();
|
|
362
526
|
};
|
|
363
527
|
}, [isOpen, closeOnEsc, onClose]);
|
|
364
528
|
if (!isOpen) return null;
|
|
365
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: { isOpen, onClose }, children: /* @__PURE__ */ jsxRuntime.jsx(FocusTrap, { active: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
529
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: { isOpen, onClose, titleId }, children: /* @__PURE__ */ jsxRuntime.jsx(FocusTrap, { active: isOpen, restoreFocus: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
530
|
+
"div",
|
|
531
|
+
{
|
|
532
|
+
className: "fixed inset-0 z-50 overflow-hidden",
|
|
533
|
+
role: "dialog",
|
|
534
|
+
"aria-modal": "true",
|
|
535
|
+
"aria-label": ariaLabel,
|
|
536
|
+
"aria-labelledby": ariaLabel ? void 0 : titleId,
|
|
537
|
+
children: [
|
|
538
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
539
|
+
"div",
|
|
540
|
+
{
|
|
541
|
+
"aria-hidden": "true",
|
|
542
|
+
onClick: onClose,
|
|
543
|
+
className: "fixed inset-0 bg-[var(--ui-bg-overlay)] backdrop-blur-sm transition-opacity animate-in fade-in duration-200"
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(drawerVariants({ placement })), children })
|
|
547
|
+
]
|
|
548
|
+
}
|
|
549
|
+
) }) }) });
|
|
376
550
|
}
|
|
377
|
-
var DrawerHeader =
|
|
378
|
-
({ className, children, ...props }, ref) => {
|
|
379
|
-
const { onClose } = useDrawer();
|
|
551
|
+
var DrawerHeader = React8.forwardRef(
|
|
552
|
+
({ className, children, id, ...props }, ref) => {
|
|
553
|
+
const { onClose, titleId } = useDrawer();
|
|
380
554
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
381
555
|
"div",
|
|
382
556
|
{
|
|
383
557
|
ref,
|
|
558
|
+
id: id || titleId,
|
|
384
559
|
className: cn("flex items-center justify-between p-5 border-b border-[var(--ui-border-subtle)]", className),
|
|
385
560
|
...props,
|
|
386
561
|
children: [
|
|
387
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children }),
|
|
562
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 font-semibold text-base text-[var(--ui-text-primary)]", children }),
|
|
388
563
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
389
564
|
"button",
|
|
390
565
|
{
|
|
391
566
|
type: "button",
|
|
392
567
|
onClick: onClose,
|
|
393
568
|
"aria-label": "Close drawer",
|
|
394
|
-
className: "p-1.5 rounded-full text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)] transition-colors ml-4",
|
|
569
|
+
className: "p-1.5 rounded-full text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)] transition-colors ml-4 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
|
|
395
570
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
396
571
|
}
|
|
397
572
|
)
|
|
@@ -401,13 +576,13 @@ var DrawerHeader = react.forwardRef(
|
|
|
401
576
|
}
|
|
402
577
|
);
|
|
403
578
|
DrawerHeader.displayName = "DrawerHeader";
|
|
404
|
-
var DrawerBody =
|
|
579
|
+
var DrawerBody = React8.forwardRef(
|
|
405
580
|
({ className, children, ...props }, ref) => {
|
|
406
581
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex-1 p-5 overflow-y-auto", className), ...props, children });
|
|
407
582
|
}
|
|
408
583
|
);
|
|
409
584
|
DrawerBody.displayName = "DrawerBody";
|
|
410
|
-
var DrawerFooter =
|
|
585
|
+
var DrawerFooter = React8.forwardRef(
|
|
411
586
|
({ className, children, ...props }, ref) => {
|
|
412
587
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
413
588
|
"div",
|
|
@@ -442,40 +617,57 @@ function Tooltip({
|
|
|
442
617
|
children,
|
|
443
618
|
placement = "top",
|
|
444
619
|
delayDuration = 200,
|
|
445
|
-
className
|
|
620
|
+
className,
|
|
621
|
+
id: customId
|
|
446
622
|
}) {
|
|
447
|
-
const
|
|
448
|
-
const
|
|
449
|
-
const
|
|
450
|
-
const
|
|
623
|
+
const generatedId = React8.useId();
|
|
624
|
+
const tooltipId = customId || `tooltip-${generatedId}`;
|
|
625
|
+
const [isVisible, setIsVisible] = React8.useState(false);
|
|
626
|
+
const [coords, setCoords] = React8.useState({ top: 0, left: 0 });
|
|
627
|
+
const timeoutRef = React8.useRef(null);
|
|
628
|
+
const triggerRef = React8.useRef(null);
|
|
629
|
+
const calculatePosition = () => {
|
|
630
|
+
if (triggerRef.current) {
|
|
631
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
632
|
+
let top = 0;
|
|
633
|
+
let left = 0;
|
|
634
|
+
if (placement === "top") {
|
|
635
|
+
top = rect.top + window.scrollY;
|
|
636
|
+
left = rect.left + rect.width / 2 + window.scrollX;
|
|
637
|
+
} else if (placement === "bottom") {
|
|
638
|
+
top = rect.bottom + window.scrollY;
|
|
639
|
+
left = rect.left + rect.width / 2 + window.scrollX;
|
|
640
|
+
} else if (placement === "left") {
|
|
641
|
+
top = rect.top + rect.height / 2 + window.scrollY;
|
|
642
|
+
left = rect.left + window.scrollX;
|
|
643
|
+
} else if (placement === "right") {
|
|
644
|
+
top = rect.top + rect.height / 2 + window.scrollY;
|
|
645
|
+
left = rect.right + window.scrollX;
|
|
646
|
+
}
|
|
647
|
+
setCoords({ top, left });
|
|
648
|
+
}
|
|
649
|
+
};
|
|
451
650
|
const handleMouseEnter = () => {
|
|
651
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
452
652
|
timeoutRef.current = setTimeout(() => {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
let top = 0;
|
|
456
|
-
let left = 0;
|
|
457
|
-
if (placement === "top") {
|
|
458
|
-
top = rect.top + window.scrollY;
|
|
459
|
-
left = rect.left + rect.width / 2 + window.scrollX;
|
|
460
|
-
} else if (placement === "bottom") {
|
|
461
|
-
top = rect.bottom + window.scrollY;
|
|
462
|
-
left = rect.left + rect.width / 2 + window.scrollX;
|
|
463
|
-
} else if (placement === "left") {
|
|
464
|
-
top = rect.top + rect.height / 2 + window.scrollY;
|
|
465
|
-
left = rect.left + window.scrollX;
|
|
466
|
-
} else if (placement === "right") {
|
|
467
|
-
top = rect.top + rect.height / 2 + window.scrollY;
|
|
468
|
-
left = rect.right + window.scrollX;
|
|
469
|
-
}
|
|
470
|
-
setCoords({ top, left });
|
|
471
|
-
setIsVisible(true);
|
|
472
|
-
}
|
|
653
|
+
calculatePosition();
|
|
654
|
+
setIsVisible(true);
|
|
473
655
|
}, delayDuration);
|
|
474
656
|
};
|
|
475
657
|
const handleMouseLeave = () => {
|
|
476
658
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
477
659
|
setIsVisible(false);
|
|
478
660
|
};
|
|
661
|
+
React8.useEffect(() => {
|
|
662
|
+
if (!isVisible) return;
|
|
663
|
+
const handleKeyDown = (e) => {
|
|
664
|
+
if (e.key === "Escape") {
|
|
665
|
+
setIsVisible(false);
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
669
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
670
|
+
}, [isVisible]);
|
|
479
671
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
480
672
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
481
673
|
"div",
|
|
@@ -485,6 +677,7 @@ function Tooltip({
|
|
|
485
677
|
onMouseLeave: handleMouseLeave,
|
|
486
678
|
onFocus: handleMouseEnter,
|
|
487
679
|
onBlur: handleMouseLeave,
|
|
680
|
+
"aria-describedby": isVisible ? tooltipId : void 0,
|
|
488
681
|
className: "inline-flex cursor-pointer",
|
|
489
682
|
children
|
|
490
683
|
}
|
|
@@ -492,28 +685,76 @@ function Tooltip({
|
|
|
492
685
|
isVisible && /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
493
686
|
"div",
|
|
494
687
|
{
|
|
495
|
-
|
|
688
|
+
id: tooltipId,
|
|
496
689
|
role: "tooltip",
|
|
690
|
+
style: { top: `${coords.top}px`, left: `${coords.left}px`, position: "absolute" },
|
|
497
691
|
className: cn(tooltipVariants({ placement }), className),
|
|
498
692
|
children: content
|
|
499
693
|
}
|
|
500
694
|
) })
|
|
501
695
|
] });
|
|
502
696
|
}
|
|
697
|
+
function useControllableState({
|
|
698
|
+
value: controlledValue,
|
|
699
|
+
defaultValue,
|
|
700
|
+
onChange,
|
|
701
|
+
name
|
|
702
|
+
}) {
|
|
703
|
+
const isControlled = controlledValue !== void 0;
|
|
704
|
+
const isControlledRef = React8.useRef(isControlled);
|
|
705
|
+
React8.useEffect(() => {
|
|
706
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production" && isControlledRef.current !== isControlled) {
|
|
707
|
+
console.warn(
|
|
708
|
+
`[${name}] is changing from ${isControlledRef.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}. Check the value/defaultValue props.`
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
isControlledRef.current = isControlled;
|
|
712
|
+
}, [isControlled, name]);
|
|
713
|
+
const [internalState, setInternalState] = React8.useState(defaultValue);
|
|
714
|
+
const value = isControlled ? controlledValue : internalState;
|
|
715
|
+
const setValue = React8.useCallback(
|
|
716
|
+
(next) => {
|
|
717
|
+
const nextValue = typeof next === "function" ? next(value) : next;
|
|
718
|
+
if (!isControlled) {
|
|
719
|
+
setInternalState(nextValue);
|
|
720
|
+
}
|
|
721
|
+
onChange?.(nextValue);
|
|
722
|
+
},
|
|
723
|
+
[isControlled, value, onChange]
|
|
724
|
+
);
|
|
725
|
+
return [value, setValue, isControlled];
|
|
726
|
+
}
|
|
503
727
|
var Popover = ({
|
|
504
728
|
trigger,
|
|
505
729
|
children,
|
|
506
|
-
|
|
730
|
+
open: controlledOpen,
|
|
731
|
+
isOpen: legacyIsOpen,
|
|
732
|
+
defaultOpen = false,
|
|
733
|
+
onOpenChange,
|
|
507
734
|
onClose,
|
|
508
735
|
placement = "bottom",
|
|
509
736
|
className
|
|
510
737
|
}) => {
|
|
511
|
-
const
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
738
|
+
const activeControlled = controlledOpen !== void 0 ? controlledOpen : legacyIsOpen;
|
|
739
|
+
const handleStateChange = React8.useCallback(
|
|
740
|
+
(nextOpen) => {
|
|
741
|
+
onOpenChange?.(nextOpen);
|
|
742
|
+
if (!nextOpen) {
|
|
743
|
+
onClose?.();
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
[onOpenChange, onClose]
|
|
747
|
+
);
|
|
748
|
+
const [isOpen, setIsOpen] = useControllableState({
|
|
749
|
+
value: activeControlled,
|
|
750
|
+
defaultValue: defaultOpen,
|
|
751
|
+
onChange: handleStateChange,
|
|
752
|
+
name: "Popover"
|
|
753
|
+
});
|
|
754
|
+
const [coords, setCoords] = React8.useState({ top: 0, left: 0 });
|
|
755
|
+
const triggerRef = React8.useRef(null);
|
|
756
|
+
const popoverRef = React8.useRef(null);
|
|
757
|
+
const calculatePosition = React8.useCallback(() => {
|
|
517
758
|
if (triggerRef.current) {
|
|
518
759
|
const rect = triggerRef.current.getBoundingClientRect();
|
|
519
760
|
let top = 0;
|
|
@@ -533,45 +774,52 @@ var Popover = ({
|
|
|
533
774
|
}
|
|
534
775
|
setCoords({ top, left });
|
|
535
776
|
}
|
|
536
|
-
};
|
|
777
|
+
}, [placement]);
|
|
537
778
|
const handleToggle = () => {
|
|
538
779
|
if (!isOpen) {
|
|
539
780
|
calculatePosition();
|
|
540
781
|
}
|
|
541
|
-
|
|
542
|
-
if (isOpen) onClose?.();
|
|
543
|
-
} else {
|
|
544
|
-
setInternalIsOpen(!internalIsOpen);
|
|
545
|
-
}
|
|
782
|
+
setIsOpen(!isOpen);
|
|
546
783
|
};
|
|
547
|
-
|
|
784
|
+
React8.useEffect(() => {
|
|
548
785
|
if (isOpen) {
|
|
549
786
|
calculatePosition();
|
|
550
787
|
}
|
|
551
|
-
}, [isOpen]);
|
|
552
|
-
|
|
788
|
+
}, [isOpen, calculatePosition]);
|
|
789
|
+
React8.useEffect(() => {
|
|
790
|
+
if (!isOpen) return;
|
|
553
791
|
const handleOutside = (e) => {
|
|
554
792
|
if (popoverRef.current && !popoverRef.current.contains(e.target) && triggerRef.current && !triggerRef.current.contains(e.target)) {
|
|
555
|
-
|
|
556
|
-
onClose?.();
|
|
557
|
-
} else {
|
|
558
|
-
setInternalIsOpen(false);
|
|
559
|
-
}
|
|
793
|
+
setIsOpen(false);
|
|
560
794
|
}
|
|
561
795
|
};
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
796
|
+
const handleKeyDown = (e) => {
|
|
797
|
+
if (e.key === "Escape") {
|
|
798
|
+
setIsOpen(false);
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
document.addEventListener("mousedown", handleOutside);
|
|
802
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
803
|
+
window.addEventListener("resize", calculatePosition);
|
|
804
|
+
window.addEventListener("scroll", calculatePosition);
|
|
567
805
|
return () => {
|
|
568
806
|
document.removeEventListener("mousedown", handleOutside);
|
|
807
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
569
808
|
window.removeEventListener("resize", calculatePosition);
|
|
570
809
|
window.removeEventListener("scroll", calculatePosition);
|
|
571
810
|
};
|
|
572
|
-
}, [isOpen,
|
|
811
|
+
}, [isOpen, setIsOpen, calculatePosition]);
|
|
573
812
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
574
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
813
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
814
|
+
"div",
|
|
815
|
+
{
|
|
816
|
+
ref: triggerRef,
|
|
817
|
+
onClick: handleToggle,
|
|
818
|
+
className: "w-full inline-block cursor-pointer",
|
|
819
|
+
"aria-expanded": isOpen,
|
|
820
|
+
children: trigger
|
|
821
|
+
}
|
|
822
|
+
),
|
|
575
823
|
isOpen && /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
576
824
|
"div",
|
|
577
825
|
{
|
|
@@ -592,9 +840,9 @@ var Popover = ({
|
|
|
592
840
|
) })
|
|
593
841
|
] });
|
|
594
842
|
};
|
|
595
|
-
var ToastContext =
|
|
843
|
+
var ToastContext = React8.createContext(null);
|
|
596
844
|
function useToast() {
|
|
597
|
-
const context =
|
|
845
|
+
const context = React8.useContext(ToastContext);
|
|
598
846
|
if (!context) {
|
|
599
847
|
throw new Error("useToast must be used within a ToasterProvider");
|
|
600
848
|
}
|
|
@@ -622,12 +870,44 @@ var toastIcons = {
|
|
|
622
870
|
warning: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "w-5 h-5 text-[var(--ui-warning)] flex-shrink-0" }),
|
|
623
871
|
error: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "w-5 h-5 text-[var(--ui-error)] flex-shrink-0" })
|
|
624
872
|
};
|
|
873
|
+
var Toast = React8__default.default.forwardRef(
|
|
874
|
+
({ className, title, description, type = "info", onDismiss, ...props }, ref) => {
|
|
875
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
876
|
+
"div",
|
|
877
|
+
{
|
|
878
|
+
ref,
|
|
879
|
+
role: "status",
|
|
880
|
+
"aria-live": "polite",
|
|
881
|
+
className: cn(toastVariants({ type }), className),
|
|
882
|
+
...props,
|
|
883
|
+
children: [
|
|
884
|
+
toastIcons[type || "info"],
|
|
885
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-1", children: [
|
|
886
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold text-[var(--ui-text-primary)]", children: title }),
|
|
887
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-[var(--ui-text-muted)]", children: description })
|
|
888
|
+
] }),
|
|
889
|
+
onDismiss && /* @__PURE__ */ jsxRuntime.jsx(
|
|
890
|
+
"button",
|
|
891
|
+
{
|
|
892
|
+
type: "button",
|
|
893
|
+
onClick: onDismiss,
|
|
894
|
+
"aria-label": "Dismiss toast",
|
|
895
|
+
className: "p-1 rounded text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)] transition-colors cursor-pointer",
|
|
896
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3.5 h-3.5" })
|
|
897
|
+
}
|
|
898
|
+
)
|
|
899
|
+
]
|
|
900
|
+
}
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
);
|
|
904
|
+
Toast.displayName = "Toast";
|
|
625
905
|
function ToasterProvider({ children, position = "bottom-right" }) {
|
|
626
|
-
const [toasts, setToasts] =
|
|
627
|
-
const dismiss =
|
|
906
|
+
const [toasts, setToasts] = React8.useState([]);
|
|
907
|
+
const dismiss = React8.useCallback((id) => {
|
|
628
908
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
629
909
|
}, []);
|
|
630
|
-
const toast =
|
|
910
|
+
const toast = React8.useCallback(
|
|
631
911
|
({ id = Math.random().toString(36).slice(2, 9), title, description, type = "info", duration = 4e3 }) => {
|
|
632
912
|
const item = { id, title, description, type, duration };
|
|
633
913
|
setToasts((prev) => [...prev, item]);
|
|
@@ -685,7 +965,7 @@ function ToasterProvider({ children, position = "bottom-right" }) {
|
|
|
685
965
|
) })
|
|
686
966
|
] });
|
|
687
967
|
}
|
|
688
|
-
var BottomSheet =
|
|
968
|
+
var BottomSheet = React8.forwardRef(
|
|
689
969
|
({
|
|
690
970
|
isOpen,
|
|
691
971
|
onClose,
|
|
@@ -694,73 +974,93 @@ var BottomSheet = react.forwardRef(
|
|
|
694
974
|
description,
|
|
695
975
|
className,
|
|
696
976
|
showHandle = true,
|
|
697
|
-
maxHeight = "max-h-[85vh]"
|
|
977
|
+
maxHeight = "max-h-[85vh]",
|
|
978
|
+
"aria-label": ariaLabel
|
|
698
979
|
}, ref) => {
|
|
699
|
-
|
|
700
|
-
|
|
980
|
+
const generatedId = React8.useId();
|
|
981
|
+
const titleId = `bottomsheet-title-${generatedId}`;
|
|
982
|
+
const descId = `bottomsheet-desc-${generatedId}`;
|
|
983
|
+
React8.useEffect(() => {
|
|
984
|
+
if (!isOpen) return;
|
|
985
|
+
lockBodyScroll();
|
|
701
986
|
const handleKeyDown = (e) => {
|
|
702
|
-
if (e.key === "Escape"
|
|
987
|
+
if (e.key === "Escape") {
|
|
703
988
|
onClose();
|
|
704
989
|
}
|
|
705
990
|
};
|
|
706
991
|
window.addEventListener("keydown", handleKeyDown);
|
|
707
|
-
return () =>
|
|
992
|
+
return () => {
|
|
993
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
994
|
+
unlockBodyScroll();
|
|
995
|
+
};
|
|
708
996
|
}, [isOpen, onClose]);
|
|
709
997
|
if (!isOpen) return null;
|
|
710
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(FocusTrap, { active: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
998
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(FocusTrap, { active: isOpen, restoreFocus: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
999
|
+
"div",
|
|
1000
|
+
{
|
|
1001
|
+
className: "fixed inset-0 z-50 flex flex-col justify-end",
|
|
1002
|
+
role: "dialog",
|
|
1003
|
+
"aria-modal": "true",
|
|
1004
|
+
"aria-label": ariaLabel,
|
|
1005
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
1006
|
+
"aria-describedby": description ? descId : void 0,
|
|
1007
|
+
children: [
|
|
1008
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1009
|
+
"div",
|
|
1010
|
+
{
|
|
1011
|
+
onClick: onClose,
|
|
1012
|
+
className: "fixed inset-0 bg-black/60 backdrop-blur-md transition-opacity animate-in fade-in duration-300",
|
|
1013
|
+
"aria-hidden": "true"
|
|
1014
|
+
}
|
|
727
1015
|
),
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
1016
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1017
|
+
"div",
|
|
1018
|
+
{
|
|
1019
|
+
ref,
|
|
1020
|
+
className: cn(
|
|
1021
|
+
"relative z-50 w-full max-w-2xl mx-auto rounded-t-[2rem] border-t border-x border-[var(--ui-border-default)] bg-[var(--ui-bg-surface)] backdrop-blur-3xl shadow-2xl overflow-hidden flex flex-col transition-transform animate-in slide-in-from-bottom duration-300",
|
|
1022
|
+
maxHeight,
|
|
1023
|
+
className
|
|
1024
|
+
),
|
|
1025
|
+
children: [
|
|
1026
|
+
showHandle && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1027
|
+
"div",
|
|
1028
|
+
{
|
|
1029
|
+
onClick: onClose,
|
|
1030
|
+
className: "w-full py-3 flex items-center justify-center cursor-grab active:cursor-grabbing",
|
|
1031
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12 h-1.5 rounded-full bg-[var(--ui-text-muted)]/40 hover:bg-[var(--ui-text-muted)] transition-colors" })
|
|
1032
|
+
}
|
|
1033
|
+
),
|
|
1034
|
+
(title || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 pb-3 flex items-center justify-between border-b border-[var(--ui-border-subtle)]", children: [
|
|
1035
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1036
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("h3", { id: titleId, className: "text-base font-bold tracking-tight text-[var(--ui-text-primary)]", children: title }),
|
|
1037
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { id: descId, className: "text-xs text-[var(--ui-text-muted)]", children: description })
|
|
1038
|
+
] }),
|
|
1039
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1040
|
+
"button",
|
|
1041
|
+
{
|
|
1042
|
+
type: "button",
|
|
1043
|
+
onClick: onClose,
|
|
1044
|
+
"aria-label": "Close sheet",
|
|
1045
|
+
className: "p-1.5 rounded-full hover:bg-[var(--ui-bg-tertiary)] text-[var(--ui-text-muted)] hover:text-[var(--ui-text-primary)] transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
|
|
1046
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
|
|
1047
|
+
}
|
|
1048
|
+
)
|
|
1049
|
+
] }),
|
|
1050
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 overflow-y-auto flex-1 space-y-4", children })
|
|
1051
|
+
]
|
|
1052
|
+
}
|
|
1053
|
+
)
|
|
1054
|
+
]
|
|
1055
|
+
}
|
|
1056
|
+
) }) });
|
|
757
1057
|
}
|
|
758
1058
|
);
|
|
759
1059
|
BottomSheet.displayName = "BottomSheet";
|
|
760
1060
|
var BottomSheetHeader = ({ className, children, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("px-6 pb-2", className), ...props, children });
|
|
761
1061
|
var BottomSheetBody = ({ className, children, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("px-6 py-2 overflow-y-auto", className), ...props, children });
|
|
762
1062
|
var BottomSheetFooter = ({ className, children, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-6 pt-3 border-t border-[var(--ui-border-subtle)] flex items-center justify-end gap-3", className), ...props, children });
|
|
763
|
-
var Kbd =
|
|
1063
|
+
var Kbd = React8.forwardRef(
|
|
764
1064
|
({ className, children, ...props }, ref) => {
|
|
765
1065
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
766
1066
|
"kbd",
|
|
@@ -791,14 +1091,21 @@ var ContextMenuItem = ({
|
|
|
791
1091
|
"div",
|
|
792
1092
|
{
|
|
793
1093
|
role: "menuitem",
|
|
1094
|
+
tabIndex: disabled ? -1 : 0,
|
|
794
1095
|
"aria-disabled": disabled,
|
|
795
1096
|
onClick: () => {
|
|
796
1097
|
if (!disabled) onSelect?.();
|
|
797
1098
|
},
|
|
1099
|
+
onKeyDown: (e) => {
|
|
1100
|
+
if (!disabled && (e.key === "Enter" || e.key === " ")) {
|
|
1101
|
+
e.preventDefault();
|
|
1102
|
+
onSelect?.();
|
|
1103
|
+
}
|
|
1104
|
+
},
|
|
798
1105
|
className: cn(
|
|
799
|
-
"flex items-center justify-between px-3 py-1.5 rounded-xl text-xs font-medium cursor-pointer transition-colors select-none",
|
|
1106
|
+
"flex items-center justify-between px-3 py-1.5 rounded-xl text-xs font-medium cursor-pointer transition-colors select-none focus:outline-none focus:bg-[var(--ui-bg-tertiary)]",
|
|
800
1107
|
disabled && "opacity-40 cursor-not-allowed pointer-events-none",
|
|
801
|
-
destructive ? "text-rose-500 hover:bg-rose-500/10" : "text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)]",
|
|
1108
|
+
destructive ? "text-rose-500 hover:bg-rose-500/10 focus:bg-rose-500/10" : "text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)]",
|
|
802
1109
|
className
|
|
803
1110
|
),
|
|
804
1111
|
...props,
|
|
@@ -813,11 +1120,11 @@ var ContextMenuItem = ({
|
|
|
813
1120
|
);
|
|
814
1121
|
};
|
|
815
1122
|
var ContextMenuSeparator = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px my-1 bg-[var(--ui-border-subtle)]", role: "separator" });
|
|
816
|
-
var ContextMenu =
|
|
1123
|
+
var ContextMenu = React8.forwardRef(
|
|
817
1124
|
({ children, menuContent, className }, ref) => {
|
|
818
|
-
const [isOpen, setIsOpen] =
|
|
819
|
-
const [position, setPosition] =
|
|
820
|
-
const menuRef =
|
|
1125
|
+
const [isOpen, setIsOpen] = React8.useState(false);
|
|
1126
|
+
const [position, setPosition] = React8.useState({ x: 0, y: 0 });
|
|
1127
|
+
const menuRef = React8.useRef(null);
|
|
821
1128
|
const handleContextMenu = (e) => {
|
|
822
1129
|
e.preventDefault();
|
|
823
1130
|
const x = Math.min(window.innerWidth - 220, e.clientX);
|
|
@@ -825,21 +1132,48 @@ var ContextMenu = react.forwardRef(
|
|
|
825
1132
|
setPosition({ x, y });
|
|
826
1133
|
setIsOpen(true);
|
|
827
1134
|
};
|
|
828
|
-
|
|
1135
|
+
React8.useEffect(() => {
|
|
1136
|
+
if (!isOpen) return;
|
|
1137
|
+
const timer = setTimeout(() => {
|
|
1138
|
+
const firstItem = menuRef.current?.querySelector('[role="menuitem"]:not([aria-disabled="true"])');
|
|
1139
|
+
firstItem?.focus();
|
|
1140
|
+
}, 10);
|
|
829
1141
|
const handleClickOutside = (e) => {
|
|
830
1142
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
831
1143
|
setIsOpen(false);
|
|
832
1144
|
}
|
|
833
1145
|
};
|
|
834
1146
|
const handleKeyDown = (e) => {
|
|
835
|
-
if (
|
|
1147
|
+
if (!menuRef.current) return;
|
|
1148
|
+
const items = Array.from(
|
|
1149
|
+
menuRef.current.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')
|
|
1150
|
+
);
|
|
1151
|
+
if (items.length === 0) return;
|
|
1152
|
+
const currentIndex = items.indexOf(document.activeElement);
|
|
1153
|
+
if (e.key === "ArrowDown") {
|
|
1154
|
+
e.preventDefault();
|
|
1155
|
+
const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % items.length;
|
|
1156
|
+
items[nextIndex]?.focus();
|
|
1157
|
+
} else if (e.key === "ArrowUp") {
|
|
1158
|
+
e.preventDefault();
|
|
1159
|
+
const prevIndex = currentIndex === -1 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length;
|
|
1160
|
+
items[prevIndex]?.focus();
|
|
1161
|
+
} else if (e.key === "Home") {
|
|
1162
|
+
e.preventDefault();
|
|
1163
|
+
items[0]?.focus();
|
|
1164
|
+
} else if (e.key === "End") {
|
|
1165
|
+
e.preventDefault();
|
|
1166
|
+
items[items.length - 1]?.focus();
|
|
1167
|
+
} else if (e.key === "Escape") {
|
|
1168
|
+
e.preventDefault();
|
|
1169
|
+
setIsOpen(false);
|
|
1170
|
+
}
|
|
836
1171
|
};
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
841
|
-
}
|
|
1172
|
+
window.addEventListener("click", handleClickOutside);
|
|
1173
|
+
window.addEventListener("contextmenu", handleClickOutside);
|
|
1174
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
842
1175
|
return () => {
|
|
1176
|
+
clearTimeout(timer);
|
|
843
1177
|
window.removeEventListener("click", handleClickOutside);
|
|
844
1178
|
window.removeEventListener("contextmenu", handleClickOutside);
|
|
845
1179
|
window.removeEventListener("keydown", handleKeyDown);
|
|
@@ -851,9 +1185,11 @@ var ContextMenu = react.forwardRef(
|
|
|
851
1185
|
"div",
|
|
852
1186
|
{
|
|
853
1187
|
ref: menuRef,
|
|
1188
|
+
role: "menu",
|
|
1189
|
+
tabIndex: -1,
|
|
854
1190
|
style: { top: `${position.y}px`, left: `${position.x}px` },
|
|
855
1191
|
onClick: () => setIsOpen(false),
|
|
856
|
-
className: "fixed z-50 min-w-48 p-1.5 rounded-2xl bg-[var(--ui-bg-surface)]/90 backdrop-blur-3xl border border-[var(--ui-border-default)] shadow-2xl space-y-0.5 animate-in fade-in zoom-in-95 duration-150",
|
|
1192
|
+
className: "fixed z-50 min-w-48 p-1.5 rounded-2xl bg-[var(--ui-bg-surface)]/90 backdrop-blur-3xl border border-[var(--ui-border-default)] shadow-2xl space-y-0.5 animate-in fade-in zoom-in-95 duration-150 focus:outline-none",
|
|
857
1193
|
children: menuContent
|
|
858
1194
|
}
|
|
859
1195
|
) })
|
|
@@ -861,13 +1197,13 @@ var ContextMenu = react.forwardRef(
|
|
|
861
1197
|
}
|
|
862
1198
|
);
|
|
863
1199
|
ContextMenu.displayName = "ContextMenu";
|
|
864
|
-
var HoverCard =
|
|
1200
|
+
var HoverCard = React8.forwardRef(
|
|
865
1201
|
({ trigger, content, openDelay = 200, closeDelay = 250, className }, ref) => {
|
|
866
|
-
const [isOpen, setIsOpen] =
|
|
867
|
-
const [coords, setCoords] =
|
|
868
|
-
const triggerRef =
|
|
869
|
-
const openTimerRef =
|
|
870
|
-
const closeTimerRef =
|
|
1202
|
+
const [isOpen, setIsOpen] = React8.useState(false);
|
|
1203
|
+
const [coords, setCoords] = React8.useState({ top: 0, left: 0 });
|
|
1204
|
+
const triggerRef = React8.useRef(null);
|
|
1205
|
+
const openTimerRef = React8.useRef(null);
|
|
1206
|
+
const closeTimerRef = React8.useRef(null);
|
|
871
1207
|
const handleMouseEnter = () => {
|
|
872
1208
|
clearTimeout(closeTimerRef.current);
|
|
873
1209
|
openTimerRef.current = setTimeout(() => {
|
|
@@ -941,6 +1277,7 @@ exports.ModalOverlay = ModalOverlay;
|
|
|
941
1277
|
exports.ModalTitle = ModalTitle;
|
|
942
1278
|
exports.Popover = Popover;
|
|
943
1279
|
exports.Portal = Portal;
|
|
1280
|
+
exports.Toast = Toast;
|
|
944
1281
|
exports.ToasterProvider = ToasterProvider;
|
|
945
1282
|
exports.Tooltip = Tooltip;
|
|
946
1283
|
exports.drawerVariants = drawerVariants;
|