@crewlethq/ui 0.39.0 → 0.40.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.
Files changed (93) hide show
  1. package/README.md +43 -1
  2. package/dist/AppShell/AppShell.d.ts +13 -2
  3. package/dist/AppShell/index.js +1 -1
  4. package/dist/{AppShell-NDU4XMGF.css → AppShell-NPSWZ3XW.css} +45 -4
  5. package/dist/ArtifactBar/index.js +6 -5
  6. package/dist/AvatarPicker/index.js +10 -6
  7. package/dist/CatalogTile/index.js +1 -1
  8. package/dist/{CatalogTile-TGR2ZZVQ.css → CatalogTile-XL4XLFUH.css} +8 -4
  9. package/dist/CharacterPicker/index.js +2 -2
  10. package/dist/Charts/Histogram.d.ts +71 -0
  11. package/dist/Charts/index.d.ts +2 -0
  12. package/dist/Charts/index.js +1 -1
  13. package/dist/{Charts-MBJG72BS.css → Charts-TZ744HT6.css} +118 -0
  14. package/dist/DataGrid/DataGrid.d.ts +267 -0
  15. package/dist/DataGrid/index.d.ts +3 -0
  16. package/dist/DataGrid/index.js +7 -0
  17. package/dist/DataGrid-AQKPJD7W.css +482 -0
  18. package/dist/HuePicker/index.js +11 -4
  19. package/dist/LayersList/index.js +2 -2
  20. package/dist/LockedLabel/LockedLabel.d.ts +34 -0
  21. package/dist/LockedLabel/index.d.ts +3 -0
  22. package/dist/LockedLabel/index.js +3 -0
  23. package/dist/LockedLabel-VQEGEB7G.css +16 -0
  24. package/dist/MarkdownEditor/index.js +8 -5
  25. package/dist/MergeConflicts/index.js +11 -5
  26. package/dist/PageNote/PageNote.d.ts +14 -0
  27. package/dist/PageNote/index.d.ts +3 -0
  28. package/dist/PageNote/index.js +2 -0
  29. package/dist/PageNote-RHLXH3ML.css +12 -0
  30. package/dist/PropertyList/PropertyList.d.ts +88 -0
  31. package/dist/PropertyList/index.d.ts +3 -0
  32. package/dist/PropertyList/index.js +7 -0
  33. package/dist/PropertyList-SCYM66LL.css +96 -0
  34. package/dist/RelatedRow/RelatedRow.d.ts +27 -0
  35. package/dist/RelatedRow/index.d.ts +3 -0
  36. package/dist/RelatedRow/index.js +9 -0
  37. package/dist/RelatedRow-2FVS6QQA.css +6 -0
  38. package/dist/RichEditor/index.js +1 -1
  39. package/dist/SectionFrame/SectionFrame.d.ts +76 -0
  40. package/dist/SectionFrame/index.d.ts +3 -0
  41. package/dist/SectionFrame/index.js +7 -0
  42. package/dist/SectionFrame-M62UUVFQ.css +164 -0
  43. package/dist/SegmentedControl/index.js +11 -4
  44. package/dist/SheetColumnEditor/index.js +6 -5
  45. package/dist/SheetGrid/index.js +3 -3
  46. package/dist/SidebarNav/SidebarNav.d.ts +35 -2
  47. package/dist/SidebarNav/index.js +2 -1
  48. package/dist/{SidebarNav-7SGUZYKK.css → SidebarNav-YI74SPDC.css} +10 -0
  49. package/dist/Tabs/Tabs.d.ts +55 -1
  50. package/dist/Tabs/fold.d.ts +54 -0
  51. package/dist/Tabs/index.d.ts +1 -1
  52. package/dist/Tabs/index.js +9 -2
  53. package/dist/Tabs/roving.d.ts +3 -3
  54. package/dist/{Tabs-WIF7457H.css → Tabs-S7F4RWAN.css} +77 -0
  55. package/dist/TagsInput/index.js +1 -1
  56. package/dist/ThemeGallery/index.js +2 -2
  57. package/dist/ThemeSwitcher/index.js +12 -5
  58. package/dist/VersionCompare/index.js +12 -5
  59. package/dist/{chunk-B5J23C73.js → chunk-2PEXZ7L4.js} +1 -1
  60. package/dist/{chunk-TZYFTC4M.js → chunk-2VOHUGUA.js} +1 -1
  61. package/dist/{chunk-2QZ2VPHR.js → chunk-4OK4DX3V.js} +2 -2
  62. package/dist/{chunk-ECGGQX2H.js → chunk-A44YHLCQ.js} +2 -2
  63. package/dist/{chunk-F4LPQA4E.js → chunk-BA32AVKS.js} +1 -1
  64. package/dist/chunk-CV4NES3P.js +9 -0
  65. package/dist/{chunk-PPHTIKZO.js → chunk-E4BOVKNJ.js} +1 -1
  66. package/dist/{chunk-W7PAIVAP.js → chunk-E7QLG3PG.js} +30 -9
  67. package/dist/{chunk-RKKO7QHH.js → chunk-EGMQURBR.js} +5 -4
  68. package/dist/{chunk-GMW4ZHST.js → chunk-EX22Q5SH.js} +2 -2
  69. package/dist/{chunk-F3WZ5AKM.js → chunk-GFYQKMQZ.js} +1 -1
  70. package/dist/{chunk-HG5VF3TZ.js → chunk-HMVQQEHW.js} +91 -2
  71. package/dist/chunk-INVSUFJK.js +71 -0
  72. package/dist/{chunk-4LRAJXHL.js → chunk-JSWOXRRE.js} +1 -1
  73. package/dist/{chunk-DYB66CNM.js → chunk-KKNHMXTE.js} +6 -3
  74. package/dist/{chunk-ZMDYQ2HH.js → chunk-KWWP3D7M.js} +1 -1
  75. package/dist/{chunk-46RL3E54.js → chunk-M6NQ4XGK.js} +1 -1
  76. package/dist/chunk-OHGH7O6T.js +19 -0
  77. package/dist/{chunk-4ISUIS6F.js → chunk-OOC7Q67K.js} +1 -1
  78. package/dist/{chunk-XNXK5MA4.js → chunk-PCT47E7O.js} +1 -1
  79. package/dist/{chunk-X3UYTAOG.js → chunk-PFZOFAQ6.js} +1 -1
  80. package/dist/{chunk-YEVG2X5R.js → chunk-SNQRGH4A.js} +1 -1
  81. package/dist/chunk-T6MXORP5.js +116 -0
  82. package/dist/chunk-X4IXXLWM.js +306 -0
  83. package/dist/chunk-XIDD7PJO.js +416 -0
  84. package/dist/chunk-ZUTUI27P.js +21 -0
  85. package/dist/generated/index.d.ts +6 -0
  86. package/dist/generated/index.js +60 -54
  87. package/dist/index.js +60 -54
  88. package/dist/styles.css +1061 -17
  89. package/package.json +3 -3
  90. package/dist/chunk-7SDUKCNW.js +0 -141
  91. package/dist/{Editor-QV4JP242.js → Editor-IRDQ3JDZ.js} +1 -1
  92. package/dist/{chunk-JZPK4IXR.js → chunk-3PR65I3H.js} +2 -2
  93. /package/dist/{chunk-QRLIWCLX.js → chunk-S3QTFUJX.js} +0 -0
@@ -0,0 +1,416 @@
1
+ import { EmptyState } from './chunk-RA2ULG6H.js';
2
+ import { useMediaMatch } from './chunk-RTPQDNW3.js';
3
+ import { Button } from './chunk-OG6CL3EB.js';
4
+ import { VisuallyHidden } from './chunk-BZFWDIV6.js';
5
+ import { cx } from './chunk-ODEQTPFM.js';
6
+ import './DataGrid-AQKPJD7W.css';
7
+ import { useId, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle } from 'react';
8
+ import { breakpoint } from '@crewlethq/tokens';
9
+ import { ChevronDownGlyph, ChevronUpGlyph } from '@crewlethq/icons/glyphs';
10
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
11
+
12
+ function columnChoicesOf(columns) {
13
+ return columns.map((column) => ({
14
+ key: column.key,
15
+ label: headerWord(column) || column.label || column.key,
16
+ optional: column.optional
17
+ }));
18
+ }
19
+ function ChooserList({ label, items, onToggle }) {
20
+ const headingId = useId();
21
+ if (items.length === 0) return null;
22
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
23
+ /* @__PURE__ */ jsx("div", { className: "crewlet-column-chooser__label", id: headingId, children: label }),
24
+ /* @__PURE__ */ jsx("div", { className: "crewlet-column-chooser__choices", role: "group", "aria-labelledby": headingId, children: items.map((item) => /* @__PURE__ */ jsxs("label", { className: "crewlet-column-chooser__choice", children: [
25
+ /* @__PURE__ */ jsx("input", { type: "checkbox", checked: item.checked, onChange: () => onToggle(item.key) }),
26
+ /* @__PURE__ */ jsx("span", { children: item.label })
27
+ ] }, item.key)) })
28
+ ] });
29
+ }
30
+ function ColumnChooser({ choices, value, onChange, label = "Columns" }) {
31
+ const chosen = new Set(value ? value.split(",").filter(Boolean) : []);
32
+ const isOn = (choice) => chosen.size === 0 ? !choice.optional : chosen.has(choice.key);
33
+ return /* @__PURE__ */ jsx(
34
+ ChooserList,
35
+ {
36
+ label,
37
+ items: choices.map((choice) => ({ key: choice.key, label: choice.label, checked: isOn(choice) })),
38
+ onToggle: (key) => {
39
+ const next = new Set(choices.filter(isOn).map((c) => c.key));
40
+ if (next.has(key)) next.delete(key);
41
+ else next.add(key);
42
+ onChange(
43
+ choices.filter((c) => next.has(c.key)).map((c) => c.key).join(",")
44
+ );
45
+ }
46
+ }
47
+ );
48
+ }
49
+ var LABELS = {
50
+ hiddenToFit: (names) => `Hidden to fit: ${names}`,
51
+ loadMore: "Load more",
52
+ showEveryColumn: "Show every column",
53
+ and: "and"
54
+ };
55
+ function parseGridSort(raw) {
56
+ if (!raw) return null;
57
+ return raw.startsWith("-") ? { key: raw.slice(1), desc: true } : { key: raw, desc: false };
58
+ }
59
+ function headerWord(column) {
60
+ return typeof column.header === "string" ? column.header : "";
61
+ }
62
+ function bandRows(band) {
63
+ return band.bands ? band.bands.flatMap(bandRows) : band.rows;
64
+ }
65
+ function compare(a, b) {
66
+ if (typeof a === "number" && typeof b === "number") {
67
+ if (Number.isNaN(a)) return Number.isNaN(b) ? 0 : 1;
68
+ if (Number.isNaN(b)) return -1;
69
+ return a < b ? -1 : a > b ? 1 : 0;
70
+ }
71
+ return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
72
+ }
73
+ var SHRINK_CAP = "20%";
74
+ var SHRINK_SHARE = 0.2;
75
+ var SQUEEZE_SAMPLE_ROWS = 12;
76
+ var NO_DROPS = [];
77
+ var NO_FIT = { set: "", width: 0, dropped: NO_DROPS };
78
+ function fitGridColumns({
79
+ fit,
80
+ width,
81
+ overflows,
82
+ visible
83
+ }) {
84
+ if (fit.dropped.length > 0 && width > fit.width) {
85
+ return { set: fit.set, width, dropped: NO_DROPS };
86
+ }
87
+ if (overflows) {
88
+ let next;
89
+ for (const c of visible) {
90
+ if (c.drop === void 0) continue;
91
+ if (!next || c.drop < next.drop) next = c;
92
+ }
93
+ if (next) return { set: fit.set, width, dropped: [...fit.dropped, next.key] };
94
+ }
95
+ if (width !== fit.width && (fit.dropped.length > 0 || fit.width === 0)) {
96
+ return { ...fit, width };
97
+ }
98
+ return null;
99
+ }
100
+ function overflowing(wrap) {
101
+ const last = wrap.querySelector(":scope > .crewlet-data-grid__head")?.lastElementChild;
102
+ if (!last) return false;
103
+ const inner = wrap.getBoundingClientRect().left + wrap.clientLeft + wrap.clientWidth;
104
+ return last.getBoundingClientRect().right > inner + 0.5;
105
+ }
106
+ function squeezed(wrap, visible) {
107
+ const heads = wrap.querySelector(":scope > .crewlet-data-grid__head")?.children;
108
+ if (!heads) return false;
109
+ const cap = wrap.clientWidth * SHRINK_SHARE - 1;
110
+ const rows = [...wrap.querySelectorAll(":scope > .crewlet-data-grid__body .crewlet-data-grid__row")].slice(
111
+ 0,
112
+ SQUEEZE_SAMPLE_ROWS
113
+ );
114
+ for (let i = 0; i < visible.length; i++) {
115
+ const column = visible[i];
116
+ if (!column.shrink || column.width) continue;
117
+ const head = heads[i];
118
+ if (!head || head.getBoundingClientRect().width >= cap) continue;
119
+ for (const row of rows) {
120
+ const cell = row.querySelectorAll(":scope > .crewlet-data-grid__cell")[i];
121
+ if (cell && cutShort(cell)) return true;
122
+ }
123
+ }
124
+ return false;
125
+ }
126
+ function cutShort(el) {
127
+ for (const node of [el, ...el.querySelectorAll("*")]) {
128
+ const box = node;
129
+ if (box.clientWidth > 1 && box.scrollWidth > box.clientWidth + 1) return true;
130
+ }
131
+ return false;
132
+ }
133
+ function droppedNames(columns, dropped, and) {
134
+ const names = dropped.map((key) => {
135
+ const c = columns.find((col) => col.key === key);
136
+ return c && (headerWord(c) || c.label) || key;
137
+ });
138
+ return names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} ${and} ${names[names.length - 1]}`;
139
+ }
140
+ function DataGrid({
141
+ rows,
142
+ bands,
143
+ columns,
144
+ rowKey,
145
+ onRowActivate,
146
+ rowHref,
147
+ isSelected,
148
+ isFailed,
149
+ sort: sortRaw = "",
150
+ onSortChange,
151
+ serverSorted = false,
152
+ cols: colsRaw = "",
153
+ onColsChange,
154
+ empty,
155
+ footer,
156
+ onLoadMore,
157
+ loadedNote,
158
+ phoneRows = "labelled",
159
+ flush = false,
160
+ handleRef,
161
+ onPointerDown,
162
+ labels,
163
+ "aria-label": ariaLabel,
164
+ "aria-labelledby": ariaLabelledby,
165
+ className
166
+ }) {
167
+ const text = { ...LABELS, ...labels };
168
+ const sort = parseGridSort(sortRaw);
169
+ const body = useRef(null);
170
+ const [cursor, setCursor] = useState(-1);
171
+ const gridId = useId();
172
+ const shownColumns = useMemo(() => {
173
+ const asked = colsRaw.split(",").map((c) => c.trim()).filter(Boolean);
174
+ if (asked.length === 0) return columns.filter((c) => !c.optional);
175
+ const byKey = new Map(columns.map((c) => [c.key, c]));
176
+ const picked = asked.map((key) => byKey.get(key)).filter((c) => !!c);
177
+ return picked.length > 0 ? picked : columns.filter((c) => !c.optional);
178
+ }, [columns, colsRaw]);
179
+ const [wrap, setWrap] = useState(null);
180
+ const phone = useMediaMatch(`(width < ${breakpoint.phone})`);
181
+ const shownKeys = shownColumns.map((c) => c.key).join(",");
182
+ const [fit, setFit] = useState(NO_FIT);
183
+ const dropped = !phone && fit.set === shownKeys ? fit.dropped : NO_DROPS;
184
+ const visibleColumns = useMemo(
185
+ () => dropped.length === 0 ? shownColumns : shownColumns.filter((c) => !dropped.includes(c.key)),
186
+ [shownColumns, dropped]
187
+ );
188
+ const sortRows = useCallback(
189
+ (input) => {
190
+ if (!sort || serverSorted) return input;
191
+ const column = columns.find((c) => c.key === sort.key);
192
+ if (!column?.sortValue) return input;
193
+ const get = column.sortValue;
194
+ return [...input].sort((a, b) => {
195
+ const av = get(a);
196
+ const bv = get(b);
197
+ if (av == null && bv == null) return 0;
198
+ if (av == null) return 1;
199
+ if (bv == null) return -1;
200
+ const cmp = compare(av, bv);
201
+ return sort.desc ? -cmp : cmp;
202
+ });
203
+ },
204
+ [columns, sort, serverSorted]
205
+ );
206
+ const flat = useMemo(() => {
207
+ const walk = (band) => band.bands ? band.bands.flatMap(walk) : sortRows(band.rows);
208
+ if (bands) return bands.flatMap(walk);
209
+ return sortRows(rows ?? []);
210
+ }, [bands, rows, sortRows]);
211
+ const [boxWidth, setBoxWidth] = useState(0);
212
+ useLayoutEffect(() => {
213
+ if (!wrap || typeof ResizeObserver !== "function") return;
214
+ const watch = new ResizeObserver(() => setBoxWidth(wrap.clientWidth));
215
+ watch.observe(wrap);
216
+ return () => watch.disconnect();
217
+ }, [wrap]);
218
+ useLayoutEffect(() => {
219
+ const el = wrap;
220
+ if (!el || phone) return;
221
+ const next = fitGridColumns({
222
+ fit: fit.set === shownKeys ? fit : { ...NO_FIT, set: shownKeys },
223
+ width: el.clientWidth,
224
+ overflows: overflowing(el) || squeezed(el, visibleColumns),
225
+ visible: visibleColumns
226
+ });
227
+ if (next !== null) setFit(next);
228
+ }, [wrap, phone, fit, shownKeys, visibleColumns, flat, boxWidth]);
229
+ useImperativeHandle(
230
+ handleRef,
231
+ () => ({
232
+ step: (by) => setCursor((at) => {
233
+ const next = Math.max(0, Math.min(flat.length - 1, at + by));
234
+ body.current?.querySelector(`[data-row-index="${next}"]`)?.scrollIntoView({ block: "nearest" });
235
+ return next;
236
+ }),
237
+ activate: (event) => {
238
+ const row = flat[cursor];
239
+ if (row === void 0 || !onRowActivate) return false;
240
+ onRowActivate(row, event);
241
+ return true;
242
+ },
243
+ rowCount: () => flat.length
244
+ }),
245
+ [flat, cursor, onRowActivate]
246
+ );
247
+ function headerClick(column) {
248
+ if (!column.sortValue || !onSortChange) return;
249
+ if (sort?.key === column.key && !sort.desc) onSortChange(`-${column.key}`);
250
+ else if (sort?.key === column.key && sort.desc) onSortChange("");
251
+ else onSortChange(column.key);
252
+ }
253
+ const template = visibleColumns.map((c) => c.width ?? (c.shrink ? `fit-content(${SHRINK_CAP})` : `minmax(${c.floor ?? 0}, 1fr)`)).join(" ");
254
+ if (flat.length === 0 && !bands?.length && empty) {
255
+ return /* @__PURE__ */ jsx("div", { className: cx("crewlet-data-grid", className), "data-flush": flush || void 0, children: /* @__PURE__ */ jsx(
256
+ EmptyState,
257
+ {
258
+ size: "compact",
259
+ icon: empty.icon,
260
+ title: empty.title,
261
+ description: empty.hint,
262
+ action: empty.action
263
+ }
264
+ ) });
265
+ }
266
+ let index = -1;
267
+ function renderRow(row) {
268
+ index += 1;
269
+ const at = index;
270
+ const link = rowHref?.(row);
271
+ const marked = Boolean(isSelected?.(row));
272
+ const rowId = `${gridId}-row-${at}`;
273
+ const overlay = link !== void 0 ? (
274
+ // eslint-disable-next-line jsx-a11y/anchor-has-content
275
+ /* @__PURE__ */ jsx(
276
+ "a",
277
+ {
278
+ className: "crewlet-data-grid__row-link",
279
+ href: link,
280
+ "aria-labelledby": rowId,
281
+ "aria-current": marked ? "true" : void 0,
282
+ onClick: (e) => onRowActivate?.(row, e)
283
+ }
284
+ )
285
+ ) : onRowActivate ? /* @__PURE__ */ jsx(
286
+ "button",
287
+ {
288
+ type: "button",
289
+ className: "crewlet-data-grid__row-link",
290
+ "aria-labelledby": rowId,
291
+ "aria-current": marked ? "true" : void 0,
292
+ onClick: (e) => onRowActivate(row, e)
293
+ }
294
+ ) : null;
295
+ const inner = visibleColumns.map((column, i) => /* @__PURE__ */ jsxs(
296
+ "span",
297
+ {
298
+ role: "cell",
299
+ className: cx(
300
+ "crewlet-data-grid__cell",
301
+ column.align === "right" && "crewlet-data-grid__cell--right",
302
+ column.shrink && "crewlet-data-grid__cell--shrink"
303
+ ),
304
+ "data-lead": column.phoneLead || void 0,
305
+ "data-phone-omit": column.phoneOmit || void 0,
306
+ "data-label": column.action ? void 0 : headerWord(column) || column.label || void 0,
307
+ children: [
308
+ i === 0 ? overlay : null,
309
+ column.cell(row)
310
+ ]
311
+ },
312
+ column.key
313
+ ));
314
+ return /* @__PURE__ */ jsx(
315
+ "div",
316
+ {
317
+ id: rowId,
318
+ role: "row",
319
+ className: cx(
320
+ "crewlet-data-grid__row",
321
+ marked && "crewlet-data-grid__row--selected",
322
+ isFailed?.(row) && "crewlet-data-grid__row--failed",
323
+ cursor === at && "crewlet-data-grid__row--cursor"
324
+ ),
325
+ "data-row-index": at,
326
+ "aria-current": overlay === null && marked ? "true" : void 0,
327
+ children: inner
328
+ },
329
+ rowKey(row)
330
+ );
331
+ }
332
+ function renderBand(band) {
333
+ const loaded = bandRows(band).length;
334
+ return (
335
+ // A BAND IS ROWS OF THE TABLE: its head and its foot are rows of one
336
+ // cell each across every column, and its own box is layout alone.
337
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-data-grid__band", role: "none", children: [
338
+ /* @__PURE__ */ jsx("div", { className: "crewlet-data-grid__band-head", role: "row", children: /* @__PURE__ */ jsxs("span", { className: "crewlet-data-grid__band-cell", role: "rowheader", "aria-colspan": visibleColumns.length, children: [
339
+ band.mark,
340
+ /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__truncate", children: band.label }),
341
+ /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__band-count", children: band.total != null && band.total !== loaded ? `${loaded} of ${band.total}` : loaded })
342
+ ] }) }),
343
+ band.bands ? band.bands.map((sub) => renderBand(sub)) : sortRows(band.rows).map(renderRow),
344
+ band.footer && /* @__PURE__ */ jsx("div", { className: "crewlet-data-grid__band-foot", role: "row", children: /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__band-cell", role: "cell", "aria-colspan": visibleColumns.length, children: band.footer }) })
345
+ ] }, band.key)
346
+ );
347
+ }
348
+ return /* @__PURE__ */ jsxs(
349
+ "div",
350
+ {
351
+ ref: setWrap,
352
+ role: "table",
353
+ "aria-label": ariaLabel,
354
+ "aria-labelledby": ariaLabelledby,
355
+ className: cx("crewlet-data-grid", className),
356
+ "data-phone-rows": phoneRows === "compact" ? "compact" : void 0,
357
+ "data-flush": flush || void 0,
358
+ style: { gridTemplateColumns: template },
359
+ onPointerDown,
360
+ children: [
361
+ /* @__PURE__ */ jsx("div", { className: "crewlet-data-grid__head", role: "row", children: visibleColumns.map((column) => {
362
+ const sorted = sort?.key === column.key;
363
+ const sortable = Boolean(column.sortValue && onSortChange);
364
+ const headClass = cx(
365
+ "crewlet-data-grid__th",
366
+ column.align === "right" && "crewlet-data-grid__th--right",
367
+ column.shrink && "crewlet-data-grid__th--shrink",
368
+ sorted && "crewlet-data-grid__th--sorted",
369
+ !sortable && "crewlet-data-grid__th--plain"
370
+ );
371
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
372
+ /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__truncate", children: column.header }),
373
+ sorted && (sort?.desc ? /* @__PURE__ */ jsx(ChevronDownGlyph, { size: "xs" }) : /* @__PURE__ */ jsx(ChevronUpGlyph, { size: "xs" }))
374
+ ] });
375
+ if (!sortable) {
376
+ const named = !headerWord(column) && !column.action ? column.label : void 0;
377
+ return /* @__PURE__ */ jsxs("div", { className: headClass, role: "columnheader", title: named, children: [
378
+ content,
379
+ named && /* @__PURE__ */ jsx(VisuallyHidden, { children: named })
380
+ ] }, column.key);
381
+ }
382
+ return /* @__PURE__ */ jsx(
383
+ "div",
384
+ {
385
+ className: headClass,
386
+ role: "columnheader",
387
+ "aria-sort": sorted ? sort?.desc ? "descending" : "ascending" : void 0,
388
+ children: /* @__PURE__ */ jsx(
389
+ "button",
390
+ {
391
+ type: "button",
392
+ className: "crewlet-data-grid__sort",
393
+ onClick: () => headerClick(column),
394
+ "aria-label": headerWord(column) ? void 0 : column.label,
395
+ children: content
396
+ }
397
+ )
398
+ },
399
+ column.key
400
+ );
401
+ }) }),
402
+ /* @__PURE__ */ jsx("div", { className: "crewlet-data-grid__body", role: "rowgroup", ref: body, children: bands ? bands.map((band) => renderBand(band)) : sortRows(rows ?? []).map(renderRow) }),
403
+ (footer || onLoadMore || loadedNote || dropped.length > 0) && /* @__PURE__ */ jsxs("div", { className: "crewlet-data-grid__foot", children: [
404
+ footer,
405
+ /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__foot-spacer", "aria-hidden": "true" }),
406
+ dropped.length > 0 && /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__note", children: text.hiddenToFit(droppedNames(shownColumns, dropped, text.and)) }),
407
+ loadedNote && /* @__PURE__ */ jsx("span", { className: "crewlet-data-grid__note", children: loadedNote }),
408
+ onLoadMore && /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", onClick: onLoadMore, children: text.loadMore })
409
+ ] }),
410
+ colsRaw && onColsChange && /* @__PURE__ */ jsx("button", { type: "button", className: "crewlet-data-grid__cols-reset", onClick: () => onColsChange(""), children: text.showEveryColumn })
411
+ ]
412
+ }
413
+ );
414
+ }
415
+
416
+ export { ChooserList, ColumnChooser, DataGrid, columnChoicesOf, fitGridColumns, parseGridSort };
@@ -0,0 +1,21 @@
1
+ import { Text } from './chunk-IKBK4A5O.js';
2
+ import { Inline, Stack, Spacer } from './chunk-ZAC7SKUN.js';
3
+ import { Card } from './chunk-INHXF2CL.js';
4
+ import { cx } from './chunk-ODEQTPFM.js';
5
+ import './RelatedRow-2FVS6QQA.css';
6
+ import { ChevronRightGlyph } from '@crewlethq/icons/glyphs';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ function RelatedRow({ href, icon, title, description, label = "Related", className }) {
10
+ return /* @__PURE__ */ jsx("nav", { "aria-label": label, className: cx("crewlet-related-row", className), children: /* @__PURE__ */ jsx(Card, { href, interactive: true, padding: "sm", children: /* @__PURE__ */ jsxs(Inline, { gap: 3, children: [
11
+ /* @__PURE__ */ jsx("span", { className: "crewlet-related-row__glyph", "aria-hidden": "true", children: icon }),
12
+ /* @__PURE__ */ jsxs(Stack, { gap: 1, children: [
13
+ /* @__PURE__ */ jsx(Text, { variant: "cell", children: title }),
14
+ /* @__PURE__ */ jsx(Text, { variant: "caption", children: description })
15
+ ] }),
16
+ /* @__PURE__ */ jsx(Spacer, {}),
17
+ /* @__PURE__ */ jsx("span", { className: "crewlet-related-row__glyph", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ChevronRightGlyph, { size: "sm" }) })
18
+ ] }) }) });
19
+ }
20
+
21
+ export { RelatedRow };
@@ -50,6 +50,7 @@ export * from '../Container/index.js';
50
50
  export * from '../Copyable/index.js';
51
51
  export * from '../Count/index.js';
52
52
  export * from '../CursorFlag/index.js';
53
+ export * from '../DataGrid/index.js';
53
54
  export * from '../DataTable/index.js';
54
55
  export * from '../DataView/index.js';
55
56
  export * from '../DatasetSource/index.js';
@@ -96,6 +97,7 @@ export * from '../ListInput/index.js';
96
97
  export * from '../Listbox/index.js';
97
98
  export * from '../LiveCursor/index.js';
98
99
  export * from '../LivePreview/index.js';
100
+ export * from '../LockedLabel/index.js';
99
101
  export * from '../Markdown/index.js';
100
102
  export * from '../MarkdownEditor/index.js';
101
103
  export * from '../MediaMatch/index.js';
@@ -111,6 +113,7 @@ export * from '../OrgNode/index.js';
111
113
  export * from '../OrgTable/index.js';
112
114
  export * from '../Outline/index.js';
113
115
  export * from '../PageHeader/index.js';
116
+ export * from '../PageNote/index.js';
114
117
  export * from '../PeopleRail/index.js';
115
118
  export * from '../PinTile/index.js';
116
119
  export * from '../Popover/index.js';
@@ -121,9 +124,11 @@ export * from '../PresenterView/index.js';
121
124
  export * from '../PricingCard/index.js';
122
125
  export * from '../Principal/index.js';
123
126
  export * from '../PrincipalPicker/index.js';
127
+ export * from '../PropertyList/index.js';
124
128
  export * from '../Prose/index.js';
125
129
  export * from '../QrCode/index.js';
126
130
  export * from '../ReadingPane/index.js';
131
+ export * from '../RelatedRow/index.js';
127
132
  export * from '../RelativeTime/index.js';
128
133
  export * from '../Reorder/index.js';
129
134
  export * from '../RichEditor/index.js';
@@ -131,6 +136,7 @@ export * from '../RichEditorMarkdown/index.js';
131
136
  export * from '../SandboxedFrame/index.js';
132
137
  export * from '../SearchTrigger/index.js';
133
138
  export * from '../Section/index.js';
139
+ export * from '../SectionFrame/index.js';
134
140
  export * from '../SegmentedControl/index.js';
135
141
  export * from '../SegmentedMeter/index.js';
136
142
  export * from '../Select/index.js';