@tensor_1/react 2.5.0 → 2.7.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/components/AppShell.d.ts +16 -2
- package/dist/components/AppShell.js +39 -6
- package/dist/components/Composer.d.ts +21 -0
- package/dist/components/Composer.js +12 -0
- package/dist/components/Field.js +10 -4
- package/dist/components/Popover.d.ts +18 -4
- package/dist/components/Popover.js +31 -2
- package/dist/components/Segmented.d.ts +29 -0
- package/dist/components/Segmented.js +36 -0
- package/dist/components/Table.d.ts +45 -4
- package/dist/components/Table.js +63 -3
- package/dist/components/Timeline.d.ts +7 -1
- package/dist/components/Timeline.js +2 -2
- package/dist/components/Toast.js +5 -4
- package/dist/components/Tooltip.d.ts +9 -5
- package/dist/components/Tooltip.js +61 -3
- package/dist/components/Tree.d.ts +15 -1
- package/dist/components/Tree.js +247 -35
- package/dist/hooks/useAnchoredPosition.d.ts +22 -0
- package/dist/hooks/useAnchoredPosition.js +44 -0
- package/dist/hooks/useDialog.js +36 -5
- package/dist/hooks/useTable.d.ts +50 -0
- package/dist/hooks/useTable.js +69 -0
- package/dist/index.cjs +1107 -141
- package/dist/index.d.cts +406 -15
- package/dist/index.d.ts +9 -2
- package/dist/index.js +40 -2
- package/dist/overlay-position.d.ts +59 -0
- package/dist/overlay-position.js +62 -0
- package/dist/table-engine.d.ts +89 -0
- package/dist/table-engine.js +251 -0
- package/dist/tree-model.d.ts +48 -0
- package/dist/tree-model.js +49 -0
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -24,22 +24,29 @@ __export(src_exports, {
|
|
|
24
24
|
AppShell: () => AppShell,
|
|
25
25
|
Avatar: () => Avatar,
|
|
26
26
|
AvatarGroup: () => AvatarGroup,
|
|
27
|
+
BulkBar: () => BulkBar,
|
|
27
28
|
Button: () => Button,
|
|
28
29
|
ButtonGroup: () => ButtonGroup,
|
|
29
30
|
Card: () => Card,
|
|
31
|
+
CellStrong: () => CellStrong,
|
|
32
|
+
CellSub: () => CellSub,
|
|
30
33
|
Checkbox: () => Checkbox,
|
|
31
34
|
CommandGroup: () => CommandGroup,
|
|
32
35
|
CommandItem: () => CommandItem,
|
|
33
36
|
CommandPalette: () => CommandPalette,
|
|
34
37
|
Comment: () => Comment,
|
|
35
38
|
Comments: () => Comments,
|
|
39
|
+
Composer: () => Composer,
|
|
40
|
+
ComposerBar: () => ComposerBar,
|
|
36
41
|
DescriptionItem: () => DescriptionItem,
|
|
37
42
|
DescriptionList: () => DescriptionList,
|
|
38
43
|
DetailLayout: () => DetailLayout,
|
|
39
44
|
Drawer: () => Drawer,
|
|
40
45
|
EmptyState: () => EmptyState,
|
|
41
46
|
ErrorState: () => ErrorState,
|
|
47
|
+
ExpandToggle: () => ExpandToggle,
|
|
42
48
|
Field: () => Field,
|
|
49
|
+
Highlighted: () => Highlighted,
|
|
43
50
|
Inbox: () => Inbox,
|
|
44
51
|
InboxDetail: () => InboxDetail,
|
|
45
52
|
InboxItem: () => InboxItem,
|
|
@@ -53,6 +60,7 @@ __export(src_exports, {
|
|
|
53
60
|
List: () => List,
|
|
54
61
|
ListItem: () => ListItem,
|
|
55
62
|
LoadingState: () => LoadingState,
|
|
63
|
+
Mark: () => Mark,
|
|
56
64
|
Meter: () => Meter,
|
|
57
65
|
Modal: () => Modal,
|
|
58
66
|
NavFavourites: () => NavFavourites,
|
|
@@ -67,6 +75,10 @@ __export(src_exports, {
|
|
|
67
75
|
Prose: () => Prose,
|
|
68
76
|
Radio: () => Radio,
|
|
69
77
|
RadioGroup: () => RadioGroup,
|
|
78
|
+
RowAction: () => RowAction,
|
|
79
|
+
RowActions: () => RowActions,
|
|
80
|
+
Segmented: () => Segmented,
|
|
81
|
+
SegmentedOption: () => SegmentedOption,
|
|
70
82
|
Select: () => Select,
|
|
71
83
|
Sidebar: () => Sidebar,
|
|
72
84
|
SidebarSection: () => SidebarSection,
|
|
@@ -92,8 +104,30 @@ __export(src_exports, {
|
|
|
92
104
|
Tr: () => Tr,
|
|
93
105
|
Tree: () => Tree,
|
|
94
106
|
UserChip: () => UserChip,
|
|
107
|
+
applyFilters: () => applyFilters,
|
|
108
|
+
clampWidth: () => clampWidth,
|
|
109
|
+
computePosition: () => computePosition,
|
|
95
110
|
cx: () => cx,
|
|
96
|
-
|
|
111
|
+
flattenTree: () => flattenTree,
|
|
112
|
+
highlightSegments: () => highlightSegments,
|
|
113
|
+
matchFilter: () => matchFilter,
|
|
114
|
+
mergePinned: () => mergePinned,
|
|
115
|
+
multiSort: () => multiSort,
|
|
116
|
+
nextSortDir: () => nextSortDir,
|
|
117
|
+
parseView: () => parseView,
|
|
118
|
+
reorder: () => reorder,
|
|
119
|
+
searchRows: () => searchRows,
|
|
120
|
+
selectAllState: () => selectAllState,
|
|
121
|
+
serializeView: () => serializeView,
|
|
122
|
+
shouldVirtualize: () => shouldVirtualize,
|
|
123
|
+
toggleId: () => toggleId,
|
|
124
|
+
togglePage: () => togglePage,
|
|
125
|
+
toggleSort: () => toggleSort,
|
|
126
|
+
treeNav: () => treeNav,
|
|
127
|
+
useAnchoredPosition: () => useAnchoredPosition,
|
|
128
|
+
useDialog: () => useDialog,
|
|
129
|
+
useTable: () => useTable,
|
|
130
|
+
virtualWindow: () => virtualWindow
|
|
97
131
|
});
|
|
98
132
|
module.exports = __toCommonJS(src_exports);
|
|
99
133
|
|
|
@@ -104,27 +138,453 @@ function cx(...args) {
|
|
|
104
138
|
|
|
105
139
|
// src/hooks/useDialog.ts
|
|
106
140
|
var import_react = require("react");
|
|
141
|
+
var lockCount = 0;
|
|
142
|
+
var saved = null;
|
|
143
|
+
function lockBodyScroll() {
|
|
144
|
+
if (typeof document === "undefined") return;
|
|
145
|
+
if (++lockCount > 1) return;
|
|
146
|
+
const el = document.scrollingElement ?? document.documentElement;
|
|
147
|
+
const scrollbarW = window.innerWidth - document.documentElement.clientWidth;
|
|
148
|
+
saved = {
|
|
149
|
+
el,
|
|
150
|
+
overflow: el.style.overflow,
|
|
151
|
+
paddingRight: el.style.paddingRight,
|
|
152
|
+
overscroll: el.style.overscrollBehavior
|
|
153
|
+
};
|
|
154
|
+
el.style.overflow = "hidden";
|
|
155
|
+
if (scrollbarW > 0) {
|
|
156
|
+
const current = parseFloat(getComputedStyle(el).paddingRight) || 0;
|
|
157
|
+
el.style.paddingRight = `${current + scrollbarW}px`;
|
|
158
|
+
}
|
|
159
|
+
el.style.overscrollBehavior = "contain";
|
|
160
|
+
}
|
|
161
|
+
function unlockBodyScroll() {
|
|
162
|
+
if (typeof document === "undefined" || lockCount === 0) return;
|
|
163
|
+
if (--lockCount > 0) return;
|
|
164
|
+
if (saved) {
|
|
165
|
+
saved.el.style.overflow = saved.overflow;
|
|
166
|
+
saved.el.style.paddingRight = saved.paddingRight;
|
|
167
|
+
saved.el.style.overscrollBehavior = saved.overscroll;
|
|
168
|
+
saved = null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
107
171
|
function useDialog(open) {
|
|
108
172
|
const ref = (0, import_react.useRef)(null);
|
|
109
173
|
(0, import_react.useEffect)(() => {
|
|
110
174
|
const el = ref.current;
|
|
111
|
-
if (!el)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
} else {
|
|
115
|
-
if (el.open) el.close();
|
|
175
|
+
if (!el || !open) {
|
|
176
|
+
if (el && el.open) el.close();
|
|
177
|
+
return;
|
|
116
178
|
}
|
|
179
|
+
if (!el.open) el.showModal();
|
|
180
|
+
lockBodyScroll();
|
|
117
181
|
return () => {
|
|
182
|
+
unlockBodyScroll();
|
|
118
183
|
if (el.open) el.close();
|
|
119
184
|
};
|
|
120
185
|
}, [open]);
|
|
121
186
|
return ref;
|
|
122
187
|
}
|
|
123
188
|
|
|
124
|
-
// src/
|
|
189
|
+
// src/hooks/useTable.ts
|
|
125
190
|
var import_react2 = require("react");
|
|
191
|
+
|
|
192
|
+
// src/table-engine.ts
|
|
193
|
+
function compare(a, b) {
|
|
194
|
+
if (a == null && b == null) return 0;
|
|
195
|
+
if (a == null) return -1;
|
|
196
|
+
if (b == null) return 1;
|
|
197
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
198
|
+
return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
|
|
199
|
+
}
|
|
200
|
+
function multiSort(rows, keys) {
|
|
201
|
+
if (!keys.length) return rows.slice();
|
|
202
|
+
return rows.map((row, i) => ({ row, i })).sort((x, y) => {
|
|
203
|
+
for (const k of keys) {
|
|
204
|
+
const c = compare(x.row[k.field], y.row[k.field]);
|
|
205
|
+
if (c !== 0) return k.dir === "ascending" ? c : -c;
|
|
206
|
+
}
|
|
207
|
+
return x.i - y.i;
|
|
208
|
+
}).map((w) => w.row);
|
|
209
|
+
}
|
|
210
|
+
function nextSortDir(current) {
|
|
211
|
+
if (current === "ascending") return "descending";
|
|
212
|
+
if (current === "descending") return "none";
|
|
213
|
+
return "ascending";
|
|
214
|
+
}
|
|
215
|
+
function toggleSort(keys, field, additive = false) {
|
|
216
|
+
const existing = keys.find((k) => k.field === field);
|
|
217
|
+
const dir = nextSortDir(existing?.dir);
|
|
218
|
+
if (!additive) return dir === "none" ? [] : [{ field, dir }];
|
|
219
|
+
const rest = keys.filter((k) => k.field !== field);
|
|
220
|
+
return dir === "none" ? rest : [...rest, { field, dir }];
|
|
221
|
+
}
|
|
222
|
+
function asNum(v) {
|
|
223
|
+
return typeof v === "number" ? v : Number(v);
|
|
224
|
+
}
|
|
225
|
+
function asTime(v) {
|
|
226
|
+
if (v == null) return NaN;
|
|
227
|
+
if (v instanceof Date) return v.getTime();
|
|
228
|
+
if (typeof v === "number") return v;
|
|
229
|
+
const s = String(v).trim();
|
|
230
|
+
if (s === "") return NaN;
|
|
231
|
+
const parsed = Date.parse(s);
|
|
232
|
+
return Number.isNaN(parsed) ? Number(s) : parsed;
|
|
233
|
+
}
|
|
234
|
+
function matchDate(cell, f) {
|
|
235
|
+
const c = asTime(cell);
|
|
236
|
+
if (Number.isNaN(c)) return false;
|
|
237
|
+
switch (f.op) {
|
|
238
|
+
case "eq":
|
|
239
|
+
return c === asTime(f.value);
|
|
240
|
+
case "lt":
|
|
241
|
+
return c < asTime(f.value);
|
|
242
|
+
case "gt":
|
|
243
|
+
return c > asTime(f.value);
|
|
244
|
+
case "between": {
|
|
245
|
+
const [lo, hi] = f.value.map(asTime);
|
|
246
|
+
return c >= lo && c <= hi;
|
|
247
|
+
}
|
|
248
|
+
default:
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function matchFilter(row, f) {
|
|
253
|
+
const cell = row[f.field];
|
|
254
|
+
if (f.kind === "date") return matchDate(cell, f);
|
|
255
|
+
switch (f.op) {
|
|
256
|
+
case "isAnyOf":
|
|
257
|
+
return Array.isArray(f.value) && f.value.includes(cell);
|
|
258
|
+
case "isNoneOf":
|
|
259
|
+
return Array.isArray(f.value) && !f.value.includes(cell);
|
|
260
|
+
case "contains":
|
|
261
|
+
return String(cell ?? "").toLowerCase().includes(String(f.value ?? "").toLowerCase());
|
|
262
|
+
case "equals":
|
|
263
|
+
return String(cell ?? "") === String(f.value ?? "");
|
|
264
|
+
case "startsWith":
|
|
265
|
+
return String(cell ?? "").toLowerCase().startsWith(String(f.value ?? "").toLowerCase());
|
|
266
|
+
case "eq":
|
|
267
|
+
return asNum(cell) === asNum(f.value);
|
|
268
|
+
case "lt":
|
|
269
|
+
return asNum(cell) < asNum(f.value);
|
|
270
|
+
case "gt":
|
|
271
|
+
return asNum(cell) > asNum(f.value);
|
|
272
|
+
case "between": {
|
|
273
|
+
const [lo, hi] = f.value.map(asNum);
|
|
274
|
+
return asNum(cell) >= lo && asNum(cell) <= hi;
|
|
275
|
+
}
|
|
276
|
+
case "is":
|
|
277
|
+
return Boolean(cell) === Boolean(f.value);
|
|
278
|
+
default:
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function applyFilters(rows, filters) {
|
|
283
|
+
if (!filters.length) return rows.slice();
|
|
284
|
+
return rows.filter((r) => filters.every((f) => matchFilter(r, f)));
|
|
285
|
+
}
|
|
286
|
+
function searchRows(rows, query, fields) {
|
|
287
|
+
const q = query.trim().toLowerCase();
|
|
288
|
+
if (!q) return rows.slice();
|
|
289
|
+
return rows.filter((r) => {
|
|
290
|
+
const vals = fields ? fields.map((f) => r[f]) : Object.values(r);
|
|
291
|
+
return vals.some((v) => v != null && String(v).toLowerCase().includes(q));
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
function highlightSegments(text, query) {
|
|
295
|
+
const q = query.trim();
|
|
296
|
+
if (!q) return [{ text, match: false }];
|
|
297
|
+
const out = [];
|
|
298
|
+
const lower = text.toLowerCase();
|
|
299
|
+
const ql = q.toLowerCase();
|
|
300
|
+
let i = 0;
|
|
301
|
+
for (; ; ) {
|
|
302
|
+
const hit = lower.indexOf(ql, i);
|
|
303
|
+
if (hit === -1) {
|
|
304
|
+
if (i < text.length) out.push({ text: text.slice(i), match: false });
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
if (hit > i) out.push({ text: text.slice(i, hit), match: false });
|
|
308
|
+
out.push({ text: text.slice(hit, hit + q.length), match: true });
|
|
309
|
+
i = hit + q.length;
|
|
310
|
+
}
|
|
311
|
+
return out;
|
|
312
|
+
}
|
|
313
|
+
var ARRAY_OPS = /* @__PURE__ */ new Set(["isAnyOf", "isNoneOf", "between"]);
|
|
314
|
+
var escapePart = (s) => encodeURIComponent(s).replace(/~/g, "%7E");
|
|
315
|
+
var unescapePart = (s) => decodeURIComponent(s);
|
|
316
|
+
var scalarToStr = (v) => v == null ? "" : String(v);
|
|
317
|
+
function parseScalar(s, kind) {
|
|
318
|
+
switch (kind) {
|
|
319
|
+
case "number":
|
|
320
|
+
return Number(s);
|
|
321
|
+
case "boolean":
|
|
322
|
+
return s === "true";
|
|
323
|
+
case "date":
|
|
324
|
+
return /^-?\d+$/.test(s) ? Number(s) : s;
|
|
325
|
+
// epoch-ms number, else the ISO/date string
|
|
326
|
+
default:
|
|
327
|
+
return s;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function kindFromOp(op) {
|
|
331
|
+
if (op === "isAnyOf" || op === "isNoneOf") return "enum";
|
|
332
|
+
if (op === "is") return "boolean";
|
|
333
|
+
if (op === "contains" || op === "equals" || op === "startsWith") return "text";
|
|
334
|
+
return "number";
|
|
335
|
+
}
|
|
336
|
+
function serializeFilter(f) {
|
|
337
|
+
const value = Array.isArray(f.value) ? f.value.map((x) => escapePart(scalarToStr(x))).join("|") : escapePart(scalarToStr(f.value));
|
|
338
|
+
return `${escapePart(f.field)}~${f.kind}~${f.op}~${value}`;
|
|
339
|
+
}
|
|
340
|
+
function parseFilter(tok) {
|
|
341
|
+
const parts = tok.split("~");
|
|
342
|
+
let field, kind, op, raw;
|
|
343
|
+
if (parts.length >= 4) {
|
|
344
|
+
[field, kind, op, raw] = [unescapePart(parts[0]), parts[1], parts[2], parts[3] ?? ""];
|
|
345
|
+
} else {
|
|
346
|
+
[field, op, raw] = [unescapePart(parts[0]), parts[1], parts[2] ?? ""];
|
|
347
|
+
kind = kindFromOp(op);
|
|
348
|
+
}
|
|
349
|
+
if (!field || !op) return null;
|
|
350
|
+
const value = ARRAY_OPS.has(op) ? raw.split("|").filter((s) => s !== "").map((s) => parseScalar(unescapePart(s), kind)) : parseScalar(unescapePart(raw), kind);
|
|
351
|
+
return { field, kind, op, value };
|
|
352
|
+
}
|
|
353
|
+
function serializeView(v) {
|
|
354
|
+
const p = new URLSearchParams();
|
|
355
|
+
if (v.sort?.length) p.set("sort", v.sort.map((s) => `${s.field}:${s.dir === "descending" ? "d" : "a"}`).join(","));
|
|
356
|
+
if (v.columns?.length) p.set("cols", v.columns.join(","));
|
|
357
|
+
if (v.density && v.density !== "standard") p.set("density", v.density);
|
|
358
|
+
if (v.q) p.set("q", v.q);
|
|
359
|
+
if (v.filters?.length) p.set("filter", v.filters.map(serializeFilter).join(","));
|
|
360
|
+
return p.toString();
|
|
361
|
+
}
|
|
362
|
+
function parseView(qs) {
|
|
363
|
+
const p = new URLSearchParams(qs.replace(/^\?/, ""));
|
|
364
|
+
const v = {};
|
|
365
|
+
const sort = p.get("sort");
|
|
366
|
+
if (sort) v.sort = sort.split(",").filter(Boolean).map((tok) => {
|
|
367
|
+
const [field, d] = tok.split(":");
|
|
368
|
+
return { field, dir: d === "d" ? "descending" : "ascending" };
|
|
369
|
+
});
|
|
370
|
+
const cols = p.get("cols");
|
|
371
|
+
if (cols) v.columns = cols.split(",").filter(Boolean);
|
|
372
|
+
const density = p.get("density");
|
|
373
|
+
if (density === "compact" || density === "comfortable" || density === "standard") v.density = density;
|
|
374
|
+
const q = p.get("q");
|
|
375
|
+
if (q) v.q = q;
|
|
376
|
+
const filter = p.get("filter");
|
|
377
|
+
if (filter) {
|
|
378
|
+
v.filters = filter.split(",").filter(Boolean).map(parseFilter).filter((f) => f !== null);
|
|
379
|
+
}
|
|
380
|
+
return v;
|
|
381
|
+
}
|
|
382
|
+
function virtualWindow(scrollTop, viewportH, rowH, count, overscan = 6) {
|
|
383
|
+
if (rowH <= 0 || count <= 0) return { start: 0, end: count, padTop: 0, padBottom: 0, total: 0 };
|
|
384
|
+
const first = Math.max(0, Math.floor(scrollTop / rowH) - overscan);
|
|
385
|
+
const visible = Math.ceil(viewportH / rowH) + overscan * 2;
|
|
386
|
+
const end = Math.min(count, first + visible);
|
|
387
|
+
return { start: first, end, padTop: first * rowH, padBottom: (count - end) * rowH, total: count * rowH };
|
|
388
|
+
}
|
|
389
|
+
function shouldVirtualize(count, threshold = 100) {
|
|
390
|
+
return count > threshold;
|
|
391
|
+
}
|
|
392
|
+
function clampWidth(width, min = 64, max = Infinity) {
|
|
393
|
+
return Math.max(min, Math.min(max, Math.round(width)));
|
|
394
|
+
}
|
|
395
|
+
function reorder(arr, from, to) {
|
|
396
|
+
const next = arr.slice();
|
|
397
|
+
if (from < 0 || from >= next.length || to < 0 || to >= next.length) return next;
|
|
398
|
+
const [moved] = next.splice(from, 1);
|
|
399
|
+
next.splice(to, 0, moved);
|
|
400
|
+
return next;
|
|
401
|
+
}
|
|
402
|
+
function toggleId(set, id) {
|
|
403
|
+
const next = new Set(set);
|
|
404
|
+
next.has(id) ? next.delete(id) : next.add(id);
|
|
405
|
+
return next;
|
|
406
|
+
}
|
|
407
|
+
function selectAllState(selected, pageIds) {
|
|
408
|
+
const on = pageIds.filter((id) => selected.has(id)).length;
|
|
409
|
+
if (on === 0) return "none";
|
|
410
|
+
return on === pageIds.length ? "all" : "some";
|
|
411
|
+
}
|
|
412
|
+
function togglePage(selected, pageIds) {
|
|
413
|
+
const next = new Set(selected);
|
|
414
|
+
const all = pageIds.every((id) => next.has(id));
|
|
415
|
+
for (const id of pageIds) all ? next.delete(id) : next.add(id);
|
|
416
|
+
return next;
|
|
417
|
+
}
|
|
418
|
+
function mergePinned(all, visible, pinnedIds, idField = "id") {
|
|
419
|
+
if (!pinnedIds.size) return visible.slice();
|
|
420
|
+
const pinned = all.filter((r) => pinnedIds.has(String(r[idField])));
|
|
421
|
+
const pinnedSet = new Set(pinned.map((r) => String(r[idField])));
|
|
422
|
+
const rest = visible.filter((r) => !pinnedSet.has(String(r[idField])));
|
|
423
|
+
return [...pinned, ...rest];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/hooks/useTable.ts
|
|
427
|
+
function useTable(data, options = {}) {
|
|
428
|
+
const { idField = "id", searchFields } = options;
|
|
429
|
+
const [sort, setSort] = (0, import_react2.useState)(() => options.initialSort ?? []);
|
|
430
|
+
const [filters, setFilters] = (0, import_react2.useState)(() => options.initialFilters ?? []);
|
|
431
|
+
const [query, setQuery] = (0, import_react2.useState)(() => options.initialQuery ?? "");
|
|
432
|
+
const [selected, setSelected] = (0, import_react2.useState)(() => /* @__PURE__ */ new Set());
|
|
433
|
+
const [pinned, setPinned] = (0, import_react2.useState)(() => new Set(options.initialPinned ?? []));
|
|
434
|
+
const rows = (0, import_react2.useMemo)(() => {
|
|
435
|
+
const filtered = applyFilters(data, filters);
|
|
436
|
+
const searched = searchRows(filtered, query, searchFields);
|
|
437
|
+
const sorted = multiSort(searched, sort);
|
|
438
|
+
return mergePinned(data, sorted, pinned, idField);
|
|
439
|
+
}, [data, filters, query, searchFields, sort, pinned, idField]);
|
|
440
|
+
const pageIds = (0, import_react2.useMemo)(() => rows.map((r) => String(r[idField])), [rows, idField]);
|
|
441
|
+
const selectAll = selectAllState(selected, pageIds);
|
|
442
|
+
const doToggleSort = (0, import_react2.useCallback)((field, additive = false) => {
|
|
443
|
+
setSort((keys) => toggleSort(keys, field, additive));
|
|
444
|
+
}, []);
|
|
445
|
+
const toggleRow = (0, import_react2.useCallback)((id) => setSelected((s) => toggleId(s, id)), []);
|
|
446
|
+
const toggleAllRows = (0, import_react2.useCallback)(() => setSelected((s) => togglePage(s, pageIds)), [pageIds]);
|
|
447
|
+
const clearSelection = (0, import_react2.useCallback)(() => setSelected(/* @__PURE__ */ new Set()), []);
|
|
448
|
+
const togglePin = (0, import_react2.useCallback)((id) => setPinned((s) => toggleId(s, id)), []);
|
|
449
|
+
const view = (0, import_react2.useMemo)(() => ({ sort, filters, q: query }), [sort, filters, query]);
|
|
450
|
+
const viewQueryString = (0, import_react2.useMemo)(() => serializeView(view), [view]);
|
|
451
|
+
const applyView = (0, import_react2.useCallback)((queryString) => {
|
|
452
|
+
const v = parseView(queryString);
|
|
453
|
+
setSort(v.sort ?? []);
|
|
454
|
+
setFilters(v.filters ?? []);
|
|
455
|
+
setQuery(v.q ?? "");
|
|
456
|
+
}, []);
|
|
457
|
+
return {
|
|
458
|
+
rows,
|
|
459
|
+
sort,
|
|
460
|
+
filters,
|
|
461
|
+
query,
|
|
462
|
+
selected,
|
|
463
|
+
pinned,
|
|
464
|
+
selectAll,
|
|
465
|
+
toggleSort: doToggleSort,
|
|
466
|
+
setSort,
|
|
467
|
+
setFilters,
|
|
468
|
+
setQuery,
|
|
469
|
+
isSelected: (id) => selected.has(id),
|
|
470
|
+
toggleRow,
|
|
471
|
+
toggleAllRows,
|
|
472
|
+
clearSelection,
|
|
473
|
+
togglePin,
|
|
474
|
+
view,
|
|
475
|
+
viewQueryString,
|
|
476
|
+
applyView
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/hooks/useAnchoredPosition.ts
|
|
481
|
+
var import_react3 = require("react");
|
|
482
|
+
|
|
483
|
+
// src/overlay-position.ts
|
|
484
|
+
var OPPOSITE = { top: "bottom", bottom: "top", left: "right", right: "left" };
|
|
485
|
+
function parsePlacement(p) {
|
|
486
|
+
const [side, align] = p.split("-");
|
|
487
|
+
return { side, align: align ?? "center" };
|
|
488
|
+
}
|
|
489
|
+
var clamp = (v, min, max) => Math.max(min, Math.min(max, v));
|
|
490
|
+
function spaceOn(side, a, vp, offset) {
|
|
491
|
+
switch (side) {
|
|
492
|
+
case "top":
|
|
493
|
+
return a.y - offset;
|
|
494
|
+
case "bottom":
|
|
495
|
+
return vp.height - (a.y + a.height) - offset;
|
|
496
|
+
case "left":
|
|
497
|
+
return a.x - offset;
|
|
498
|
+
case "right":
|
|
499
|
+
return vp.width - (a.x + a.width) - offset;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function fitsOn(side, a, f, vp, offset, padding) {
|
|
503
|
+
const need = side === "top" || side === "bottom" ? f.height : f.width;
|
|
504
|
+
return spaceOn(side, a, vp, offset) >= need + padding;
|
|
505
|
+
}
|
|
506
|
+
function computePosition(anchor, floating, viewport, options = {}) {
|
|
507
|
+
const { placement = "bottom-start", offset = 6, padding = 8, flip = true, shift = true } = options;
|
|
508
|
+
const { side: preferred, align } = parsePlacement(placement);
|
|
509
|
+
let side = preferred;
|
|
510
|
+
if (flip && !fitsOn(side, anchor, floating, viewport, offset, padding)) {
|
|
511
|
+
const opp = OPPOSITE[side];
|
|
512
|
+
if (fitsOn(opp, anchor, floating, viewport, offset, padding) || spaceOn(opp, anchor, viewport, offset) > spaceOn(side, anchor, viewport, offset)) {
|
|
513
|
+
side = opp;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
let x, y;
|
|
517
|
+
const horizontal = side === "top" || side === "bottom";
|
|
518
|
+
if (side === "top") y = anchor.y - floating.height - offset;
|
|
519
|
+
else if (side === "bottom") y = anchor.y + anchor.height + offset;
|
|
520
|
+
else if (side === "left") x = anchor.x - floating.width - offset;
|
|
521
|
+
else x = anchor.x + anchor.width + offset;
|
|
522
|
+
if (horizontal) {
|
|
523
|
+
const start = anchor.x;
|
|
524
|
+
const end = anchor.x + anchor.width - floating.width;
|
|
525
|
+
const center = anchor.x + (anchor.width - floating.width) / 2;
|
|
526
|
+
x = align === "start" ? start : align === "end" ? end : center;
|
|
527
|
+
if (shift) x = clamp(x, padding, Math.max(padding, viewport.width - floating.width - padding));
|
|
528
|
+
} else {
|
|
529
|
+
const start = anchor.y;
|
|
530
|
+
const end = anchor.y + anchor.height - floating.height;
|
|
531
|
+
const center = anchor.y + (anchor.height - floating.height) / 2;
|
|
532
|
+
y = align === "start" ? start : align === "end" ? end : center;
|
|
533
|
+
if (shift) y = clamp(y, padding, Math.max(padding, viewport.height - floating.height - padding));
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
x,
|
|
537
|
+
y,
|
|
538
|
+
placement: align === "center" ? side : `${side}-${align}`,
|
|
539
|
+
side,
|
|
540
|
+
align
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// src/hooks/useAnchoredPosition.ts
|
|
545
|
+
var useIsomorphicLayoutEffect = typeof document !== "undefined" ? import_react3.useLayoutEffect : import_react3.useEffect;
|
|
546
|
+
var resolve = (a) => a && typeof a === "object" && "current" in a ? a.current : a ?? null;
|
|
547
|
+
function useAnchoredPosition(anchor, floatingRef, { open, placement = "bottom-start", offset = 6, padding = 8 }) {
|
|
548
|
+
const opts = (0, import_react3.useRef)({ placement, offset, padding });
|
|
549
|
+
opts.current = { placement, offset, padding };
|
|
550
|
+
const reposition = (0, import_react3.useCallback)(() => {
|
|
551
|
+
const anchorEl = resolve(anchor);
|
|
552
|
+
const floating = floatingRef.current;
|
|
553
|
+
if (!anchorEl || !floating) return;
|
|
554
|
+
const s = floating.style;
|
|
555
|
+
s.position = "fixed";
|
|
556
|
+
s.inset = "auto";
|
|
557
|
+
s.margin = "0";
|
|
558
|
+
const a = anchorEl.getBoundingClientRect();
|
|
559
|
+
const { placement: p, offset: o, padding: pad } = opts.current;
|
|
560
|
+
const pos = computePosition(
|
|
561
|
+
{ x: a.x, y: a.y, width: a.width, height: a.height },
|
|
562
|
+
{ width: floating.offsetWidth, height: floating.offsetHeight },
|
|
563
|
+
{ width: window.innerWidth, height: window.innerHeight },
|
|
564
|
+
{ placement: p, offset: o, padding: pad }
|
|
565
|
+
);
|
|
566
|
+
s.left = `${Math.round(pos.x)}px`;
|
|
567
|
+
s.top = `${Math.round(pos.y)}px`;
|
|
568
|
+
floating.dataset.placement = pos.placement;
|
|
569
|
+
}, [anchor, floatingRef]);
|
|
570
|
+
useIsomorphicLayoutEffect(() => {
|
|
571
|
+
if (!open) return;
|
|
572
|
+
reposition();
|
|
573
|
+
const onScroll = () => reposition();
|
|
574
|
+
window.addEventListener("scroll", onScroll, { passive: true, capture: true });
|
|
575
|
+
window.addEventListener("resize", onScroll);
|
|
576
|
+
return () => {
|
|
577
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
578
|
+
window.removeEventListener("resize", onScroll);
|
|
579
|
+
};
|
|
580
|
+
}, [open, reposition]);
|
|
581
|
+
return reposition;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// src/components/Button.tsx
|
|
585
|
+
var import_react4 = require("react");
|
|
126
586
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
127
|
-
var Button = (0,
|
|
587
|
+
var Button = (0, import_react4.forwardRef)(
|
|
128
588
|
({ variant = "secondary", size = "md", icon = false, loading = false, className, children, disabled, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
129
589
|
"button",
|
|
130
590
|
{
|
|
@@ -149,9 +609,9 @@ function ButtonGroup({ children, className }) {
|
|
|
149
609
|
}
|
|
150
610
|
|
|
151
611
|
// src/components/Input.tsx
|
|
152
|
-
var
|
|
612
|
+
var import_react5 = require("react");
|
|
153
613
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
154
|
-
var Input = (0,
|
|
614
|
+
var Input = (0, import_react5.forwardRef)(
|
|
155
615
|
({ size = "md", invalid, valid, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
156
616
|
"input",
|
|
157
617
|
{
|
|
@@ -184,9 +644,9 @@ function InputGroup({ children, leadingIcon, trailingIcon, className }) {
|
|
|
184
644
|
}
|
|
185
645
|
|
|
186
646
|
// src/components/Textarea.tsx
|
|
187
|
-
var
|
|
647
|
+
var import_react6 = require("react");
|
|
188
648
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
189
|
-
var Textarea = (0,
|
|
649
|
+
var Textarea = (0, import_react6.forwardRef)(
|
|
190
650
|
({ invalid, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
191
651
|
"textarea",
|
|
192
652
|
{
|
|
@@ -200,9 +660,9 @@ var Textarea = (0, import_react4.forwardRef)(
|
|
|
200
660
|
Textarea.displayName = "Textarea";
|
|
201
661
|
|
|
202
662
|
// src/components/Select.tsx
|
|
203
|
-
var
|
|
663
|
+
var import_react7 = require("react");
|
|
204
664
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
205
|
-
var Select = (0,
|
|
665
|
+
var Select = (0, import_react7.forwardRef)(
|
|
206
666
|
({ size = "md", className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
207
667
|
"select",
|
|
208
668
|
{
|
|
@@ -215,14 +675,14 @@ var Select = (0, import_react5.forwardRef)(
|
|
|
215
675
|
Select.displayName = "Select";
|
|
216
676
|
|
|
217
677
|
// src/components/Checkbox.tsx
|
|
218
|
-
var
|
|
678
|
+
var import_react8 = require("react");
|
|
219
679
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
220
680
|
var CheckIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "1.5,6 4.5,9 10.5,3" }) });
|
|
221
681
|
var IndeterminateIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 12 12", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "2", y: "5", width: "8", height: "2", rx: "1", fill: "currentColor" }) });
|
|
222
|
-
var Checkbox = (0,
|
|
682
|
+
var Checkbox = (0, import_react8.forwardRef)(
|
|
223
683
|
({ label, indeterminate, className, ...props }, forwardedRef) => {
|
|
224
|
-
const innerRef = (0,
|
|
225
|
-
(0,
|
|
684
|
+
const innerRef = (0, import_react8.useRef)(null);
|
|
685
|
+
(0, import_react8.useEffect)(() => {
|
|
226
686
|
const el = innerRef.current;
|
|
227
687
|
if (el) el.indeterminate = !!indeterminate;
|
|
228
688
|
}, [indeterminate]);
|
|
@@ -247,9 +707,9 @@ var Checkbox = (0, import_react6.forwardRef)(
|
|
|
247
707
|
Checkbox.displayName = "Checkbox";
|
|
248
708
|
|
|
249
709
|
// src/components/Radio.tsx
|
|
250
|
-
var
|
|
710
|
+
var import_react9 = require("react");
|
|
251
711
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
252
|
-
var Radio = (0,
|
|
712
|
+
var Radio = (0, import_react9.forwardRef)(
|
|
253
713
|
({ label, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: cx("uix-radio", className), children: [
|
|
254
714
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "radio", ref, ...props }),
|
|
255
715
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "uix-radio__dot" }),
|
|
@@ -262,9 +722,9 @@ function RadioGroup({ children, className }) {
|
|
|
262
722
|
}
|
|
263
723
|
|
|
264
724
|
// src/components/Switch.tsx
|
|
265
|
-
var
|
|
725
|
+
var import_react10 = require("react");
|
|
266
726
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
267
|
-
var Switch = (0,
|
|
727
|
+
var Switch = (0, import_react10.forwardRef)(
|
|
268
728
|
({ label, className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: cx("uix-switch", className), children: [
|
|
269
729
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", role: "switch", ref, ...props }),
|
|
270
730
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "uix-switch__track" }),
|
|
@@ -274,14 +734,20 @@ var Switch = (0, import_react8.forwardRef)(
|
|
|
274
734
|
Switch.displayName = "Switch";
|
|
275
735
|
|
|
276
736
|
// src/components/Field.tsx
|
|
737
|
+
var import_react11 = require("react");
|
|
277
738
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
278
739
|
function Field({ label, hint, error, success, required, children, className, htmlFor }) {
|
|
740
|
+
const uid = (0, import_react11.useId)();
|
|
741
|
+
const msgId = `${uid}-msg`;
|
|
742
|
+
const describedBy = error || success || hint ? msgId : void 0;
|
|
743
|
+
const control = (0, import_react11.isValidElement)(children) ? (0, import_react11.cloneElement)(children, {
|
|
744
|
+
"aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0,
|
|
745
|
+
"aria-invalid": error ? true : children.props["aria-invalid"]
|
|
746
|
+
}) : children;
|
|
279
747
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cx("uix-field", className), children: [
|
|
280
748
|
label && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "uix-field__label", htmlFor, "data-required": required || void 0, children: label }),
|
|
281
|
-
|
|
282
|
-
error
|
|
283
|
-
success && !error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "uix-field__success", children: success }),
|
|
284
|
-
hint && !error && !success && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "uix-field__hint", children: hint })
|
|
749
|
+
control,
|
|
750
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "uix-field__msg", id: msgId, children: error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "uix-field__error", role: "alert", children: error }) : success ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "uix-field__success", children: success }) : hint ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "uix-field__hint", children: hint }) : null })
|
|
285
751
|
] });
|
|
286
752
|
}
|
|
287
753
|
|
|
@@ -411,11 +877,11 @@ function ListItem({ title, meta, trail, leading, children, className, ...props }
|
|
|
411
877
|
}
|
|
412
878
|
|
|
413
879
|
// src/components/DescriptionList.tsx
|
|
414
|
-
var
|
|
880
|
+
var import_react12 = require("react");
|
|
415
881
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
416
882
|
function DescriptionList({ items, children, className, ...props }) {
|
|
417
883
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("dl", { className: cx("uix-dl", className), ...props, children: [
|
|
418
|
-
items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
884
|
+
items?.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react12.Fragment, { children: [
|
|
419
885
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { children: item.term }),
|
|
420
886
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { children: item.description })
|
|
421
887
|
] }, item.id ?? i)),
|
|
@@ -430,14 +896,14 @@ function DescriptionItem({ term, children }) {
|
|
|
430
896
|
}
|
|
431
897
|
|
|
432
898
|
// src/components/Tabs.tsx
|
|
433
|
-
var
|
|
899
|
+
var import_react13 = require("react");
|
|
434
900
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
435
|
-
var TabsCtx = (0,
|
|
901
|
+
var TabsCtx = (0, import_react13.createContext)({});
|
|
436
902
|
function Tabs({ variant = "line", value, onChange, children, className }) {
|
|
437
903
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TabsCtx.Provider, { value: { value, onChange }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { role: "tablist", className: cx("uix-tabs", `uix-tabs--${variant}`, className), children }) });
|
|
438
904
|
}
|
|
439
905
|
function Tab({ value, children, disabled, className, onClick, ...props }) {
|
|
440
|
-
const ctx = (0,
|
|
906
|
+
const ctx = (0, import_react13.useContext)(TabsCtx);
|
|
441
907
|
const selected = ctx.value === value;
|
|
442
908
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
443
909
|
"button",
|
|
@@ -457,17 +923,49 @@ function Tab({ value, children, disabled, className, onClick, ...props }) {
|
|
|
457
923
|
}
|
|
458
924
|
|
|
459
925
|
// src/components/AppShell.tsx
|
|
926
|
+
var import_react14 = require("react");
|
|
460
927
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
461
|
-
function AppShell({
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
928
|
+
function AppShell({
|
|
929
|
+
nav,
|
|
930
|
+
collapsed,
|
|
931
|
+
focus,
|
|
932
|
+
onExitFocus,
|
|
933
|
+
mainBleed,
|
|
934
|
+
sidebar,
|
|
935
|
+
topbar,
|
|
936
|
+
children,
|
|
937
|
+
className,
|
|
938
|
+
...props
|
|
939
|
+
}) {
|
|
940
|
+
const navState = nav ?? (collapsed ? "rail" : "full");
|
|
941
|
+
(0, import_react14.useEffect)(() => {
|
|
942
|
+
if (!focus || !onExitFocus) return;
|
|
943
|
+
const onKey = (e) => {
|
|
944
|
+
if (e.key === "Escape") onExitFocus();
|
|
945
|
+
};
|
|
946
|
+
document.addEventListener("keydown", onKey);
|
|
947
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
948
|
+
}, [focus, onExitFocus]);
|
|
949
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
950
|
+
"div",
|
|
951
|
+
{
|
|
952
|
+
className: cx("uix-shell", className),
|
|
953
|
+
"data-nav": navState !== "full" ? navState : void 0,
|
|
954
|
+
"data-collapsed": collapsed && nav == null ? "" : void 0,
|
|
955
|
+
"data-focus": focus || void 0,
|
|
956
|
+
...props,
|
|
957
|
+
children: [
|
|
958
|
+
sidebar && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "uix-shell__sidebar", children: sidebar }),
|
|
959
|
+
topbar && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "uix-shell__topbar", children: topbar }),
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("main", { className: cx("uix-shell__main", mainBleed && "uix-shell__main--bleed"), children }),
|
|
961
|
+
focus && onExitFocus && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "uix-shell__focus-exit", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: onExitFocus, children: "Esc \xB7 Exit focus" }) })
|
|
962
|
+
]
|
|
963
|
+
}
|
|
964
|
+
);
|
|
467
965
|
}
|
|
468
966
|
|
|
469
967
|
// src/components/Sidebar.tsx
|
|
470
|
-
var
|
|
968
|
+
var import_react15 = require("react");
|
|
471
969
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
472
970
|
var ChevronIcon = () => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { className: "uix-navgroup__chevron", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M2 4l4 4 4-4" }) });
|
|
473
971
|
function Sidebar({ collapsed, onToggle, brand, toggleIcon, children, className, ...props }) {
|
|
@@ -521,7 +1019,7 @@ function NavItem({ icon, badge, active, as: Tag = "a", children, className, ...p
|
|
|
521
1019
|
);
|
|
522
1020
|
}
|
|
523
1021
|
function NavGroup({ icon, label, children, defaultExpanded = true }) {
|
|
524
|
-
const [expanded, setExpanded] = (0,
|
|
1022
|
+
const [expanded, setExpanded] = (0, import_react15.useState)(defaultExpanded);
|
|
525
1023
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "uix-navgroup", children: [
|
|
526
1024
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
527
1025
|
"button",
|
|
@@ -589,7 +1087,7 @@ function StarButton({
|
|
|
589
1087
|
}
|
|
590
1088
|
|
|
591
1089
|
// src/components/NavFavourites.tsx
|
|
592
|
-
var
|
|
1090
|
+
var import_react16 = require("react");
|
|
593
1091
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
594
1092
|
var ChevronDownIcon = () => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
595
1093
|
"svg",
|
|
@@ -653,13 +1151,13 @@ function NavFavourites({
|
|
|
653
1151
|
emptyReason,
|
|
654
1152
|
className
|
|
655
1153
|
}) {
|
|
656
|
-
const regionId = (0,
|
|
657
|
-
const headerRef = (0,
|
|
658
|
-
const regionRef = (0,
|
|
659
|
-
const focusAfterRef = (0,
|
|
660
|
-
const triggerRefs = (0,
|
|
1154
|
+
const regionId = (0, import_react16.useId)();
|
|
1155
|
+
const headerRef = (0, import_react16.useRef)(null);
|
|
1156
|
+
const regionRef = (0, import_react16.useRef)(null);
|
|
1157
|
+
const focusAfterRef = (0, import_react16.useRef)(null);
|
|
1158
|
+
const triggerRefs = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
|
|
661
1159
|
const order = items.map((i) => i.id);
|
|
662
|
-
(0,
|
|
1160
|
+
(0, import_react16.useEffect)(() => {
|
|
663
1161
|
const id = focusAfterRef.current;
|
|
664
1162
|
if (!id) return;
|
|
665
1163
|
focusAfterRef.current = null;
|
|
@@ -770,18 +1268,18 @@ function FavouriteRow({
|
|
|
770
1268
|
onRemove,
|
|
771
1269
|
registerTrigger
|
|
772
1270
|
}) {
|
|
773
|
-
const [open, setOpen] = (0,
|
|
774
|
-
const [revealed, setRevealed] = (0,
|
|
775
|
-
const menuId = (0,
|
|
776
|
-
const triggerRef = (0,
|
|
777
|
-
const itemRefs = (0,
|
|
1271
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
1272
|
+
const [revealed, setRevealed] = (0, import_react16.useState)(false);
|
|
1273
|
+
const menuId = (0, import_react16.useId)();
|
|
1274
|
+
const triggerRef = (0, import_react16.useRef)(null);
|
|
1275
|
+
const itemRefs = (0, import_react16.useRef)([]);
|
|
778
1276
|
const optionsTemplate = labels.options ?? "{label} favourite options";
|
|
779
1277
|
const actions = [
|
|
780
1278
|
...isFirst ? [] : [{ label: labels.moveUp, onSelect: onMoveUp }],
|
|
781
1279
|
...isLast ? [] : [{ label: labels.moveDown, onSelect: onMoveDown }],
|
|
782
1280
|
{ label: labels.remove.replace("{label}", item.label), onSelect: onRemove }
|
|
783
1281
|
];
|
|
784
|
-
(0,
|
|
1282
|
+
(0, import_react16.useEffect)(() => {
|
|
785
1283
|
if (open) itemRefs.current[0]?.focus();
|
|
786
1284
|
}, [open]);
|
|
787
1285
|
const closeAndReturnFocus = () => {
|
|
@@ -966,16 +1464,17 @@ function Spinner({ size = "md", accent, className, ...props }) {
|
|
|
966
1464
|
// src/components/Toast.tsx
|
|
967
1465
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
968
1466
|
function Toast({ title, message, tone, icon, onClose, leaving, className, ...props }) {
|
|
1467
|
+
const assertive = tone === "danger";
|
|
969
1468
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
970
1469
|
"div",
|
|
971
1470
|
{
|
|
972
1471
|
className: cx("uix-toast", tone && `uix-toast--${tone}`, className),
|
|
973
1472
|
"data-leaving": leaving || void 0,
|
|
974
|
-
role: "status",
|
|
975
|
-
"aria-live": "polite",
|
|
1473
|
+
role: assertive ? "alert" : "status",
|
|
1474
|
+
"aria-live": assertive ? "assertive" : "polite",
|
|
976
1475
|
...props,
|
|
977
1476
|
children: [
|
|
978
|
-
icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "uix-toast__icon", children: icon }),
|
|
1477
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "uix-toast__icon", "aria-hidden": "true", children: icon }),
|
|
979
1478
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "uix-toast__body", children: [
|
|
980
1479
|
title && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "uix-toast__title", children: title }),
|
|
981
1480
|
message && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "uix-toast__msg", children: message })
|
|
@@ -986,7 +1485,7 @@ function Toast({ title, message, tone, icon, onClose, leaving, className, ...pro
|
|
|
986
1485
|
);
|
|
987
1486
|
}
|
|
988
1487
|
function Toaster({ children, className, ...props }) {
|
|
989
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cx("uix-toaster", className),
|
|
1488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cx("uix-toaster", className), ...props, children });
|
|
990
1489
|
}
|
|
991
1490
|
|
|
992
1491
|
// src/components/Table.tsx
|
|
@@ -998,6 +1497,7 @@ function Table({
|
|
|
998
1497
|
density = "standard",
|
|
999
1498
|
zebra = true,
|
|
1000
1499
|
pinnedCol,
|
|
1500
|
+
fixed,
|
|
1001
1501
|
rowPeek,
|
|
1002
1502
|
v2,
|
|
1003
1503
|
className,
|
|
@@ -1007,7 +1507,13 @@ function Table({
|
|
|
1007
1507
|
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1008
1508
|
"table",
|
|
1009
1509
|
{
|
|
1010
|
-
className: cx(
|
|
1510
|
+
className: cx(
|
|
1511
|
+
"uix-table",
|
|
1512
|
+
!zebra && "uix-table--no-zebra",
|
|
1513
|
+
pinnedCol && "uix-table--pinned-col",
|
|
1514
|
+
fixed && "uix-table--fixed",
|
|
1515
|
+
className
|
|
1516
|
+
),
|
|
1011
1517
|
"data-density": density !== "standard" ? density : void 0,
|
|
1012
1518
|
"data-uix-rowpeek": rowPeek || void 0,
|
|
1013
1519
|
"data-uix-table-v2": v2 || void 0,
|
|
@@ -1016,12 +1522,13 @@ function Table({
|
|
|
1016
1522
|
}
|
|
1017
1523
|
);
|
|
1018
1524
|
}
|
|
1019
|
-
function Th({ sortable, sortDirection, onSort, className, children, onClick, ...props }) {
|
|
1525
|
+
function Th({ sortable, sortDirection, sortOrder, onSort, className, children, onClick, ...props }) {
|
|
1020
1526
|
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1021
1527
|
"th",
|
|
1022
1528
|
{
|
|
1023
1529
|
className,
|
|
1024
1530
|
"data-sort": sortable || void 0,
|
|
1531
|
+
"data-sort-order": sortOrder != null && sortOrder > 0 ? sortOrder : void 0,
|
|
1025
1532
|
"aria-sort": sortDirection && sortDirection !== "none" ? sortDirection : void 0,
|
|
1026
1533
|
onClick: sortable ? onSort ?? onClick : onClick,
|
|
1027
1534
|
...props,
|
|
@@ -1044,6 +1551,49 @@ function Tr({ selected, pinned, className, children, ...props }) {
|
|
|
1044
1551
|
}
|
|
1045
1552
|
);
|
|
1046
1553
|
}
|
|
1554
|
+
function BulkBar({ count, children, className, ...props }) {
|
|
1555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cx("uix-bulkbar", className), role: "toolbar", "aria-label": "Bulk actions", ...props, children: [
|
|
1556
|
+
count != null && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "uix-bulkbar__count", children: [
|
|
1557
|
+
count,
|
|
1558
|
+
" selected"
|
|
1559
|
+
] }),
|
|
1560
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "uix-bulkbar__spacer" }),
|
|
1561
|
+
children
|
|
1562
|
+
] });
|
|
1563
|
+
}
|
|
1564
|
+
function RowActions({ children, className, ...props }) {
|
|
1565
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("td", { className: cx("uix-table__actions", className), ...props, children });
|
|
1566
|
+
}
|
|
1567
|
+
function RowAction({ children, className, type = "button", ...props }) {
|
|
1568
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type, className: cx("uix-rowact", className), ...props, children });
|
|
1569
|
+
}
|
|
1570
|
+
function ExpandToggle({ expanded, className, type = "button", ...props }) {
|
|
1571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1572
|
+
"button",
|
|
1573
|
+
{
|
|
1574
|
+
type,
|
|
1575
|
+
className: cx("uix-table__expand", className),
|
|
1576
|
+
"aria-expanded": expanded,
|
|
1577
|
+
"aria-label": expanded ? "Collapse row" : "Expand row",
|
|
1578
|
+
...props,
|
|
1579
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "M6 4l4 4-4 4" }) })
|
|
1580
|
+
}
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
function CellStrong({ children, className, ...props }) {
|
|
1584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: cx("uix-cell-strong", className), ...props, children });
|
|
1585
|
+
}
|
|
1586
|
+
function CellSub({ children, className, ...props }) {
|
|
1587
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: cx("uix-cell-sub", className), ...props, children });
|
|
1588
|
+
}
|
|
1589
|
+
function Mark({ children, className, ...props }) {
|
|
1590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("mark", { className: cx("uix-mark", className), ...props, children });
|
|
1591
|
+
}
|
|
1592
|
+
function Highlighted({ text, query }) {
|
|
1593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: highlightSegments(text, query).map(
|
|
1594
|
+
(seg, i) => seg.match ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("mark", { className: "uix-mark", children: seg.text }, i) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: seg.text }, i)
|
|
1595
|
+
) });
|
|
1596
|
+
}
|
|
1047
1597
|
|
|
1048
1598
|
// src/components/Pagination.tsx
|
|
1049
1599
|
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
@@ -1172,9 +1722,64 @@ function Stat({ label, value, icon, meta, trend, className, ...props }) {
|
|
|
1172
1722
|
}
|
|
1173
1723
|
|
|
1174
1724
|
// src/components/Tooltip.tsx
|
|
1725
|
+
var import_react17 = require("react");
|
|
1175
1726
|
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1176
|
-
function Tooltip({ label, children, ...props }) {
|
|
1177
|
-
|
|
1727
|
+
function Tooltip({ label, placement = "top", className, children, ...props }) {
|
|
1728
|
+
const triggerRef = (0, import_react17.useRef)(null);
|
|
1729
|
+
const bubbleRef = (0, import_react17.useRef)(null);
|
|
1730
|
+
const [open, setOpen] = (0, import_react17.useState)(false);
|
|
1731
|
+
const id = (0, import_react17.useId)();
|
|
1732
|
+
useAnchoredPosition(triggerRef, bubbleRef, { open, placement, offset: 6 });
|
|
1733
|
+
const show = () => {
|
|
1734
|
+
const b = bubbleRef.current;
|
|
1735
|
+
if (b && !b.matches(":popover-open")) {
|
|
1736
|
+
try {
|
|
1737
|
+
b.showPopover();
|
|
1738
|
+
} catch {
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
setOpen(true);
|
|
1742
|
+
};
|
|
1743
|
+
const hide = () => {
|
|
1744
|
+
const b = bubbleRef.current;
|
|
1745
|
+
if (b && b.matches(":popover-open")) {
|
|
1746
|
+
try {
|
|
1747
|
+
b.hidePopover();
|
|
1748
|
+
} catch {
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
setOpen(false);
|
|
1752
|
+
};
|
|
1753
|
+
(0, import_react17.useEffect)(() => () => {
|
|
1754
|
+
const b = bubbleRef.current;
|
|
1755
|
+
if (b && b.matches(":popover-open")) {
|
|
1756
|
+
try {
|
|
1757
|
+
b.hidePopover();
|
|
1758
|
+
} catch {
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
}, []);
|
|
1762
|
+
const bubbleAttr = { popover: "manual" };
|
|
1763
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
1764
|
+
"span",
|
|
1765
|
+
{
|
|
1766
|
+
ref: triggerRef,
|
|
1767
|
+
className: cx("uix-tooltip", className),
|
|
1768
|
+
"aria-describedby": id,
|
|
1769
|
+
onMouseEnter: show,
|
|
1770
|
+
onMouseLeave: hide,
|
|
1771
|
+
onFocus: show,
|
|
1772
|
+
onBlur: hide,
|
|
1773
|
+
onKeyDown: (e) => {
|
|
1774
|
+
if (e.key === "Escape") hide();
|
|
1775
|
+
},
|
|
1776
|
+
...props,
|
|
1777
|
+
children: [
|
|
1778
|
+
children,
|
|
1779
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { ref: bubbleRef, id, role: "tooltip", className: "uix-tooltip__bubble", ...bubbleAttr, children: label })
|
|
1780
|
+
]
|
|
1781
|
+
}
|
|
1782
|
+
);
|
|
1178
1783
|
}
|
|
1179
1784
|
|
|
1180
1785
|
// src/components/States.tsx
|
|
@@ -1266,72 +1871,140 @@ function Comment({ avatar, author, meta, children, className, ...props }) {
|
|
|
1266
1871
|
] });
|
|
1267
1872
|
}
|
|
1268
1873
|
|
|
1269
|
-
// src/components/
|
|
1874
|
+
// src/components/Composer.tsx
|
|
1270
1875
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1876
|
+
function Composer({ children, className, ...props }) {
|
|
1877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cx("uix-composer", className), ...props, children });
|
|
1878
|
+
}
|
|
1879
|
+
function ComposerBar({ children, className, ...props }) {
|
|
1880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cx("uix-composer__bar", className), ...props, children });
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
// src/components/Segmented.tsx
|
|
1884
|
+
var import_react18 = require("react");
|
|
1885
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1886
|
+
var SegmentedCtx = (0, import_react18.createContext)({});
|
|
1887
|
+
function Segmented({ value, onChange, children, className, ...props }) {
|
|
1888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(SegmentedCtx.Provider, { value: { value, onChange }, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { role: "group", className: cx("uix-segmented", className), ...props, children }) });
|
|
1889
|
+
}
|
|
1890
|
+
function SegmentedOption({
|
|
1891
|
+
value,
|
|
1892
|
+
children,
|
|
1893
|
+
className,
|
|
1894
|
+
onClick,
|
|
1895
|
+
...props
|
|
1896
|
+
}) {
|
|
1897
|
+
const ctx = (0, import_react18.useContext)(SegmentedCtx);
|
|
1898
|
+
const selected = ctx.value === value;
|
|
1899
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1900
|
+
"button",
|
|
1901
|
+
{
|
|
1902
|
+
type: "button",
|
|
1903
|
+
className: cx("uix-segmented__option", className),
|
|
1904
|
+
"aria-pressed": selected,
|
|
1905
|
+
onClick: (e) => {
|
|
1906
|
+
ctx.onChange?.(value);
|
|
1907
|
+
onClick?.(e);
|
|
1908
|
+
},
|
|
1909
|
+
...props,
|
|
1910
|
+
children
|
|
1911
|
+
}
|
|
1912
|
+
);
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
// src/components/Timeline.tsx
|
|
1916
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1271
1917
|
function Timeline({ children, className, ...props }) {
|
|
1272
|
-
return /* @__PURE__ */ (0,
|
|
1918
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: cx("uix-timeline", className), ...props, children });
|
|
1273
1919
|
}
|
|
1274
|
-
function TimelineItem({ meta, children, className, ...props }) {
|
|
1275
|
-
return /* @__PURE__ */ (0,
|
|
1276
|
-
/* @__PURE__ */ (0,
|
|
1277
|
-
/* @__PURE__ */ (0,
|
|
1278
|
-
/* @__PURE__ */ (0,
|
|
1920
|
+
function TimelineItem({ node, meta, children, className, ...props }) {
|
|
1921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: cx("uix-timeline__item", className), ...props, children: [
|
|
1922
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "uix-timeline__rail", children: [
|
|
1923
|
+
node ?? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "uix-timeline__node" }),
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "uix-timeline__line" })
|
|
1279
1925
|
] }),
|
|
1280
|
-
/* @__PURE__ */ (0,
|
|
1281
|
-
meta != null && /* @__PURE__ */ (0,
|
|
1926
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "uix-timeline__body", children: [
|
|
1927
|
+
meta != null && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "uix-timeline__meta", children: meta }),
|
|
1282
1928
|
children
|
|
1283
1929
|
] })
|
|
1284
1930
|
] });
|
|
1285
1931
|
}
|
|
1286
1932
|
|
|
1287
1933
|
// src/components/Prose.tsx
|
|
1288
|
-
var
|
|
1934
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1289
1935
|
function Prose({ children, className, ...props }) {
|
|
1290
|
-
return /* @__PURE__ */ (0,
|
|
1936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: cx("uix-prose", className), ...props, children });
|
|
1291
1937
|
}
|
|
1292
1938
|
function Note({ tone, icon, children, className, ...props }) {
|
|
1293
|
-
return /* @__PURE__ */ (0,
|
|
1294
|
-
icon != null && /* @__PURE__ */ (0,
|
|
1295
|
-
/* @__PURE__ */ (0,
|
|
1939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cx("uix-note", tone && `uix-note--${tone}`, className), ...props, children: [
|
|
1940
|
+
icon != null && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-note__icon", children: icon }),
|
|
1941
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "uix-note__body", children })
|
|
1296
1942
|
] });
|
|
1297
1943
|
}
|
|
1298
1944
|
|
|
1299
1945
|
// src/components/Popover.tsx
|
|
1300
|
-
var
|
|
1301
|
-
|
|
1946
|
+
var import_react19 = require("react");
|
|
1947
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
1948
|
+
function Popover({
|
|
1949
|
+
popover = "auto",
|
|
1950
|
+
anchor,
|
|
1951
|
+
placement = "bottom-start",
|
|
1952
|
+
offset = 6,
|
|
1953
|
+
className,
|
|
1954
|
+
children,
|
|
1955
|
+
...props
|
|
1956
|
+
}) {
|
|
1957
|
+
const ref = (0, import_react19.useRef)(null);
|
|
1958
|
+
const [open, setOpen] = (0, import_react19.useState)(false);
|
|
1302
1959
|
const popoverAttr = { popover };
|
|
1303
|
-
|
|
1960
|
+
const reposition = useAnchoredPosition(anchor ?? null, ref, {
|
|
1961
|
+
open: open && !!anchor,
|
|
1962
|
+
placement,
|
|
1963
|
+
offset
|
|
1964
|
+
});
|
|
1965
|
+
(0, import_react19.useEffect)(() => {
|
|
1966
|
+
const el = ref.current;
|
|
1967
|
+
if (!el || !anchor) return;
|
|
1968
|
+
const sync = () => {
|
|
1969
|
+
const isOpen = el.matches(":popover-open");
|
|
1970
|
+
if (isOpen) reposition();
|
|
1971
|
+
setOpen(isOpen);
|
|
1972
|
+
};
|
|
1973
|
+
el.addEventListener("toggle", sync);
|
|
1974
|
+
return () => el.removeEventListener("toggle", sync);
|
|
1975
|
+
}, [anchor, reposition]);
|
|
1976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { ref, className: cx("uix-popover", className), ...popoverAttr, ...props, children });
|
|
1304
1977
|
}
|
|
1305
1978
|
|
|
1306
1979
|
// src/components/CommandPalette.tsx
|
|
1307
|
-
var
|
|
1980
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
1308
1981
|
function CommandPalette({ inputProps, children, className, ...props }) {
|
|
1309
|
-
return /* @__PURE__ */ (0,
|
|
1310
|
-
/* @__PURE__ */ (0,
|
|
1311
|
-
/* @__PURE__ */ (0,
|
|
1982
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: cx("uix-cmdk", className), ...props, children: [
|
|
1983
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { className: "uix-cmdk__input", ...inputProps }),
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uix-cmdk__list", children })
|
|
1312
1985
|
] });
|
|
1313
1986
|
}
|
|
1314
1987
|
function CommandGroup({ label, children }) {
|
|
1315
|
-
return /* @__PURE__ */ (0,
|
|
1316
|
-
label != null && /* @__PURE__ */ (0,
|
|
1988
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
|
|
1989
|
+
label != null && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uix-cmdk__group", children: label }),
|
|
1317
1990
|
children
|
|
1318
1991
|
] });
|
|
1319
1992
|
}
|
|
1320
1993
|
function CommandItem({ icon, shortcut, active, children, className, ...props }) {
|
|
1321
|
-
return /* @__PURE__ */ (0,
|
|
1994
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: cx("uix-cmdk__item", className), "data-active": active || void 0, ...props, children: [
|
|
1322
1995
|
icon,
|
|
1323
|
-
/* @__PURE__ */ (0,
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children }),
|
|
1324
1997
|
shortcut
|
|
1325
1998
|
] });
|
|
1326
1999
|
}
|
|
1327
2000
|
|
|
1328
2001
|
// src/components/Inbox.tsx
|
|
1329
|
-
var
|
|
2002
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
1330
2003
|
function Inbox({ children, className, ...props }) {
|
|
1331
|
-
return /* @__PURE__ */ (0,
|
|
2004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: cx("uix-inbox", className), ...props, children });
|
|
1332
2005
|
}
|
|
1333
2006
|
function InboxList({ children, className, ...props }) {
|
|
1334
|
-
return /* @__PURE__ */ (0,
|
|
2007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: cx("uix-inbox__list", className), role: "listbox", ...props, children });
|
|
1335
2008
|
}
|
|
1336
2009
|
function InboxItem({
|
|
1337
2010
|
subject,
|
|
@@ -1343,7 +2016,7 @@ function InboxItem({
|
|
|
1343
2016
|
className,
|
|
1344
2017
|
...props
|
|
1345
2018
|
}) {
|
|
1346
|
-
return /* @__PURE__ */ (0,
|
|
2019
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
1347
2020
|
"div",
|
|
1348
2021
|
{
|
|
1349
2022
|
role: "option",
|
|
@@ -1353,82 +2026,158 @@ function InboxItem({
|
|
|
1353
2026
|
...props,
|
|
1354
2027
|
children: [
|
|
1355
2028
|
leading,
|
|
1356
|
-
subject != null && /* @__PURE__ */ (0,
|
|
1357
|
-
preview != null && /* @__PURE__ */ (0,
|
|
2029
|
+
subject != null && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "uix-inbox__subject", children: subject }),
|
|
2030
|
+
preview != null && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "uix-inbox__preview", children: preview }),
|
|
1358
2031
|
children
|
|
1359
2032
|
]
|
|
1360
2033
|
}
|
|
1361
2034
|
);
|
|
1362
2035
|
}
|
|
1363
2036
|
function InboxDetail({ children, className, ...props }) {
|
|
1364
|
-
return /* @__PURE__ */ (0,
|
|
2037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: cx("uix-inbox__detail", className), ...props, children });
|
|
1365
2038
|
}
|
|
1366
2039
|
|
|
1367
2040
|
// src/components/Kanban.tsx
|
|
1368
|
-
var
|
|
2041
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
1369
2042
|
function Kanban({ children, className, ...props }) {
|
|
1370
|
-
return /* @__PURE__ */ (0,
|
|
2043
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: cx("uix-kanban", className), ...props, children });
|
|
1371
2044
|
}
|
|
1372
2045
|
function KanbanColumn({ title, count, children, className, ...props }) {
|
|
1373
|
-
return /* @__PURE__ */ (0,
|
|
1374
|
-
(title != null || count != null) && /* @__PURE__ */ (0,
|
|
2046
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cx("uix-kanban__col", className), ...props, children: [
|
|
2047
|
+
(title != null || count != null) && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "uix-kanban__head", children: [
|
|
1375
2048
|
title,
|
|
1376
|
-
count != null && /* @__PURE__ */ (0,
|
|
2049
|
+
count != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "uix-kanban__count", children: count })
|
|
1377
2050
|
] }),
|
|
1378
|
-
/* @__PURE__ */ (0,
|
|
2051
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "uix-kanban__body", children })
|
|
1379
2052
|
] });
|
|
1380
2053
|
}
|
|
1381
2054
|
function KanbanCard({ title, meta, children, className, ...props }) {
|
|
1382
|
-
return /* @__PURE__ */ (0,
|
|
1383
|
-
title && /* @__PURE__ */ (0,
|
|
1384
|
-
meta && /* @__PURE__ */ (0,
|
|
2055
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cx("uix-kanban__card", className), ...props, children: [
|
|
2056
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "uix-kanban__card-title", children: title }),
|
|
2057
|
+
meta && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "uix-kanban__card-meta", children: meta }),
|
|
1385
2058
|
children
|
|
1386
2059
|
] });
|
|
1387
2060
|
}
|
|
1388
2061
|
|
|
1389
2062
|
// src/components/Tree.tsx
|
|
1390
|
-
var
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
function
|
|
2063
|
+
var import_react20 = require("react");
|
|
2064
|
+
|
|
2065
|
+
// src/tree-model.ts
|
|
2066
|
+
function flattenTree(nodes, expanded, level = 1) {
|
|
2067
|
+
const out = [];
|
|
2068
|
+
const setsize = nodes.length;
|
|
2069
|
+
nodes.forEach((node, i) => {
|
|
2070
|
+
const hasChildren = Array.isArray(node.children) && node.children.length > 0;
|
|
2071
|
+
const isExpanded = hasChildren && expanded.has(node.id);
|
|
2072
|
+
out.push({ node, level, setsize, posinset: i + 1, hasChildren, isExpanded });
|
|
2073
|
+
if (isExpanded) out.push(...flattenTree(node.children, expanded, level + 1));
|
|
2074
|
+
});
|
|
2075
|
+
return out;
|
|
2076
|
+
}
|
|
2077
|
+
function treeNav(flat, currentId, key) {
|
|
2078
|
+
const idx = flat.findIndex((f) => f.node.id === currentId);
|
|
2079
|
+
if (idx < 0) return {};
|
|
2080
|
+
const cur = flat[idx];
|
|
2081
|
+
const focusAt = (i) => {
|
|
2082
|
+
const clamped = Math.max(0, Math.min(flat.length - 1, i));
|
|
2083
|
+
return { focusId: flat[clamped]?.node.id };
|
|
2084
|
+
};
|
|
2085
|
+
switch (key) {
|
|
2086
|
+
case "ArrowDown":
|
|
2087
|
+
return focusAt(idx + 1);
|
|
2088
|
+
case "ArrowUp":
|
|
2089
|
+
return focusAt(idx - 1);
|
|
2090
|
+
case "Home":
|
|
2091
|
+
return focusAt(0);
|
|
2092
|
+
case "End":
|
|
2093
|
+
return focusAt(flat.length - 1);
|
|
2094
|
+
case "ArrowRight":
|
|
2095
|
+
if (cur.hasChildren && !cur.isExpanded) return { toggleId: cur.node.id };
|
|
2096
|
+
if (cur.hasChildren && cur.isExpanded) return focusAt(idx + 1);
|
|
2097
|
+
return {};
|
|
2098
|
+
case "ArrowLeft":
|
|
2099
|
+
if (cur.hasChildren && cur.isExpanded) return { toggleId: cur.node.id };
|
|
2100
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
2101
|
+
if (flat[i].level === cur.level - 1) return { focusId: flat[i].node.id };
|
|
2102
|
+
}
|
|
2103
|
+
return {};
|
|
2104
|
+
case "Enter":
|
|
2105
|
+
case " ":
|
|
2106
|
+
return cur.hasChildren ? { toggleId: cur.node.id, selectId: cur.node.id } : { selectId: cur.node.id };
|
|
2107
|
+
default:
|
|
2108
|
+
return {};
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
// src/components/Tree.tsx
|
|
2113
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2114
|
+
var ChevronIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("svg", { viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("path", { d: "M2 4l4 4 4-4" }) });
|
|
2115
|
+
function TreeNode({ node, expanded, selected, selectable, tabbableId, onToggle, onSelect, onFocusNode, level = 1 }) {
|
|
1394
2116
|
const hasChildren = Array.isArray(node.children) && node.children.length > 0;
|
|
1395
2117
|
const isExpanded = expanded.has(node.id);
|
|
1396
|
-
return /* @__PURE__ */ (0,
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "uix-tree__toggle", children: hasChildren && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChevronIcon2, {}) }),
|
|
1409
|
-
node.icon && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { "aria-hidden": "true", children: node.icon }),
|
|
1410
|
-
node.label
|
|
1411
|
-
]
|
|
1412
|
-
}
|
|
1413
|
-
),
|
|
1414
|
-
hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { children: node.children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
1415
|
-
TreeNode,
|
|
1416
|
-
{
|
|
1417
|
-
node: child,
|
|
1418
|
-
expanded,
|
|
1419
|
-
selected,
|
|
1420
|
-
onToggle,
|
|
1421
|
-
onSelect,
|
|
1422
|
-
level: level + 1
|
|
2118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2119
|
+
"li",
|
|
2120
|
+
{
|
|
2121
|
+
role: "treeitem",
|
|
2122
|
+
"aria-level": level,
|
|
2123
|
+
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
2124
|
+
"aria-selected": selectable ? selected === node.id : void 0,
|
|
2125
|
+
"data-id": node.id,
|
|
2126
|
+
tabIndex: tabbableId === node.id ? 0 : -1,
|
|
2127
|
+
className: "uix-tree__item",
|
|
2128
|
+
onFocus: (e) => {
|
|
2129
|
+
if (e.target === e.currentTarget) onFocusNode(node.id);
|
|
1423
2130
|
},
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
2131
|
+
onClick: (e) => {
|
|
2132
|
+
e.stopPropagation();
|
|
2133
|
+
if (hasChildren) onToggle(node.id);
|
|
2134
|
+
onSelect?.(node.id);
|
|
2135
|
+
onFocusNode(node.id);
|
|
2136
|
+
},
|
|
2137
|
+
children: [
|
|
2138
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "uix-tree__row", children: [
|
|
2139
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-tree__toggle", children: hasChildren && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChevronIcon2, {}) }),
|
|
2140
|
+
node.icon && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { "aria-hidden": "true", children: node.icon }),
|
|
2141
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-tree__label", children: node.label })
|
|
2142
|
+
] }),
|
|
2143
|
+
hasChildren && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { role: "group", className: "uix-tree__group", children: node.children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2144
|
+
TreeNode,
|
|
2145
|
+
{
|
|
2146
|
+
node: child,
|
|
2147
|
+
expanded,
|
|
2148
|
+
selected,
|
|
2149
|
+
selectable,
|
|
2150
|
+
tabbableId,
|
|
2151
|
+
onToggle,
|
|
2152
|
+
onSelect,
|
|
2153
|
+
onFocusNode,
|
|
2154
|
+
level: level + 1
|
|
2155
|
+
},
|
|
2156
|
+
child.id
|
|
2157
|
+
)) })
|
|
2158
|
+
]
|
|
2159
|
+
}
|
|
2160
|
+
);
|
|
1427
2161
|
}
|
|
1428
|
-
function Tree({
|
|
1429
|
-
|
|
2162
|
+
function Tree({
|
|
2163
|
+
nodes,
|
|
2164
|
+
expanded: controlledExpanded,
|
|
2165
|
+
defaultExpanded,
|
|
2166
|
+
selected,
|
|
2167
|
+
onToggle,
|
|
2168
|
+
onSelect,
|
|
2169
|
+
virtualize,
|
|
2170
|
+
rowHeight = 32,
|
|
2171
|
+
maxHeight = 384,
|
|
2172
|
+
className,
|
|
2173
|
+
...props
|
|
2174
|
+
}) {
|
|
2175
|
+
const [internalExpanded, setInternalExpanded] = (0, import_react20.useState)(defaultExpanded ?? /* @__PURE__ */ new Set());
|
|
1430
2176
|
const expanded = controlledExpanded ?? internalExpanded;
|
|
1431
|
-
|
|
2177
|
+
const rootRef = (0, import_react20.useRef)(null);
|
|
2178
|
+
const [focusedId, setFocusedId] = (0, import_react20.useState)(void 0);
|
|
2179
|
+
const selectable = selected !== void 0 || onSelect != null;
|
|
2180
|
+
const handleToggle = (0, import_react20.useCallback)((id) => {
|
|
1432
2181
|
if (!controlledExpanded) {
|
|
1433
2182
|
setInternalExpanded((prev) => {
|
|
1434
2183
|
const next = new Set(prev);
|
|
@@ -1438,41 +2187,231 @@ function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected,
|
|
|
1438
2187
|
});
|
|
1439
2188
|
}
|
|
1440
2189
|
onToggle?.(id);
|
|
2190
|
+
}, [controlledExpanded, onToggle]);
|
|
2191
|
+
const flat = (0, import_react20.useMemo)(() => flattenTree(nodes, expanded), [nodes, expanded]);
|
|
2192
|
+
const useVirtual = virtualize ?? shouldVirtualize(flat.length);
|
|
2193
|
+
const tabbableId = focusedId ?? selected ?? nodes[0]?.id;
|
|
2194
|
+
if (useVirtual) {
|
|
2195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2196
|
+
VirtualTreeView,
|
|
2197
|
+
{
|
|
2198
|
+
flat,
|
|
2199
|
+
rowHeight,
|
|
2200
|
+
maxHeight,
|
|
2201
|
+
selectable,
|
|
2202
|
+
selected,
|
|
2203
|
+
tabbableId,
|
|
2204
|
+
onToggle: handleToggle,
|
|
2205
|
+
onSelect,
|
|
2206
|
+
focusedId,
|
|
2207
|
+
setFocusedId,
|
|
2208
|
+
className,
|
|
2209
|
+
...props
|
|
2210
|
+
}
|
|
2211
|
+
);
|
|
1441
2212
|
}
|
|
1442
|
-
|
|
2213
|
+
const treeItems = () => Array.from(rootRef.current?.querySelectorAll('[role="treeitem"]') ?? []);
|
|
2214
|
+
const focusItem = (el) => {
|
|
2215
|
+
if (el) {
|
|
2216
|
+
el.focus();
|
|
2217
|
+
setFocusedId(el.dataset.id);
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
const onKeyDown = (e) => {
|
|
2221
|
+
const cur = e.target.closest('[role="treeitem"]');
|
|
2222
|
+
if (!cur || !rootRef.current?.contains(cur)) return;
|
|
2223
|
+
const list = treeItems();
|
|
2224
|
+
const idx = list.indexOf(cur);
|
|
2225
|
+
const id = cur.dataset.id;
|
|
2226
|
+
const exp = cur.getAttribute("aria-expanded");
|
|
2227
|
+
switch (e.key) {
|
|
2228
|
+
case "ArrowDown":
|
|
2229
|
+
e.preventDefault();
|
|
2230
|
+
focusItem(list[Math.min(idx + 1, list.length - 1)]);
|
|
2231
|
+
break;
|
|
2232
|
+
case "ArrowUp":
|
|
2233
|
+
e.preventDefault();
|
|
2234
|
+
focusItem(list[Math.max(idx - 1, 0)]);
|
|
2235
|
+
break;
|
|
2236
|
+
case "Home":
|
|
2237
|
+
e.preventDefault();
|
|
2238
|
+
focusItem(list[0]);
|
|
2239
|
+
break;
|
|
2240
|
+
case "End":
|
|
2241
|
+
e.preventDefault();
|
|
2242
|
+
focusItem(list[list.length - 1]);
|
|
2243
|
+
break;
|
|
2244
|
+
case "ArrowRight":
|
|
2245
|
+
e.preventDefault();
|
|
2246
|
+
if (exp === "false") handleToggle(id);
|
|
2247
|
+
else if (exp === "true") focusItem(cur.querySelector(':scope > [role="group"] > [role="treeitem"]'));
|
|
2248
|
+
break;
|
|
2249
|
+
case "ArrowLeft":
|
|
2250
|
+
e.preventDefault();
|
|
2251
|
+
if (exp === "true") handleToggle(id);
|
|
2252
|
+
else focusItem(cur.parentElement?.closest('[role="treeitem"]'));
|
|
2253
|
+
break;
|
|
2254
|
+
case "Enter":
|
|
2255
|
+
case " ":
|
|
2256
|
+
e.preventDefault();
|
|
2257
|
+
if (exp !== null) handleToggle(id);
|
|
2258
|
+
onSelect?.(id);
|
|
2259
|
+
setFocusedId(id);
|
|
2260
|
+
break;
|
|
2261
|
+
default:
|
|
2262
|
+
break;
|
|
2263
|
+
}
|
|
2264
|
+
};
|
|
2265
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { ref: rootRef, className: cx("uix-tree", className), role: "tree", onKeyDown, ...props, children: nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
1443
2266
|
TreeNode,
|
|
1444
2267
|
{
|
|
1445
2268
|
node,
|
|
1446
2269
|
expanded,
|
|
1447
2270
|
selected,
|
|
2271
|
+
selectable,
|
|
2272
|
+
tabbableId,
|
|
1448
2273
|
onToggle: handleToggle,
|
|
1449
|
-
onSelect
|
|
2274
|
+
onSelect,
|
|
2275
|
+
onFocusNode: setFocusedId,
|
|
2276
|
+
level: 1
|
|
1450
2277
|
},
|
|
1451
2278
|
node.id
|
|
1452
2279
|
)) });
|
|
1453
2280
|
}
|
|
2281
|
+
function VirtualTreeView({
|
|
2282
|
+
flat,
|
|
2283
|
+
rowHeight,
|
|
2284
|
+
maxHeight,
|
|
2285
|
+
selectable,
|
|
2286
|
+
selected,
|
|
2287
|
+
tabbableId,
|
|
2288
|
+
onToggle,
|
|
2289
|
+
onSelect,
|
|
2290
|
+
focusedId,
|
|
2291
|
+
setFocusedId,
|
|
2292
|
+
className,
|
|
2293
|
+
...props
|
|
2294
|
+
}) {
|
|
2295
|
+
const scrollRef = (0, import_react20.useRef)(null);
|
|
2296
|
+
const [scrollTop, setScrollTop] = (0, import_react20.useState)(0);
|
|
2297
|
+
const pendingFocus = (0, import_react20.useRef)(false);
|
|
2298
|
+
const win = virtualWindow(scrollTop, maxHeight, rowHeight, flat.length);
|
|
2299
|
+
const rows = flat.slice(win.start, win.end);
|
|
2300
|
+
(0, import_react20.useEffect)(() => {
|
|
2301
|
+
if (!pendingFocus.current || focusedId == null) return;
|
|
2302
|
+
const el = scrollRef.current?.querySelector(`[role="treeitem"][data-id="${CSS.escape(focusedId)}"]`);
|
|
2303
|
+
if (el) {
|
|
2304
|
+
el.focus();
|
|
2305
|
+
pendingFocus.current = false;
|
|
2306
|
+
}
|
|
2307
|
+
}, [focusedId, win.start, win.end]);
|
|
2308
|
+
const moveTo = (id) => {
|
|
2309
|
+
const i = flat.findIndex((f) => f.node.id === id);
|
|
2310
|
+
if (i < 0) return;
|
|
2311
|
+
const top = i * rowHeight;
|
|
2312
|
+
let next = scrollTop;
|
|
2313
|
+
if (top < scrollTop) next = top;
|
|
2314
|
+
else if (top + rowHeight > scrollTop + maxHeight) next = top + rowHeight - maxHeight;
|
|
2315
|
+
if (next !== scrollTop) {
|
|
2316
|
+
if (scrollRef.current) scrollRef.current.scrollTop = next;
|
|
2317
|
+
setScrollTop(next);
|
|
2318
|
+
}
|
|
2319
|
+
pendingFocus.current = true;
|
|
2320
|
+
setFocusedId(id);
|
|
2321
|
+
};
|
|
2322
|
+
const onKeyDown = (e) => {
|
|
2323
|
+
const curId = e.target.closest('[role="treeitem"]')?.dataset.id ?? focusedId;
|
|
2324
|
+
const act = treeNav(flat, curId, e.key);
|
|
2325
|
+
if (act.focusId === void 0 && act.toggleId === void 0 && act.selectId === void 0) return;
|
|
2326
|
+
e.preventDefault();
|
|
2327
|
+
if (act.toggleId !== void 0) onToggle(act.toggleId);
|
|
2328
|
+
if (act.selectId !== void 0) {
|
|
2329
|
+
onSelect?.(act.selectId);
|
|
2330
|
+
if (act.focusId === void 0) {
|
|
2331
|
+
pendingFocus.current = true;
|
|
2332
|
+
setFocusedId(act.selectId);
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
if (act.focusId !== void 0) moveTo(act.focusId);
|
|
2336
|
+
};
|
|
2337
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2338
|
+
"ul",
|
|
2339
|
+
{
|
|
2340
|
+
ref: scrollRef,
|
|
2341
|
+
className: cx("uix-tree", "uix-tree--virtual", className),
|
|
2342
|
+
role: "tree",
|
|
2343
|
+
style: { maxHeight, overflow: "auto" },
|
|
2344
|
+
onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
|
|
2345
|
+
onKeyDown,
|
|
2346
|
+
...props,
|
|
2347
|
+
children: [
|
|
2348
|
+
win.padTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("li", { "aria-hidden": "true", style: { height: win.padTop } }),
|
|
2349
|
+
rows.map((f) => {
|
|
2350
|
+
const rowStyle = { height: rowHeight, paddingLeft: `calc(${f.level - 1} * var(--uix-space-5))` };
|
|
2351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2352
|
+
"li",
|
|
2353
|
+
{
|
|
2354
|
+
role: "treeitem",
|
|
2355
|
+
"aria-level": f.level,
|
|
2356
|
+
"aria-setsize": f.setsize,
|
|
2357
|
+
"aria-posinset": f.posinset,
|
|
2358
|
+
"aria-expanded": f.hasChildren ? f.isExpanded : void 0,
|
|
2359
|
+
"aria-selected": selectable ? selected === f.node.id : void 0,
|
|
2360
|
+
"data-id": f.node.id,
|
|
2361
|
+
tabIndex: tabbableId === f.node.id ? 0 : -1,
|
|
2362
|
+
className: "uix-tree__item",
|
|
2363
|
+
onFocus: (e) => {
|
|
2364
|
+
if (e.target === e.currentTarget) setFocusedId(f.node.id);
|
|
2365
|
+
},
|
|
2366
|
+
onClick: (e) => {
|
|
2367
|
+
e.stopPropagation();
|
|
2368
|
+
if (f.hasChildren) onToggle(f.node.id);
|
|
2369
|
+
onSelect?.(f.node.id);
|
|
2370
|
+
setFocusedId(f.node.id);
|
|
2371
|
+
},
|
|
2372
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "uix-tree__row", style: rowStyle, children: [
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-tree__toggle", children: f.hasChildren && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ChevronIcon2, {}) }),
|
|
2374
|
+
f.node.icon && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { "aria-hidden": "true", children: f.node.icon }),
|
|
2375
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "uix-tree__label", children: f.node.label })
|
|
2376
|
+
] })
|
|
2377
|
+
},
|
|
2378
|
+
f.node.id
|
|
2379
|
+
);
|
|
2380
|
+
}),
|
|
2381
|
+
win.padBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("li", { "aria-hidden": "true", style: { height: win.padBottom } })
|
|
2382
|
+
]
|
|
2383
|
+
}
|
|
2384
|
+
);
|
|
2385
|
+
}
|
|
1454
2386
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1455
2387
|
0 && (module.exports = {
|
|
1456
2388
|
Alert,
|
|
1457
2389
|
AppShell,
|
|
1458
2390
|
Avatar,
|
|
1459
2391
|
AvatarGroup,
|
|
2392
|
+
BulkBar,
|
|
1460
2393
|
Button,
|
|
1461
2394
|
ButtonGroup,
|
|
1462
2395
|
Card,
|
|
2396
|
+
CellStrong,
|
|
2397
|
+
CellSub,
|
|
1463
2398
|
Checkbox,
|
|
1464
2399
|
CommandGroup,
|
|
1465
2400
|
CommandItem,
|
|
1466
2401
|
CommandPalette,
|
|
1467
2402
|
Comment,
|
|
1468
2403
|
Comments,
|
|
2404
|
+
Composer,
|
|
2405
|
+
ComposerBar,
|
|
1469
2406
|
DescriptionItem,
|
|
1470
2407
|
DescriptionList,
|
|
1471
2408
|
DetailLayout,
|
|
1472
2409
|
Drawer,
|
|
1473
2410
|
EmptyState,
|
|
1474
2411
|
ErrorState,
|
|
2412
|
+
ExpandToggle,
|
|
1475
2413
|
Field,
|
|
2414
|
+
Highlighted,
|
|
1476
2415
|
Inbox,
|
|
1477
2416
|
InboxDetail,
|
|
1478
2417
|
InboxItem,
|
|
@@ -1486,6 +2425,7 @@ function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected,
|
|
|
1486
2425
|
List,
|
|
1487
2426
|
ListItem,
|
|
1488
2427
|
LoadingState,
|
|
2428
|
+
Mark,
|
|
1489
2429
|
Meter,
|
|
1490
2430
|
Modal,
|
|
1491
2431
|
NavFavourites,
|
|
@@ -1500,6 +2440,10 @@ function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected,
|
|
|
1500
2440
|
Prose,
|
|
1501
2441
|
Radio,
|
|
1502
2442
|
RadioGroup,
|
|
2443
|
+
RowAction,
|
|
2444
|
+
RowActions,
|
|
2445
|
+
Segmented,
|
|
2446
|
+
SegmentedOption,
|
|
1503
2447
|
Select,
|
|
1504
2448
|
Sidebar,
|
|
1505
2449
|
SidebarSection,
|
|
@@ -1525,6 +2469,28 @@ function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected,
|
|
|
1525
2469
|
Tr,
|
|
1526
2470
|
Tree,
|
|
1527
2471
|
UserChip,
|
|
2472
|
+
applyFilters,
|
|
2473
|
+
clampWidth,
|
|
2474
|
+
computePosition,
|
|
1528
2475
|
cx,
|
|
1529
|
-
|
|
2476
|
+
flattenTree,
|
|
2477
|
+
highlightSegments,
|
|
2478
|
+
matchFilter,
|
|
2479
|
+
mergePinned,
|
|
2480
|
+
multiSort,
|
|
2481
|
+
nextSortDir,
|
|
2482
|
+
parseView,
|
|
2483
|
+
reorder,
|
|
2484
|
+
searchRows,
|
|
2485
|
+
selectAllState,
|
|
2486
|
+
serializeView,
|
|
2487
|
+
shouldVirtualize,
|
|
2488
|
+
toggleId,
|
|
2489
|
+
togglePage,
|
|
2490
|
+
toggleSort,
|
|
2491
|
+
treeNav,
|
|
2492
|
+
useAnchoredPosition,
|
|
2493
|
+
useDialog,
|
|
2494
|
+
useTable,
|
|
2495
|
+
virtualWindow
|
|
1530
2496
|
});
|