@dxos/react-ui-table 0.4.10-main.0302e13 → 0.4.10-main.06ef97a

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 (64) hide show
  1. package/dist/lib/browser/index.mjs +540 -276
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts +19 -0
  5. package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts.map +1 -0
  6. package/dist/types/src/components/{ColumnMenu.stories.d.ts → ColumnMenu/ColumnMenu.stories.d.ts} +5 -1
  7. package/dist/types/src/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -0
  8. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts +11 -0
  9. package/dist/types/src/components/ColumnMenu/ColumnSettingsForm.d.ts.map +1 -0
  10. package/dist/types/src/components/ColumnMenu/index.d.ts +3 -0
  11. package/dist/types/src/components/ColumnMenu/index.d.ts.map +1 -0
  12. package/dist/types/src/components/index.d.ts +1 -1
  13. package/dist/types/src/components/index.d.ts.map +1 -1
  14. package/dist/types/src/helpers.d.ts +4 -0
  15. package/dist/types/src/helpers.d.ts.map +1 -1
  16. package/dist/types/src/hooks/index.d.ts +3 -0
  17. package/dist/types/src/hooks/index.d.ts.map +1 -0
  18. package/dist/types/src/hooks/useColumnSorting.d.ts +9 -0
  19. package/dist/types/src/hooks/useColumnSorting.d.ts.map +1 -0
  20. package/dist/types/src/hooks/usePinLastRow.d.ts.map +1 -0
  21. package/dist/types/src/index.d.ts +2 -1
  22. package/dist/types/src/index.d.ts.map +1 -1
  23. package/dist/types/src/schema/SchemaToTable.stories.d.ts +11 -0
  24. package/dist/types/src/schema/SchemaToTable.stories.d.ts.map +1 -0
  25. package/dist/types/src/schema/index.d.ts +3 -0
  26. package/dist/types/src/schema/index.d.ts.map +1 -0
  27. package/dist/types/src/schema/schema.d.ts +5 -0
  28. package/dist/types/src/schema/schema.d.ts.map +1 -0
  29. package/dist/types/src/schema/schema.test.d.ts +2 -0
  30. package/dist/types/src/schema/schema.test.d.ts.map +1 -0
  31. package/dist/types/src/schema/schemaToColumns.d.ts +4 -0
  32. package/dist/types/src/schema/schemaToColumns.d.ts.map +1 -0
  33. package/dist/types/src/{schema.d.ts → schema/types.d.ts} +1 -1
  34. package/dist/types/src/schema/types.d.ts.map +1 -0
  35. package/package.json +18 -15
  36. package/src/components/ColumnMenu/ColumnMenu.stories.tsx +97 -0
  37. package/src/components/ColumnMenu/ColumnMenu.tsx +166 -0
  38. package/src/components/ColumnMenu/ColumnSettingsForm.tsx +208 -0
  39. package/src/components/ColumnMenu/index.ts +6 -0
  40. package/src/components/Table/Table.tsx +1 -1
  41. package/src/components/index.ts +1 -1
  42. package/src/helpers.tsx +23 -1
  43. package/src/hooks/index.ts +6 -0
  44. package/src/hooks/useColumnSorting.ts +54 -0
  45. package/src/index.ts +3 -1
  46. package/src/schema/SchemaToTable.stories.tsx +72 -0
  47. package/src/schema/index.ts +6 -0
  48. package/src/schema/schema.test.ts +148 -0
  49. package/src/schema/schema.ts +93 -0
  50. package/src/schema/schemaToColumns.ts +47 -0
  51. package/src/theme.ts +1 -1
  52. package/dist/types/src/components/ColumnMenu.d.ts +0 -13
  53. package/dist/types/src/components/ColumnMenu.d.ts.map +0 -1
  54. package/dist/types/src/components/ColumnMenu.stories.d.ts.map +0 -1
  55. package/dist/types/src/components/SortButton.d.ts +0 -8
  56. package/dist/types/src/components/SortButton.d.ts.map +0 -1
  57. package/dist/types/src/components/hooks/usePinLastRow.d.ts.map +0 -1
  58. package/dist/types/src/schema.d.ts.map +0 -1
  59. package/src/components/ColumnMenu.stories.tsx +0 -46
  60. package/src/components/ColumnMenu.tsx +0 -248
  61. package/src/components/SortButton.tsx +0 -34
  62. /package/dist/types/src/{components/hooks → hooks}/usePinLastRow.d.ts +0 -0
  63. /package/src/{components/hooks → hooks}/usePinLastRow.ts +0 -0
  64. /package/src/{schema.ts → schema/types.ts} +0 -0
@@ -1,40 +1,3 @@
1
- // packages/ui/react-ui-table/src/components/ColumnMenu.tsx
2
- import { Check, Trash, X, GearSix } from "@phosphor-icons/react";
3
- import React2, { useRef, useState } from "react";
4
- import { Button as Button2, DensityProvider, Input, Popover, Select, Separator, useTranslation } from "@dxos/react-ui";
5
- import { getSize as getSize2, mx } from "@dxos/react-ui-theme";
6
- import { safeParseInt } from "@dxos/util";
7
-
8
- // packages/ui/react-ui-table/src/components/SortButton.tsx
9
- import { CaretUpDown, SortAscending, SortDescending } from "@phosphor-icons/react";
10
- import React from "react";
11
- import { Button } from "@dxos/react-ui";
12
- import { getSize } from "@dxos/react-ui-theme";
13
- var SortButton = ({ sortDirection, onClick }) => {
14
- let icon;
15
- const size = getSize(4);
16
- switch (sortDirection) {
17
- case "asc":
18
- icon = /* @__PURE__ */ React.createElement(SortAscending, {
19
- className: size
20
- });
21
- break;
22
- case "desc":
23
- icon = /* @__PURE__ */ React.createElement(SortDescending, {
24
- className: size
25
- });
26
- break;
27
- default:
28
- icon = /* @__PURE__ */ React.createElement(CaretUpDown, {
29
- className: size
30
- });
31
- }
32
- return /* @__PURE__ */ React.createElement(Button, {
33
- variant: "ghost",
34
- onClick
35
- }, icon);
36
- };
37
-
38
1
  // packages/ui/react-ui-table/src/translations.ts
39
2
  var translationKey = "table";
40
3
  var translations_default = [
@@ -58,45 +21,103 @@ var translations_default = [
58
21
  }
59
22
  ];
60
23
 
61
- // packages/ui/react-ui-table/src/components/ColumnMenu.tsx
62
- var ColumnMenu = ({ column, ...props }) => {
63
- const title = column.label?.length ? column.label : column.id;
64
- const header = props.context.header;
65
- const canSort = header.column.getCanSort();
66
- const sortDirection = header.column.getIsSorted();
67
- const toggleSort = header.column.getToggleSortingHandler();
68
- return /* @__PURE__ */ React2.createElement("div", {
69
- className: "flex items-center gap-2"
70
- }, /* @__PURE__ */ React2.createElement("div", {
71
- className: "flex-1 min-is-0 truncate",
72
- title
73
- }, title), /* @__PURE__ */ React2.createElement("div", {
74
- className: "flex gap-0"
75
- }, canSort && toggleSort && /* @__PURE__ */ React2.createElement(SortButton, {
76
- sortDirection,
77
- onClick: toggleSort
78
- }), /* @__PURE__ */ React2.createElement(ColumnPanel, {
79
- ...props,
80
- column
81
- })));
24
+ // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
25
+ import { CaretDown } from "@phosphor-icons/react";
26
+ import React, { useCallback, useState } from "react";
27
+ import { Popover, useTranslation } from "@dxos/react-ui";
28
+ import { PopoverCombobox } from "@dxos/react-ui-searchlist";
29
+ import { descriptionText, getSize, mx, staticPlaceholderText } from "@dxos/react-ui-theme";
30
+ var initialItems = (model, value) => value ? {
31
+ [model.getId(value)]: {
32
+ label: model.getText(value),
33
+ data: value
34
+ }
35
+ } : {};
36
+ var CellCombobox = ({ model, value, onValueChange }) => {
37
+ const { t } = useTranslation(translationKey);
38
+ const [items, setItems] = useState(initialItems(model, value));
39
+ const [loading, setLoading] = useState(false);
40
+ const [searchInputValue, setSearchInputValue] = useState("");
41
+ const handleSearchInputValueChange = async (text) => {
42
+ setSearchInputValue(text ?? "");
43
+ setLoading(true);
44
+ const items2 = await model.query(text);
45
+ setItems(items2.reduce((acc, item) => {
46
+ acc[model.getId(item)] = {
47
+ label: model.getText(item),
48
+ data: item
49
+ };
50
+ return acc;
51
+ }, initialItems(model, value)));
52
+ setLoading(false);
53
+ };
54
+ const handleValueChange = useCallback((id) => {
55
+ onValueChange(items[id]?.data);
56
+ }, [
57
+ items,
58
+ onValueChange
59
+ ]);
60
+ return /* @__PURE__ */ React.createElement(PopoverCombobox.Root, {
61
+ placeholder: t("no selection label")
62
+ }, /* @__PURE__ */ React.createElement(PopoverCombobox.Trigger, {
63
+ variant: "ghost",
64
+ classNames: "is-full rounded-none ring-inset"
65
+ }, value ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
66
+ className: mx("font-normal text-start text-base flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
67
+ }, model.getText(value)), /* @__PURE__ */ React.createElement(CaretDown, {
68
+ weight: "bold",
69
+ className: getSize(3)
70
+ })) : null), /* @__PURE__ */ React.createElement(PopoverCombobox.Content, {
71
+ shouldFilter: false,
72
+ classNames: "is-[--radix-popover-trigger-width]"
73
+ }, /* @__PURE__ */ React.createElement(PopoverCombobox.Input, {
74
+ value: searchInputValue,
75
+ onValueChange: handleSearchInputValueChange
76
+ }), /* @__PURE__ */ React.createElement(PopoverCombobox.List, null, searchInputValue.length < 1 ? /* @__PURE__ */ React.createElement("p", {
77
+ className: mx("text-center", descriptionText)
78
+ }, "Start typing to search") : loading ? /* @__PURE__ */ React.createElement("p", {
79
+ className: mx("text-center", descriptionText)
80
+ }, "Searching\u2026") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(PopoverCombobox.Empty, {
81
+ classNames: [
82
+ "text-center",
83
+ descriptionText
84
+ ]
85
+ }, "No results"), Object.entries(items).map(([id, { label }]) => /* @__PURE__ */ React.createElement(PopoverCombobox.Item, {
86
+ key: id,
87
+ value: id,
88
+ onSelect: handleValueChange,
89
+ classNames: "truncate"
90
+ }, label)))), /* @__PURE__ */ React.createElement(Popover.Arrow, null)));
82
91
  };
92
+
93
+ // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnMenu.tsx
94
+ import { X as X2, GearSix, CaretDown as CaretDown2, ArrowDown, ArrowUp } from "@phosphor-icons/react";
95
+ import React3, { useRef as useRef2, useState as useState5, useCallback as useCallback2 } from "react";
96
+ import { Button as Button2, DensityProvider, Popover as Popover2, DropdownMenu } from "@dxos/react-ui";
97
+ import { getSize as getSize3, mx as mx3 } from "@dxos/react-ui-theme";
98
+
99
+ // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnSettingsForm.tsx
100
+ import { Check, Trash, X } from "@phosphor-icons/react";
101
+ import React2, { useRef, useState as useState2 } from "react";
102
+ import { Button, Input, Select, Separator, useTranslation as useTranslation2 } from "@dxos/react-ui";
103
+ import { getSize as getSize2, mx as mx2 } from "@dxos/react-ui-theme";
104
+ import { safeParseInt } from "@dxos/util";
83
105
  var Section = ({ children, className }) => /* @__PURE__ */ React2.createElement("div", {
84
106
  role: "none",
85
- className: mx("p-2", className)
107
+ className: mx2("p-2", className)
86
108
  }, children);
87
- var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete }) => {
88
- const [open, setOpen] = useState(false);
89
- const [prop, setProp] = useState(column.id);
90
- const [refTable, setRefTable] = useState(column.refTable);
91
- const [refProp, setRefProp] = useState(column.refProp);
92
- const [type, setType] = useState(String(column.type));
93
- const [label, setLabel] = useState(column.label);
94
- const [digits, setDigits] = useState(String(column.digits ?? "0"));
109
+ var ColumnSettingsForm = ({ column, tableDef, tableDefs, onUpdate, onDelete, onClose }) => {
110
+ const [prop, setProp] = useState2(column.id);
111
+ const [refTable, setRefTable] = useState2(column.refTable);
112
+ const [refProp, setRefProp] = useState2(column.refProp);
113
+ const [type, setType] = useState2(String(column.type));
114
+ const [label, setLabel] = useState2(column.label);
115
+ const [digits, setDigits] = useState2(String(column.digits ?? "0"));
95
116
  const propRef = useRef(null);
96
- const { t } = useTranslation(translationKey);
117
+ const { t } = useTranslation2(translationKey);
97
118
  const handleCancel = () => {
98
119
  setProp(column.id);
99
- setOpen(false);
120
+ onClose?.();
100
121
  };
101
122
  const handleSave = () => {
102
123
  if (!prop.length || !prop.match(/^[a-zA-Z_].+/i)) {
@@ -119,22 +140,9 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
119
140
  refProp,
120
141
  digits: safeParseInt(digits)
121
142
  });
122
- setOpen(false);
143
+ onClose?.();
123
144
  };
124
- return /* @__PURE__ */ React2.createElement(Popover.Root, {
125
- open,
126
- onOpenChange: (nextOpen) => setOpen(nextOpen)
127
- }, /* @__PURE__ */ React2.createElement(Popover.Trigger, {
128
- asChild: true
129
- }, /* @__PURE__ */ React2.createElement(Button2, {
130
- variant: "ghost"
131
- }, /* @__PURE__ */ React2.createElement(GearSix, {
132
- className: mx(getSize2(4), "rotate-90")
133
- }))), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, null, /* @__PURE__ */ React2.createElement(Popover.Viewport, {
134
- classNames: "w-60"
135
- }, /* @__PURE__ */ React2.createElement(DensityProvider, {
136
- density: "fine"
137
- }, /* @__PURE__ */ React2.createElement("div", {
145
+ return /* @__PURE__ */ React2.createElement("div", {
138
146
  className: "flex flex-col gap-1"
139
147
  }, /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
140
148
  classNames: "mbe-1"
@@ -198,7 +206,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
198
206
  classNames: "mli-2"
199
207
  }), /* @__PURE__ */ React2.createElement(Section, {
200
208
  className: "space-b-1.5"
201
- }, /* @__PURE__ */ React2.createElement(Button2, {
209
+ }, /* @__PURE__ */ React2.createElement(Button, {
202
210
  variant: "primary",
203
211
  classNames: "is-full flex gap-2",
204
212
  onClick: handleSave
@@ -206,7 +214,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
206
214
  className: "grow"
207
215
  }), /* @__PURE__ */ React2.createElement(Check, {
208
216
  className: getSize2(5)
209
- })), /* @__PURE__ */ React2.createElement(Button2, {
217
+ })), /* @__PURE__ */ React2.createElement(Button, {
210
218
  classNames: "is-full flex gap-2",
211
219
  onClick: handleCancel
212
220
  }, /* @__PURE__ */ React2.createElement("span", null, t("cancel label", {
@@ -215,34 +223,241 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
215
223
  className: "grow"
216
224
  }), /* @__PURE__ */ React2.createElement(X, {
217
225
  className: getSize2(5)
218
- })), /* @__PURE__ */ React2.createElement(Button2, {
226
+ })), /* @__PURE__ */ React2.createElement(Button, {
219
227
  classNames: "is-full flex gap-2",
220
228
  onClick: () => onDelete?.(column.id)
221
229
  }, /* @__PURE__ */ React2.createElement("span", null, t("delete label")), /* @__PURE__ */ React2.createElement("div", {
222
230
  className: "grow"
223
231
  }), /* @__PURE__ */ React2.createElement(Trash, {
224
232
  className: getSize2(5)
225
- })))))), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))));
233
+ }))));
234
+ };
235
+
236
+ // packages/ui/react-ui-table/src/hooks/useColumnSorting.ts
237
+ import { useState as useState3 } from "react";
238
+ var useColumnSorting = (column) => {
239
+ const [sortDirection, setSortDirection] = useState3(column.getIsSorted());
240
+ const [firstSort, setFirstSort] = useState3();
241
+ const canSort = column.getCanSort();
242
+ const updateColumnSort = (direction) => {
243
+ setSortDirection(direction);
244
+ switch (direction) {
245
+ case false:
246
+ column.clearSorting();
247
+ break;
248
+ case "asc":
249
+ column.toggleSorting(false);
250
+ break;
251
+ case "desc":
252
+ column.toggleSorting(true);
253
+ break;
254
+ }
255
+ };
256
+ const onToggleSort = () => {
257
+ if (sortDirection === false) {
258
+ return;
259
+ }
260
+ if (sortDirection === firstSort) {
261
+ updateColumnSort(firstSort === "asc" ? "desc" : "asc");
262
+ } else {
263
+ updateColumnSort(false);
264
+ }
265
+ };
266
+ const onSelectSort = (direction) => {
267
+ setFirstSort(direction);
268
+ updateColumnSort(direction);
269
+ };
270
+ const onClearSort = () => {
271
+ updateColumnSort(false);
272
+ };
273
+ return {
274
+ canSort,
275
+ sortDirection,
276
+ onSelectSort,
277
+ onToggleSort,
278
+ onClearSort
279
+ };
280
+ };
281
+
282
+ // packages/ui/react-ui-table/src/hooks/usePinLastRow.ts
283
+ import { useEffect, useState as useState4 } from "react";
284
+ var usePinLastRow = (pinLastRow, table, data, getScrollElement) => {
285
+ const [pinnedRowKey, setPinnedRowKey] = useState4();
286
+ useEffect(() => {
287
+ if (!pinLastRow) {
288
+ return;
289
+ }
290
+ const rows = table.getRowModel().rows;
291
+ const rowToPin = rows[rows.length - 1];
292
+ const rowId = rowToPin.id;
293
+ if (rowId === pinnedRowKey) {
294
+ return;
295
+ }
296
+ table.resetRowPinning();
297
+ rowToPin.pin("bottom");
298
+ const scrollElement = getScrollElement?.();
299
+ const isFirstRender = pinnedRowKey === void 0;
300
+ if (scrollElement && !isFirstRender) {
301
+ requestAnimationFrame(() => {
302
+ scrollElement.scrollTo({
303
+ top: scrollElement.scrollHeight
304
+ });
305
+ });
306
+ }
307
+ setPinnedRowKey(rowId);
308
+ }, [
309
+ pinLastRow,
310
+ table,
311
+ getScrollElement,
312
+ pinnedRowKey,
313
+ setPinnedRowKey,
314
+ data
315
+ ]);
316
+ };
317
+
318
+ // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnMenu.tsx
319
+ var ColumnMenu = ({ column, ...props }) => {
320
+ const title = column.label?.length ? column.label : column.id;
321
+ const header = props.context.header;
322
+ const { canSort, sortDirection, onSelectSort, onToggleSort, onClearSort } = useColumnSorting(header.column);
323
+ const columnSettingsAnchorRef = useRef2(null);
324
+ const [isColumnSettingsOpen, setIsColumnSettingsOpen] = useState5(false);
325
+ const shouldPreventFocusOnClose = useRef2(false);
326
+ const onOpenColumnSettings = useCallback2(() => {
327
+ shouldPreventFocusOnClose.current = true;
328
+ setIsColumnSettingsOpen(true);
329
+ }, [
330
+ shouldPreventFocusOnClose,
331
+ setIsColumnSettingsOpen
332
+ ]);
333
+ const onDropdownCloseAutoFocus = useCallback2((event) => {
334
+ if (shouldPreventFocusOnClose.current) {
335
+ event.preventDefault();
336
+ shouldPreventFocusOnClose.current = false;
337
+ }
338
+ }, [
339
+ shouldPreventFocusOnClose
340
+ ]);
341
+ return /* @__PURE__ */ React3.createElement("div", {
342
+ className: "flex items-center justify-center justify-between"
343
+ }, /* @__PURE__ */ React3.createElement("div", {
344
+ className: "flex items-center gap-1 truncate",
345
+ title
346
+ }, /* @__PURE__ */ React3.createElement(SortIndicator, {
347
+ direction: sortDirection,
348
+ onClick: onToggleSort
349
+ }), /* @__PURE__ */ React3.createElement("div", {
350
+ className: "truncate"
351
+ }, title)), /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
352
+ modal: false
353
+ }, /* @__PURE__ */ React3.createElement(Popover2.Root, {
354
+ open: isColumnSettingsOpen,
355
+ onOpenChange: setIsColumnSettingsOpen,
356
+ modal: false
357
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
358
+ ref: columnSettingsAnchorRef,
359
+ asChild: true
360
+ }, /* @__PURE__ */ React3.createElement(Popover2.Anchor, {
361
+ asChild: true
362
+ }, /* @__PURE__ */ React3.createElement(Button2, {
363
+ variant: "ghost"
364
+ }, /* @__PURE__ */ React3.createElement(CaretDown2, {
365
+ className: getSize3(4)
366
+ })))), /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
367
+ onCloseAutoFocus: onDropdownCloseAutoFocus,
368
+ sideOffset: 4,
369
+ collisionPadding: 8
370
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, canSort && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
371
+ onClick: () => onSelectSort("asc")
372
+ }, /* @__PURE__ */ React3.createElement("span", {
373
+ className: "grow"
374
+ }, "Sort ascending"), /* @__PURE__ */ React3.createElement("span", {
375
+ className: "opacity-50"
376
+ }, /* @__PURE__ */ React3.createElement(ArrowUp, {
377
+ className: getSize3(4)
378
+ }))), /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
379
+ onClick: () => onSelectSort("desc")
380
+ }, /* @__PURE__ */ React3.createElement("span", {
381
+ className: "grow"
382
+ }, "Sort descending"), /* @__PURE__ */ React3.createElement("span", {
383
+ className: "opacity-50"
384
+ }, /* @__PURE__ */ React3.createElement(ArrowDown, {
385
+ className: getSize3(4)
386
+ }))), sortDirection !== false && /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
387
+ onClick: onClearSort
388
+ }, /* @__PURE__ */ React3.createElement("span", {
389
+ className: "grow"
390
+ }, "Clear sort"), /* @__PURE__ */ React3.createElement("span", {
391
+ className: "opacity-50"
392
+ }, /* @__PURE__ */ React3.createElement(X2, {
393
+ className: getSize3(4)
394
+ })))), /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
395
+ onClick: onOpenColumnSettings
396
+ }, /* @__PURE__ */ React3.createElement("span", {
397
+ className: "grow"
398
+ }, "Column settings"), /* @__PURE__ */ React3.createElement("span", {
399
+ className: "opacity-50"
400
+ }, /* @__PURE__ */ React3.createElement(GearSix, {
401
+ className: mx3(getSize3(4), "rotate-90")
402
+ })))), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)), /* @__PURE__ */ React3.createElement(ColumnSettingsPanel, {
403
+ ...props,
404
+ column,
405
+ onClose: () => setIsColumnSettingsOpen(false)
406
+ }))));
407
+ };
408
+ var ColumnSettingsPanel = ({ tableDefs, tableDef, column, onUpdate, onDelete, onClose }) => /* @__PURE__ */ React3.createElement(Popover2.Portal, null, /* @__PURE__ */ React3.createElement(Popover2.Content, null, /* @__PURE__ */ React3.createElement(Popover2.Viewport, {
409
+ classNames: "w-60"
410
+ }, /* @__PURE__ */ React3.createElement(DensityProvider, {
411
+ density: "fine"
412
+ }, /* @__PURE__ */ React3.createElement(ColumnSettingsForm, {
413
+ column,
414
+ tableDefs,
415
+ tableDef,
416
+ onUpdate,
417
+ onDelete,
418
+ onClose
419
+ }))), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null)));
420
+ var SortIndicator = ({ direction, onClick }) => {
421
+ if (direction === false) {
422
+ return null;
423
+ }
424
+ let icon;
425
+ switch (direction) {
426
+ case "asc":
427
+ icon = /* @__PURE__ */ React3.createElement(ArrowUp, {
428
+ className: getSize3(3)
429
+ });
430
+ break;
431
+ case "desc":
432
+ icon = /* @__PURE__ */ React3.createElement(ArrowDown, {
433
+ className: getSize3(3)
434
+ });
435
+ break;
436
+ }
437
+ return /* @__PURE__ */ React3.createElement("div", {
438
+ onClick,
439
+ className: "flex items-center cursor-pointer"
440
+ }, icon);
226
441
  };
227
442
 
228
443
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
229
444
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
230
445
  import { getCoreRowModel, getSortedRowModel, useReactTable, getGroupedRowModel, getExpandedRowModel } from "@tanstack/react-table";
231
446
  import { useVirtualizer } from "@tanstack/react-virtual";
232
- import React8, { Fragment, useCallback, useEffect as useEffect2, useState as useState3 } from "react";
447
+ import React9, { Fragment, useCallback as useCallback3, useEffect as useEffect2, useState as useState6 } from "react";
233
448
  import { log } from "@dxos/log";
234
449
  import { useDefaultValue, useOnTransition } from "@dxos/react-ui";
235
450
 
236
451
  // packages/ui/react-ui-table/src/components/Table/TableBody.tsx
237
452
  import { useArrowNavigationGroup } from "@fluentui/react-tabster";
238
453
  import { flexRender } from "@tanstack/react-table";
239
- import React5 from "react";
454
+ import React6 from "react";
240
455
 
241
456
  // packages/ui/react-ui-table/src/components/Table/TableContext.tsx
242
- import React3, { useContext, createContext } from "react";
457
+ import React4, { useContext, createContext } from "react";
243
458
  var TableContext = /* @__PURE__ */ createContext({});
244
459
  var TableProvider = ({ children, ...value }) => {
245
- return /* @__PURE__ */ React3.createElement(TableContext.Provider, {
460
+ return /* @__PURE__ */ React4.createElement(TableContext.Provider, {
246
461
  value
247
462
  }, children);
248
463
  };
@@ -252,32 +467,32 @@ var useTableContext = () => {
252
467
  };
253
468
 
254
469
  // packages/ui/react-ui-table/src/theme.ts
255
- import { modalSurface, focusRing, ghostSelected, ghostSelectedCurrent, groupBorder, mx as mx2 } from "@dxos/react-ui-theme";
470
+ import { modalSurface, focusRing, ghostSelected, ghostSelectedCurrent, groupBorder, mx as mx4 } from "@dxos/react-ui-theme";
256
471
  var currentRow = "!bg-neutral-75 !dark:bg-neutral-850";
257
472
  var selectedRow = "!bg-primary-100 dark:!bg-primary-700";
258
473
  var flushPadding = "pli-0 plb-0";
259
474
  var textPadding = "pli-2 plb-0.5";
260
475
  var headPadding = "pli-2 plb-1";
261
476
  var gridCellFocusRing = "focus-within:z-[11] focus-within:outline outline-2 outline-primary-500 dark:outline-primary-400";
262
- var tableRoot = ({ fullWidth }, ...etc) => mx2("table-fixed", fullWidth && "is-full", ...etc);
263
- var groupTh = (_props, ...etc) => mx2("text-start font-medium", flushPadding, ...etc);
264
- var theadRoot = ({ header, stickyHeader }, ...etc) => mx2(header ? stickyHeader && "sticky block-start-[--sticky-top] z-[1]" : "collapse", header && "base-surface", "drop-shadow-sm", ...etc);
265
- var theadTr = (_props, ...etc) => mx2("group", ...etc);
266
- var theadTh = ({ border }, ...etc) => mx2("relative", "text-start font-medium select-none truncate", headPadding, border && groupBorder, border && "border border-t-0 border-b-0 border-neutral-200", ...etc);
477
+ var tableRoot = ({ fullWidth }, ...etc) => mx4("table-fixed", fullWidth && "is-full", ...etc);
478
+ var groupTh = (_props, ...etc) => mx4("text-start font-medium", flushPadding, ...etc);
479
+ var theadRoot = ({ header, stickyHeader }, ...etc) => mx4(header ? stickyHeader && "sticky block-start-[--sticky-top] z-[1]" : "collapse", header && "base-surface", "drop-shadow-sm", ...etc);
480
+ var theadTr = (_props, ...etc) => mx4("group", ...etc);
481
+ var theadTh = ({ border }, ...etc) => mx4("relative", "text-start font-medium select-none truncate", headPadding, border && groupBorder, border && "border border-t-0 border-b-0 border-neutral-200", ...etc);
267
482
  var theadResizeRoot = ({ isResizing }) => {
268
- return mx2("absolute h-full w-[4px] top-0 right-0", "cursor-col-resize", "user-select-none", "touch-action-none", !isResizing && "group-hover:bg-neutral-100 dark:group-hover:bg-neutral-800", "pointer-coarse:bg-neutral-100 dark:pointer-coarse:bg-neutral-800", isResizing && "bg-primary-500 dark:bg-primary-400");
483
+ return mx4("absolute h-full w-[4px] top-0 right-0", "cursor-col-resize", "user-select-none", "touch-action-none", !isResizing && "group-hover:bg-neutral-100 dark:group-hover:bg-neutral-800", "pointer-coarse:bg-neutral-100 dark:pointer-coarse:bg-neutral-800", isResizing && "bg-primary-500 dark:bg-primary-400");
269
484
  };
270
- var tbodyRoot = (_props, ...etc) => mx2(...etc);
271
- var tbodyTr = ({ canBeCurrent, isPinned }, ...etc) => mx2("group", canBeCurrent ? ghostSelectedCurrent : ghostSelected, canBeCurrent && focusRing, canBeCurrent && "cursor-pointer rounded", isPinned && "sticky z-[20] bottom-[-1px] base-surface shadow-sm", ...etc);
272
- var tdRoot = ({ border, isGrid }, ...etc) => mx2("relative", flushPadding, border && "border", border && groupBorder, isGrid && gridCellFocusRing, ...etc);
273
- var tdContent = (_props, ...etc) => mx2(...etc);
274
- var tfootRoot = (_props, ...etc) => mx2("sticky block-end-0 z-10", modalSurface, ...etc);
275
- var tfootTr = (_props, ...etc) => mx2(...etc);
276
- var tfootTh = ({ border }, ...etc) => mx2(textPadding, modalSurface, border && groupBorder, ...etc);
485
+ var tbodyRoot = (_props, ...etc) => mx4(...etc);
486
+ var tbodyTr = ({ canBeCurrent, isPinned }, ...etc) => mx4("group", canBeCurrent ? ghostSelectedCurrent : ghostSelected, canBeCurrent && focusRing, canBeCurrent && "cursor-pointer rounded", isPinned && "sticky z-1 bottom-[-1px] base-surface", ...etc);
487
+ var tdRoot = ({ border, isGrid }, ...etc) => mx4("relative", flushPadding, border && "border", border && groupBorder, isGrid && gridCellFocusRing, ...etc);
488
+ var tdContent = (_props, ...etc) => mx4(...etc);
489
+ var tfootRoot = (_props, ...etc) => mx4("sticky block-end-0 z-10", modalSurface, ...etc);
490
+ var tfootTr = (_props, ...etc) => mx4(...etc);
491
+ var tfootTh = ({ border }, ...etc) => mx4(textPadding, modalSurface, border && groupBorder, ...etc);
277
492
 
278
493
  // packages/ui/react-ui-table/src/components/Cell/Cell.tsx
279
494
  import { useFocusableGroup } from "@fluentui/react-tabster";
280
- import React4 from "react";
495
+ import React5 from "react";
281
496
  var CELL_NAME = "Cell";
282
497
  var FocusableCell = ({ cell, children }) => {
283
498
  const tableContext = useTableContext();
@@ -285,7 +500,7 @@ var FocusableCell = ({ cell, children }) => {
285
500
  tabBehavior: "limited"
286
501
  });
287
502
  const className = tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames);
288
- return /* @__PURE__ */ React4.createElement("td", {
503
+ return /* @__PURE__ */ React5.createElement("td", {
289
504
  tabIndex: 0,
290
505
  ...domAttributes,
291
506
  className
@@ -293,14 +508,14 @@ var FocusableCell = ({ cell, children }) => {
293
508
  };
294
509
  var StaticCell = ({ cell, children }) => {
295
510
  const tableContext = useTableContext();
296
- return /* @__PURE__ */ React4.createElement("td", {
511
+ return /* @__PURE__ */ React5.createElement("td", {
297
512
  className: tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames)
298
513
  }, children);
299
514
  };
300
515
  var Cell = ({ cell, children }) => {
301
516
  const { isGrid } = useTableContext();
302
517
  const Root = isGrid ? FocusableCell : StaticCell;
303
- return /* @__PURE__ */ React4.createElement(Root, {
518
+ return /* @__PURE__ */ React5.createElement(Root, {
304
519
  cell
305
520
  }, children);
306
521
  };
@@ -315,7 +530,7 @@ var TableBody = ({ rows }) => {
315
530
  axis: "grid"
316
531
  });
317
532
  const canBeCurrent = !isGrid && !!onDatumClick;
318
- return /* @__PURE__ */ React5.createElement("tbody", isGrid && domAttributes, rows.map((row) => {
533
+ return /* @__PURE__ */ React6.createElement("tbody", isGrid && domAttributes, rows.map((row) => {
319
534
  const isCurrent = currentDatum === row.original;
320
535
  const isSelected = rowSelection?.[row.id];
321
536
  const isPinned = row.getIsPinned();
@@ -323,7 +538,7 @@ var TableBody = ({ rows }) => {
323
538
  canBeCurrent,
324
539
  isPinned: isPinned !== false
325
540
  });
326
- return /* @__PURE__ */ React5.createElement("tr", {
541
+ return /* @__PURE__ */ React6.createElement("tr", {
327
542
  key: keyAccessor ? keyAccessor(row.original) : row.id,
328
543
  className: classNames,
329
544
  ...isCurrent && {
@@ -343,57 +558,57 @@ var TableBody = ({ rows }) => {
343
558
  }
344
559
  }
345
560
  }
346
- }, debug && /* @__PURE__ */ React5.createElement("td", null, row.id), row.getVisibleCells().map((cell) => {
347
- return /* @__PURE__ */ React5.createElement(Cell, {
561
+ }, debug && /* @__PURE__ */ React6.createElement("td", null, row.id), row.getVisibleCells().map((cell) => {
562
+ return /* @__PURE__ */ React6.createElement(Cell, {
348
563
  key: cell.id,
349
564
  cell
350
565
  }, flexRender(cell.column.columnDef.cell, {
351
566
  className: "pli-2",
352
567
  ...cell.getContext()
353
568
  }));
354
- }), expand && /* @__PURE__ */ React5.createElement("td", null));
569
+ }), expand && /* @__PURE__ */ React6.createElement("td", null));
355
570
  }));
356
571
  };
357
572
  TableBody.displayName = TABLE_BODY_NAME;
358
573
 
359
574
  // packages/ui/react-ui-table/src/components/Table/TableFooter.tsx
360
575
  import { flexRender as flexRender2 } from "@tanstack/react-table";
361
- import React6 from "react";
576
+ import React7 from "react";
362
577
  var TABLE_FOOT_NAME = "TableFooter";
363
578
  var TableFooter = (props) => {
364
579
  const tableContext = useTableContext();
365
580
  const { table, expand, debug } = tableContext;
366
581
  const footers = table.getFooterGroups();
367
- return /* @__PURE__ */ React6.createElement("tfoot", {
582
+ return /* @__PURE__ */ React7.createElement("tfoot", {
368
583
  className: tfootRoot(props)
369
- }, footers.map((footerGroup) => /* @__PURE__ */ React6.createElement("tr", {
584
+ }, footers.map((footerGroup) => /* @__PURE__ */ React7.createElement("tr", {
370
585
  key: footerGroup.id,
371
586
  className: tfootTr(tableContext)
372
- }, debug && /* @__PURE__ */ React6.createElement("th", null), footerGroup.headers.map((footer) => {
373
- return /* @__PURE__ */ React6.createElement("th", {
587
+ }, debug && /* @__PURE__ */ React7.createElement("th", null), footerGroup.headers.map((footer) => {
588
+ return /* @__PURE__ */ React7.createElement("th", {
374
589
  key: footer.id,
375
590
  className: tfootTh(tableContext, footer.column.columnDef.meta?.footer?.classNames)
376
591
  }, footer.isPlaceholder ? null : flexRender2(footer.column.columnDef.footer, footer.getContext()));
377
- }), expand && /* @__PURE__ */ React6.createElement("th", null))));
592
+ }), expand && /* @__PURE__ */ React7.createElement("th", null))));
378
593
  };
379
594
  TableFooter.displayName = TABLE_FOOT_NAME;
380
595
 
381
596
  // packages/ui/react-ui-table/src/components/Table/TableHead.tsx
382
597
  import { flexRender as flexRender3 } from "@tanstack/react-table";
383
- import React7 from "react";
598
+ import React8 from "react";
384
599
  var TABLE_HEAD_NAME = "TableHeader";
385
600
  var TableHead = (_props) => {
386
601
  const tableContext = useTableContext();
387
602
  const headerGroups = tableContext.table.getHeaderGroups();
388
- return /* @__PURE__ */ React7.createElement("thead", {
603
+ return /* @__PURE__ */ React8.createElement("thead", {
389
604
  className: theadRoot(tableContext)
390
605
  }, headerGroups.map((headerGroup) => {
391
606
  return (
392
607
  // Group element to hover resize handles.
393
- /* @__PURE__ */ React7.createElement("tr", {
608
+ /* @__PURE__ */ React8.createElement("tr", {
394
609
  key: headerGroup.id,
395
610
  className: theadTr(tableContext)
396
- }, tableContext.debug && /* @__PURE__ */ React7.createElement("th", {
611
+ }, tableContext.debug && /* @__PURE__ */ React8.createElement("th", {
397
612
  className: "font-mono",
398
613
  style: {
399
614
  width: 32
@@ -402,13 +617,13 @@ var TableHead = (_props) => {
402
617
  const isResizing = header.column.getIsResizing();
403
618
  const onResize = header.getResizeHandler();
404
619
  const resizable = header.column.columnDef.meta?.resizable;
405
- return /* @__PURE__ */ React7.createElement("th", {
620
+ return /* @__PURE__ */ React8.createElement("th", {
406
621
  key: header.id,
407
622
  style: {
408
623
  width: header.getSize()
409
624
  },
410
625
  className: theadTh(tableContext, header.column.columnDef.meta?.header?.classNames)
411
- }, !header || header.isPlaceholder ? null : flexRender3(header.column.columnDef.header, header.getContext()), resizable && /* @__PURE__ */ React7.createElement("div", {
626
+ }, !header || header.isPlaceholder ? null : flexRender3(header.column.columnDef.header, header.getContext()), resizable && /* @__PURE__ */ React8.createElement("div", {
412
627
  className: theadResizeRoot({
413
628
  isResizing
414
629
  }),
@@ -416,48 +631,12 @@ var TableHead = (_props) => {
416
631
  onMouseDown: onResize,
417
632
  onTouchStart: onResize
418
633
  }));
419
- }), tableContext.expand && /* @__PURE__ */ React7.createElement("th", null))
634
+ }), tableContext.expand && /* @__PURE__ */ React8.createElement("th", null))
420
635
  );
421
636
  }));
422
637
  };
423
638
  TableHead.displayName = TABLE_HEAD_NAME;
424
639
 
425
- // packages/ui/react-ui-table/src/components/hooks/usePinLastRow.ts
426
- import { useEffect, useState as useState2 } from "react";
427
- var usePinLastRow = (pinLastRow, table, data, getScrollElement) => {
428
- const [pinnedRowKey, setPinnedRowKey] = useState2();
429
- useEffect(() => {
430
- if (!pinLastRow) {
431
- return;
432
- }
433
- const rows = table.getRowModel().rows;
434
- const rowToPin = rows[rows.length - 1];
435
- const rowId = rowToPin.id;
436
- if (rowId === pinnedRowKey) {
437
- return;
438
- }
439
- table.resetRowPinning();
440
- rowToPin.pin("bottom");
441
- const scrollElement = getScrollElement?.();
442
- const isFirstRender = pinnedRowKey === void 0;
443
- if (scrollElement && !isFirstRender) {
444
- requestAnimationFrame(() => {
445
- scrollElement.scrollTo({
446
- top: scrollElement.scrollHeight
447
- });
448
- });
449
- }
450
- setPinnedRowKey(rowId);
451
- }, [
452
- pinLastRow,
453
- table,
454
- getScrollElement,
455
- pinnedRowKey,
456
- setPinnedRowKey,
457
- data
458
- ]);
459
- };
460
-
461
640
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
462
641
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
463
642
  var Table = (props) => {
@@ -465,8 +644,8 @@ var Table = (props) => {
465
644
  const columns = useDefaultValue(props.columns, []);
466
645
  const data = useDefaultValue(props.data, []);
467
646
  const TableProvider2 = TableProvider;
468
- const [columnsInitialised, setColumnsInitialised] = useState3(false);
469
- const [columnSizing, setColumnSizing] = useState3({});
647
+ const [columnsInitialised, setColumnsInitialised] = useState6(false);
648
+ const [columnSizing, setColumnSizing] = useState6({});
470
649
  useEffect2(() => {
471
650
  if (columnsInitialised) {
472
651
  return;
@@ -480,8 +659,8 @@ var Table = (props) => {
480
659
  columns,
481
660
  setColumnSizing
482
661
  ]);
483
- const [columnSizingInfo, setColumnSizingInfo] = useState3({});
484
- const notifyColumnResize = useCallback(() => onColumnResize?.(columnSizing), [
662
+ const [columnSizingInfo, setColumnSizingInfo] = useState6({});
663
+ const notifyColumnResize = useCallback3(() => onColumnResize?.(columnSizing), [
485
664
  onColumnResize,
486
665
  columnSizing
487
666
  ]);
@@ -491,7 +670,7 @@ var Table = (props) => {
491
670
  onChange: props.onRowSelectionChange,
492
671
  defaultProp: props.defaultRowSelection
493
672
  });
494
- const handleRowSelectionChange = useCallback((updaterOrValue) => {
673
+ const handleRowSelectionChange = useCallback3((updaterOrValue) => {
495
674
  const nextRowSelection = typeof updaterOrValue === "function" ? updaterOrValue(rowSelection) : updaterOrValue;
496
675
  if (rowsSelectable === "multi") {
497
676
  setRowSelection(nextRowSelection);
@@ -508,7 +687,7 @@ var Table = (props) => {
508
687
  setRowSelection,
509
688
  rowSelection
510
689
  ]);
511
- const [grouping, handleGroupingChange] = useState3(props.grouping ?? []);
690
+ const [grouping, handleGroupingChange] = useState6(props.grouping ?? []);
512
691
  useEffect2(() => handleGroupingChange(props.grouping ?? []), [
513
692
  handleGroupingChange,
514
693
  props.grouping
@@ -568,13 +747,13 @@ var Table = (props) => {
568
747
  C: (f, a) => f(...a)
569
748
  });
570
749
  }
571
- return /* @__PURE__ */ React8.createElement(TableProvider2, {
750
+ return /* @__PURE__ */ React9.createElement(TableProvider2, {
572
751
  ...props,
573
752
  table,
574
753
  header,
575
754
  expand,
576
755
  isGrid: role === "grid" || role === "treegrid"
577
- }, /* @__PURE__ */ React8.createElement(TableImpl, {
756
+ }, /* @__PURE__ */ React9.createElement(TableImpl, {
578
757
  debug: false,
579
758
  getScrollElement,
580
759
  ...props
@@ -590,13 +769,13 @@ var TableImpl = (props) => {
590
769
  ...bottomRows
591
770
  ];
592
771
  if (debug) {
593
- return /* @__PURE__ */ React8.createElement("pre", {
772
+ return /* @__PURE__ */ React9.createElement("pre", {
594
773
  className: "font-mono text-xs text-neutral-500 m-1 p-2 ring"
595
- }, /* @__PURE__ */ React8.createElement("code", null, JSON.stringify(table.getState(), void 0, 2)));
774
+ }, /* @__PURE__ */ React9.createElement("code", null, JSON.stringify(table.getState(), void 0, 2)));
596
775
  }
597
776
  const virtualisable = getScrollElement !== void 0;
598
777
  const isResizingColumn = table.getState().columnSizingInfo.isResizingColumn;
599
- return /* @__PURE__ */ React8.createElement("table", {
778
+ return /* @__PURE__ */ React9.createElement("table", {
600
779
  role,
601
780
  className: tableRoot(props, classNames),
602
781
  ...!fullWidth && {
@@ -604,13 +783,13 @@ var TableImpl = (props) => {
604
783
  width: table.getTotalSize()
605
784
  }
606
785
  }
607
- }, /* @__PURE__ */ React8.createElement(TableHead, null), grouping?.length !== 0 ? virtualisable ? isResizingColumn ? /* @__PURE__ */ React8.createElement(MemoizedVirtualisedTableContent, {
786
+ }, /* @__PURE__ */ React9.createElement(TableHead, null), grouping?.length !== 0 ? virtualisable ? isResizingColumn ? /* @__PURE__ */ React9.createElement(MemoizedVirtualisedTableContent, {
608
787
  getScrollElement
609
- }) : /* @__PURE__ */ React8.createElement(VirtualizedTableContent, {
788
+ }) : /* @__PURE__ */ React9.createElement(VirtualizedTableContent, {
610
789
  getScrollElement
611
- }) : /* @__PURE__ */ React8.createElement(TableBody, {
790
+ }) : /* @__PURE__ */ React9.createElement(TableBody, {
612
791
  rows
613
- }) : /* @__PURE__ */ React8.createElement(GroupedTableContent, null), footer && /* @__PURE__ */ React8.createElement(TableFooter, null));
792
+ }) : /* @__PURE__ */ React9.createElement(GroupedTableContent, null), footer && /* @__PURE__ */ React9.createElement(TableFooter, null));
614
793
  };
615
794
  var VirtualizedTableContent = ({ getScrollElement }) => {
616
795
  const { table } = useTableContext();
@@ -630,123 +809,54 @@ var VirtualizedTableContent = ({ getScrollElement }) => {
630
809
  ...virtualRows.map((virtualRow) => centerRows[virtualRow.index]),
631
810
  ...pinnedRows
632
811
  ];
633
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, paddingTop > 0 && /* @__PURE__ */ React8.createElement("tbody", {
812
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, paddingTop > 0 && /* @__PURE__ */ React9.createElement("tbody", {
634
813
  role: "none"
635
- }, /* @__PURE__ */ React8.createElement("tr", {
814
+ }, /* @__PURE__ */ React9.createElement("tr", {
636
815
  role: "none"
637
- }, /* @__PURE__ */ React8.createElement("td", {
816
+ }, /* @__PURE__ */ React9.createElement("td", {
638
817
  style: {
639
818
  height: `${paddingTop}px`
640
819
  },
641
820
  role: "none"
642
- }))), /* @__PURE__ */ React8.createElement(TableBody, {
821
+ }))), /* @__PURE__ */ React9.createElement(TableBody, {
643
822
  rows: rowsToRender
644
- }), paddingBottom > 0 && /* @__PURE__ */ React8.createElement("tbody", {
823
+ }), paddingBottom > 0 && /* @__PURE__ */ React9.createElement("tbody", {
645
824
  role: "none"
646
- }, /* @__PURE__ */ React8.createElement("tr", {
825
+ }, /* @__PURE__ */ React9.createElement("tr", {
647
826
  role: "none"
648
- }, /* @__PURE__ */ React8.createElement("td", {
827
+ }, /* @__PURE__ */ React9.createElement("td", {
649
828
  style: {
650
829
  height: `${paddingBottom}px`
651
830
  },
652
831
  role: "none"
653
832
  }))));
654
833
  };
655
- var MemoizedVirtualisedTableContent = /* @__PURE__ */ React8.memo(VirtualizedTableContent);
834
+ var MemoizedVirtualisedTableContent = /* @__PURE__ */ React9.memo(VirtualizedTableContent);
656
835
  var GroupedTableContent = () => {
657
836
  const { table: { getGroupedRowModel: getGroupedRowModel2, getHeaderGroups, getState }, debug } = useTableContext();
658
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, getGroupedRowModel2().rows.map((row, i) => {
659
- return /* @__PURE__ */ React8.createElement(Fragment, {
837
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, getGroupedRowModel2().rows.map((row, i) => {
838
+ return /* @__PURE__ */ React9.createElement(Fragment, {
660
839
  key: i
661
- }, /* @__PURE__ */ React8.createElement("thead", null, /* @__PURE__ */ React8.createElement("tr", null, debug && /* @__PURE__ */ React8.createElement("th", null), /* @__PURE__ */ React8.createElement("th", {
840
+ }, /* @__PURE__ */ React9.createElement("thead", null, /* @__PURE__ */ React9.createElement("tr", null, debug && /* @__PURE__ */ React9.createElement("th", null), /* @__PURE__ */ React9.createElement("th", {
662
841
  // TODO(burdon): Calculate row span.
663
842
  colSpan: getHeaderGroups()[0].headers.length,
664
843
  className: groupTh({})
665
- }, getState().grouping[0], "[", String(row.getGroupingValue(getState().grouping[0])), "]"))), /* @__PURE__ */ React8.createElement(TableBody, {
844
+ }, getState().grouping[0], "[", String(row.getGroupingValue(getState().grouping[0])), "]"))), /* @__PURE__ */ React9.createElement(TableBody, {
666
845
  rows: row.subRows
667
846
  }));
668
847
  }));
669
848
  };
670
849
 
671
- // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
672
- import { CaretDown } from "@phosphor-icons/react";
673
- import React9, { useCallback as useCallback2, useState as useState4 } from "react";
674
- import { Popover as Popover2, useTranslation as useTranslation2 } from "@dxos/react-ui";
675
- import { PopoverCombobox } from "@dxos/react-ui-searchlist";
676
- import { descriptionText, getSize as getSize3, mx as mx3, staticPlaceholderText } from "@dxos/react-ui-theme";
677
- var initialItems = (model, value) => value ? {
678
- [model.getId(value)]: {
679
- label: model.getText(value),
680
- data: value
681
- }
682
- } : {};
683
- var CellCombobox = ({ model, value, onValueChange }) => {
684
- const { t } = useTranslation2(translationKey);
685
- const [items, setItems] = useState4(initialItems(model, value));
686
- const [loading, setLoading] = useState4(false);
687
- const [searchInputValue, setSearchInputValue] = useState4("");
688
- const handleSearchInputValueChange = async (text) => {
689
- setSearchInputValue(text ?? "");
690
- setLoading(true);
691
- const items2 = await model.query(text);
692
- setItems(items2.reduce((acc, item) => {
693
- acc[model.getId(item)] = {
694
- label: model.getText(item),
695
- data: item
696
- };
697
- return acc;
698
- }, initialItems(model, value)));
699
- setLoading(false);
700
- };
701
- const handleValueChange = useCallback2((id) => {
702
- onValueChange(items[id]?.data);
703
- }, [
704
- items,
705
- onValueChange
706
- ]);
707
- return /* @__PURE__ */ React9.createElement(PopoverCombobox.Root, {
708
- placeholder: t("no selection label")
709
- }, /* @__PURE__ */ React9.createElement(PopoverCombobox.Trigger, {
710
- variant: "ghost",
711
- classNames: "is-full rounded-none ring-inset"
712
- }, value ? /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement("span", {
713
- className: mx3("font-normal text-start text-base flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
714
- }, model.getText(value)), /* @__PURE__ */ React9.createElement(CaretDown, {
715
- weight: "bold",
716
- className: getSize3(3)
717
- })) : null), /* @__PURE__ */ React9.createElement(PopoverCombobox.Content, {
718
- shouldFilter: false,
719
- classNames: "is-[--radix-popover-trigger-width]"
720
- }, /* @__PURE__ */ React9.createElement(PopoverCombobox.Input, {
721
- value: searchInputValue,
722
- onValueChange: handleSearchInputValueChange
723
- }), /* @__PURE__ */ React9.createElement(PopoverCombobox.List, null, searchInputValue.length < 1 ? /* @__PURE__ */ React9.createElement("p", {
724
- className: mx3("text-center", descriptionText)
725
- }, "Start typing to search") : loading ? /* @__PURE__ */ React9.createElement("p", {
726
- className: mx3("text-center", descriptionText)
727
- }, "Searching\u2026") : /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(PopoverCombobox.Empty, {
728
- classNames: [
729
- "text-center",
730
- descriptionText
731
- ]
732
- }, "No results"), Object.entries(items).map(([id, { label }]) => /* @__PURE__ */ React9.createElement(PopoverCombobox.Item, {
733
- key: id,
734
- value: id,
735
- onSelect: handleValueChange,
736
- classNames: "truncate"
737
- }, label)))), /* @__PURE__ */ React9.createElement(Popover2.Arrow, null)));
738
- };
739
-
740
850
  // packages/ui/react-ui-table/src/helpers.tsx
741
851
  import { useFocusFinders } from "@fluentui/react-tabster";
742
- import { Check as Check2, ClipboardText, X as X2 } from "@phosphor-icons/react";
852
+ import { Check as Check2, ClipboardText, X as X3 } from "@phosphor-icons/react";
743
853
  import { createColumnHelper } from "@tanstack/react-table";
744
854
  import { format } from "date-fns/format";
745
855
  import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
746
- import React10, { useEffect as useEffect3, useRef as useRef2, useState as useState5 } from "react";
856
+ import React10, { useEffect as useEffect3, useRef as useRef3, useState as useState7 } from "react";
747
857
  import { log as log2 } from "@dxos/log";
748
858
  import { Input as Input2, Tooltip } from "@dxos/react-ui";
749
- import { getSize as getSize4, mx as mx4 } from "@dxos/react-ui-theme";
859
+ import { getSize as getSize4, mx as mx5 } from "@dxos/react-ui-theme";
750
860
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/helpers.tsx";
751
861
  var createColumnBuilder = () => ({
752
862
  helper: createColumnHelper(),
@@ -761,11 +871,11 @@ var ComboboxBuilderCell = (cellContext) => {
761
871
  }) : null;
762
872
  };
763
873
  var StringBuilderCell = (cellContext) => {
764
- const ref = useRef2(null);
874
+ const ref = useRef3(null);
765
875
  const { findPrevFocusable } = useFocusFinders();
766
876
  const { onUpdate, cell } = cellContext.column.columnDef.meta;
767
877
  const initialValue = cellContext.getValue();
768
- const [value, setValue] = useState5(() => {
878
+ const [value, setValue] = useState7(() => {
769
879
  if (initialValue?.content) {
770
880
  return initialValue?.content;
771
881
  }
@@ -807,9 +917,9 @@ var displayNumber = (value, digits) => value || value === 0 ? value.toLocaleStri
807
917
  var NumberBuilderCell = (cellContext) => {
808
918
  const { onUpdate, digits } = cellContext.column.columnDef.meta;
809
919
  const value = cellContext.getValue();
810
- const [text, setText] = useState5(displayNumber(value, digits));
920
+ const [text, setText] = useState7(displayNumber(value, digits));
811
921
  const { findPrevFocusable } = useFocusFinders();
812
- const ref = useRef2(null);
922
+ const ref = useRef3(null);
813
923
  useEffect3(() => {
814
924
  (!document.activeElement || document.activeElement !== ref.current) && setText(displayNumber(value, digits));
815
925
  }, [
@@ -897,7 +1007,7 @@ var ColumnBuilder = class {
897
1007
  cell: model && onUpdate ? ComboboxBuilderCell : (cellContext) => {
898
1008
  const cellValue = cellContext.getValue();
899
1009
  return /* @__PURE__ */ React10.createElement("div", {
900
- className: mx4("truncate", classNames)
1010
+ className: mx5("truncate", classNames)
901
1011
  }, cellValue ? model?.getText(cellValue) : "");
902
1012
  },
903
1013
  ...props,
@@ -928,7 +1038,7 @@ var ColumnBuilder = class {
928
1038
  value = value.content;
929
1039
  }
930
1040
  return /* @__PURE__ */ React10.createElement("div", {
931
- className: mx4("truncate", textPadding, classNames)
1041
+ className: mx5("truncate", textPadding, classNames)
932
1042
  }, value);
933
1043
  },
934
1044
  ...props,
@@ -957,7 +1067,6 @@ var ColumnBuilder = class {
957
1067
  onUpdate,
958
1068
  digits,
959
1069
  header: {
960
- classNames: "text-end",
961
1070
  ...props.meta?.header
962
1071
  },
963
1072
  cell: {
@@ -983,7 +1092,7 @@ var ColumnBuilder = class {
983
1092
  addSuffix: true
984
1093
  }) : value.toISOString() : void 0;
985
1094
  return /* @__PURE__ */ React10.createElement("div", {
986
- className: mx4(textPadding, classNames)
1095
+ className: mx5(textPadding, classNames)
987
1096
  }, str);
988
1097
  } catch (err) {
989
1098
  log2.info("formatError", {
@@ -1110,7 +1219,7 @@ var ColumnBuilder = class {
1110
1219
  */
1111
1220
  icon({ label, size, on, off, ...props } = {}) {
1112
1221
  const IconOn = on?.Icon ?? Check2;
1113
- const IconOff = off?.Icon ?? X2;
1222
+ const IconOff = off?.Icon ?? X3;
1114
1223
  return {
1115
1224
  size: size ?? 32,
1116
1225
  // TODO(Zan): Implement sort algorithm
@@ -1122,11 +1231,11 @@ var ColumnBuilder = class {
1122
1231
  const value = cell.getValue();
1123
1232
  if (value) {
1124
1233
  return /* @__PURE__ */ React10.createElement(IconOn, {
1125
- className: mx4("block mli-auto", getSize4(6), on?.className ?? "text-green-700")
1234
+ className: mx5("block mli-auto", getSize4(6), on?.className ?? "text-green-700")
1126
1235
  });
1127
1236
  } else if (value === false) {
1128
1237
  return /* @__PURE__ */ React10.createElement(IconOff, {
1129
- className: mx4("block mli-auto", getSize4(6), off?.className ?? "text-red-700")
1238
+ className: mx5("block mli-auto", getSize4(6), off?.className ?? "text-red-700")
1130
1239
  });
1131
1240
  } else {
1132
1241
  return null;
@@ -1135,13 +1244,165 @@ var ColumnBuilder = class {
1135
1244
  ...props
1136
1245
  };
1137
1246
  }
1247
+ /**
1248
+ * This display column type is for nested/unhandled data to appear as JSON.
1249
+ */
1250
+ display({ label, classNames, ...props } = {}) {
1251
+ return {
1252
+ size: 120,
1253
+ minSize: 120,
1254
+ header: (cell) => label ?? cell.header.id,
1255
+ cell: (cell) => {
1256
+ const value = cell.getValue();
1257
+ return /* @__PURE__ */ React10.createElement("div", {
1258
+ className: "overflow-scroll"
1259
+ }, /* @__PURE__ */ React10.createElement("code", {
1260
+ className: "text-xs"
1261
+ }, JSON.stringify(value)));
1262
+ },
1263
+ ...props,
1264
+ meta: {
1265
+ ...props.meta,
1266
+ cell: {
1267
+ ...props.meta?.cell,
1268
+ classNames: [
1269
+ "font-mono",
1270
+ textPadding,
1271
+ classNames
1272
+ ]
1273
+ }
1274
+ }
1275
+ };
1276
+ }
1277
+ };
1278
+
1279
+ // packages/ui/react-ui-table/src/schema/schema.ts
1280
+ import { AST } from "@effect/schema";
1281
+ var isOptionalUnion = (prop) => AST.isUnion(prop.type) && prop.isOptional;
1282
+ var unwrapOptionProperty = (prop) => {
1283
+ if (!isOptionalUnion(prop)) {
1284
+ throw new Error("Not an optional property");
1285
+ }
1286
+ if (!AST.isUnion(prop.type)) {
1287
+ throw new Error("Not a union type");
1288
+ }
1289
+ const [type, _undefinedCase] = prop.type.types;
1290
+ return type;
1291
+ };
1292
+ var typeToColumn = (type) => {
1293
+ if (AST.isStringKeyword(type)) {
1294
+ return "string";
1295
+ } else if (AST.isNumberKeyword(type)) {
1296
+ return "number";
1297
+ } else if (AST.isBooleanKeyword(type)) {
1298
+ return "boolean";
1299
+ }
1300
+ if (AST.isRefinement(type)) {
1301
+ return typeToColumn(type.from);
1302
+ }
1303
+ if (AST.isTransform(type)) {
1304
+ const identifier = AST.getIdentifierAnnotation(type);
1305
+ if (identifier._tag === "Some") {
1306
+ if (identifier.value === "DateFromString") {
1307
+ return "date";
1308
+ }
1309
+ }
1310
+ }
1311
+ return "display";
1312
+ };
1313
+ var propertyToColumn = (property) => {
1314
+ let type = property.type;
1315
+ if (property.isOptional) {
1316
+ type = unwrapOptionProperty(property);
1317
+ }
1318
+ return typeToColumn(type);
1319
+ };
1320
+ var isStruct = (node) => AST.isTypeLiteral(node);
1321
+ var classifySchemaProperties = (schema) => {
1322
+ const recurse = (node, path, acc) => {
1323
+ const properties = AST.getPropertySignatures(node);
1324
+ properties.forEach((prop) => {
1325
+ const propName = prop.name.toString();
1326
+ if (prop.isOptional) {
1327
+ const unwrappedAst = unwrapOptionProperty(prop);
1328
+ if (isStruct(unwrappedAst)) {
1329
+ return recurse(unwrappedAst, [
1330
+ ...path,
1331
+ propName
1332
+ ], acc);
1333
+ }
1334
+ }
1335
+ if (isStruct(prop.type)) {
1336
+ recurse(prop.type, [
1337
+ ...path,
1338
+ propName
1339
+ ], acc);
1340
+ } else {
1341
+ acc.push([
1342
+ path.concat(propName).join("."),
1343
+ propertyToColumn(prop)
1344
+ ]);
1345
+ }
1346
+ });
1347
+ return acc;
1348
+ };
1349
+ return recurse(schema.ast, [], []);
1350
+ };
1351
+
1352
+ // packages/ui/react-ui-table/src/schema/schemaToColumns.ts
1353
+ var schemaToColumnDefs = (schema) => {
1354
+ const { helper, builder } = createColumnBuilder();
1355
+ const classified = classifySchemaProperties(schema);
1356
+ return classified.map(([name, type]) => {
1357
+ const propertyKey = name.toString();
1358
+ let column;
1359
+ switch (type) {
1360
+ case "string": {
1361
+ column = builder.string({
1362
+ label: propertyKey
1363
+ });
1364
+ break;
1365
+ }
1366
+ case "number": {
1367
+ column = builder.number({
1368
+ label: propertyKey
1369
+ });
1370
+ break;
1371
+ }
1372
+ case "boolean": {
1373
+ column = builder.switch({
1374
+ label: propertyKey
1375
+ });
1376
+ break;
1377
+ }
1378
+ case "date": {
1379
+ column = builder.date({
1380
+ label: propertyKey
1381
+ });
1382
+ break;
1383
+ }
1384
+ case "display": {
1385
+ column = builder.display({
1386
+ label: propertyKey,
1387
+ id: propertyKey
1388
+ });
1389
+ break;
1390
+ }
1391
+ default: {
1392
+ throw new Error(`Unhandled column type: ${type}`);
1393
+ }
1394
+ }
1395
+ return helper.accessor(propertyKey, column);
1396
+ });
1138
1397
  };
1139
1398
  export {
1140
1399
  CellCombobox,
1141
1400
  ColumnBuilder,
1142
1401
  ColumnMenu,
1143
- ColumnPanel,
1402
+ ColumnSettingsForm,
1403
+ ColumnSettingsPanel,
1144
1404
  MemoizedVirtualisedTableContent,
1405
+ SortIndicator,
1145
1406
  Table,
1146
1407
  createColumnBuilder,
1147
1408
  currentRow,
@@ -1149,6 +1410,7 @@ export {
1149
1410
  gridCellFocusRing,
1150
1411
  groupTh,
1151
1412
  headPadding,
1413
+ schemaToColumnDefs,
1152
1414
  selectedRow,
1153
1415
  tableRoot,
1154
1416
  tbodyRoot,
@@ -1163,6 +1425,8 @@ export {
1163
1425
  theadRoot,
1164
1426
  theadTh,
1165
1427
  theadTr,
1166
- translations_default as translations
1428
+ translations_default as translations,
1429
+ useColumnSorting,
1430
+ usePinLastRow
1167
1431
  };
1168
1432
  //# sourceMappingURL=index.mjs.map