@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
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Popover } from './chunk-
|
|
2
|
-
import { FocusTrap } from './chunk-
|
|
3
|
-
import { Portal } from './chunk-
|
|
4
|
-
import { Kbd } from './chunk-
|
|
5
|
-
import { Button } from './chunk-
|
|
6
|
-
import { __export, cn } from './chunk-
|
|
7
|
-
import { createContext, useContext,
|
|
1
|
+
import { Popover } from './chunk-YOCGBORV.js';
|
|
2
|
+
import { FocusTrap } from './chunk-ZEDXARXW.js';
|
|
3
|
+
import { Portal } from './chunk-ADO3SVUA.js';
|
|
4
|
+
import { Kbd } from './chunk-I5O2WCGF.js';
|
|
5
|
+
import { Button } from './chunk-I2FQBMVW.js';
|
|
6
|
+
import { __export, cn } from './chunk-2YJBW4E2.js';
|
|
7
|
+
import React4, { createContext, useContext, useId, useState, useCallback, useEffect, forwardRef, useRef } from 'react';
|
|
8
8
|
import { cva } from 'class-variance-authority';
|
|
9
9
|
import { X, AlertCircle, AlertTriangle, CheckCircle2, Info } from 'lucide-react';
|
|
10
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -37,6 +37,7 @@ __export(overlays_exports, {
|
|
|
37
37
|
ModalTitle: () => ModalTitle,
|
|
38
38
|
Popover: () => Popover,
|
|
39
39
|
Portal: () => Portal,
|
|
40
|
+
Toast: () => Toast,
|
|
40
41
|
ToasterProvider: () => ToasterProvider,
|
|
41
42
|
Tooltip: () => Tooltip,
|
|
42
43
|
drawerVariants: () => drawerVariants,
|
|
@@ -47,6 +48,25 @@ __export(overlays_exports, {
|
|
|
47
48
|
useModal: () => useModal,
|
|
48
49
|
useToast: () => useToast
|
|
49
50
|
});
|
|
51
|
+
|
|
52
|
+
// src/utils/scroll-lock.ts
|
|
53
|
+
var lockCount = 0;
|
|
54
|
+
var previousOverflow = "";
|
|
55
|
+
function lockBodyScroll() {
|
|
56
|
+
if (typeof document === "undefined") return;
|
|
57
|
+
if (lockCount === 0) {
|
|
58
|
+
previousOverflow = document.body.style.overflow;
|
|
59
|
+
document.body.style.overflow = "hidden";
|
|
60
|
+
}
|
|
61
|
+
lockCount++;
|
|
62
|
+
}
|
|
63
|
+
function unlockBodyScroll() {
|
|
64
|
+
if (typeof document === "undefined") return;
|
|
65
|
+
lockCount = Math.max(0, lockCount - 1);
|
|
66
|
+
if (lockCount === 0) {
|
|
67
|
+
document.body.style.overflow = previousOverflow;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
50
70
|
var ModalContext = createContext(null);
|
|
51
71
|
function useModal() {
|
|
52
72
|
const context = useContext(ModalContext);
|
|
@@ -60,33 +80,76 @@ function Modal({
|
|
|
60
80
|
onClose,
|
|
61
81
|
children,
|
|
62
82
|
closeOnEsc = true,
|
|
63
|
-
closeOnOverlayClick = true
|
|
83
|
+
closeOnOverlayClick = true,
|
|
84
|
+
role = "dialog",
|
|
85
|
+
"aria-label": ariaLabel,
|
|
86
|
+
"aria-labelledby": customLabelledBy,
|
|
87
|
+
"aria-describedby": customDescribedBy
|
|
64
88
|
}) {
|
|
89
|
+
const generatedId = useId();
|
|
90
|
+
const titleId = customLabelledBy || `modal-title-${generatedId}`;
|
|
91
|
+
const descriptionId = customDescribedBy || `modal-desc-${generatedId}`;
|
|
92
|
+
const [mountedTitleId, setMountedTitleId] = useState(null);
|
|
93
|
+
const [mountedDescId, setMountedDescId] = useState(null);
|
|
94
|
+
const registerTitle = useCallback(
|
|
95
|
+
(id) => {
|
|
96
|
+
const activeId = id || titleId;
|
|
97
|
+
setMountedTitleId(activeId);
|
|
98
|
+
return () => setMountedTitleId(null);
|
|
99
|
+
},
|
|
100
|
+
[titleId]
|
|
101
|
+
);
|
|
102
|
+
const registerDescription = useCallback(
|
|
103
|
+
(id) => {
|
|
104
|
+
const activeId = id || descriptionId;
|
|
105
|
+
setMountedDescId(activeId);
|
|
106
|
+
return () => setMountedDescId(null);
|
|
107
|
+
},
|
|
108
|
+
[descriptionId]
|
|
109
|
+
);
|
|
65
110
|
useEffect(() => {
|
|
66
111
|
if (!isOpen) return;
|
|
112
|
+
lockBodyScroll();
|
|
67
113
|
const handleKeyDown = (e) => {
|
|
68
114
|
if (closeOnEsc && e.key === "Escape") {
|
|
69
115
|
onClose();
|
|
70
116
|
}
|
|
71
117
|
};
|
|
72
|
-
const originalOverflow = document.body.style.overflow;
|
|
73
|
-
document.body.style.overflow = "hidden";
|
|
74
118
|
window.addEventListener("keydown", handleKeyDown);
|
|
75
119
|
return () => {
|
|
76
120
|
window.removeEventListener("keydown", handleKeyDown);
|
|
77
|
-
|
|
121
|
+
unlockBodyScroll();
|
|
78
122
|
};
|
|
79
123
|
}, [isOpen, closeOnEsc, onClose]);
|
|
80
124
|
if (!isOpen) return null;
|
|
81
|
-
|
|
82
|
-
|
|
125
|
+
const resolvedLabelledBy = customLabelledBy || (ariaLabel ? void 0 : mountedTitleId || void 0);
|
|
126
|
+
const resolvedDescribedBy = customDescribedBy || (mountedDescId || void 0);
|
|
127
|
+
return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
|
|
128
|
+
ModalContext.Provider,
|
|
83
129
|
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
130
|
+
value: {
|
|
131
|
+
isOpen,
|
|
132
|
+
onClose,
|
|
133
|
+
closeOnOverlayClick,
|
|
134
|
+
titleId,
|
|
135
|
+
descriptionId,
|
|
136
|
+
registerTitle,
|
|
137
|
+
registerDescription
|
|
138
|
+
},
|
|
139
|
+
children: /* @__PURE__ */ jsx(FocusTrap, { active: isOpen, restoreFocus: true, children: /* @__PURE__ */ jsx(
|
|
140
|
+
"div",
|
|
141
|
+
{
|
|
142
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6",
|
|
143
|
+
role,
|
|
144
|
+
"aria-modal": "true",
|
|
145
|
+
"aria-label": ariaLabel,
|
|
146
|
+
"aria-labelledby": resolvedLabelledBy,
|
|
147
|
+
"aria-describedby": resolvedDescribedBy,
|
|
148
|
+
children
|
|
149
|
+
}
|
|
150
|
+
) })
|
|
88
151
|
}
|
|
89
|
-
) })
|
|
152
|
+
) });
|
|
90
153
|
}
|
|
91
154
|
var ModalOverlay = forwardRef(
|
|
92
155
|
({ className, onClick, ...props }, ref) => {
|
|
@@ -149,14 +212,42 @@ var ModalHeader = forwardRef(
|
|
|
149
212
|
);
|
|
150
213
|
ModalHeader.displayName = "ModalHeader";
|
|
151
214
|
var ModalTitle = forwardRef(
|
|
152
|
-
({ className, children, ...props }, ref) => {
|
|
153
|
-
|
|
215
|
+
({ className, children, id, ...props }, ref) => {
|
|
216
|
+
const { titleId, registerTitle } = useModal();
|
|
217
|
+
const activeId = id || titleId;
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
return registerTitle(activeId);
|
|
220
|
+
}, [registerTitle, activeId]);
|
|
221
|
+
return /* @__PURE__ */ jsx(
|
|
222
|
+
"h2",
|
|
223
|
+
{
|
|
224
|
+
ref,
|
|
225
|
+
id: activeId,
|
|
226
|
+
className: cn("text-lg sm:text-xl font-bold tracking-tight text-[var(--ui-text-primary)]", className),
|
|
227
|
+
...props,
|
|
228
|
+
children
|
|
229
|
+
}
|
|
230
|
+
);
|
|
154
231
|
}
|
|
155
232
|
);
|
|
156
233
|
ModalTitle.displayName = "ModalTitle";
|
|
157
234
|
var ModalDescription = forwardRef(
|
|
158
|
-
({ className, children, ...props }, ref) => {
|
|
159
|
-
|
|
235
|
+
({ className, children, id, ...props }, ref) => {
|
|
236
|
+
const { descriptionId, registerDescription } = useModal();
|
|
237
|
+
const activeId = id || descriptionId;
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
return registerDescription(activeId);
|
|
240
|
+
}, [registerDescription, activeId]);
|
|
241
|
+
return /* @__PURE__ */ jsx(
|
|
242
|
+
"p",
|
|
243
|
+
{
|
|
244
|
+
ref,
|
|
245
|
+
id: activeId,
|
|
246
|
+
className: cn("text-sm text-[var(--ui-text-muted)]", className),
|
|
247
|
+
...props,
|
|
248
|
+
children
|
|
249
|
+
}
|
|
250
|
+
);
|
|
160
251
|
}
|
|
161
252
|
);
|
|
162
253
|
ModalDescription.displayName = "ModalDescription";
|
|
@@ -186,7 +277,7 @@ var ModalCloseButton = forwardRef(
|
|
|
186
277
|
},
|
|
187
278
|
"aria-label": "Close dialog",
|
|
188
279
|
className: cn(
|
|
189
|
-
"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",
|
|
280
|
+
"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)]",
|
|
190
281
|
className
|
|
191
282
|
),
|
|
192
283
|
...props,
|
|
@@ -205,32 +296,43 @@ function AlertDialog({
|
|
|
205
296
|
confirmText = "Confirm",
|
|
206
297
|
cancelText = "Cancel",
|
|
207
298
|
variant = "danger",
|
|
208
|
-
isLoading = false
|
|
299
|
+
isLoading = false,
|
|
300
|
+
closeOnOverlayClick = false
|
|
209
301
|
}) {
|
|
210
|
-
return /* @__PURE__ */ jsxs(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
/* @__PURE__ */
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
onClick:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
302
|
+
return /* @__PURE__ */ jsxs(
|
|
303
|
+
Modal,
|
|
304
|
+
{
|
|
305
|
+
isOpen,
|
|
306
|
+
onClose,
|
|
307
|
+
role: "alertdialog",
|
|
308
|
+
closeOnOverlayClick,
|
|
309
|
+
children: [
|
|
310
|
+
/* @__PURE__ */ jsx(ModalOverlay, {}),
|
|
311
|
+
/* @__PURE__ */ jsxs(ModalContent, { size: "sm", children: [
|
|
312
|
+
/* @__PURE__ */ jsx(ModalCloseButton, {}),
|
|
313
|
+
/* @__PURE__ */ jsxs(ModalHeader, { children: [
|
|
314
|
+
/* @__PURE__ */ jsx(ModalTitle, { children: title }),
|
|
315
|
+
/* @__PURE__ */ jsx(ModalDescription, { children: description })
|
|
316
|
+
] }),
|
|
317
|
+
/* @__PURE__ */ jsxs(ModalFooter, { children: [
|
|
318
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onClose, disabled: isLoading, autoFocus: true, children: cancelText }),
|
|
319
|
+
/* @__PURE__ */ jsx(
|
|
320
|
+
Button,
|
|
321
|
+
{
|
|
322
|
+
variant: variant === "danger" ? "danger" : "primary",
|
|
323
|
+
size: "sm",
|
|
324
|
+
loading: isLoading,
|
|
325
|
+
onClick: onConfirm,
|
|
326
|
+
children: confirmText
|
|
327
|
+
}
|
|
328
|
+
)
|
|
329
|
+
] })
|
|
330
|
+
] })
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
);
|
|
233
334
|
}
|
|
335
|
+
AlertDialog.displayName = "AlertDialog";
|
|
234
336
|
var DrawerContext = createContext(null);
|
|
235
337
|
function useDrawer() {
|
|
236
338
|
const context = useContext(DrawerContext);
|
|
@@ -260,54 +362,68 @@ function Drawer({
|
|
|
260
362
|
onClose,
|
|
261
363
|
placement = "right",
|
|
262
364
|
children,
|
|
263
|
-
closeOnEsc = true
|
|
365
|
+
closeOnEsc = true,
|
|
366
|
+
"aria-label": ariaLabel,
|
|
367
|
+
"aria-labelledby": customLabelledBy
|
|
264
368
|
}) {
|
|
369
|
+
const generatedId = useId();
|
|
370
|
+
const titleId = customLabelledBy || `drawer-title-${generatedId}`;
|
|
265
371
|
useEffect(() => {
|
|
266
372
|
if (!isOpen) return;
|
|
373
|
+
lockBodyScroll();
|
|
267
374
|
const handleKeyDown = (e) => {
|
|
268
375
|
if (closeOnEsc && e.key === "Escape") {
|
|
269
376
|
onClose();
|
|
270
377
|
}
|
|
271
378
|
};
|
|
272
|
-
const originalOverflow = document.body.style.overflow;
|
|
273
|
-
document.body.style.overflow = "hidden";
|
|
274
379
|
window.addEventListener("keydown", handleKeyDown);
|
|
275
380
|
return () => {
|
|
276
381
|
window.removeEventListener("keydown", handleKeyDown);
|
|
277
|
-
|
|
382
|
+
unlockBodyScroll();
|
|
278
383
|
};
|
|
279
384
|
}, [isOpen, closeOnEsc, onClose]);
|
|
280
385
|
if (!isOpen) return null;
|
|
281
|
-
return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(DrawerContext.Provider, { value: { isOpen, onClose }, children: /* @__PURE__ */ jsx(FocusTrap, { active: isOpen, children: /* @__PURE__ */ jsxs(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
386
|
+
return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(DrawerContext.Provider, { value: { isOpen, onClose, titleId }, children: /* @__PURE__ */ jsx(FocusTrap, { active: isOpen, restoreFocus: true, children: /* @__PURE__ */ jsxs(
|
|
387
|
+
"div",
|
|
388
|
+
{
|
|
389
|
+
className: "fixed inset-0 z-50 overflow-hidden",
|
|
390
|
+
role: "dialog",
|
|
391
|
+
"aria-modal": "true",
|
|
392
|
+
"aria-label": ariaLabel,
|
|
393
|
+
"aria-labelledby": ariaLabel ? void 0 : titleId,
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ jsx(
|
|
396
|
+
"div",
|
|
397
|
+
{
|
|
398
|
+
"aria-hidden": "true",
|
|
399
|
+
onClick: onClose,
|
|
400
|
+
className: "fixed inset-0 bg-[var(--ui-bg-overlay)] backdrop-blur-sm transition-opacity animate-in fade-in duration-200"
|
|
401
|
+
}
|
|
402
|
+
),
|
|
403
|
+
/* @__PURE__ */ jsx("div", { className: cn(drawerVariants({ placement })), children })
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
) }) }) });
|
|
292
407
|
}
|
|
293
408
|
var DrawerHeader = forwardRef(
|
|
294
|
-
({ className, children, ...props }, ref) => {
|
|
295
|
-
const { onClose } = useDrawer();
|
|
409
|
+
({ className, children, id, ...props }, ref) => {
|
|
410
|
+
const { onClose, titleId } = useDrawer();
|
|
296
411
|
return /* @__PURE__ */ jsxs(
|
|
297
412
|
"div",
|
|
298
413
|
{
|
|
299
414
|
ref,
|
|
415
|
+
id: id || titleId,
|
|
300
416
|
className: cn("flex items-center justify-between p-5 border-b border-[var(--ui-border-subtle)]", className),
|
|
301
417
|
...props,
|
|
302
418
|
children: [
|
|
303
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1", children }),
|
|
419
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 font-semibold text-base text-[var(--ui-text-primary)]", children }),
|
|
304
420
|
/* @__PURE__ */ jsx(
|
|
305
421
|
"button",
|
|
306
422
|
{
|
|
307
423
|
type: "button",
|
|
308
424
|
onClick: onClose,
|
|
309
425
|
"aria-label": "Close drawer",
|
|
310
|
-
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",
|
|
426
|
+
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)]",
|
|
311
427
|
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
312
428
|
}
|
|
313
429
|
)
|
|
@@ -358,40 +474,57 @@ function Tooltip({
|
|
|
358
474
|
children,
|
|
359
475
|
placement = "top",
|
|
360
476
|
delayDuration = 200,
|
|
361
|
-
className
|
|
477
|
+
className,
|
|
478
|
+
id: customId
|
|
362
479
|
}) {
|
|
480
|
+
const generatedId = useId();
|
|
481
|
+
const tooltipId = customId || `tooltip-${generatedId}`;
|
|
363
482
|
const [isVisible, setIsVisible] = useState(false);
|
|
364
483
|
const [coords, setCoords] = useState({ top: 0, left: 0 });
|
|
365
484
|
const timeoutRef = useRef(null);
|
|
366
485
|
const triggerRef = useRef(null);
|
|
486
|
+
const calculatePosition = () => {
|
|
487
|
+
if (triggerRef.current) {
|
|
488
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
489
|
+
let top = 0;
|
|
490
|
+
let left = 0;
|
|
491
|
+
if (placement === "top") {
|
|
492
|
+
top = rect.top + window.scrollY;
|
|
493
|
+
left = rect.left + rect.width / 2 + window.scrollX;
|
|
494
|
+
} else if (placement === "bottom") {
|
|
495
|
+
top = rect.bottom + window.scrollY;
|
|
496
|
+
left = rect.left + rect.width / 2 + window.scrollX;
|
|
497
|
+
} else if (placement === "left") {
|
|
498
|
+
top = rect.top + rect.height / 2 + window.scrollY;
|
|
499
|
+
left = rect.left + window.scrollX;
|
|
500
|
+
} else if (placement === "right") {
|
|
501
|
+
top = rect.top + rect.height / 2 + window.scrollY;
|
|
502
|
+
left = rect.right + window.scrollX;
|
|
503
|
+
}
|
|
504
|
+
setCoords({ top, left });
|
|
505
|
+
}
|
|
506
|
+
};
|
|
367
507
|
const handleMouseEnter = () => {
|
|
508
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
368
509
|
timeoutRef.current = setTimeout(() => {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
let top = 0;
|
|
372
|
-
let left = 0;
|
|
373
|
-
if (placement === "top") {
|
|
374
|
-
top = rect.top + window.scrollY;
|
|
375
|
-
left = rect.left + rect.width / 2 + window.scrollX;
|
|
376
|
-
} else if (placement === "bottom") {
|
|
377
|
-
top = rect.bottom + window.scrollY;
|
|
378
|
-
left = rect.left + rect.width / 2 + window.scrollX;
|
|
379
|
-
} else if (placement === "left") {
|
|
380
|
-
top = rect.top + rect.height / 2 + window.scrollY;
|
|
381
|
-
left = rect.left + window.scrollX;
|
|
382
|
-
} else if (placement === "right") {
|
|
383
|
-
top = rect.top + rect.height / 2 + window.scrollY;
|
|
384
|
-
left = rect.right + window.scrollX;
|
|
385
|
-
}
|
|
386
|
-
setCoords({ top, left });
|
|
387
|
-
setIsVisible(true);
|
|
388
|
-
}
|
|
510
|
+
calculatePosition();
|
|
511
|
+
setIsVisible(true);
|
|
389
512
|
}, delayDuration);
|
|
390
513
|
};
|
|
391
514
|
const handleMouseLeave = () => {
|
|
392
515
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
393
516
|
setIsVisible(false);
|
|
394
517
|
};
|
|
518
|
+
useEffect(() => {
|
|
519
|
+
if (!isVisible) return;
|
|
520
|
+
const handleKeyDown = (e) => {
|
|
521
|
+
if (e.key === "Escape") {
|
|
522
|
+
setIsVisible(false);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
526
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
527
|
+
}, [isVisible]);
|
|
395
528
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
396
529
|
/* @__PURE__ */ jsx(
|
|
397
530
|
"div",
|
|
@@ -401,6 +534,7 @@ function Tooltip({
|
|
|
401
534
|
onMouseLeave: handleMouseLeave,
|
|
402
535
|
onFocus: handleMouseEnter,
|
|
403
536
|
onBlur: handleMouseLeave,
|
|
537
|
+
"aria-describedby": isVisible ? tooltipId : void 0,
|
|
404
538
|
className: "inline-flex cursor-pointer",
|
|
405
539
|
children
|
|
406
540
|
}
|
|
@@ -408,8 +542,9 @@ function Tooltip({
|
|
|
408
542
|
isVisible && /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
|
|
409
543
|
"div",
|
|
410
544
|
{
|
|
411
|
-
|
|
545
|
+
id: tooltipId,
|
|
412
546
|
role: "tooltip",
|
|
547
|
+
style: { top: `${coords.top}px`, left: `${coords.left}px`, position: "absolute" },
|
|
413
548
|
className: cn(tooltipVariants({ placement }), className),
|
|
414
549
|
children: content
|
|
415
550
|
}
|
|
@@ -446,6 +581,38 @@ var toastIcons = {
|
|
|
446
581
|
warning: /* @__PURE__ */ jsx(AlertTriangle, { className: "w-5 h-5 text-[var(--ui-warning)] flex-shrink-0" }),
|
|
447
582
|
error: /* @__PURE__ */ jsx(AlertCircle, { className: "w-5 h-5 text-[var(--ui-error)] flex-shrink-0" })
|
|
448
583
|
};
|
|
584
|
+
var Toast = React4.forwardRef(
|
|
585
|
+
({ className, title, description, type = "info", onDismiss, ...props }, ref) => {
|
|
586
|
+
return /* @__PURE__ */ jsxs(
|
|
587
|
+
"div",
|
|
588
|
+
{
|
|
589
|
+
ref,
|
|
590
|
+
role: "status",
|
|
591
|
+
"aria-live": "polite",
|
|
592
|
+
className: cn(toastVariants({ type }), className),
|
|
593
|
+
...props,
|
|
594
|
+
children: [
|
|
595
|
+
toastIcons[type || "info"],
|
|
596
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1", children: [
|
|
597
|
+
/* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold text-[var(--ui-text-primary)]", children: title }),
|
|
598
|
+
description && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ui-text-muted)]", children: description })
|
|
599
|
+
] }),
|
|
600
|
+
onDismiss && /* @__PURE__ */ jsx(
|
|
601
|
+
"button",
|
|
602
|
+
{
|
|
603
|
+
type: "button",
|
|
604
|
+
onClick: onDismiss,
|
|
605
|
+
"aria-label": "Dismiss toast",
|
|
606
|
+
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",
|
|
607
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
|
|
608
|
+
}
|
|
609
|
+
)
|
|
610
|
+
]
|
|
611
|
+
}
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
);
|
|
615
|
+
Toast.displayName = "Toast";
|
|
449
616
|
function ToasterProvider({ children, position = "bottom-right" }) {
|
|
450
617
|
const [toasts, setToasts] = useState([]);
|
|
451
618
|
const dismiss = useCallback((id) => {
|
|
@@ -518,66 +685,86 @@ var BottomSheet = forwardRef(
|
|
|
518
685
|
description,
|
|
519
686
|
className,
|
|
520
687
|
showHandle = true,
|
|
521
|
-
maxHeight = "max-h-[85vh]"
|
|
688
|
+
maxHeight = "max-h-[85vh]",
|
|
689
|
+
"aria-label": ariaLabel
|
|
522
690
|
}, ref) => {
|
|
523
|
-
|
|
691
|
+
const generatedId = useId();
|
|
692
|
+
const titleId = `bottomsheet-title-${generatedId}`;
|
|
693
|
+
const descId = `bottomsheet-desc-${generatedId}`;
|
|
524
694
|
useEffect(() => {
|
|
695
|
+
if (!isOpen) return;
|
|
696
|
+
lockBodyScroll();
|
|
525
697
|
const handleKeyDown = (e) => {
|
|
526
|
-
if (e.key === "Escape"
|
|
698
|
+
if (e.key === "Escape") {
|
|
527
699
|
onClose();
|
|
528
700
|
}
|
|
529
701
|
};
|
|
530
702
|
window.addEventListener("keydown", handleKeyDown);
|
|
531
|
-
return () =>
|
|
703
|
+
return () => {
|
|
704
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
705
|
+
unlockBodyScroll();
|
|
706
|
+
};
|
|
532
707
|
}, [isOpen, onClose]);
|
|
533
708
|
if (!isOpen) return null;
|
|
534
|
-
return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(FocusTrap, { active: isOpen, children: /* @__PURE__ */ jsxs(
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
709
|
+
return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(FocusTrap, { active: isOpen, restoreFocus: true, children: /* @__PURE__ */ jsxs(
|
|
710
|
+
"div",
|
|
711
|
+
{
|
|
712
|
+
className: "fixed inset-0 z-50 flex flex-col justify-end",
|
|
713
|
+
role: "dialog",
|
|
714
|
+
"aria-modal": "true",
|
|
715
|
+
"aria-label": ariaLabel,
|
|
716
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
717
|
+
"aria-describedby": description ? descId : void 0,
|
|
718
|
+
children: [
|
|
719
|
+
/* @__PURE__ */ jsx(
|
|
720
|
+
"div",
|
|
721
|
+
{
|
|
722
|
+
onClick: onClose,
|
|
723
|
+
className: "fixed inset-0 bg-black/60 backdrop-blur-md transition-opacity animate-in fade-in duration-300",
|
|
724
|
+
"aria-hidden": "true"
|
|
725
|
+
}
|
|
551
726
|
),
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
727
|
+
/* @__PURE__ */ jsxs(
|
|
728
|
+
"div",
|
|
729
|
+
{
|
|
730
|
+
ref,
|
|
731
|
+
className: cn(
|
|
732
|
+
"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",
|
|
733
|
+
maxHeight,
|
|
734
|
+
className
|
|
735
|
+
),
|
|
736
|
+
children: [
|
|
737
|
+
showHandle && /* @__PURE__ */ jsx(
|
|
738
|
+
"div",
|
|
739
|
+
{
|
|
740
|
+
onClick: onClose,
|
|
741
|
+
className: "w-full py-3 flex items-center justify-center cursor-grab active:cursor-grabbing",
|
|
742
|
+
children: /* @__PURE__ */ jsx("div", { className: "w-12 h-1.5 rounded-full bg-[var(--ui-text-muted)]/40 hover:bg-[var(--ui-text-muted)] transition-colors" })
|
|
743
|
+
}
|
|
744
|
+
),
|
|
745
|
+
(title || description) && /* @__PURE__ */ jsxs("div", { className: "px-6 pb-3 flex items-center justify-between border-b border-[var(--ui-border-subtle)]", children: [
|
|
746
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
747
|
+
title && /* @__PURE__ */ jsx("h3", { id: titleId, className: "text-base font-bold tracking-tight text-[var(--ui-text-primary)]", children: title }),
|
|
748
|
+
description && /* @__PURE__ */ jsx("p", { id: descId, className: "text-xs text-[var(--ui-text-muted)]", children: description })
|
|
749
|
+
] }),
|
|
750
|
+
/* @__PURE__ */ jsx(
|
|
751
|
+
"button",
|
|
752
|
+
{
|
|
753
|
+
type: "button",
|
|
754
|
+
onClick: onClose,
|
|
755
|
+
"aria-label": "Close sheet",
|
|
756
|
+
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)]",
|
|
757
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" })
|
|
758
|
+
}
|
|
759
|
+
)
|
|
760
|
+
] }),
|
|
761
|
+
/* @__PURE__ */ jsx("div", { className: "p-6 overflow-y-auto flex-1 space-y-4", children })
|
|
762
|
+
]
|
|
763
|
+
}
|
|
764
|
+
)
|
|
765
|
+
]
|
|
766
|
+
}
|
|
767
|
+
) }) });
|
|
581
768
|
}
|
|
582
769
|
);
|
|
583
770
|
BottomSheet.displayName = "BottomSheet";
|
|
@@ -598,14 +785,21 @@ var ContextMenuItem = ({
|
|
|
598
785
|
"div",
|
|
599
786
|
{
|
|
600
787
|
role: "menuitem",
|
|
788
|
+
tabIndex: disabled ? -1 : 0,
|
|
601
789
|
"aria-disabled": disabled,
|
|
602
790
|
onClick: () => {
|
|
603
791
|
if (!disabled) onSelect?.();
|
|
604
792
|
},
|
|
793
|
+
onKeyDown: (e) => {
|
|
794
|
+
if (!disabled && (e.key === "Enter" || e.key === " ")) {
|
|
795
|
+
e.preventDefault();
|
|
796
|
+
onSelect?.();
|
|
797
|
+
}
|
|
798
|
+
},
|
|
605
799
|
className: cn(
|
|
606
|
-
"flex items-center justify-between px-3 py-1.5 rounded-xl text-xs font-medium cursor-pointer transition-colors select-none",
|
|
800
|
+
"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)]",
|
|
607
801
|
disabled && "opacity-40 cursor-not-allowed pointer-events-none",
|
|
608
|
-
destructive ? "text-rose-500 hover:bg-rose-500/10" : "text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)]",
|
|
802
|
+
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)]",
|
|
609
803
|
className
|
|
610
804
|
),
|
|
611
805
|
...props,
|
|
@@ -633,20 +827,47 @@ var ContextMenu = forwardRef(
|
|
|
633
827
|
setIsOpen(true);
|
|
634
828
|
};
|
|
635
829
|
useEffect(() => {
|
|
830
|
+
if (!isOpen) return;
|
|
831
|
+
const timer = setTimeout(() => {
|
|
832
|
+
const firstItem = menuRef.current?.querySelector('[role="menuitem"]:not([aria-disabled="true"])');
|
|
833
|
+
firstItem?.focus();
|
|
834
|
+
}, 10);
|
|
636
835
|
const handleClickOutside = (e) => {
|
|
637
836
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
638
837
|
setIsOpen(false);
|
|
639
838
|
}
|
|
640
839
|
};
|
|
641
840
|
const handleKeyDown = (e) => {
|
|
642
|
-
if (
|
|
841
|
+
if (!menuRef.current) return;
|
|
842
|
+
const items = Array.from(
|
|
843
|
+
menuRef.current.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')
|
|
844
|
+
);
|
|
845
|
+
if (items.length === 0) return;
|
|
846
|
+
const currentIndex = items.indexOf(document.activeElement);
|
|
847
|
+
if (e.key === "ArrowDown") {
|
|
848
|
+
e.preventDefault();
|
|
849
|
+
const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % items.length;
|
|
850
|
+
items[nextIndex]?.focus();
|
|
851
|
+
} else if (e.key === "ArrowUp") {
|
|
852
|
+
e.preventDefault();
|
|
853
|
+
const prevIndex = currentIndex === -1 ? items.length - 1 : (currentIndex - 1 + items.length) % items.length;
|
|
854
|
+
items[prevIndex]?.focus();
|
|
855
|
+
} else if (e.key === "Home") {
|
|
856
|
+
e.preventDefault();
|
|
857
|
+
items[0]?.focus();
|
|
858
|
+
} else if (e.key === "End") {
|
|
859
|
+
e.preventDefault();
|
|
860
|
+
items[items.length - 1]?.focus();
|
|
861
|
+
} else if (e.key === "Escape") {
|
|
862
|
+
e.preventDefault();
|
|
863
|
+
setIsOpen(false);
|
|
864
|
+
}
|
|
643
865
|
};
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
648
|
-
}
|
|
866
|
+
window.addEventListener("click", handleClickOutside);
|
|
867
|
+
window.addEventListener("contextmenu", handleClickOutside);
|
|
868
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
649
869
|
return () => {
|
|
870
|
+
clearTimeout(timer);
|
|
650
871
|
window.removeEventListener("click", handleClickOutside);
|
|
651
872
|
window.removeEventListener("contextmenu", handleClickOutside);
|
|
652
873
|
window.removeEventListener("keydown", handleKeyDown);
|
|
@@ -658,9 +879,11 @@ var ContextMenu = forwardRef(
|
|
|
658
879
|
"div",
|
|
659
880
|
{
|
|
660
881
|
ref: menuRef,
|
|
882
|
+
role: "menu",
|
|
883
|
+
tabIndex: -1,
|
|
661
884
|
style: { top: `${position.y}px`, left: `${position.x}px` },
|
|
662
885
|
onClick: () => setIsOpen(false),
|
|
663
|
-
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",
|
|
886
|
+
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",
|
|
664
887
|
children: menuContent
|
|
665
888
|
}
|
|
666
889
|
) })
|
|
@@ -723,6 +946,6 @@ var HoverCard = forwardRef(
|
|
|
723
946
|
);
|
|
724
947
|
HoverCard.displayName = "HoverCard";
|
|
725
948
|
|
|
726
|
-
export { AlertDialog, BottomSheet, BottomSheetBody, BottomSheetFooter, BottomSheetHeader, ContextMenu, ContextMenuItem, ContextMenuSeparator, Drawer, DrawerBody, DrawerFooter, DrawerHeader, HoverCard, Modal, ModalBody, ModalCloseButton, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalTitle, ToasterProvider, Tooltip, drawerVariants, modalContentVariants, overlays_exports, toastVariants, tooltipVariants, useDrawer, useModal, useToast };
|
|
727
|
-
//# sourceMappingURL=chunk-
|
|
728
|
-
//# sourceMappingURL=chunk-
|
|
949
|
+
export { AlertDialog, BottomSheet, BottomSheetBody, BottomSheetFooter, BottomSheetHeader, ContextMenu, ContextMenuItem, ContextMenuSeparator, Drawer, DrawerBody, DrawerFooter, DrawerHeader, HoverCard, Modal, ModalBody, ModalCloseButton, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalTitle, Toast, ToasterProvider, Tooltip, drawerVariants, modalContentVariants, overlays_exports, toastVariants, tooltipVariants, useDrawer, useModal, useToast };
|
|
950
|
+
//# sourceMappingURL=chunk-PC5SZFZC.js.map
|
|
951
|
+
//# sourceMappingURL=chunk-PC5SZFZC.js.map
|