gridsmith-ui 0.29.1 → 0.30.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/CHANGELOG.md +54 -0
- package/README.md +5 -1
- package/dist/DropdownMenu-DqT7ZQ0D.d.ts +39 -0
- package/dist/charts.js +4 -2
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +4 -4
- package/dist/{chunk-OYNUU346.js → chunk-7QLXYRPD.js} +3 -12
- package/dist/chunk-7QLXYRPD.js.map +1 -0
- package/dist/chunk-F2BNJSON.js +1348 -0
- package/dist/chunk-F2BNJSON.js.map +1 -0
- package/dist/{chunk-37WOC7F7.js → chunk-GQVBZ4GW.js} +29 -8
- package/dist/chunk-GQVBZ4GW.js.map +1 -0
- package/dist/{chunk-MFAWJSMJ.js → chunk-INGF2CPW.js} +3 -22
- package/dist/chunk-INGF2CPW.js.map +1 -0
- package/dist/{chunk-I3MTQ3CS.js → chunk-KTPGMJUK.js} +5 -5
- package/dist/{chunk-I3MTQ3CS.js.map → chunk-KTPGMJUK.js.map} +1 -1
- package/dist/{chunk-MKFWHWBK.js → chunk-L6HWACK7.js} +7 -7
- package/dist/chunk-L6HWACK7.js.map +1 -0
- package/dist/chunk-LJYSVZMI.js +25 -0
- package/dist/chunk-LJYSVZMI.js.map +1 -0
- package/dist/{chunk-FUKSLQ77.js → chunk-NI5542ZM.js} +39 -35
- package/dist/chunk-NI5542ZM.js.map +1 -0
- package/dist/chunk-NKUCS67T.js +13 -0
- package/dist/chunk-NKUCS67T.js.map +1 -0
- package/dist/{chunk-RECCCA7Z.js → chunk-NLXQ323J.js} +4 -4
- package/dist/{chunk-RECCCA7Z.js.map → chunk-NLXQ323J.js.map} +1 -1
- package/dist/{chunk-ZI3OQDET.js → chunk-OIOII5L6.js} +93 -4
- package/dist/chunk-OIOII5L6.js.map +1 -0
- package/dist/{chunk-RJEUQ7RL.js → chunk-Q36JVJX4.js} +46 -89
- package/dist/chunk-Q36JVJX4.js.map +1 -0
- package/dist/{chunk-FD4YED7O.js → chunk-RHWTMTU5.js} +3 -3
- package/dist/{chunk-FD4YED7O.js.map → chunk-RHWTMTU5.js.map} +1 -1
- package/dist/chunk-TYNDXMBV.js +105 -0
- package/dist/chunk-TYNDXMBV.js.map +1 -0
- package/dist/{chunk-4TUJXDRU.js → chunk-UNS4TGGK.js} +20 -11
- package/dist/chunk-UNS4TGGK.js.map +1 -0
- package/dist/chunk-Z4MCD73B.js +316 -0
- package/dist/chunk-Z4MCD73B.js.map +1 -0
- package/dist/data-grid.d.ts +25 -6
- package/dist/data-grid.js +177 -55
- package/dist/data-grid.js.map +1 -1
- package/dist/editor-mentions.js +1 -1
- package/dist/editor.js +3 -3
- package/dist/{feather-FNBQ74RR.js → feather-XFFEFLTV.js} +5 -3
- package/dist/feather-XFFEFLTV.js.map +1 -0
- package/dist/{heroicons-DODCSYWD.js → heroicons-L6DOHBEA.js} +5 -3
- package/dist/heroicons-L6DOHBEA.js.map +1 -0
- package/dist/icons.d.ts +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +138 -39
- package/dist/index.js +660 -1568
- package/dist/index.js.map +1 -1
- package/dist/kanban.d.ts +26 -8
- package/dist/kanban.js +200 -76
- package/dist/kanban.js.map +1 -1
- package/dist/{lucide-ZWE3EPGP.js → lucide-JOORDTO6.js} +5 -3
- package/dist/lucide-JOORDTO6.js.map +1 -0
- package/dist/{phosphor-DIHPA4AJ.js → phosphor-TKGDYNGR.js} +5 -3
- package/dist/phosphor-TKGDYNGR.js.map +1 -0
- package/dist/resizable.js +10 -9
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +12 -8
- package/dist/{table-utils-CxnpFHRF.d.ts → table-utils-BXkP-2Hx.d.ts} +3 -1
- package/dist/{tabler-D3VYTSGI.js → tabler-YGETLYRU.js} +5 -3
- package/dist/tabler-YGETLYRU.js.map +1 -0
- package/dist/tokens.css +14 -0
- package/dist/utils.js.map +1 -1
- package/dist/virtualized.js +8 -7
- package/dist/virtualized.js.map +1 -1
- package/dist-static/tokens.css +14 -0
- package/package.json +1 -1
- package/dist/chunk-37WOC7F7.js.map +0 -1
- package/dist/chunk-4TUJXDRU.js.map +0 -1
- package/dist/chunk-FUKSLQ77.js.map +0 -1
- package/dist/chunk-MFAWJSMJ.js.map +0 -1
- package/dist/chunk-MKFWHWBK.js.map +0 -1
- package/dist/chunk-OYNUU346.js.map +0 -1
- package/dist/chunk-QM4SJKWV.js +0 -51
- package/dist/chunk-QM4SJKWV.js.map +0 -1
- package/dist/chunk-QNHVPE2B.js +0 -117
- package/dist/chunk-QNHVPE2B.js.map +0 -1
- package/dist/chunk-RJEUQ7RL.js.map +0 -1
- package/dist/chunk-ZI3OQDET.js.map +0 -1
- package/dist/feather-FNBQ74RR.js.map +0 -1
- package/dist/heroicons-DODCSYWD.js.map +0 -1
- package/dist/lucide-ZWE3EPGP.js.map +0 -1
- package/dist/phosphor-DIHPA4AJ.js.map +0 -1
- package/dist/tabler-D3VYTSGI.js.map +0 -1
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { triggerType } from './chunk-Q36JVJX4.js';
|
|
3
|
+
import { useBreakpoint } from './chunk-ZHUVLBCC.js';
|
|
4
|
+
import { usePopupFocus } from './chunk-OIOII5L6.js';
|
|
5
|
+
import { Slot } from './chunk-7Q46JXSK.js';
|
|
6
|
+
import { Icon } from './chunk-L6HWACK7.js';
|
|
7
|
+
import { usePosition } from './chunk-HP7WUZPK.js';
|
|
8
|
+
import { cn, GLASS_DROPDOWN, FOCUS_RING } from './chunk-JTU7OBYJ.js';
|
|
9
|
+
import { useState, useRef, useEffect, useLayoutEffect } from 'react';
|
|
10
|
+
import { createPortal } from 'react-dom';
|
|
11
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
12
|
+
|
|
13
|
+
function isDivider(entry) {
|
|
14
|
+
return "type" in entry && entry.type === "divider";
|
|
15
|
+
}
|
|
16
|
+
function isSubmenu(entry) {
|
|
17
|
+
return "items" in entry;
|
|
18
|
+
}
|
|
19
|
+
var stopsOf = (entries) => entries.reduce((acc, e, i) => {
|
|
20
|
+
if (!isDivider(e) && !isUnavailable(e)) acc.push(i);
|
|
21
|
+
return acc;
|
|
22
|
+
}, []);
|
|
23
|
+
function isUnavailable(entry) {
|
|
24
|
+
return !!entry.disabled || isSubmenu(entry) && stopsOf(entry.items).length === 0;
|
|
25
|
+
}
|
|
26
|
+
var SUBMENU_GRACE_MS = 300;
|
|
27
|
+
var ITEM = "flex items-center gap-ds-2 w-full text-left px-ds-3 py-ds-2 text-sm cursor-pointer transition-colors rounded-[var(--ds-radius-sm)]";
|
|
28
|
+
var itemLook = (entry, open = false) => cn(
|
|
29
|
+
ITEM,
|
|
30
|
+
FOCUS_RING,
|
|
31
|
+
isUnavailable(entry) ? "opacity-disabled cursor-not-allowed" : "variant" in entry && entry.variant === "destructive" ? "text-[var(--ds-status-error-text)] hover:bg-[var(--ds-status-error-bg)] focus-visible:bg-[var(--ds-status-error-bg)]" : cn("text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-emphasis)] focus-visible:bg-[var(--ds-bg-emphasis)]", open && "bg-[var(--ds-bg-emphasis)]")
|
|
32
|
+
);
|
|
33
|
+
var PANEL = cn(
|
|
34
|
+
// the items' outline has its 4 px of room at any density (Sprint 30, P3)
|
|
35
|
+
"fixed z-[var(--ds-z-popover)] min-w-[180px] p-[max(var(--ds-space-1),4px)]",
|
|
36
|
+
"bg-[var(--ds-bg-surface-elevated)]",
|
|
37
|
+
GLASS_DROPDOWN,
|
|
38
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
39
|
+
"rounded-[var(--ds-radius-md)] overflow-hidden"
|
|
40
|
+
);
|
|
41
|
+
var Divider = () => /* @__PURE__ */ jsx("div", { role: "separator", className: "my-ds-1 h-px bg-[var(--ds-border-default)]" });
|
|
42
|
+
function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
43
|
+
const [open, setOpen] = useState(false);
|
|
44
|
+
const [focusedIdx, setFocusedIdx] = useState(-1);
|
|
45
|
+
const [sub, setSub] = useState(null);
|
|
46
|
+
const [subFocusedIdx, setSubFocusedIdx] = useState(-1);
|
|
47
|
+
const triggerRef = useRef(null);
|
|
48
|
+
const panelsRef = useRef(null);
|
|
49
|
+
const menuRef = useRef(null);
|
|
50
|
+
const subRef = useRef(null);
|
|
51
|
+
const subItemRef = useRef(null);
|
|
52
|
+
const isPhone = useBreakpoint("sm");
|
|
53
|
+
const graceTimer = useRef(null);
|
|
54
|
+
const cancelGrace = () => {
|
|
55
|
+
if (graceTimer.current) {
|
|
56
|
+
clearTimeout(graceTimer.current);
|
|
57
|
+
graceTimer.current = null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const afterGrace = (then) => {
|
|
61
|
+
cancelGrace();
|
|
62
|
+
graceTimer.current = setTimeout(() => {
|
|
63
|
+
graceTimer.current = null;
|
|
64
|
+
then();
|
|
65
|
+
}, SUBMENU_GRACE_MS);
|
|
66
|
+
};
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!open) cancelGrace();
|
|
69
|
+
}, [open]);
|
|
70
|
+
useEffect(() => cancelGrace, []);
|
|
71
|
+
const pos = usePosition(triggerRef, menuRef, open, { side: "bottom", align, offset: 4, flip: true });
|
|
72
|
+
const [subPos, setSubPos] = useState({ top: 0, left: 0 });
|
|
73
|
+
useLayoutEffect(() => {
|
|
74
|
+
if (!open || sub === null || isPhone) return;
|
|
75
|
+
const place = () => {
|
|
76
|
+
const menu = menuRef.current;
|
|
77
|
+
const entry = subItemRef.current;
|
|
78
|
+
const panel = subRef.current;
|
|
79
|
+
if (!menu || !entry || !panel) return;
|
|
80
|
+
const m = menu.getBoundingClientRect();
|
|
81
|
+
const e = entry.getBoundingClientRect();
|
|
82
|
+
const p = panel.getBoundingClientRect();
|
|
83
|
+
const first = panel.querySelector("[data-sub-index]")?.getBoundingClientRect();
|
|
84
|
+
let left = m.right + 4;
|
|
85
|
+
if (left + p.width > window.innerWidth - 8) left = Math.max(8, m.left - 4 - p.width);
|
|
86
|
+
const top = Math.max(8, Math.min(e.top - (first ? first.top - p.top : 0), window.innerHeight - p.height - 8));
|
|
87
|
+
setSubPos((cur) => cur.top === top && cur.left === left ? cur : { top, left });
|
|
88
|
+
};
|
|
89
|
+
place();
|
|
90
|
+
window.addEventListener("resize", place);
|
|
91
|
+
window.addEventListener("scroll", place, true);
|
|
92
|
+
return () => {
|
|
93
|
+
window.removeEventListener("resize", place);
|
|
94
|
+
window.removeEventListener("scroll", place, true);
|
|
95
|
+
};
|
|
96
|
+
}, [open, sub, isPhone]);
|
|
97
|
+
const enabledIndices = stopsOf(items);
|
|
98
|
+
const subEntry = sub !== null && isSubmenu(items[sub]) ? items[sub] : null;
|
|
99
|
+
const subIndices = subEntry ? stopsOf(subEntry.items) : [];
|
|
100
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
101
|
+
if (open !== prevOpen) {
|
|
102
|
+
setPrevOpen(open);
|
|
103
|
+
if (!open) {
|
|
104
|
+
setFocusedIdx(-1);
|
|
105
|
+
setSub(null);
|
|
106
|
+
setSubFocusedIdx(-1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: panelsRef, close: () => setOpen(false), tabExits: "any" });
|
|
110
|
+
const closeSub = () => {
|
|
111
|
+
if (sub === null) return;
|
|
112
|
+
setFocusedIdx(sub);
|
|
113
|
+
setSub(null);
|
|
114
|
+
setSubFocusedIdx(-1);
|
|
115
|
+
};
|
|
116
|
+
const openSub = (i, focusFirst) => {
|
|
117
|
+
const entry = items[i];
|
|
118
|
+
if (!isSubmenu(entry) || isUnavailable(entry)) return;
|
|
119
|
+
cancelGrace();
|
|
120
|
+
setSub(i);
|
|
121
|
+
setFocusedIdx(i);
|
|
122
|
+
setSubFocusedIdx(focusFirst ? stopsOf(entry.items)[0] ?? -1 : -1);
|
|
123
|
+
};
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (!open) return;
|
|
126
|
+
const onKeyDown = (e) => {
|
|
127
|
+
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
if (sub !== null) {
|
|
130
|
+
closeSub();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
returnFocus();
|
|
134
|
+
setOpen(false);
|
|
135
|
+
};
|
|
136
|
+
const onClick = (e) => {
|
|
137
|
+
const target = e.target;
|
|
138
|
+
if (triggerRef.current?.contains(target) || panelsRef.current?.contains(target)) return;
|
|
139
|
+
setOpen(false);
|
|
140
|
+
};
|
|
141
|
+
document.addEventListener("keydown", onKeyDown);
|
|
142
|
+
document.addEventListener("mousedown", onClick);
|
|
143
|
+
return () => {
|
|
144
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
145
|
+
document.removeEventListener("mousedown", onClick);
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
if (!open) return;
|
|
150
|
+
if (sub !== null && subFocusedIdx >= 0) panelsRef.current?.querySelector(`[data-sub-index="${subFocusedIdx}"]`)?.focus();
|
|
151
|
+
else if (sub !== null && isPhone) panelsRef.current?.querySelector("[data-sub-back]")?.focus();
|
|
152
|
+
else if (focusedIdx >= 0) menuRef.current?.querySelector(`[data-index="${focusedIdx}"]`)?.focus();
|
|
153
|
+
}, [open, focusedIdx, sub, subFocusedIdx, isPhone]);
|
|
154
|
+
const step = (stops, at, by) => stops[((stops.indexOf(at) + by) % stops.length + stops.length) % stops.length];
|
|
155
|
+
function handleMenuKeyDown(e) {
|
|
156
|
+
const inSub = sub !== null;
|
|
157
|
+
const stops = inSub ? subIndices : enabledIndices;
|
|
158
|
+
const at = inSub ? subFocusedIdx : focusedIdx;
|
|
159
|
+
const go = (i) => {
|
|
160
|
+
if (i === void 0) return;
|
|
161
|
+
if (inSub) setSubFocusedIdx(i);
|
|
162
|
+
else setFocusedIdx(i);
|
|
163
|
+
};
|
|
164
|
+
if (e.key === "ArrowDown") {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
go(at < 0 ? stops[0] : step(stops, at, 1));
|
|
167
|
+
} else if (e.key === "ArrowUp") {
|
|
168
|
+
e.preventDefault();
|
|
169
|
+
go(at < 0 ? stops[stops.length - 1] : step(stops, at, -1));
|
|
170
|
+
} else if (e.key === "Home") {
|
|
171
|
+
e.preventDefault();
|
|
172
|
+
go(stops[0]);
|
|
173
|
+
} else if (e.key === "End") {
|
|
174
|
+
e.preventDefault();
|
|
175
|
+
go(stops[stops.length - 1]);
|
|
176
|
+
} else if (e.key === "ArrowRight" && !inSub && focusedIdx >= 0 && isSubmenu(items[focusedIdx])) {
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
openSub(focusedIdx, true);
|
|
179
|
+
} else if (e.key === "ArrowLeft" && inSub) {
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
closeSub();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const choose = (item) => {
|
|
185
|
+
if (item.disabled) return;
|
|
186
|
+
returnFocus();
|
|
187
|
+
item.onClick();
|
|
188
|
+
setOpen(false);
|
|
189
|
+
};
|
|
190
|
+
const subItems = (entries) => entries.map((item, i) => isDivider(item) ? /* @__PURE__ */ jsx(Divider, {}, i) : /* @__PURE__ */ jsxs("button", { type: "button", "data-sub-index": i, role: "menuitem", disabled: item.disabled, tabIndex: subFocusedIdx === i ? 0 : -1, onFocus: () => setSubFocusedIdx(i), onClick: () => choose(item), className: itemLook(item), children: [
|
|
191
|
+
item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 16, className: "shrink-0" }),
|
|
192
|
+
/* @__PURE__ */ jsx("span", { children: item.label })
|
|
193
|
+
] }, i));
|
|
194
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
195
|
+
/* @__PURE__ */ jsx(
|
|
196
|
+
Slot,
|
|
197
|
+
{
|
|
198
|
+
...triggerType(trigger),
|
|
199
|
+
"aria-haspopup": "menu",
|
|
200
|
+
"aria-expanded": open,
|
|
201
|
+
ref: triggerRef,
|
|
202
|
+
onClick: () => {
|
|
203
|
+
setOpen(!open);
|
|
204
|
+
if (!open && enabledIndices.length) setFocusedIdx(enabledIndices[0]);
|
|
205
|
+
},
|
|
206
|
+
children: trigger
|
|
207
|
+
}
|
|
208
|
+
),
|
|
209
|
+
open && createPortal(
|
|
210
|
+
/* @__PURE__ */ jsxs("div", { ref: panelsRef, className: "contents", children: [
|
|
211
|
+
/* @__PURE__ */ jsx(
|
|
212
|
+
"div",
|
|
213
|
+
{
|
|
214
|
+
ref: menuRef,
|
|
215
|
+
role: "menu",
|
|
216
|
+
"data-gs": "menu",
|
|
217
|
+
"aria-label": isPhone && subEntry ? subEntry.label : void 0,
|
|
218
|
+
onKeyDown: handleMenuKeyDown,
|
|
219
|
+
className: cn(PANEL, className),
|
|
220
|
+
style: { top: pos.top, left: pos.left },
|
|
221
|
+
onClick: (e) => e.stopPropagation(),
|
|
222
|
+
children: isPhone && subEntry ? (
|
|
223
|
+
// on a phone the submenu takes the menu's place: Back first, its entry's name on it
|
|
224
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
225
|
+
/* @__PURE__ */ jsxs("button", { type: "button", "data-sub-back": "", role: "menuitem", "aria-label": `Back from ${subEntry.label}`, tabIndex: -1, onClick: closeSub, className: cn(itemLook(subEntry), "text-[var(--ds-text-secondary)] font-[var(--ds-weight-heading)]"), children: [
|
|
226
|
+
/* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 16, className: "shrink-0" }),
|
|
227
|
+
/* @__PURE__ */ jsx("span", { children: subEntry.label })
|
|
228
|
+
] }),
|
|
229
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
230
|
+
subItems(subEntry.items)
|
|
231
|
+
] })
|
|
232
|
+
) : items.map((item, i) => {
|
|
233
|
+
if (isDivider(item)) return /* @__PURE__ */ jsx(Divider, {}, i);
|
|
234
|
+
if (isSubmenu(item)) {
|
|
235
|
+
const isOpen = sub === i;
|
|
236
|
+
return /* @__PURE__ */ jsxs(
|
|
237
|
+
"button",
|
|
238
|
+
{
|
|
239
|
+
type: "button",
|
|
240
|
+
ref: isOpen ? (el) => {
|
|
241
|
+
subItemRef.current = el;
|
|
242
|
+
} : void 0,
|
|
243
|
+
"data-index": i,
|
|
244
|
+
role: "menuitem",
|
|
245
|
+
"aria-haspopup": "menu",
|
|
246
|
+
"aria-expanded": isOpen,
|
|
247
|
+
disabled: isUnavailable(item),
|
|
248
|
+
tabIndex: focusedIdx === i ? 0 : -1,
|
|
249
|
+
onFocus: () => setFocusedIdx(i),
|
|
250
|
+
onClick: () => openSub(i, true),
|
|
251
|
+
onMouseEnter: (e) => {
|
|
252
|
+
if (isPhone || e.buttons !== 0) return;
|
|
253
|
+
if (isOpen) cancelGrace();
|
|
254
|
+
else if (sub === null) openSub(i, false);
|
|
255
|
+
else afterGrace(() => openSub(i, false));
|
|
256
|
+
},
|
|
257
|
+
className: itemLook(item, isOpen),
|
|
258
|
+
children: [
|
|
259
|
+
item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 16, className: "shrink-0" }),
|
|
260
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: item.label }),
|
|
261
|
+
/* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "shrink-0 text-[var(--ds-text-muted)]" })
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
i
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
return /* @__PURE__ */ jsxs(
|
|
268
|
+
"button",
|
|
269
|
+
{
|
|
270
|
+
type: "button",
|
|
271
|
+
"data-index": i,
|
|
272
|
+
role: "menuitem",
|
|
273
|
+
disabled: item.disabled,
|
|
274
|
+
tabIndex: focusedIdx === i ? 0 : -1,
|
|
275
|
+
onFocus: () => setFocusedIdx(i),
|
|
276
|
+
onClick: () => choose(item),
|
|
277
|
+
onMouseEnter: () => {
|
|
278
|
+
if (!isPhone && sub !== null) afterGrace(() => {
|
|
279
|
+
setSub(null);
|
|
280
|
+
setSubFocusedIdx(-1);
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
className: itemLook(item),
|
|
284
|
+
children: [
|
|
285
|
+
item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 16, className: "shrink-0" }),
|
|
286
|
+
/* @__PURE__ */ jsx("span", { children: item.label })
|
|
287
|
+
]
|
|
288
|
+
},
|
|
289
|
+
i
|
|
290
|
+
);
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
),
|
|
294
|
+
!isPhone && subEntry && /* @__PURE__ */ jsx(
|
|
295
|
+
"div",
|
|
296
|
+
{
|
|
297
|
+
ref: subRef,
|
|
298
|
+
role: "menu",
|
|
299
|
+
"aria-label": subEntry.label,
|
|
300
|
+
onKeyDown: handleMenuKeyDown,
|
|
301
|
+
className: PANEL,
|
|
302
|
+
style: { top: subPos.top, left: subPos.left },
|
|
303
|
+
onClick: (e) => e.stopPropagation(),
|
|
304
|
+
onMouseEnter: cancelGrace,
|
|
305
|
+
children: subItems(subEntry.items)
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
] }),
|
|
309
|
+
container ?? document.body
|
|
310
|
+
)
|
|
311
|
+
] });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export { DropdownMenu };
|
|
315
|
+
//# sourceMappingURL=chunk-Z4MCD73B.js.map
|
|
316
|
+
//# sourceMappingURL=chunk-Z4MCD73B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/DropdownMenu.tsx"],"names":[],"mappings":"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","file":"chunk-Z4MCD73B.js","sourcesContent":["import { useRef, useEffect, useLayoutEffect, useState, type ReactNode, type KeyboardEvent as ReactKeyboardEvent } from \"react\";\nimport { useBreakpoint } from \"../lib/use-breakpoint\";\nimport { createPortal } from \"react-dom\";\nimport { cn, FOCUS_RING, GLASS_DROPDOWN } from \"../lib/utils\";\nimport { Icon, type IconName } from \"../lib/icons\";\nimport { Slot } from \"../lib/slot\";\nimport { triggerType } from \"./Button\";\nimport { usePosition, type Align } from \"../lib/use-position\";\nimport { usePopupFocus } from \"../lib/focus\";\n\nexport interface DropdownMenuItem {\n label: string;\n icon?: IconName;\n onClick: () => void;\n variant?: \"default\" | \"destructive\";\n disabled?: boolean;\n}\n\nexport interface DropdownMenuDivider {\n type: \"divider\";\n}\n\n/**\n * An entry that opens a submenu of its own (Sprint 25.8.7's look check: a card's Move among its other actions), one\n * level deep. On a desktop it opens beside the menu: → or Enter opens it, its first item focused; ← or Escape closes it,\n * focus back on this entry; a hover opens it too. On a phone its items take the menu's place, under a Back item.\n */\nexport interface DropdownMenuSubmenu {\n label: string;\n icon?: IconName;\n items: (DropdownMenuItem | DropdownMenuDivider)[];\n disabled?: boolean;\n}\n\nexport type DropdownMenuEntry = DropdownMenuItem | DropdownMenuDivider | DropdownMenuSubmenu;\n\nfunction isDivider(entry: DropdownMenuEntry): entry is DropdownMenuDivider {\n return \"type\" in entry && entry.type === \"divider\";\n}\nfunction isSubmenu(entry: DropdownMenuEntry): entry is DropdownMenuSubmenu {\n return \"items\" in entry;\n}\n/** The indices of a list's items the arrows stop at: no divider, nothing unavailable. */\nconst stopsOf = (entries: DropdownMenuEntry[]): number[] => entries.reduce<number[]>((acc, e, i) => {\n if (!isDivider(e) && !isUnavailable(e)) acc.push(i);\n return acc;\n}, []);\n/** An entry that can't be chosen: disabled, or a submenu with nothing in it to choose, which never opens empty. */\nfunction isUnavailable(entry: DropdownMenuItem | DropdownMenuSubmenu): boolean {\n return !!entry.disabled || (isSubmenu(entry) && stopsOf(entry.items).length === 0);\n}\n/**\n * How long a hover on another entry waits before it closes the open submenu (or opens the other's): a pointer on its way\n * to the submenu crosses the entries below its own, and reaching the submenu in that time keeps it open.\n */\nconst SUBMENU_GRACE_MS = 300;\n\nconst ITEM = \"flex items-center gap-ds-2 w-full text-left px-ds-3 py-ds-2 text-sm cursor-pointer transition-colors rounded-[var(--ds-radius-sm)]\";\nconst itemLook = (entry: DropdownMenuItem | DropdownMenuSubmenu, open = false) => cn(\n ITEM,\n FOCUS_RING,\n isUnavailable(entry)\n ? \"opacity-disabled cursor-not-allowed\"\n : \"variant\" in entry && entry.variant === \"destructive\"\n ? \"text-[var(--ds-status-error-text)] hover:bg-[var(--ds-status-error-bg)] focus-visible:bg-[var(--ds-status-error-bg)]\"\n : cn(\"text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-emphasis)] focus-visible:bg-[var(--ds-bg-emphasis)]\", open && \"bg-[var(--ds-bg-emphasis)]\"),\n);\nconst PANEL = cn(\n // the items' outline has its 4 px of room at any density (Sprint 30, P3)\n \"fixed z-[var(--ds-z-popover)] min-w-[180px] p-[max(var(--ds-space-1),4px)]\",\n \"bg-[var(--ds-bg-surface-elevated)]\",\n GLASS_DROPDOWN,\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"rounded-[var(--ds-radius-md)] overflow-hidden\",\n);\nconst Divider = () => <div role=\"separator\" className=\"my-ds-1 h-px bg-[var(--ds-border-default)]\" />;\n\ninterface DropdownMenuProps {\n trigger: ReactNode;\n items: DropdownMenuEntry[];\n align?: Align;\n className?: string;\n container?: Element | DocumentFragment;\n}\n\nexport function DropdownMenu({ trigger, items, align = \"end\", className, container }: DropdownMenuProps) {\n const [open, setOpen] = useState(false);\n const [focusedIdx, setFocusedIdx] = useState(-1);\n // the submenu open, by its entry's index, and the focus inside it\n const [sub, setSub] = useState<number | null>(null);\n const [subFocusedIdx, setSubFocusedIdx] = useState(-1);\n const triggerRef = useRef<HTMLElement>(null);\n // both panels, the menu and its submenu, sit in one box (display: contents) that is the popup's for focus and presses\n const panelsRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const subRef = useRef<HTMLDivElement>(null);\n const subItemRef = useRef<HTMLElement>(null);\n const isPhone = useBreakpoint(\"sm\");\n // a hover elsewhere, waiting before it closes the open submenu (SUBMENU_GRACE_MS)\n const graceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const cancelGrace = () => {\n if (graceTimer.current) { clearTimeout(graceTimer.current); graceTimer.current = null; }\n };\n const afterGrace = (then: () => void) => {\n cancelGrace();\n graceTimer.current = setTimeout(() => { graceTimer.current = null; then(); }, SUBMENU_GRACE_MS);\n };\n // closing the menu, or leaving the page, drops a hover's wait\n useEffect(() => { if (!open) cancelGrace(); }, [open]);\n useEffect(() => cancelGrace, []);\n\n const pos = usePosition(triggerRef, menuRef, open, { side: \"bottom\", align, offset: 4, flip: true });\n // beside the menu, 4 px from its edge, its first item level with its entry; on the other side where the screen has no\n // room, and inside the screen (measured against the menu, not the entry: the menu's padding and edge sit between them)\n const [subPos, setSubPos] = useState({ top: 0, left: 0 });\n useLayoutEffect(() => {\n if (!open || sub === null || isPhone) return;\n const place = () => {\n const menu = menuRef.current;\n const entry = subItemRef.current;\n const panel = subRef.current;\n if (!menu || !entry || !panel) return;\n const m = menu.getBoundingClientRect();\n const e = entry.getBoundingClientRect();\n const p = panel.getBoundingClientRect();\n const first = panel.querySelector(\"[data-sub-index]\")?.getBoundingClientRect();\n let left = m.right + 4;\n if (left + p.width > window.innerWidth - 8) left = Math.max(8, m.left - 4 - p.width);\n const top = Math.max(8, Math.min(e.top - (first ? first.top - p.top : 0), window.innerHeight - p.height - 8));\n setSubPos((cur) => (cur.top === top && cur.left === left ? cur : { top, left }));\n };\n place();\n window.addEventListener(\"resize\", place);\n window.addEventListener(\"scroll\", place, true);\n return () => {\n window.removeEventListener(\"resize\", place);\n window.removeEventListener(\"scroll\", place, true);\n };\n }, [open, sub, isPhone]);\n\n const enabledIndices = stopsOf(items);\n const subEntry = sub !== null && isSubmenu(items[sub]) ? (items[sub] as DropdownMenuSubmenu) : null;\n const subIndices = subEntry ? stopsOf(subEntry.items) : [];\n\n // Closing clears the keyboard focus index and the submenu (render-time state adjustment).\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (!open) { setFocusedIdx(-1); setSub(null); setSubFocusedIdx(-1); }\n }\n\n // Sprint 25.7: focus hands back on close, and Tab out carries on from the trigger (lib/focus usePopupFocus).\n const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: panelsRef, close: () => setOpen(false), tabExits: \"any\" });\n\n /** The submenu closes, and focus goes back to the entry that opened it. */\n const closeSub = () => {\n if (sub === null) return;\n setFocusedIdx(sub);\n setSub(null);\n setSubFocusedIdx(-1);\n };\n const openSub = (i: number, focusFirst: boolean) => {\n const entry = items[i];\n if (!isSubmenu(entry) || isUnavailable(entry)) return;\n cancelGrace();\n setSub(i);\n setFocusedIdx(i);\n setSubFocusedIdx(focusFirst ? stopsOf(entry.items)[0] ?? -1 : -1);\n };\n\n useEffect(() => {\n if (!open) return;\n\n // An Escape a control inside already handled is its own; the one this acts on is marked for overlays around it.\n // In a submenu it closes the submenu alone.\n const onKeyDown = (e: globalThis.KeyboardEvent) => {\n if (e.key !== \"Escape\" || e.defaultPrevented || !isTopLayer()) return;\n e.preventDefault();\n if (sub !== null) { closeSub(); return; }\n returnFocus();\n setOpen(false);\n };\n\n const onClick = (e: MouseEvent) => {\n const target = e.target as Node;\n if (triggerRef.current?.contains(target) || panelsRef.current?.contains(target)) return;\n setOpen(false);\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n document.addEventListener(\"mousedown\", onClick);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.removeEventListener(\"mousedown\", onClick);\n };\n });\n\n useEffect(() => {\n if (!open) return;\n // By the item's own index: items and dividers share one numbering, so indexing the buttons alone left every\n // item after a divider unreachable by the arrows (the shell's user menu: Settings, divider, Log out).\n if (sub !== null && subFocusedIdx >= 0) panelsRef.current?.querySelector<HTMLElement>(`[data-sub-index=\"${subFocusedIdx}\"]`)?.focus();\n else if (sub !== null && isPhone) panelsRef.current?.querySelector<HTMLElement>(\"[data-sub-back]\")?.focus();\n else if (focusedIdx >= 0) menuRef.current?.querySelector<HTMLElement>(`[data-index=\"${focusedIdx}\"]`)?.focus();\n }, [open, focusedIdx, sub, subFocusedIdx, isPhone]);\n\n const step = (stops: number[], at: number, by: number) => stops[((stops.indexOf(at) + by) % stops.length + stops.length) % stops.length];\n function handleMenuKeyDown(e: ReactKeyboardEvent) {\n const inSub = sub !== null;\n const stops = inSub ? subIndices : enabledIndices;\n const at = inSub ? subFocusedIdx : focusedIdx;\n const go = (i: number | undefined) => { if (i === undefined) return; if (inSub) setSubFocusedIdx(i); else setFocusedIdx(i); };\n if (e.key === \"ArrowDown\") { e.preventDefault(); go(at < 0 ? stops[0] : step(stops, at, 1)); }\n else if (e.key === \"ArrowUp\") { e.preventDefault(); go(at < 0 ? stops[stops.length - 1] : step(stops, at, -1)); }\n else if (e.key === \"Home\") { e.preventDefault(); go(stops[0]); }\n else if (e.key === \"End\") { e.preventDefault(); go(stops[stops.length - 1]); }\n else if (e.key === \"ArrowRight\" && !inSub && focusedIdx >= 0 && isSubmenu(items[focusedIdx])) { e.preventDefault(); openSub(focusedIdx, true); }\n else if (e.key === \"ArrowLeft\" && inSub) { e.preventDefault(); closeSub(); }\n }\n\n /** A choice: focus back on the trigger first, so a dialog the item opens returns there (Sprint 25.7). */\n const choose = (item: DropdownMenuItem) => {\n if (item.disabled) return;\n returnFocus();\n item.onClick();\n setOpen(false);\n };\n\n const subItems = (entries: (DropdownMenuItem | DropdownMenuDivider)[]) => entries.map((item, i) => (isDivider(item) ? <Divider key={i} /> : (\n <button type=\"button\" key={i} data-sub-index={i} role=\"menuitem\" disabled={item.disabled} tabIndex={subFocusedIdx === i ? 0 : -1} onFocus={() => setSubFocusedIdx(i)} onClick={() => choose(item)} className={itemLook(item)}>\n {item.icon && <Icon name={item.icon} size={16} className=\"shrink-0\" />}\n <span>{item.label}</span>\n </button>\n )));\n\n return (\n <>\n <Slot\n {...triggerType(trigger)}\n // the APG's menu button: the trigger says it opens a menu, and whether it is open\n aria-haspopup=\"menu\"\n aria-expanded={open}\n ref={triggerRef}\n onClick={() => {\n setOpen(!open);\n if (!open && enabledIndices.length) setFocusedIdx(enabledIndices[0]);\n }}\n >\n {trigger}\n </Slot>\n {open && createPortal(\n <div ref={panelsRef} className=\"contents\">\n <div\n ref={menuRef}\n role=\"menu\"\n data-gs=\"menu\"\n aria-label={isPhone && subEntry ? subEntry.label : undefined}\n onKeyDown={handleMenuKeyDown}\n className={cn(PANEL, className)}\n style={{ top: pos.top, left: pos.left }}\n // A choice is the menu's own: the click must not also reach a clickable row or card the menu sits in\n // (React carries events from a portal to its React parents).\n onClick={(e) => e.stopPropagation()}\n >\n {isPhone && subEntry ? (\n // on a phone the submenu takes the menu's place: Back first, its entry's name on it\n <>\n <button type=\"button\" data-sub-back=\"\" role=\"menuitem\" aria-label={`Back from ${subEntry.label}`} tabIndex={-1} onClick={closeSub} className={cn(itemLook(subEntry), \"text-[var(--ds-text-secondary)] font-[var(--ds-weight-heading)]\")}>\n <Icon name=\"chevron-left\" size={16} className=\"shrink-0\" />\n <span>{subEntry.label}</span>\n </button>\n <Divider />\n {subItems(subEntry.items)}\n </>\n ) : items.map((item, i) => {\n if (isDivider(item)) return <Divider key={i} />;\n if (isSubmenu(item)) {\n const isOpen = sub === i;\n return (\n <button type=\"button\"\n key={i}\n ref={isOpen ? (el) => { subItemRef.current = el; } : undefined}\n data-index={i}\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n disabled={isUnavailable(item)}\n tabIndex={focusedIdx === i ? 0 : -1}\n // the arrows go on from wherever focus is, however it got there (a click, a screen reader's command)\n onFocus={() => setFocusedIdx(i)}\n // Enter (its click) or a press goes into the submenu, its first item focused, whether a hover had\n // opened it or not (the APG's menu: Enter opens it and focuses its first item); ←, Escape or Back\n // closes it\n onClick={() => openSub(i, true)}\n // a hover opens it at once where no other is open; with another open it waits, as the pointer may be\n // on its way to that one (SUBMENU_GRACE_MS); back on its own entry, the wait for a close is dropped\n onMouseEnter={(e) => {\n if (isPhone || e.buttons !== 0) return;\n if (isOpen) cancelGrace();\n else if (sub === null) openSub(i, false);\n else afterGrace(() => openSub(i, false));\n }}\n className={itemLook(item, isOpen)}\n >\n {item.icon && <Icon name={item.icon} size={16} className=\"shrink-0\" />}\n <span className=\"flex-1\">{item.label}</span>\n <Icon name=\"chevron-right\" size={14} className=\"shrink-0 text-[var(--ds-text-muted)]\" />\n </button>\n );\n }\n return (\n <button type=\"button\"\n key={i}\n data-index={i}\n role=\"menuitem\"\n disabled={item.disabled}\n tabIndex={focusedIdx === i ? 0 : -1}\n onFocus={() => setFocusedIdx(i)}\n onClick={() => choose(item)}\n // a hover on another entry closes an open submenu, as moving on from it does, after a moment: the\n // pointer may only be crossing it on its way to the submenu (SUBMENU_GRACE_MS)\n onMouseEnter={() => { if (!isPhone && sub !== null) afterGrace(() => { setSub(null); setSubFocusedIdx(-1); }); }}\n className={itemLook(item)}\n >\n {item.icon && <Icon name={item.icon} size={16} className=\"shrink-0\" />}\n <span>{item.label}</span>\n </button>\n );\n })}\n </div>\n {!isPhone && subEntry && (\n <div\n ref={subRef}\n role=\"menu\"\n aria-label={subEntry.label}\n onKeyDown={handleMenuKeyDown}\n className={PANEL}\n style={{ top: subPos.top, left: subPos.left }}\n onClick={(e) => e.stopPropagation()}\n // the pointer has reached the submenu: a hover it crossed on the way closes nothing\n onMouseEnter={cancelGrace}\n >\n {subItems(subEntry.items)}\n </div>\n )}\n </div>,\n container ?? document.body\n )}\n </>\n );\n}\n"]}
|
package/dist/data-grid.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ColumnDef } from '@tanstack/react-table';
|
|
3
|
-
import { B as BreakpointKey, C as ColumnKind } from './table-utils-
|
|
3
|
+
import { B as BreakpointKey, C as ColumnKind } from './table-utils-BXkP-2Hx.js';
|
|
4
4
|
import { P as Pager } from './use-pagination-QykGSREv.js';
|
|
5
5
|
import 'react';
|
|
6
6
|
|
|
7
|
+
/** One of a choice column's options: the value its cells hold, and the words shown for it. */
|
|
8
|
+
interface DataGridOption {
|
|
9
|
+
value: string | number;
|
|
10
|
+
label: string;
|
|
11
|
+
}
|
|
7
12
|
/** Column meta for opt-in truncation. Set on ColumnDef.meta. */
|
|
8
13
|
interface DataGridColumnMeta {
|
|
9
14
|
/** true = single-line, or { lines: N } for multi-line clamp. */
|
|
@@ -16,15 +21,29 @@ interface DataGridColumnMeta {
|
|
|
16
21
|
width?: string;
|
|
17
22
|
/** CSS min-width for the column. */
|
|
18
23
|
minWidth?: string;
|
|
19
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Explicit column kind. When omitted the DataGrid infers it from data values (a yes or no too; never a choice). In an
|
|
26
|
+
* editable grid it chooses the editor, where the control can hold the cell's value: "number" a NumberInput for a
|
|
27
|
+
* number, "date" a DatePicker for a Date or an ISO date ("2026-10-14"), "choice" a Dropdown of `options`, "boolean" a
|
|
28
|
+
* Checkbox; any other kind, and a number or a date written as text ("18 KB", "12 Jan 2026"), a text Input.
|
|
29
|
+
*/
|
|
20
30
|
kind?: ColumnKind;
|
|
21
31
|
/** Horizontal alignment of the header and the cells; a block element (a Checkbox, a Button) is laid out with flex so it follows too (round 14). Default: numbers right, everything else left. */
|
|
22
32
|
align?: "left" | "center" | "right";
|
|
23
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* In an editable grid, whether this column's cells edit (default true); false for a column that shows (a status, a
|
|
35
|
+
* calculated value, actions): its cells show no edit cue, and assistive tech hears them as read-only.
|
|
36
|
+
*/
|
|
24
37
|
editable?: boolean;
|
|
25
38
|
/**
|
|
26
|
-
*
|
|
27
|
-
* `
|
|
39
|
+
* A choice column's options (with `kind: "choice"`): its cells edit with a Dropdown of them, and a save gives the
|
|
40
|
+
* option's `value`. Give the column a `cell` that shows the option's label.
|
|
41
|
+
*/
|
|
42
|
+
options?: readonly DataGridOption[];
|
|
43
|
+
/**
|
|
44
|
+
* In an editable grid, the value onCellEdit gets from what was typed in a text cell, or in a number cell as its text
|
|
45
|
+
* (default the text itself, or the number): a price written as text, `(text) => Number(text.replace(/[$,]/g, ""))`.
|
|
46
|
+
* A date, a choice and a yes or no are given as their own values.
|
|
28
47
|
*/
|
|
29
48
|
parse?: (text: string) => unknown;
|
|
30
49
|
}
|
|
@@ -66,4 +85,4 @@ interface DataGridProps<T> {
|
|
|
66
85
|
}
|
|
67
86
|
declare function DataGrid<T>({ data, columns, pageSize, editable, onCellEdit, mobileBreakpoint: mobileBreakpointProp, cardsBelow, pager: pagerProp, "aria-label": ariaLabel, className, }: DataGridProps<T>): react_jsx_runtime.JSX.Element;
|
|
68
87
|
|
|
69
|
-
export { DataGrid, type DataGridColumnMeta };
|
|
88
|
+
export { DataGrid, type DataGridColumnMeta, type DataGridOption };
|