gridsmith-ui 0.14.0 → 0.15.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/dist/charts.js +1 -1
- package/dist/chat.js +4 -4
- package/dist/{chunk-PKLVP5ZB.js → chunk-7Q46JXSK.js} +5 -4
- package/dist/chunk-7Q46JXSK.js.map +1 -0
- package/dist/{chunk-JSQPVRHQ.js → chunk-ATONRIEB.js} +6 -6
- package/dist/chunk-ATONRIEB.js.map +1 -0
- package/dist/{chunk-IYD6ZDM2.js → chunk-EMCSARQO.js} +7 -6
- package/dist/chunk-EMCSARQO.js.map +1 -0
- package/dist/{chunk-QJBCZ7BR.js → chunk-LU3YRNES.js} +3 -3
- package/dist/{chunk-QJBCZ7BR.js.map → chunk-LU3YRNES.js.map} +1 -1
- package/dist/{chunk-CR2KF73R.js → chunk-OENJCGTJ.js} +3 -3
- package/dist/{chunk-CR2KF73R.js.map → chunk-OENJCGTJ.js.map} +1 -1
- package/dist/chunk-VFAKME7Q.js +350 -0
- package/dist/chunk-VFAKME7Q.js.map +1 -0
- package/dist/{chunk-U2JT37GJ.js → chunk-XCSTU6IJ.js} +3 -3
- package/dist/{chunk-U2JT37GJ.js.map → chunk-XCSTU6IJ.js.map} +1 -1
- package/dist/data-grid.js +3 -3
- package/dist/editor.js +25 -7
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +502 -147
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +3 -3
- package/dist/resizable.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-IYD6ZDM2.js.map +0 -1
- package/dist/chunk-JSQPVRHQ.js.map +0 -1
- package/dist/chunk-NHQCMOAN.js +0 -137
- package/dist/chunk-NHQCMOAN.js.map +0 -1
- package/dist/chunk-PKLVP5ZB.js.map +0 -1
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
2
|
+
import { useRef, useInsertionEffect, useEffect, useCallback, useState, useLayoutEffect } from 'react';
|
|
3
|
+
import { flushSync } from 'react-dom';
|
|
4
|
+
|
|
5
|
+
var FOCUSABLE = 'a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"]), [contenteditable]:not([contenteditable="false"])';
|
|
6
|
+
var FIELD = "input, select, textarea, [contenteditable='true']";
|
|
7
|
+
var SAFE_BUTTON = 'button:not([data-variant="destructive"])';
|
|
8
|
+
var OVERLAY_CLOSE_ATTR = "data-overlay-close";
|
|
9
|
+
function isRendered(el) {
|
|
10
|
+
if (typeof el.checkVisibility === "function") return el.checkVisibility({ checkVisibilityCSS: true });
|
|
11
|
+
for (let n = el; n; n = n.parentElement) {
|
|
12
|
+
if (n instanceof HTMLElement && n.hidden) return false;
|
|
13
|
+
const style = getComputedStyle(n);
|
|
14
|
+
if (style.display === "none") return false;
|
|
15
|
+
if (n === el && style.visibility === "hidden") return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
function isRadioStop(el) {
|
|
20
|
+
if (!el.name) return true;
|
|
21
|
+
const scope = el.form ?? el.ownerDocument;
|
|
22
|
+
const group = Array.from(scope.querySelectorAll('input[type="radio"]')).filter((r) => r.name === el.name && !r.disabled && r.form === el.form);
|
|
23
|
+
const checked = group.find((r) => r.checked);
|
|
24
|
+
return (checked ?? group[0]) === el;
|
|
25
|
+
}
|
|
26
|
+
function isTabStop(el) {
|
|
27
|
+
if (!(el instanceof HTMLElement) || el.tabIndex < 0) return false;
|
|
28
|
+
if ((el instanceof HTMLButtonElement || el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement) && el.disabled) return false;
|
|
29
|
+
if (el instanceof HTMLInputElement && (el.type === "hidden" || el.type === "radio" && !isRadioStop(el))) return false;
|
|
30
|
+
if (el.closest("[inert]")) return false;
|
|
31
|
+
return isRendered(el);
|
|
32
|
+
}
|
|
33
|
+
function tabStops(root) {
|
|
34
|
+
return Array.from(root.querySelectorAll(FOCUSABLE)).filter(isTabStop);
|
|
35
|
+
}
|
|
36
|
+
function focusInitial(root, opts = {}) {
|
|
37
|
+
if (!root) return false;
|
|
38
|
+
const all = tabStops(root);
|
|
39
|
+
if (!all.length) return false;
|
|
40
|
+
const candidates = all.filter((el) => !el.hasAttribute(OVERLAY_CLOSE_ATTR));
|
|
41
|
+
const field = candidates.find((el) => el.matches(FIELD));
|
|
42
|
+
if (opts.destructive && !field) {
|
|
43
|
+
const safe = candidates.find((el) => el.matches(SAFE_BUTTON));
|
|
44
|
+
if (safe) {
|
|
45
|
+
safe.focus();
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const target = candidates.find((el) => el.matches(FIELD)) ?? candidates[0] ?? all[0];
|
|
50
|
+
target.focus();
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
function useFocusBeforeOpen(open) {
|
|
54
|
+
const before = useRef(null);
|
|
55
|
+
useInsertionEffect(() => {
|
|
56
|
+
if (open) before.current = document.activeElement;
|
|
57
|
+
}, [open]);
|
|
58
|
+
return before;
|
|
59
|
+
}
|
|
60
|
+
var ROW = 'tr, li, [role="row"], [data-card], [data-row]';
|
|
61
|
+
function rememberFocus(el) {
|
|
62
|
+
const href = location.href;
|
|
63
|
+
const row = el.closest(ROW);
|
|
64
|
+
const before = row?.previousElementSibling ?? null;
|
|
65
|
+
const after = row?.nextElementSibling ?? null;
|
|
66
|
+
const list = row?.parentElement ?? null;
|
|
67
|
+
const index = row ? tabStops(row).indexOf(el) : -1;
|
|
68
|
+
const text = row?.textContent ?? "";
|
|
69
|
+
const shown = new Set(list ? Array.from(list.children, (r) => r.textContent) : []);
|
|
70
|
+
const shifted = () => {
|
|
71
|
+
if (!list || !row?.isConnected || row.parentElement !== list || row.textContent === text || !shown.has(row.textContent)) return void 0;
|
|
72
|
+
return Array.from(list.children).find((r) => r.textContent === text) ?? row.previousElementSibling;
|
|
73
|
+
};
|
|
74
|
+
const land = (target) => {
|
|
75
|
+
if (!target || !target.isConnected) return false;
|
|
76
|
+
target.focus();
|
|
77
|
+
return document.activeElement === target;
|
|
78
|
+
};
|
|
79
|
+
const inRow = (r) => {
|
|
80
|
+
if (!r || !r.isConnected) return false;
|
|
81
|
+
const stops = tabStops(r);
|
|
82
|
+
return land(stops[Math.max(0, Math.min(index, stops.length - 1))]);
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
el,
|
|
86
|
+
restore(fallback) {
|
|
87
|
+
if (location.href !== href) return false;
|
|
88
|
+
if (inRow(shifted() ?? null)) return true;
|
|
89
|
+
if (land(el)) return true;
|
|
90
|
+
if (row && !row.isConnected && (inRow(before) || inRow(after) || !!list?.isConnected && land(tabStops(list)[0]))) return true;
|
|
91
|
+
return land(fallback);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function useReturnFocus(open, root) {
|
|
96
|
+
const remembered = useRef(null);
|
|
97
|
+
const before = useFocusBeforeOpen(open);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (open) {
|
|
100
|
+
const active2 = before.current;
|
|
101
|
+
remembered.current = active2 instanceof HTMLElement && active2 !== document.body && active2.isConnected ? rememberFocus(active2) : null;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const r = remembered.current;
|
|
105
|
+
remembered.current = null;
|
|
106
|
+
if (!r) return;
|
|
107
|
+
const active = document.activeElement;
|
|
108
|
+
const lost = !active || active === document.body || !active.isConnected;
|
|
109
|
+
if (!root || lost || active instanceof Node && !!root.current?.contains(active)) r.restore();
|
|
110
|
+
}, [open, root, before]);
|
|
111
|
+
return useCallback(() => {
|
|
112
|
+
remembered.current?.restore();
|
|
113
|
+
}, []);
|
|
114
|
+
}
|
|
115
|
+
function rovingTabStop(items, isChecked, isDisabled = () => false) {
|
|
116
|
+
const checked = items.findIndex((item) => isChecked(item) && !isDisabled(item));
|
|
117
|
+
return checked >= 0 ? checked : items.findIndex((item) => !isDisabled(item));
|
|
118
|
+
}
|
|
119
|
+
function focusAfterRemoval(items, index, fallback) {
|
|
120
|
+
(items[index - 1] ?? items[index] ?? fallback)?.focus();
|
|
121
|
+
}
|
|
122
|
+
var layers = [];
|
|
123
|
+
function useOverlayLayer(open) {
|
|
124
|
+
const [id] = useState(() => /* @__PURE__ */ Symbol("overlay-layer"));
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (!open) return;
|
|
127
|
+
layers.push(id);
|
|
128
|
+
return () => {
|
|
129
|
+
const i = layers.indexOf(id);
|
|
130
|
+
if (i >= 0) layers.splice(i, 1);
|
|
131
|
+
};
|
|
132
|
+
}, [open, id]);
|
|
133
|
+
return useCallback(() => layers[layers.length - 1] === id, [id]);
|
|
134
|
+
}
|
|
135
|
+
function useCloseOnFocusOut(open, triggerRef, panelRef, onClose, isTop = ALWAYS_TOP) {
|
|
136
|
+
const onCloseRef = useLatest(onClose);
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (!open) return;
|
|
139
|
+
let pointerInside = false;
|
|
140
|
+
const inside = (n) => n instanceof Node && (!!triggerRef.current?.contains(n) || !!panelRef.current?.contains(n));
|
|
141
|
+
const onPointerDown = (e) => {
|
|
142
|
+
pointerInside = inside(e.target);
|
|
143
|
+
};
|
|
144
|
+
const onFocusOut = (e) => {
|
|
145
|
+
if (!inside(e.target)) return;
|
|
146
|
+
if (e.relatedTarget) {
|
|
147
|
+
if (!inside(e.relatedTarget) && isTop()) onCloseRef.current();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
if (pointerInside) {
|
|
152
|
+
pointerInside = false;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (!inside(document.activeElement) && isTop()) onCloseRef.current();
|
|
156
|
+
}, 0);
|
|
157
|
+
};
|
|
158
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
159
|
+
document.addEventListener("focusout", onFocusOut, true);
|
|
160
|
+
return () => {
|
|
161
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
162
|
+
document.removeEventListener("focusout", onFocusOut, true);
|
|
163
|
+
};
|
|
164
|
+
}, [open, triggerRef, panelRef, isTop, onCloseRef]);
|
|
165
|
+
}
|
|
166
|
+
var openPopups = /* @__PURE__ */ new Map();
|
|
167
|
+
function usePopupFocus(open, { trigger, panel, close, tabExits, onTabOut }) {
|
|
168
|
+
const isTop = useOverlayLayer(open);
|
|
169
|
+
const [id] = useState(() => /* @__PURE__ */ Symbol("popup"));
|
|
170
|
+
const closeRef = useLatest(close);
|
|
171
|
+
const onTabOutRef = useLatest(onTabOut);
|
|
172
|
+
const remembered = useRef(null);
|
|
173
|
+
const pointerOutside = useRef(false);
|
|
174
|
+
const wasOpen = useRef(false);
|
|
175
|
+
useCloseOnFocusOut(open, trigger, panel, close, isTop);
|
|
176
|
+
const before = useFocusBeforeOpen(open);
|
|
177
|
+
useLayoutEffect(() => {
|
|
178
|
+
if (!open) return;
|
|
179
|
+
const active = before.current;
|
|
180
|
+
const inPanel = active instanceof Node && !!panel.current?.contains(active);
|
|
181
|
+
const opener = active instanceof HTMLElement && active !== document.body && !inPanel ? active : trigger.current;
|
|
182
|
+
remembered.current = opener ? rememberFocus(opener) : null;
|
|
183
|
+
pointerOutside.current = false;
|
|
184
|
+
}, [open, trigger, panel, before]);
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
if (!open) return;
|
|
187
|
+
const onPointerDown = (e) => {
|
|
188
|
+
const t = e.target;
|
|
189
|
+
pointerOutside.current = !(t instanceof Node && (!!trigger.current?.contains(t) || !!panel.current?.contains(t)));
|
|
190
|
+
};
|
|
191
|
+
const leave = (e) => {
|
|
192
|
+
onTabOutRef.current?.(e);
|
|
193
|
+
const r = remembered.current;
|
|
194
|
+
const opener = r && r.el.isConnected ? r.el : trigger.current;
|
|
195
|
+
opener?.focus();
|
|
196
|
+
flushSync(() => closeRef.current());
|
|
197
|
+
if (!opener || !opener.isConnected) return;
|
|
198
|
+
if (e.shiftKey) {
|
|
199
|
+
e.preventDefault();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const modal = opener.closest('[aria-modal="true"]');
|
|
203
|
+
if (modal) {
|
|
204
|
+
const stops = tabStops(modal);
|
|
205
|
+
if (stops.length && stops[stops.length - 1] === opener) {
|
|
206
|
+
e.preventDefault();
|
|
207
|
+
stops[0].focus();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
for (const [otherId, other] of openPopups) {
|
|
212
|
+
const outer = other.panel.current;
|
|
213
|
+
if (otherId === id || !outer?.contains(opener)) continue;
|
|
214
|
+
const stops = tabStops(outer);
|
|
215
|
+
if (other.tabExits === "any" || stops[stops.length - 1] === opener) {
|
|
216
|
+
other.leave(e);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
const onKeyDown = (e) => {
|
|
223
|
+
if (e.key !== "Tab" || e.defaultPrevented || tabExits === "none" || !isTop()) return;
|
|
224
|
+
const p = panel.current;
|
|
225
|
+
const active = document.activeElement;
|
|
226
|
+
if (!p || !(active instanceof Node) || !p.contains(active)) return;
|
|
227
|
+
if (tabExits === "edges") {
|
|
228
|
+
const stops = tabStops(p);
|
|
229
|
+
if (stops.length && active !== (e.shiftKey ? stops[0] : stops[stops.length - 1])) return;
|
|
230
|
+
}
|
|
231
|
+
leave(e);
|
|
232
|
+
};
|
|
233
|
+
openPopups.set(id, { panel, tabExits, leave });
|
|
234
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
235
|
+
document.addEventListener("keydown", onKeyDown);
|
|
236
|
+
return () => {
|
|
237
|
+
openPopups.delete(id);
|
|
238
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
239
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
240
|
+
};
|
|
241
|
+
}, [open, tabExits, isTop, id, trigger, panel, closeRef, onTabOutRef]);
|
|
242
|
+
useLayoutEffect(() => {
|
|
243
|
+
if (open) {
|
|
244
|
+
wasOpen.current = true;
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (!wasOpen.current) return;
|
|
248
|
+
wasOpen.current = false;
|
|
249
|
+
const r = remembered.current;
|
|
250
|
+
remembered.current = null;
|
|
251
|
+
if (pointerOutside.current || !r) return;
|
|
252
|
+
const active = document.activeElement;
|
|
253
|
+
if (active !== r.el && active && active !== document.body && active.isConnected) return;
|
|
254
|
+
r.restore(trigger.current);
|
|
255
|
+
}, [open, trigger]);
|
|
256
|
+
useLayoutEffect(() => () => {
|
|
257
|
+
if (!wasOpen.current) return;
|
|
258
|
+
const r = remembered.current;
|
|
259
|
+
queueMicrotask(() => {
|
|
260
|
+
const active = document.activeElement;
|
|
261
|
+
if (active && active !== document.body && active.isConnected) return;
|
|
262
|
+
r?.restore();
|
|
263
|
+
});
|
|
264
|
+
}, []);
|
|
265
|
+
const returnFocus = useCallback(() => {
|
|
266
|
+
remembered.current?.restore(trigger.current);
|
|
267
|
+
}, [trigger]);
|
|
268
|
+
return { isTop, returnFocus };
|
|
269
|
+
}
|
|
270
|
+
function focusGridKey(root, key) {
|
|
271
|
+
const el = root?.querySelector(`[data-grid-key="${key}"]`);
|
|
272
|
+
if (!el) return false;
|
|
273
|
+
el.focus();
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
function useGridKeyboard({ container, active, setActive, keyOf, move }) {
|
|
277
|
+
const pending = useRef(null);
|
|
278
|
+
useLayoutEffect(() => {
|
|
279
|
+
const key = pending.current;
|
|
280
|
+
if (key !== null && focusGridKey(container.current, key)) pending.current = null;
|
|
281
|
+
});
|
|
282
|
+
const activeKey = keyOf(active);
|
|
283
|
+
const onKeyDown = (e) => {
|
|
284
|
+
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
285
|
+
const next = move(active, e);
|
|
286
|
+
if (next === null) return;
|
|
287
|
+
e.preventDefault();
|
|
288
|
+
const key = keyOf(next);
|
|
289
|
+
setActive(next);
|
|
290
|
+
if (!focusGridKey(container.current, key)) pending.current = key;
|
|
291
|
+
};
|
|
292
|
+
const focusActive = () => {
|
|
293
|
+
if (!focusGridKey(container.current, activeKey)) pending.current = activeKey;
|
|
294
|
+
};
|
|
295
|
+
const tabIndexOf = (item) => keyOf(item) === activeKey ? 0 : -1;
|
|
296
|
+
return { onKeyDown, tabIndexOf, focusActive };
|
|
297
|
+
}
|
|
298
|
+
var ALWAYS_TOP = () => true;
|
|
299
|
+
function useFocusTrap(root, active, isTop = ALWAYS_TOP) {
|
|
300
|
+
useEffect(() => {
|
|
301
|
+
if (!active) return;
|
|
302
|
+
const onKeyDown = (e) => {
|
|
303
|
+
if (e.key !== "Tab" || e.defaultPrevented || !root.current || !isTop()) return;
|
|
304
|
+
const focusable = tabStops(root.current);
|
|
305
|
+
if (focusable.length === 0) {
|
|
306
|
+
e.preventDefault();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const first = focusable[0];
|
|
310
|
+
const last = focusable[focusable.length - 1];
|
|
311
|
+
const current = document.activeElement;
|
|
312
|
+
const inside = current instanceof Node && root.current.contains(current);
|
|
313
|
+
if (e.shiftKey) {
|
|
314
|
+
if (!inside || current === first) {
|
|
315
|
+
e.preventDefault();
|
|
316
|
+
last.focus();
|
|
317
|
+
}
|
|
318
|
+
} else if (!inside || current === last) {
|
|
319
|
+
e.preventDefault();
|
|
320
|
+
first.focus();
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
document.addEventListener("keydown", onKeyDown);
|
|
324
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
325
|
+
}, [root, active, isTop]);
|
|
326
|
+
}
|
|
327
|
+
function useNonModalDialog(root, active, onClose, isTop = ALWAYS_TOP) {
|
|
328
|
+
const onCloseRef = useLatest(onClose);
|
|
329
|
+
useReturnFocus(active);
|
|
330
|
+
useEffect(() => {
|
|
331
|
+
if (!active) return;
|
|
332
|
+
const raf = requestAnimationFrame(() => focusInitial(root.current));
|
|
333
|
+
return () => cancelAnimationFrame(raf);
|
|
334
|
+
}, [active, root]);
|
|
335
|
+
useEffect(() => {
|
|
336
|
+
if (!active) return;
|
|
337
|
+
const onKeyDown = (e) => {
|
|
338
|
+
if (e.key !== "Escape" || !isTop()) return;
|
|
339
|
+
const el = root.current;
|
|
340
|
+
if (!el || !el.contains(document.activeElement)) return;
|
|
341
|
+
onCloseRef.current();
|
|
342
|
+
};
|
|
343
|
+
document.addEventListener("keydown", onKeyDown);
|
|
344
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
345
|
+
}, [active, root, isTop, onCloseRef]);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export { OVERLAY_CLOSE_ATTR, focusAfterRemoval, focusInitial, rememberFocus, rovingTabStop, useCloseOnFocusOut, useFocusBeforeOpen, useFocusTrap, useGridKeyboard, useNonModalDialog, useOverlayLayer, usePopupFocus, useReturnFocus };
|
|
349
|
+
//# sourceMappingURL=chunk-VFAKME7Q.js.map
|
|
350
|
+
//# sourceMappingURL=chunk-VFAKME7Q.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/focus.ts"],"names":["active"],"mappings":"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","file":"chunk-VFAKME7Q.js","sourcesContent":["import { useCallback, useEffect, useInsertionEffect, useLayoutEffect, useRef, useState, type KeyboardEvent as ReactKeyboardEvent, type RefObject } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { useLatest } from \"./use-latest\";\n\n/**\n * Everything a keyboard user might land on: the candidates. Whether one is a\n * Tab stop right now is `isTabStop`'s call (a roving item with tabindex=\"-1\", a\n * hidden input or a disabled field matches this selector but is not a stop).\n */\nexport const FOCUSABLE =\n 'a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex=\"-1\"]), [contenteditable]:not([contenteditable=\"false\"])';\n\nconst FIELD = \"input, select, textarea, [contenteditable='true']\";\nconst SAFE_BUTTON = 'button:not([data-variant=\"destructive\"])';\n\n/** Mark an overlay's own close/dismiss button so initial focus skips it. */\nexport const OVERLAY_CLOSE_ATTR = \"data-overlay-close\";\n\n// ─── Tab stops ───────────────────────────────────────────────────────────────\n\n/** Rendered and not hidden. Real browsers answer with checkVisibility; with no layout (jsdom) the tree is walked. */\nfunction isRendered(el: HTMLElement): boolean {\n if (typeof el.checkVisibility === \"function\") return el.checkVisibility({ checkVisibilityCSS: true });\n for (let n: Element | null = el; n; n = n.parentElement) {\n if (n instanceof HTMLElement && n.hidden) return false;\n const style = getComputedStyle(n);\n if (style.display === \"none\") return false;\n if (n === el && style.visibility === \"hidden\") return false;\n }\n return true;\n}\n\n/** A native radio is a Tab stop when it is its group's checked radio, or the first when none is checked. */\nfunction isRadioStop(el: HTMLInputElement): boolean {\n if (!el.name) return true;\n const scope: ParentNode = el.form ?? el.ownerDocument;\n const group = Array.from(scope.querySelectorAll<HTMLInputElement>('input[type=\"radio\"]'))\n .filter((r) => r.name === el.name && !r.disabled && r.form === el.form);\n const checked = group.find((r) => r.checked);\n return (checked ?? group[0]) === el;\n}\n\n/**\n * Could the browser's own Tab land here? A focusable element with a\n * non-negative tabIndex, not disabled, not a hidden input, not inside an inert\n * subtree, rendered, and for a native radio the group's one stop (Sprint 25.7).\n */\nexport function isTabStop(el: Element): el is HTMLElement {\n if (!(el instanceof HTMLElement) || el.tabIndex < 0) return false;\n if ((el instanceof HTMLButtonElement || el instanceof HTMLInputElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement) && el.disabled) return false;\n if (el instanceof HTMLInputElement && (el.type === \"hidden\" || (el.type === \"radio\" && !isRadioStop(el)))) return false;\n if (el.closest(\"[inert]\")) return false;\n return isRendered(el);\n}\n\n/** The Tab stops inside `root`, in document order. */\nexport function tabStops(root: ParentNode): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(isTabStop);\n}\n\n/**\n * Move initial focus into an overlay the way users expect: the first visible\n * form field if there is one, otherwise the first focusable element that is\n * not the overlay's own close button.\n *\n * For destructive confirmations (`destructive: true`) the corpus rule applies\n * instead: focus the non-destructive action so Enter can't confirm by\n * accident. That is the first button not rendered with the destructive\n * variant, regardless of footer order; a lone destructive button falls back to\n * the general rule.\n *\n * React's `autoFocus` prop is not reflected as a DOM attribute, so a\n * field-first rule is the reliable general behaviour.\n */\nexport function focusInitial(root: HTMLElement | null | undefined, opts: { destructive?: boolean } = {}): boolean {\n if (!root) return false;\n const all = tabStops(root);\n if (!all.length) return false;\n const candidates = all.filter((el) => !el.hasAttribute(OVERLAY_CLOSE_ATTR));\n\n // Round 18 (the owner, 55.5; round 17 F-9): a destructive dialog that holds a field is a type-to-confirm dialog — its\n // confirm stays disabled until the text matches, so the field is the safe target. Cancel is the target only when the\n // dialog is buttons-only.\n const field = candidates.find((el) => el.matches(FIELD));\n if (opts.destructive && !field) {\n const safe = candidates.find((el) => el.matches(SAFE_BUTTON));\n if (safe) {\n safe.focus();\n return true;\n }\n }\n\n const target = candidates.find((el) => el.matches(FIELD)) ?? candidates[0] ?? all[0];\n target.focus();\n return true;\n}\n\n// ─── Remembering where focus was ─────────────────────────────────────────────\n\n/**\n * The element that had focus when `open` turned true, read before this commit's children can move it. An `autoFocus`\n * field inside a dialog takes focus while React commits (the layout phase), so an effect that reads\n * document.activeElement afterwards sees that field, not the opener (run 57's type-to-confirm dialog, Sprint 25.7).\n * Insertion effects run earlier in the commit, before any of that.\n */\nexport function useFocusBeforeOpen(open: boolean): RefObject<Element | null> {\n const before = useRef<Element | null>(null);\n useInsertionEffect(() => {\n if (open) before.current = document.activeElement;\n }, [open]);\n return before;\n}\n\n/** What counts as \"the row\" an opener sits in, for a row that is deleted while its menu or dialog is open. */\nconst ROW = 'tr, li, [role=\"row\"], [data-card], [data-row]';\n\nexport interface RememberedFocus {\n readonly el: HTMLElement;\n /**\n * Put focus back (Sprint 25.7). Nothing happens once the page has changed:\n * the new page owns focus (D14(d)). Otherwise the element itself; if its row\n * was deleted, the same control in the row before, else the row after, else\n * the first Tab stop of the list (D14(c), MOJ \"Add another\" order); else\n * `fallback`. True when focus landed.\n *\n * A list keyed by position (the library Table, `key={i}`) keeps a deleted\n * row's elements and fills them with the next item, and a paged list keeps\n * its length. So when this row now shows what another row showed, the list\n * has shifted: focus follows this item to its new row, or, when it is gone,\n * goes to the row before (else this row, which now holds the item after). A\n * row edited in place shows something no row showed, and keeps focus.\n */\n restore(fallback?: HTMLElement | null): boolean;\n}\n\nexport function rememberFocus(el: HTMLElement): RememberedFocus {\n const href = location.href;\n const row = el.closest<HTMLElement>(ROW);\n const before = row?.previousElementSibling ?? null;\n const after = row?.nextElementSibling ?? null;\n const list = row?.parentElement ?? null;\n const index = row ? tabStops(row).indexOf(el) : -1;\n const text = row?.textContent ?? \"\";\n const shown = new Set(list ? Array.from(list.children, (r) => r.textContent) : []);\n /** This row now shows another row's item: the row that has this item now, else the row before. */\n const shifted = () => {\n if (!list || !row?.isConnected || row.parentElement !== list || row.textContent === text || !shown.has(row.textContent)) return undefined;\n return Array.from(list.children).find((r) => r.textContent === text) ?? row.previousElementSibling;\n };\n const land = (target: HTMLElement | null | undefined) => {\n if (!target || !target.isConnected) return false;\n target.focus();\n return document.activeElement === target;\n };\n const inRow = (r: Element | null) => {\n if (!r || !r.isConnected) return false;\n const stops = tabStops(r);\n return land(stops[Math.max(0, Math.min(index, stops.length - 1))]);\n };\n return {\n el,\n restore(fallback) {\n if (location.href !== href) return false;\n if (inRow(shifted() ?? null)) return true;\n if (land(el)) return true;\n if (row && !row.isConnected && (inRow(before) || inRow(after) || (!!list?.isConnected && land(tabStops(list)[0])))) return true;\n return land(fallback);\n },\n };\n}\n\n/**\n * Remember what had focus when a modal overlay opened and give it back on\n * close (corpus: \"After an overlay closes, return focus to the element that\n * triggered it\"). With `root`, focus is given back only when it was lost or is\n * still inside the closing overlay, so a focus move the consumer made on close\n * wins. Returns `returnFocus()` for a command that must hand focus back before\n * it runs (CommandPalette: a command that opens a Dialog).\n */\nexport function useReturnFocus(open: boolean, root?: RefObject<HTMLElement | null>) {\n const remembered = useRef<RememberedFocus | null>(null);\n const before = useFocusBeforeOpen(open);\n useEffect(() => {\n if (open) {\n const active = before.current;\n remembered.current = active instanceof HTMLElement && active !== document.body && active.isConnected ? rememberFocus(active) : null;\n return;\n }\n const r = remembered.current;\n remembered.current = null;\n if (!r) return;\n const active = document.activeElement;\n const lost = !active || active === document.body || !active.isConnected;\n if (!root || lost || (active instanceof Node && !!root.current?.contains(active))) r.restore();\n }, [open, root, before]);\n return useCallback(() => { remembered.current?.restore(); }, []);\n}\n\n/**\n * Index of the single Tab stop in a radio-style group (APG radio pattern):\n * the checked item, else the first enabled item so a group with no selection\n * is still reachable. −1 when every item is disabled.\n */\nexport function rovingTabStop<T>(items: T[], isChecked: (item: T) => boolean, isDisabled: (item: T) => boolean = () => false): number {\n const checked = items.findIndex((item) => isChecked(item) && !isDisabled(item));\n return checked >= 0 ? checked : items.findIndex((item) => !isDisabled(item));\n}\n\n/**\n * Rule 4 (D14(c), MOJ \"Add another\" order): after the item at `index` was\n * removed, focus the item before it, else the one now in its place, else\n * `fallback`. `items` is the list as it is after the removal.\n */\nexport function focusAfterRemoval(items: ArrayLike<HTMLElement>, index: number, fallback?: HTMLElement | null) {\n (items[index - 1] ?? items[index] ?? fallback)?.focus();\n}\n\n// ─── Overlay layers ──────────────────────────────────────────────────────────\n// Every overlay that closes on Escape listens on `document`, so a Dropdown open\n// inside a Drawer used to close both with one key press. Open overlays register\n// here in the order they opened; only the topmost one acts on a global key.\n// (Two overlays opening in the same commit register child-first; in practice\n// overlays open one user action at a time.)\n\nconst layers: symbol[] = [];\n\n/**\n * Register this overlay as a layer while `open`. Returns a stable predicate\n * that is true when this overlay is the topmost open one — check it before\n * acting on Escape or trapping Tab.\n */\nexport function useOverlayLayer(open: boolean): () => boolean {\n const [id] = useState(() => Symbol(\"overlay-layer\"));\n useEffect(() => {\n if (!open) return;\n layers.push(id);\n return () => {\n const i = layers.indexOf(id);\n if (i >= 0) layers.splice(i, 1);\n };\n }, [open, id]);\n return useCallback(() => layers[layers.length - 1] === id, [id]);\n}\n\n/** Number of registered overlay layers (test seam). */\nexport function getOverlayLayerCount(): number {\n return layers.length;\n}\n\n// ─── Close on focus-out ──────────────────────────────────────────────────────\n\n/**\n * Close a non-modal popover (menu, picker, panel) when keyboard focus leaves\n * both its trigger and its panel — Tab and Shift+Tab out, or focus leaving the\n * document. Nested overlays (a Dropdown inside a Popover) register a layer on\n * top, so focus moving into them does not count as leaving. A pointer-down on\n * a non-focusable spot inside the panel briefly sends focus to body; that is\n * ignored so clicking panel chrome never closes it.\n */\nexport function useCloseOnFocusOut(\n open: boolean,\n triggerRef: RefObject<HTMLElement | null>,\n panelRef: RefObject<HTMLElement | null>,\n onClose: () => void,\n isTop: () => boolean = ALWAYS_TOP,\n) {\n // Latest-value ref written in a layout effect, not during render (React Compiler `refs` rule).\n const onCloseRef = useLatest(onClose);\n useEffect(() => {\n if (!open) return;\n let pointerInside = false;\n const inside = (n: EventTarget | Node | null) =>\n n instanceof Node && (!!triggerRef.current?.contains(n) || !!panelRef.current?.contains(n));\n const onPointerDown = (e: PointerEvent) => { pointerInside = inside(e.target); };\n const onFocusOut = (e: FocusEvent) => {\n if (!inside(e.target)) return;\n if (e.relatedTarget) {\n if (!inside(e.relatedTarget) && isTop()) onCloseRef.current();\n return;\n }\n setTimeout(() => {\n if (pointerInside) { pointerInside = false; return; }\n if (!inside(document.activeElement) && isTop()) onCloseRef.current();\n }, 0);\n };\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n document.addEventListener(\"focusout\", onFocusOut, true);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n document.removeEventListener(\"focusout\", onFocusOut, true);\n };\n }, [open, triggerRef, panelRef, isTop, onCloseRef]);\n}\n\n// ─── Popup focus (Sprint 25.7) ───────────────────────────────────────────────\n// Every non-modal popup — a list, a menu, a picker, a panel — renders in a portal\n// at the end of <body>. Without help, a choice removes the focused option and\n// focus falls to the page, and Tab out of the panel moves on from the end of the\n// document. usePopupFocus hands focus back and makes Tab carry on from the\n// control that opened the popup, in the browser's own order.\n\nexport type PopupTabExits = \"any\" | \"edges\" | \"none\";\n\ninterface OpenPopup {\n panel: RefObject<HTMLElement | null>;\n tabExits: PopupTabExits;\n leave: (e: KeyboardEvent) => void;\n}\n\n/** Open popups, so a popup inside another popup's panel can hand a Tab exit on to it. */\nconst openPopups = new Map<symbol, OpenPopup>();\n\nexport interface PopupFocusOptions {\n trigger: RefObject<HTMLElement | null>;\n panel: RefObject<HTMLElement | null>;\n /** Closes the popup (sets its open state false). */\n close: () => void;\n /**\n * How Tab leaves the panel. \"any\": every Tab leaves (single-stop lists and\n * menus). \"edges\": Tab leaves from the panel's last Tab stop and Shift+Tab\n * from its first (panels with several stops). \"none\": focus never enters the\n * panel (a combobox keeps it in its input), so the browser's Tab is left alone.\n */\n tabExits: PopupTabExits;\n /** Runs first when Tab leaves, before the popup closes — a list commits the option the user moved to (D14(a)). */\n onTabOut?: (e: KeyboardEvent) => void;\n}\n\n/**\n * Focus for a non-modal popup (Sprint 25.7, P10):\n * - records the opener when the popup opens (the trigger when focus was on the page);\n * - closes on focus-out, and registers the overlay layer (`isTop`);\n * - Tab out of the panel closes it and carries on from the opener: Shift+Tab lands\n * on the opener; Tab puts focus on the opener and lets the browser's own Tab run,\n * except that inside a modal the opener's being its last stop wraps to its first,\n * and inside another popup's panel that popup's own exit rule then applies;\n * - on close, when focus was lost (the focused option went with the panel), puts it\n * back — unless the close followed a pointer-down outside or the page changed;\n * - returns `returnFocus()`, which a select handler calls before the consumer's\n * callback so a dialog that callback opens records the opener, and any focus\n * move the consumer makes wins.\n */\nexport function usePopupFocus(open: boolean, { trigger, panel, close, tabExits, onTabOut }: PopupFocusOptions) {\n const isTop = useOverlayLayer(open);\n const [id] = useState(() => Symbol(\"popup\"));\n const closeRef = useLatest(close);\n const onTabOutRef = useLatest(onTabOut);\n const remembered = useRef<RememberedFocus | null>(null);\n const pointerOutside = useRef(false);\n const wasOpen = useRef(false);\n\n useCloseOnFocusOut(open, trigger, panel, close, isTop);\n\n // The opener, as it was before this commit (content with autoFocus moves focus in during it).\n const before = useFocusBeforeOpen(open);\n useLayoutEffect(() => {\n if (!open) return;\n const active = before.current;\n const inPanel = active instanceof Node && !!panel.current?.contains(active);\n const opener = active instanceof HTMLElement && active !== document.body && !inPanel ? active : trigger.current;\n remembered.current = opener ? rememberFocus(opener) : null;\n pointerOutside.current = false;\n }, [open, trigger, panel, before]);\n\n useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: PointerEvent) => {\n const t = e.target;\n pointerOutside.current = !(t instanceof Node && (!!trigger.current?.contains(t) || !!panel.current?.contains(t)));\n };\n const leave = (e: KeyboardEvent) => {\n onTabOutRef.current?.(e);\n const r = remembered.current;\n const opener = r && r.el.isConnected ? r.el : trigger.current;\n // Focus the opener, then close now, so the panel is gone before the browser moves focus on.\n opener?.focus();\n flushSync(() => closeRef.current());\n if (!opener || !opener.isConnected) return;\n if (e.shiftKey) {\n e.preventDefault();\n return;\n }\n const modal = opener.closest<HTMLElement>('[aria-modal=\"true\"]');\n if (modal) {\n const stops = tabStops(modal);\n if (stops.length && stops[stops.length - 1] === opener) {\n e.preventDefault();\n stops[0].focus();\n return;\n }\n }\n for (const [otherId, other] of openPopups) {\n const outer = other.panel.current;\n if (otherId === id || !outer?.contains(opener)) continue;\n const stops = tabStops(outer);\n if (other.tabExits === \"any\" || stops[stops.length - 1] === opener) {\n other.leave(e);\n return;\n }\n break;\n }\n // The browser's own Tab carries on from the opener.\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Tab\" || e.defaultPrevented || tabExits === \"none\" || !isTop()) return;\n const p = panel.current;\n const active = document.activeElement;\n if (!p || !(active instanceof Node) || !p.contains(active)) return;\n if (tabExits === \"edges\") {\n const stops = tabStops(p);\n if (stops.length && active !== (e.shiftKey ? stops[0] : stops[stops.length - 1])) return;\n }\n leave(e);\n };\n openPopups.set(id, { panel, tabExits, leave });\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n openPopups.delete(id);\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open, tabExits, isTop, id, trigger, panel, closeRef, onTabOutRef]);\n\n // The safety net: a close the component could not see (content that closes it,\n // a choice that removed the focused option) puts focus back when it was lost.\n useLayoutEffect(() => {\n if (open) {\n wasOpen.current = true;\n return;\n }\n if (!wasOpen.current) return;\n wasOpen.current = false;\n const r = remembered.current;\n remembered.current = null;\n if (pointerOutside.current || !r) return;\n // Focus that is somewhere real stays there: the user or the consumer put it there. Focus on the opener is\n // checked again, because the choice may have deleted the opener's row in this commit (see rememberFocus).\n const active = document.activeElement;\n if (active !== r.el && active && active !== document.body && active.isConnected) return;\n r.restore(trigger.current);\n }, [open, trigger]);\n\n // Removed while open (a row menu whose Delete removed its own row): give focus back once the DOM has settled.\n useLayoutEffect(() => () => {\n if (!wasOpen.current) return;\n const r = remembered.current;\n queueMicrotask(() => {\n const active = document.activeElement;\n if (active && active !== document.body && active.isConnected) return;\n r?.restore();\n });\n }, []);\n\n const returnFocus = useCallback(() => {\n remembered.current?.restore(trigger.current);\n }, [trigger]);\n\n return { isTop, returnFocus };\n}\n\n// ─── Grid keyboard (Sprint 25.7, P11) ────────────────────────────────────────\n\n/**\n * One Tab stop over a grid or rows of items (APG grid and tree patterns): the\n * caller says where each key moves (`move`), and the hook keeps the roving\n * tabindex and puts focus on the new item — after the next render when the\n * item is not in the DOM yet (a date grid moving into the next month). Items\n * carry `data-grid-key={keyOf(item)}`. Built for the date pickers; Sprint 25.7\n * Part D extends it for Gantt rows (it is Sprint 2X.3's `useGridNavigation`).\n */\nfunction focusGridKey(root: HTMLElement | null, key: string): boolean {\n const el = root?.querySelector<HTMLElement>(`[data-grid-key=\"${key}\"]`);\n if (!el) return false;\n el.focus();\n return true;\n}\n\nexport function useGridKeyboard<K>({ container, active, setActive, keyOf, move }: {\n container: RefObject<HTMLElement | null>;\n active: K;\n setActive: (item: K) => void;\n keyOf: (item: K) => string;\n move: (from: K, e: ReactKeyboardEvent) => K | null;\n}) {\n const pending = useRef<string | null>(null);\n useLayoutEffect(() => {\n const key = pending.current;\n if (key !== null && focusGridKey(container.current, key)) pending.current = null;\n });\n const activeKey = keyOf(active);\n const onKeyDown = (e: ReactKeyboardEvent) => {\n if (e.altKey || e.ctrlKey || e.metaKey) return;\n const next = move(active, e);\n if (next === null) return;\n e.preventDefault();\n const key = keyOf(next);\n setActive(next);\n if (!focusGridKey(container.current, key)) pending.current = key;\n };\n const focusActive = () => {\n if (!focusGridKey(container.current, activeKey)) pending.current = activeKey;\n };\n const tabIndexOf = (item: K) => (keyOf(item) === activeKey ? 0 : -1);\n return { onKeyDown, tabIndexOf, focusActive };\n}\n\n// ─── Focus trap ──────────────────────────────────────────────────────────────\n\nconst ALWAYS_TOP = () => true;\n\n/**\n * Keep Tab and Shift+Tab inside `root` while `active` (corpus: a modal\n * overlay owns keyboard focus until it closes). Focus that has escaped the\n * root — a portalled menu that just closed, or the body — is pulled back in on\n * the next Tab. Pass the predicate from `useOverlayLayer` so a nested overlay\n * on top of this one keeps its own keyboard handling.\n */\nexport function useFocusTrap(root: RefObject<HTMLElement | null>, active: boolean, isTop: () => boolean = ALWAYS_TOP) {\n useEffect(() => {\n if (!active) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Tab\" || e.defaultPrevented || !root.current || !isTop()) return;\n const focusable = tabStops(root.current);\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const current = document.activeElement;\n const inside = current instanceof Node && root.current.contains(current);\n if (e.shiftKey) {\n if (!inside || current === first) {\n e.preventDefault();\n last.focus();\n }\n } else if (!inside || current === last) {\n e.preventDefault();\n first.focus();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [root, active, isTop]);\n}\n\n// ─── Non-modal dialog ────────────────────────────────────────────────────────\n\n/**\n * The lifecycle of a persistent, non-modal dialog — an assistant panel the\n * user works alongside (Drawer with modal={false}, CornerPanel). Unlike a\n * popover it does not close when focus leaves; unlike a modal it never traps.\n *\n * While `active`: remembers the opener and gives focus back on close; moves\n * focus into the panel on open (first field, else first non-close control);\n * closes on Escape only while focus is inside the panel and it is the topmost\n * layer, so Escape elsewhere on the page is untouched. Outside clicks do\n * nothing. Tab out of the panel is allowed — the panel is portalled to the end\n * of the document, so the last Tab reaches the browser chrome; a Launcher\n * shortcut is the way back in.\n */\nexport function useNonModalDialog(\n root: RefObject<HTMLElement | null>,\n active: boolean,\n onClose: () => void,\n isTop: () => boolean = ALWAYS_TOP,\n) {\n const onCloseRef = useLatest(onClose);\n useReturnFocus(active);\n useEffect(() => {\n if (!active) return;\n const raf = requestAnimationFrame(() => focusInitial(root.current));\n return () => cancelAnimationFrame(raf);\n }, [active, root]);\n useEffect(() => {\n if (!active) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\" || !isTop()) return;\n const el = root.current;\n if (!el || !el.contains(document.activeElement)) return;\n onCloseRef.current();\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [active, root, isTop, onCloseRef]);\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useTextOverflow, Tooltip } from './chunk-
|
|
1
|
+
import { useTextOverflow, Tooltip } from './chunk-EMCSARQO.js';
|
|
2
2
|
import { Icon } from './chunk-X4CNZFWC.js';
|
|
3
3
|
import { cn } from './chunk-4KVFH5KC.js';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -97,5 +97,5 @@ function Badge({ variant = "default", severity, size = "md", color, iconLeft, ic
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
export { Badge };
|
|
100
|
-
//# sourceMappingURL=chunk-
|
|
101
|
-
//# sourceMappingURL=chunk-
|
|
100
|
+
//# sourceMappingURL=chunk-XCSTU6IJ.js.map
|
|
101
|
+
//# sourceMappingURL=chunk-XCSTU6IJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/components/Badge.tsx"],"names":[],"mappings":";;;;;AAsBA,IAAM,iBAAA,GAAyD;AAAA,EAC7D,IAAA,EAAM,SAAA;AAAA,EACN,GAAA,EAAK,cAAA;AAAA,EACL,MAAA,EAAQ,cAAA;AAAA,EACR,IAAA,EAAM,YAAA;AAAA,EACN,QAAA,EAAU;AACZ,CAAA;AAEA,IAAM,aAAA,GAA8C;AAAA,EAClD,OAAA,EAAS,sGAAA;AAAA,EACT,OAAA,EAAS,kEAAA;AAAA,EACT,MAAA,EAAQ,yDAAA;AAAA,EACR,OAAA,EAAS,gEAAA;AAAA,EACT,cAAA,EAAgB,iJAAA;AAAA,EAChB,OAAA,EAAS,gEAAA;AAAA,EACT,cAAA,EAAgB,sJAAA;AAAA,EAChB,KAAA,EAAO,4DAAA;AAAA,EACP,YAAA,EAAc,2IAAA;AAAA,EACd,OAAA,EAAS;AACX,CAAA;AAEA,IAAM,UAAA,GAAwC;AAAA,EAC5C,EAAA,EAAI,iDAAA;AAAA,EACJ,EAAA,EAAI,iEAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAEA,IAAM,SAAA,GAAuC;AAAA,EAC3C,EAAA,EAAI,EAAA;AAAA,EACJ,EAAA,EAAI,EAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAIA,IAAM,gBAAA,GAAmD;AAAA,EACvD,OAAA,EAAS,CAAC,CAAA,KAAM,cAAA,CAAe,CAAC,CAAA;AAAA,EAChC,OAAA,EAAS,CAAC,CAAA,KAAM,aAAA,CAAc,CAAC,CAAA;AAAA,EAC/B,MAAA,EAAQ,CAAC,CAAA,KAAM,aAAA,CAAc,CAAC,CAAA;AAAA,EAC9B,OAAA,EAAS,CAAC,CAAA,KAAM,cAAA,CAAe,CAAC;AAClC,CAAA;AAEA,IAAM,cAAA,GAAoD;AAAA,EACxD,CAAA,EAAG,kEAAA;AAAA,EACH,CAAA,EAAG,kEAAA;AAAA,EACH,CAAA,EAAG,kEAAA;AAAA,EACH,CAAA,EAAG,kEAAA;AAAA,EACH,CAAA,EAAG;AACL,CAAA;AAEA,IAAM,aAAA,GAAmD;AAAA,EACvD,CAAA,EAAG,6DAAA;AAAA,EACH,CAAA,EAAG,6DAAA;AAAA,EACH,CAAA,EAAG,6DAAA;AAAA,EACH,CAAA,EAAG,6DAAA;AAAA,EACH,CAAA,EAAG;AACL,CAAA;AAEA,IAAM,cAAA,GAAoD;AAAA,EACxD,CAAA,EAAG,yHAAA;AAAA,EACH,CAAA,EAAG,yHAAA;AAAA,EACH,CAAA,EAAG,yHAAA;AAAA,EACH,CAAA,EAAG,yHAAA;AAAA,EACH,CAAA,EAAG;AACL,CAAA;AAEA,SAAS,iBAAA,CAAkB,OAA0B,OAAA,EAA+B;AAClF,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAiB,OAAO,CAAA,IAAK,gBAAA,CAAiB,OAAA;AAC9D,EAAA,OAAO,QAAQ,KAAK,CAAA;AACtB;AAmBO,SAAS,KAAA,CAAM,EAAE,OAAA,GAAU,SAAA,EAAW,QAAA,EAAU,IAAA,GAAO,IAAA,EAAM,KAAA,EAAO,QAAA,EAAU,SAAA,EAAW,QAAA,EAAU,SAAA,EAAW,UAAS,EAAe;AAE3I,EAAA,MAAM,eAAA,GAAkB,QAAA,GAAW,iBAAA,CAAkB,QAAQ,CAAA,GAAI,OAAA;AACjE,EAAA,MAAM,EAAE,GAAA,EAAK,QAAA,EAAU,WAAA,EAAY,GAAI,eAAA,CAAgB,EAAE,KAAA,EAAO,CAAA,EAAG,QAAA,EAAU,CAAC,QAAA,EAAU,CAAA;AACxF,EAAA,MAAM,QAAA,GAAW,UAAU,IAAI,CAAA;AAC/B,EAAA,MAAM,UAAA,GAAA,CAAc,QAAA,IAAY,SAAA,KAAc,CAAC,QAAA;AAE/C,EAAA,MAAM,eAAe,KAAA,GACjB,iBAAA,CAAkB,OAAO,eAAe,CAAA,GACxC,cAAc,eAAe,CAAA;AAEjC,EAAA,MAAM,KAAA,mBACJ,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,4EAAA;AAAA,QACA,iCAAA;AAAA,QACA,WAAW,IAAI,CAAA;AAAA,QACf,UAAA,IAAc,SAAS,IAAA,IAAQ,UAAA;AAAA,QAC/B,UAAA,IAAc,SAAS,IAAA,IAAQ,SAAA;AAAA,QAC/B,UAAA,IAAc,SAAS,IAAA,IAAQ,WAAA;AAAA,QAC/B,YAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,KAAA,EAAO,QAAA,GAAW,EAAE,QAAA,EAAS,GAAI,MAAA;AAAA,MAEhC,QAAA,EAAA;AAAA,QAAA,QAAA,wBAAa,IAAA,EAAA,EAAK,IAAA,EAAM,UAAU,IAAA,EAAM,QAAA,EAAU,WAAU,UAAA,EAAW,CAAA;AAAA,QACvE,QAAA,uBACE,MAAA,EAAA,EAAK,GAAA,EAAK,UAAU,SAAA,EAAU,UAAA,EAAY,UAAS,CAAA,GAEpD,QAAA;AAAA,QAED,SAAA,wBAAc,IAAA,EAAA,EAAK,IAAA,EAAM,WAAW,IAAA,EAAM,QAAA,EAAU,WAAU,UAAA,EAAW;AAAA;AAAA;AAAA,GAC5E;AAGF,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,uBAAO,GAAA,CAAC,OAAA,EAAA,EAAQ,OAAA,EAAS,QAAA,EAAW,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,EAC5C;AACA,EAAA,OAAO,KAAA;AACT","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/Badge.tsx"],"names":[],"mappings":"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","file":"chunk-XCSTU6IJ.js","sourcesContent":["import { cn } from \"../lib/utils\";\nimport { Icon, type IconName } from \"../lib/icons\";\nimport { Tooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport type { ReactNode } from \"react\";\n\nexport type BadgeVariant =\n | \"default\"\n | \"neutral\"\n | \"subtle\"\n | \"success\"\n | \"success-soft\"\n | \"warning\"\n | \"warning-soft\"\n | \"error\"\n | \"error-soft\"\n | \"outline\";\n\nexport type BadgeSize = \"xs\" | \"sm\" | \"md\";\nexport type BadgePaletteColor = 1 | 2 | 3 | 4 | 5;\nexport type BadgeSeverity = \"info\" | \"low\" | \"medium\" | \"high\" | \"critical\";\n\nconst severityToVariant: Record<BadgeSeverity, BadgeVariant> = {\n info: \"neutral\",\n low: \"success-soft\",\n medium: \"warning-soft\",\n high: \"error-soft\",\n critical: \"error\",\n};\n\nconst variantStyles: Record<BadgeVariant, string> = {\n default: \"bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)]\",\n neutral: \"bg-[var(--ds-text-muted)]/[0.12] text-[var(--ds-text-secondary)]\",\n subtle: \"bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]\",\n success: \"bg-[var(--ds-status-success)] text-[var(--ds-text-on-success)]\",\n \"success-soft\": \"bg-[var(--ds-status-success-bg)] text-[var(--ds-status-success)] border-[length:var(--ds-border-width)] border-[var(--ds-status-success)]/[0.2]\",\n warning: \"bg-[var(--ds-status-warning)] text-[var(--ds-text-on-warning)]\",\n \"warning-soft\": \"bg-[var(--ds-status-warning-bg)] text-[var(--ds-status-warning-text)] border-[length:var(--ds-border-width)] border-[var(--ds-status-warning)]/[0.2]\",\n error: \"bg-[var(--ds-status-error)] text-[var(--ds-text-on-error)]\",\n \"error-soft\": \"bg-[var(--ds-status-error-bg)] text-[var(--ds-status-error)] border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]/[0.2]\",\n outline: \"bg-transparent text-[var(--ds-text-primary)] border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n};\n\nconst sizeStyles: Record<BadgeSize, string> = {\n xs: \"px-ds-1.5 py-[1px] text-[length:10px] gap-[3px]\",\n sm: \"px-ds-2 py-ds-0.5 text-[length:var(--ds-font-size-xs)] gap-ds-1\",\n md: \"px-ds-2.5 py-ds-0.5 text-[length:var(--ds-font-size-xs)] gap-ds-1\",\n};\n\nconst iconSizes: Record<BadgeSize, number> = {\n xs: 10,\n sm: 12,\n md: 12,\n};\n\ntype PaletteStyleFn = (n: BadgePaletteColor) => string;\n\nconst paletteByVariant: Record<string, PaletteStyleFn> = {\n default: (n) => paletteDefault[n],\n neutral: (n) => paletteSubtle[n],\n subtle: (n) => paletteSubtle[n],\n outline: (n) => paletteOutline[n],\n};\n\nconst paletteDefault: Record<BadgePaletteColor, string> = {\n 1: \"bg-[var(--ds-palette-1-bold)] text-[var(--ds-palette-1-on-bold)]\",\n 2: \"bg-[var(--ds-palette-2-bold)] text-[var(--ds-palette-2-on-bold)]\",\n 3: \"bg-[var(--ds-palette-3-bold)] text-[var(--ds-palette-3-on-bold)]\",\n 4: \"bg-[var(--ds-palette-4-bold)] text-[var(--ds-palette-4-on-bold)]\",\n 5: \"bg-[var(--ds-palette-5-bold)] text-[var(--ds-palette-5-on-bold)]\",\n};\n\nconst paletteSubtle: Record<BadgePaletteColor, string> = {\n 1: \"bg-[var(--ds-palette-1-bg)] text-[var(--ds-palette-1-text)]\",\n 2: \"bg-[var(--ds-palette-2-bg)] text-[var(--ds-palette-2-text)]\",\n 3: \"bg-[var(--ds-palette-3-bg)] text-[var(--ds-palette-3-text)]\",\n 4: \"bg-[var(--ds-palette-4-bg)] text-[var(--ds-palette-4-text)]\",\n 5: \"bg-[var(--ds-palette-5-bg)] text-[var(--ds-palette-5-text)]\",\n};\n\nconst paletteOutline: Record<BadgePaletteColor, string> = {\n 1: \"bg-transparent text-[var(--ds-palette-1-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-1-bold)]\",\n 2: \"bg-transparent text-[var(--ds-palette-2-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-2-bold)]\",\n 3: \"bg-transparent text-[var(--ds-palette-3-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-3-bold)]\",\n 4: \"bg-transparent text-[var(--ds-palette-4-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-4-bold)]\",\n 5: \"bg-transparent text-[var(--ds-palette-5-bold)] border-[length:var(--ds-border-width)] border-[var(--ds-palette-5-bold)]\",\n};\n\nfunction getPaletteClasses(color: BadgePaletteColor, variant: BadgeVariant): string {\n const styleFn = paletteByVariant[variant] ?? paletteByVariant.default;\n return styleFn(color);\n}\n\ninterface BadgeProps {\n variant?: BadgeVariant;\n /** Severity shorthand — maps to a variant. When set, overrides `variant`. */\n severity?: BadgeSeverity;\n size?: BadgeSize;\n /** Palette colour (1-5). Overrides variant colour with decorative palette tokens. */\n color?: BadgePaletteColor;\n /** Icon to show before the label */\n iconLeft?: IconName;\n /** Icon to show after the label */\n iconRight?: IconName;\n /** Max width before truncation (e.g. \"120px\", \"16ch\"). Shows tooltip when truncated. */\n maxWidth?: string;\n className?: string;\n children?: ReactNode;\n}\n\nexport function Badge({ variant = \"default\", severity, size = \"md\", color, iconLeft, iconRight, maxWidth, className, children }: BadgeProps) {\n // severity sets the variant and variant is ignored when both are written\n const resolvedVariant = severity ? severityToVariant[severity] : variant;\n const { ref: truncRef, isTruncated } = useTextOverflow({ lines: 1, disabled: !maxWidth });\n const iconSize = iconSizes[size];\n const isIconOnly = (iconLeft || iconRight) && !children;\n\n const colorClasses = color\n ? getPaletteClasses(color, resolvedVariant)\n : variantStyles[resolvedVariant];\n\n const badge = (\n <span\n className={cn(\n \"inline-flex items-center font-medium max-w-full whitespace-nowrap shrink-0\",\n \"rounded-[var(--ds-radius-full)]\",\n sizeStyles[size],\n isIconOnly && size === \"xs\" && \"px-[3px]\",\n isIconOnly && size === \"sm\" && \"px-ds-1\",\n isIconOnly && size === \"md\" && \"px-ds-1.5\",\n colorClasses,\n className\n )}\n style={maxWidth ? { maxWidth } : undefined}\n >\n {iconLeft && <Icon name={iconLeft} size={iconSize} className=\"shrink-0\" />}\n {maxWidth ? (\n <span ref={truncRef} className=\"truncate\">{children}</span>\n ) : (\n children\n )}\n {iconRight && <Icon name={iconRight} size={iconSize} className=\"shrink-0\" />}\n </span>\n );\n\n if (isTruncated) {\n return <Tooltip content={children}>{badge}</Tooltip>;\n }\n return badge;\n}\n"]}
|
package/dist/data-grid.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { inferColumnKinds, CardValue } from './chunk-
|
|
1
|
+
import { inferColumnKinds, CardValue } from './chunk-OENJCGTJ.js';
|
|
2
2
|
import { useShellPreferences, TableCardCtx } from './chunk-TKVTZWBN.js';
|
|
3
3
|
import { useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
4
|
-
import { useTextOverflow, Tooltip } from './chunk-
|
|
5
|
-
import './chunk-
|
|
4
|
+
import { useTextOverflow, Tooltip } from './chunk-EMCSARQO.js';
|
|
5
|
+
import './chunk-7Q46JXSK.js';
|
|
6
6
|
import './chunk-WH2FUFAC.js';
|
|
7
7
|
import { Icon } from './chunk-X4CNZFWC.js';
|
|
8
8
|
import { cn } from './chunk-4KVFH5KC.js';
|
package/dist/editor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useOverlayLayer } from './chunk-
|
|
1
|
+
import { useOverlayLayer, useCloseOnFocusOut } from './chunk-VFAKME7Q.js';
|
|
2
2
|
import { useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
3
3
|
import './chunk-WH2FUFAC.js';
|
|
4
4
|
import { Icon } from './chunk-X4CNZFWC.js';
|
|
@@ -350,13 +350,19 @@ function ColorPicker({
|
|
|
350
350
|
const isTopLayer = useOverlayLayer(open);
|
|
351
351
|
const ref = useRef(null);
|
|
352
352
|
const close = useCallback(() => setOpen(false), []);
|
|
353
|
+
const closeToButton = useCallback(() => {
|
|
354
|
+
const inside = !!ref.current?.contains(document.activeElement);
|
|
355
|
+
close();
|
|
356
|
+
if (inside) ref.current?.querySelector("button")?.focus();
|
|
357
|
+
}, [close]);
|
|
358
|
+
useCloseOnFocusOut(open, ref, ref, close, isTopLayer);
|
|
353
359
|
useEffect(() => {
|
|
354
360
|
if (!open) return;
|
|
355
361
|
const onClick = (e) => {
|
|
356
362
|
if (!ref.current?.contains(e.target)) close();
|
|
357
363
|
};
|
|
358
364
|
const onKey = (e) => {
|
|
359
|
-
if (e.key === "Escape" && isTopLayer())
|
|
365
|
+
if (e.key === "Escape" && isTopLayer()) closeToButton();
|
|
360
366
|
};
|
|
361
367
|
document.addEventListener("mousedown", onClick);
|
|
362
368
|
document.addEventListener("keydown", onKey);
|
|
@@ -364,7 +370,7 @@ function ColorPicker({
|
|
|
364
370
|
document.removeEventListener("mousedown", onClick);
|
|
365
371
|
document.removeEventListener("keydown", onKey);
|
|
366
372
|
};
|
|
367
|
-
}, [open, close, isTopLayer]);
|
|
373
|
+
}, [open, close, closeToButton, isTopLayer]);
|
|
368
374
|
return /* @__PURE__ */ jsxs("div", { ref, className: "relative", children: [
|
|
369
375
|
/* @__PURE__ */ jsxs(
|
|
370
376
|
"button",
|
|
@@ -414,6 +420,12 @@ function LinkPopover({ editor }) {
|
|
|
414
420
|
setOpen(false);
|
|
415
421
|
setUrl("");
|
|
416
422
|
}, []);
|
|
423
|
+
const closeToButton = useCallback(() => {
|
|
424
|
+
const inside = !!ref.current?.contains(document.activeElement);
|
|
425
|
+
close();
|
|
426
|
+
if (inside) ref.current?.querySelector("button")?.focus();
|
|
427
|
+
}, [close]);
|
|
428
|
+
useCloseOnFocusOut(open, ref, ref, close, isTopLayer);
|
|
417
429
|
const toggle = useCallback(() => {
|
|
418
430
|
if (editor.isActive("link")) {
|
|
419
431
|
editor.chain().focus().unsetLink().run();
|
|
@@ -429,7 +441,7 @@ function LinkPopover({ editor }) {
|
|
|
429
441
|
if (!ref.current?.contains(e.target)) close();
|
|
430
442
|
};
|
|
431
443
|
const onKey = (e) => {
|
|
432
|
-
if (e.key === "Escape" && isTopLayer())
|
|
444
|
+
if (e.key === "Escape" && isTopLayer()) closeToButton();
|
|
433
445
|
};
|
|
434
446
|
document.addEventListener("mousedown", onClick);
|
|
435
447
|
document.addEventListener("keydown", onKey);
|
|
@@ -438,7 +450,7 @@ function LinkPopover({ editor }) {
|
|
|
438
450
|
document.removeEventListener("mousedown", onClick);
|
|
439
451
|
document.removeEventListener("keydown", onKey);
|
|
440
452
|
};
|
|
441
|
-
}, [open, close, isTopLayer]);
|
|
453
|
+
}, [open, close, closeToButton, isTopLayer]);
|
|
442
454
|
const apply = () => {
|
|
443
455
|
if (url) editor.chain().focus().setLink({ href: url }).run();
|
|
444
456
|
close();
|
|
@@ -494,13 +506,19 @@ function ImagePopover({ editor }) {
|
|
|
494
506
|
setUrl("");
|
|
495
507
|
setAlt("");
|
|
496
508
|
}, []);
|
|
509
|
+
const closeToButton = useCallback(() => {
|
|
510
|
+
const inside = !!ref.current?.contains(document.activeElement);
|
|
511
|
+
close();
|
|
512
|
+
if (inside) ref.current?.querySelector("button")?.focus();
|
|
513
|
+
}, [close]);
|
|
514
|
+
useCloseOnFocusOut(open, ref, ref, close, isTopLayer);
|
|
497
515
|
useEffect(() => {
|
|
498
516
|
if (!open) return;
|
|
499
517
|
const onClick = (e) => {
|
|
500
518
|
if (!ref.current?.contains(e.target)) close();
|
|
501
519
|
};
|
|
502
520
|
const onKey = (e) => {
|
|
503
|
-
if (e.key === "Escape" && isTopLayer())
|
|
521
|
+
if (e.key === "Escape" && isTopLayer()) closeToButton();
|
|
504
522
|
};
|
|
505
523
|
document.addEventListener("mousedown", onClick);
|
|
506
524
|
document.addEventListener("keydown", onKey);
|
|
@@ -509,7 +527,7 @@ function ImagePopover({ editor }) {
|
|
|
509
527
|
document.removeEventListener("mousedown", onClick);
|
|
510
528
|
document.removeEventListener("keydown", onKey);
|
|
511
529
|
};
|
|
512
|
-
}, [open, close, isTopLayer]);
|
|
530
|
+
}, [open, close, closeToButton, isTopLayer]);
|
|
513
531
|
const insert = () => {
|
|
514
532
|
if (url) editor.chain().focus().setImage({ src: url, alt: alt || void 0 }).run();
|
|
515
533
|
close();
|