@dxos/react-ui-table 0.4.9 → 0.4.10-main.068c3d8

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 (71) hide show
  1. package/dist/lib/browser/index.mjs +632 -293
  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} +10 -2
  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/Table/Table.d.ts.map +1 -1
  13. package/dist/types/src/components/Table/Table.stories.d.ts +6 -0
  14. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/Table/TableBody.d.ts.map +1 -1
  16. package/dist/types/src/components/index.d.ts +1 -1
  17. package/dist/types/src/components/index.d.ts.map +1 -1
  18. package/dist/types/src/helpers.d.ts +4 -0
  19. package/dist/types/src/helpers.d.ts.map +1 -1
  20. package/dist/types/src/hooks/index.d.ts +3 -0
  21. package/dist/types/src/hooks/index.d.ts.map +1 -0
  22. package/dist/types/src/hooks/useColumnSorting.d.ts +9 -0
  23. package/dist/types/src/hooks/useColumnSorting.d.ts.map +1 -0
  24. package/dist/types/src/hooks/usePinLastRow.d.ts +3 -0
  25. package/dist/types/src/hooks/usePinLastRow.d.ts.map +1 -0
  26. package/dist/types/src/index.d.ts +2 -1
  27. package/dist/types/src/index.d.ts.map +1 -1
  28. package/dist/types/src/schema/SchemaToTable.stories.d.ts +11 -0
  29. package/dist/types/src/schema/SchemaToTable.stories.d.ts.map +1 -0
  30. package/dist/types/src/schema/index.d.ts +3 -0
  31. package/dist/types/src/schema/index.d.ts.map +1 -0
  32. package/dist/types/src/schema/schema.d.ts +5 -0
  33. package/dist/types/src/schema/schema.d.ts.map +1 -0
  34. package/dist/types/src/schema/schema.test.d.ts +2 -0
  35. package/dist/types/src/schema/schema.test.d.ts.map +1 -0
  36. package/dist/types/src/schema/schemaToColumns.d.ts +4 -0
  37. package/dist/types/src/schema/schemaToColumns.d.ts.map +1 -0
  38. package/dist/types/src/{schema.d.ts → schema/types.d.ts} +1 -1
  39. package/dist/types/src/schema/types.d.ts.map +1 -0
  40. package/dist/types/src/theme.d.ts +1 -0
  41. package/dist/types/src/theme.d.ts.map +1 -1
  42. package/package.json +19 -16
  43. package/src/components/ColumnMenu/ColumnMenu.stories.tsx +127 -0
  44. package/src/components/ColumnMenu/ColumnMenu.tsx +166 -0
  45. package/src/components/ColumnMenu/ColumnSettingsForm.tsx +214 -0
  46. package/src/components/ColumnMenu/index.ts +6 -0
  47. package/src/components/Table/Table.stories.tsx +89 -3
  48. package/src/components/Table/Table.tsx +28 -22
  49. package/src/components/Table/TableBody.tsx +6 -1
  50. package/src/components/index.ts +1 -1
  51. package/src/helpers.tsx +23 -1
  52. package/src/hooks/index.ts +6 -0
  53. package/src/hooks/useColumnSorting.ts +54 -0
  54. package/src/hooks/usePinLastRow.ts +64 -0
  55. package/src/index.ts +3 -1
  56. package/src/schema/SchemaToTable.stories.tsx +72 -0
  57. package/src/schema/index.ts +6 -0
  58. package/src/schema/schema.test.ts +148 -0
  59. package/src/schema/schema.ts +92 -0
  60. package/src/schema/schemaToColumns.ts +48 -0
  61. package/src/theme.ts +3 -2
  62. package/dist/types/src/components/ColumnMenu.d.ts +0 -13
  63. package/dist/types/src/components/ColumnMenu.d.ts.map +0 -1
  64. package/dist/types/src/components/ColumnMenu.stories.d.ts.map +0 -1
  65. package/dist/types/src/components/SortButton.d.ts +0 -8
  66. package/dist/types/src/components/SortButton.d.ts.map +0 -1
  67. package/dist/types/src/schema.d.ts.map +0 -1
  68. package/src/components/ColumnMenu.stories.tsx +0 -46
  69. package/src/components/ColumnMenu.tsx +0 -248
  70. package/src/components/SortButton.tsx +0 -34
  71. /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,47 +21,107 @@ 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 useCallback3 } 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 [formState, setFormState] = useState2({
111
+ prop: column.id,
112
+ refTable: column.refTable,
113
+ refProp: column.refProp,
114
+ type: String(column.type),
115
+ label: column.label,
116
+ digits: String(column.digits ?? "0")
117
+ });
95
118
  const propRef = useRef(null);
96
- const { t } = useTranslation(translationKey);
119
+ const { t } = useTranslation2(translationKey);
97
120
  const handleCancel = () => {
98
- setProp(column.id);
99
- setOpen(false);
121
+ onClose?.();
100
122
  };
101
123
  const handleSave = () => {
124
+ const { prop, refTable, refProp, type, label, digits } = formState;
102
125
  if (!prop.length || !prop.match(/^[a-zA-Z_].+/i)) {
103
126
  propRef.current?.focus();
104
127
  return;
@@ -110,7 +133,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
110
133
  return;
111
134
  }
112
135
  }
113
- onUpdate?.(prop, {
136
+ onUpdate?.(column.id, {
114
137
  id: prop,
115
138
  prop,
116
139
  label,
@@ -119,43 +142,38 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
119
142
  refProp,
120
143
  digits: safeParseInt(digits)
121
144
  });
122
- setOpen(false);
145
+ onClose?.();
123
146
  };
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", {
147
+ return /* @__PURE__ */ React2.createElement("div", {
138
148
  className: "flex flex-col gap-1"
139
149
  }, /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
140
150
  classNames: "mbe-1"
141
151
  }, t("column label label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
142
152
  placeholder: "Column label",
143
- value: label ?? "",
144
- onChange: (event) => setLabel(event.target.value),
153
+ value: formState.label ?? "",
154
+ onChange: (event) => setFormState((prevState) => ({
155
+ ...prevState,
156
+ label: event.target.value
157
+ })),
145
158
  autoFocus: true
146
159
  })), /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
147
160
  classNames: "mbe-1 mbs-3"
148
161
  }, t("property key label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
149
162
  ref: propRef,
150
163
  placeholder: "Property key",
151
- // TODO(burdon): Provide hooks for value normalization, ENTER, ESC, etc.
152
- value: prop ?? "",
153
- onChange: (event) => setProp(event.target.value.replace(/[^\w_]/g, ""))
164
+ value: formState.prop ?? "",
165
+ onChange: (event) => setFormState((prevState) => ({
166
+ ...prevState,
167
+ prop: event.target.value.replace(/[^\w_]/g, "")
168
+ }))
154
169
  })), /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
155
170
  classNames: "mbe-1 mbs-3"
156
171
  }, t("column type label")), /* @__PURE__ */ React2.createElement(Select.Root, {
157
- value: type,
158
- onValueChange: setType
172
+ value: formState.type,
173
+ onValueChange: (value) => setFormState((prevState) => ({
174
+ ...prevState,
175
+ type: value
176
+ }))
159
177
  }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
160
178
  placeholder: "Type",
161
179
  classNames: "is-full"
@@ -164,41 +182,50 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
164
182
  "boolean",
165
183
  "string",
166
184
  "ref"
167
- ].map((type2) => /* @__PURE__ */ React2.createElement(Select.Option, {
168
- key: type2,
169
- value: type2
170
- }, t(`${type2} column type label`))))))))), type === "number" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
185
+ ].map((type) => /* @__PURE__ */ React2.createElement(Select.Option, {
186
+ key: type,
187
+ value: type
188
+ }, t(`${type} column type label`))))))))), formState.type === "number" && /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
171
189
  classNames: "mbe-1 mbs-3"
172
190
  }, t("digits label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
173
- value: digits ?? "",
174
- onChange: (event) => setDigits(event.target.value)
175
- })))), type === "ref" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
191
+ value: formState.digits ?? "",
192
+ onChange: (event) => setFormState((prevState) => ({
193
+ ...prevState,
194
+ digits: event.target.value
195
+ }))
196
+ }))), formState.type === "ref" && /* @__PURE__ */ React2.createElement(Section, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
176
197
  classNames: "mbe-1 mbs-3"
177
198
  }, "Table"), /* @__PURE__ */ React2.createElement(Select.Root, {
178
- value: refTable,
179
- onValueChange: setRefTable
199
+ value: formState.refTable,
200
+ onValueChange: (value) => setFormState((prevState) => ({
201
+ ...prevState,
202
+ refTable: value
203
+ }))
180
204
  }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
181
205
  placeholder: "Table",
182
206
  classNames: "is-full"
183
207
  }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tableDefs.filter((t2) => t2.id !== tableDef.id).map(({ id, name }) => /* @__PURE__ */ React2.createElement(Select.Option, {
184
208
  key: id,
185
209
  value: id
186
- }, name ?? id))))))), refTable && /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
210
+ }, name ?? id))))))), formState.refTable && /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, {
187
211
  classNames: "mbe-1 mbs-3"
188
212
  }, "Table property"), /* @__PURE__ */ React2.createElement(Select.Root, {
189
- value: refProp,
190
- onValueChange: setRefProp
213
+ value: formState.refProp,
214
+ onValueChange: (value) => setFormState((prevState) => ({
215
+ ...prevState,
216
+ refProp: value
217
+ }))
191
218
  }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
192
219
  placeholder: "Property",
193
220
  classNames: "is-full"
194
- }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tableDefs.find((tableDef2) => tableDef2.id === refTable)?.columns.map(({ id, label: label2 }) => /* @__PURE__ */ React2.createElement(Select.Option, {
221
+ }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tableDefs.find((tableDef2) => tableDef2.id === formState.refTable)?.columns.map(({ id, label }) => /* @__PURE__ */ React2.createElement(Select.Option, {
195
222
  key: id,
196
223
  value: id
197
- }, label2 ?? id))))))))), /* @__PURE__ */ React2.createElement(Separator, {
224
+ }, label ?? id)))))))), /* @__PURE__ */ React2.createElement(Separator, {
198
225
  classNames: "mli-2"
199
226
  }), /* @__PURE__ */ React2.createElement(Section, {
200
227
  className: "space-b-1.5"
201
- }, /* @__PURE__ */ React2.createElement(Button2, {
228
+ }, /* @__PURE__ */ React2.createElement(Button, {
202
229
  variant: "primary",
203
230
  classNames: "is-full flex gap-2",
204
231
  onClick: handleSave
@@ -206,7 +233,7 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
206
233
  className: "grow"
207
234
  }), /* @__PURE__ */ React2.createElement(Check, {
208
235
  className: getSize2(5)
209
- })), /* @__PURE__ */ React2.createElement(Button2, {
236
+ })), /* @__PURE__ */ React2.createElement(Button, {
210
237
  classNames: "is-full flex gap-2",
211
238
  onClick: handleCancel
212
239
  }, /* @__PURE__ */ React2.createElement("span", null, t("cancel label", {
@@ -215,34 +242,261 @@ var ColumnPanel = ({ context, tableDefs, tableDef, column, onUpdate, onDelete })
215
242
  className: "grow"
216
243
  }), /* @__PURE__ */ React2.createElement(X, {
217
244
  className: getSize2(5)
218
- })), /* @__PURE__ */ React2.createElement(Button2, {
245
+ })), /* @__PURE__ */ React2.createElement(Button, {
219
246
  classNames: "is-full flex gap-2",
220
247
  onClick: () => onDelete?.(column.id)
221
248
  }, /* @__PURE__ */ React2.createElement("span", null, t("delete label")), /* @__PURE__ */ React2.createElement("div", {
222
249
  className: "grow"
223
250
  }), /* @__PURE__ */ React2.createElement(Trash, {
224
251
  className: getSize2(5)
225
- })))))), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))));
252
+ }))));
253
+ };
254
+
255
+ // packages/ui/react-ui-table/src/hooks/useColumnSorting.ts
256
+ import { useState as useState3 } from "react";
257
+ var useColumnSorting = (column) => {
258
+ const [sortDirection, setSortDirection] = useState3(column.getIsSorted());
259
+ const [firstSort, setFirstSort] = useState3();
260
+ const canSort = column.getCanSort();
261
+ const updateColumnSort = (direction) => {
262
+ setSortDirection(direction);
263
+ switch (direction) {
264
+ case false:
265
+ column.clearSorting();
266
+ break;
267
+ case "asc":
268
+ column.toggleSorting(false);
269
+ break;
270
+ case "desc":
271
+ column.toggleSorting(true);
272
+ break;
273
+ }
274
+ };
275
+ const onToggleSort = () => {
276
+ if (sortDirection === false) {
277
+ return;
278
+ }
279
+ if (sortDirection === firstSort) {
280
+ updateColumnSort(firstSort === "asc" ? "desc" : "asc");
281
+ } else {
282
+ updateColumnSort(false);
283
+ }
284
+ };
285
+ const onSelectSort = (direction) => {
286
+ setFirstSort(direction);
287
+ updateColumnSort(direction);
288
+ };
289
+ const onClearSort = () => {
290
+ updateColumnSort(false);
291
+ };
292
+ return {
293
+ canSort,
294
+ sortDirection,
295
+ onSelectSort,
296
+ onToggleSort,
297
+ onClearSort
298
+ };
299
+ };
300
+
301
+ // packages/ui/react-ui-table/src/hooks/usePinLastRow.ts
302
+ import { useCallback as useCallback2, useEffect, useState as useState4 } from "react";
303
+ var usePinLastRow = (pinLastRow, table, data, getScrollElement) => {
304
+ const [pinnedRowKey, setPinnedRowKey] = useState4();
305
+ const scrollToBottom = useCallback2(() => {
306
+ const scrollElement = getScrollElement?.();
307
+ if (scrollElement) {
308
+ requestAnimationFrame(() => scrollElement.scrollTo({
309
+ top: scrollElement.scrollHeight
310
+ }));
311
+ }
312
+ }, [
313
+ getScrollElement
314
+ ]);
315
+ const pinRow = useCallback2((rowToPin) => {
316
+ table.resetRowPinning();
317
+ rowToPin.pin("bottom");
318
+ setPinnedRowKey(rowToPin.id);
319
+ }, [
320
+ table
321
+ ]);
322
+ const clearRowPinning = useCallback2(() => {
323
+ table.resetRowPinning();
324
+ setPinnedRowKey(void 0);
325
+ }, [
326
+ table
327
+ ]);
328
+ const pinLastRowCallback = useCallback2(() => {
329
+ const rows = table.getRowModel().rows;
330
+ if (rows.length === 0) {
331
+ return clearRowPinning();
332
+ }
333
+ const lastRow = rows[rows.length - 1];
334
+ if (lastRow.id === pinnedRowKey) {
335
+ return;
336
+ }
337
+ pinRow(lastRow);
338
+ if (pinnedRowKey !== void 0) {
339
+ scrollToBottom();
340
+ }
341
+ }, [
342
+ table,
343
+ scrollToBottom,
344
+ pinnedRowKey
345
+ ]);
346
+ useEffect(() => {
347
+ if (pinLastRow) {
348
+ pinLastRowCallback();
349
+ }
350
+ }, [
351
+ data,
352
+ pinLastRow,
353
+ pinLastRowCallback
354
+ ]);
355
+ };
356
+
357
+ // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnMenu.tsx
358
+ var ColumnMenu = ({ column, ...props }) => {
359
+ const title = column.label?.length ? column.label : column.id;
360
+ const header = props.context.header;
361
+ const { canSort, sortDirection, onSelectSort, onToggleSort, onClearSort } = useColumnSorting(header.column);
362
+ const columnSettingsAnchorRef = useRef2(null);
363
+ const [isColumnSettingsOpen, setIsColumnSettingsOpen] = useState5(false);
364
+ const shouldPreventFocusOnClose = useRef2(false);
365
+ const onOpenColumnSettings = useCallback3(() => {
366
+ shouldPreventFocusOnClose.current = true;
367
+ setIsColumnSettingsOpen(true);
368
+ }, [
369
+ shouldPreventFocusOnClose,
370
+ setIsColumnSettingsOpen
371
+ ]);
372
+ const onDropdownCloseAutoFocus = useCallback3((event) => {
373
+ if (shouldPreventFocusOnClose.current) {
374
+ event.preventDefault();
375
+ shouldPreventFocusOnClose.current = false;
376
+ }
377
+ }, [
378
+ shouldPreventFocusOnClose
379
+ ]);
380
+ return /* @__PURE__ */ React3.createElement("div", {
381
+ className: "flex items-center justify-center justify-between"
382
+ }, /* @__PURE__ */ React3.createElement("div", {
383
+ className: "flex items-center gap-1 truncate",
384
+ title
385
+ }, /* @__PURE__ */ React3.createElement(SortIndicator, {
386
+ direction: sortDirection,
387
+ onClick: onToggleSort
388
+ }), /* @__PURE__ */ React3.createElement("div", {
389
+ className: "truncate"
390
+ }, title)), /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
391
+ modal: false
392
+ }, /* @__PURE__ */ React3.createElement(Popover2.Root, {
393
+ open: isColumnSettingsOpen,
394
+ onOpenChange: setIsColumnSettingsOpen,
395
+ modal: false
396
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
397
+ ref: columnSettingsAnchorRef,
398
+ asChild: true
399
+ }, /* @__PURE__ */ React3.createElement(Popover2.Anchor, {
400
+ asChild: true
401
+ }, /* @__PURE__ */ React3.createElement(Button2, {
402
+ variant: "ghost"
403
+ }, /* @__PURE__ */ React3.createElement(CaretDown2, {
404
+ className: getSize3(4)
405
+ })))), /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
406
+ onCloseAutoFocus: onDropdownCloseAutoFocus,
407
+ sideOffset: 4,
408
+ collisionPadding: 8
409
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, canSort && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
410
+ onClick: () => onSelectSort("asc")
411
+ }, /* @__PURE__ */ React3.createElement("span", {
412
+ className: "grow"
413
+ }, "Sort ascending"), /* @__PURE__ */ React3.createElement("span", {
414
+ className: "opacity-50"
415
+ }, /* @__PURE__ */ React3.createElement(ArrowUp, {
416
+ className: getSize3(4)
417
+ }))), /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
418
+ onClick: () => onSelectSort("desc")
419
+ }, /* @__PURE__ */ React3.createElement("span", {
420
+ className: "grow"
421
+ }, "Sort descending"), /* @__PURE__ */ React3.createElement("span", {
422
+ className: "opacity-50"
423
+ }, /* @__PURE__ */ React3.createElement(ArrowDown, {
424
+ className: getSize3(4)
425
+ }))), sortDirection !== false && /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
426
+ onClick: onClearSort
427
+ }, /* @__PURE__ */ React3.createElement("span", {
428
+ className: "grow"
429
+ }, "Clear sort"), /* @__PURE__ */ React3.createElement("span", {
430
+ className: "opacity-50"
431
+ }, /* @__PURE__ */ React3.createElement(X2, {
432
+ className: getSize3(4)
433
+ })))), /* @__PURE__ */ React3.createElement(DropdownMenu.Item, {
434
+ onClick: onOpenColumnSettings
435
+ }, /* @__PURE__ */ React3.createElement("span", {
436
+ className: "grow"
437
+ }, "Column settings"), /* @__PURE__ */ React3.createElement("span", {
438
+ className: "opacity-50"
439
+ }, /* @__PURE__ */ React3.createElement(GearSix, {
440
+ className: mx3(getSize3(4), "rotate-90")
441
+ })))), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)), /* @__PURE__ */ React3.createElement(ColumnSettingsPanel, {
442
+ ...props,
443
+ column,
444
+ onClose: () => setIsColumnSettingsOpen(false)
445
+ }))));
446
+ };
447
+ 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, {
448
+ classNames: "w-60"
449
+ }, /* @__PURE__ */ React3.createElement(DensityProvider, {
450
+ density: "fine"
451
+ }, /* @__PURE__ */ React3.createElement(ColumnSettingsForm, {
452
+ column,
453
+ tableDefs,
454
+ tableDef,
455
+ onUpdate,
456
+ onDelete,
457
+ onClose
458
+ }))), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null)));
459
+ var SortIndicator = ({ direction, onClick }) => {
460
+ if (direction === false) {
461
+ return null;
462
+ }
463
+ let icon;
464
+ switch (direction) {
465
+ case "asc":
466
+ icon = /* @__PURE__ */ React3.createElement(ArrowUp, {
467
+ className: getSize3(3)
468
+ });
469
+ break;
470
+ case "desc":
471
+ icon = /* @__PURE__ */ React3.createElement(ArrowDown, {
472
+ className: getSize3(3)
473
+ });
474
+ break;
475
+ }
476
+ return /* @__PURE__ */ React3.createElement("div", {
477
+ onClick,
478
+ className: "flex items-center cursor-pointer"
479
+ }, icon);
226
480
  };
227
481
 
228
482
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
229
483
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
230
484
  import { getCoreRowModel, getSortedRowModel, useReactTable, getGroupedRowModel, getExpandedRowModel } from "@tanstack/react-table";
231
485
  import { useVirtualizer } from "@tanstack/react-virtual";
232
- import React8, { Fragment, useCallback, useEffect, useState as useState2 } from "react";
486
+ import React9, { Fragment, useCallback as useCallback4, useEffect as useEffect2, useState as useState6 } from "react";
233
487
  import { log } from "@dxos/log";
234
488
  import { useDefaultValue, useOnTransition } from "@dxos/react-ui";
235
489
 
236
490
  // packages/ui/react-ui-table/src/components/Table/TableBody.tsx
237
491
  import { useArrowNavigationGroup } from "@fluentui/react-tabster";
238
492
  import { flexRender } from "@tanstack/react-table";
239
- import React5 from "react";
493
+ import React6 from "react";
240
494
 
241
495
  // packages/ui/react-ui-table/src/components/Table/TableContext.tsx
242
- import React3, { useContext, createContext } from "react";
496
+ import React4, { useContext, createContext } from "react";
243
497
  var TableContext = /* @__PURE__ */ createContext({});
244
498
  var TableProvider = ({ children, ...value }) => {
245
- return /* @__PURE__ */ React3.createElement(TableContext.Provider, {
499
+ return /* @__PURE__ */ React4.createElement(TableContext.Provider, {
246
500
  value
247
501
  }, children);
248
502
  };
@@ -252,32 +506,32 @@ var useTableContext = () => {
252
506
  };
253
507
 
254
508
  // packages/ui/react-ui-table/src/theme.ts
255
- import { modalSurface, focusRing, ghostSelected, ghostSelectedCurrent, groupBorder, mx as mx2 } from "@dxos/react-ui-theme";
509
+ import { modalSurface, focusRing, ghostSelected, ghostSelectedCurrent, groupBorder, mx as mx4 } from "@dxos/react-ui-theme";
256
510
  var currentRow = "!bg-neutral-75 !dark:bg-neutral-850";
257
511
  var selectedRow = "!bg-primary-100 dark:!bg-primary-700";
258
512
  var flushPadding = "pli-0 plb-0";
259
513
  var textPadding = "pli-2 plb-0.5";
260
514
  var headPadding = "pli-2 plb-1";
261
515
  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);
516
+ var tableRoot = ({ fullWidth }, ...etc) => mx4("table-fixed", fullWidth && "is-full", ...etc);
517
+ var groupTh = (_props, ...etc) => mx4("text-start font-medium", flushPadding, ...etc);
518
+ var theadRoot = ({ header, stickyHeader }, ...etc) => mx4(header ? stickyHeader && "sticky block-start-[--sticky-top] z-[1]" : "collapse", header && "base-surface", "drop-shadow-sm", ...etc);
519
+ var theadTr = (_props, ...etc) => mx4("group", ...etc);
520
+ 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
521
  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");
522
+ 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
523
  };
270
- var tbodyRoot = (_props, ...etc) => mx2(...etc);
271
- var tbodyTr = ({ canBeCurrent }, ...etc) => mx2("group", canBeCurrent ? ghostSelectedCurrent : ghostSelected, canBeCurrent && focusRing, canBeCurrent && "cursor-pointer rounded", ...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);
524
+ var tbodyRoot = (_props, ...etc) => mx4(...etc);
525
+ 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);
526
+ var tdRoot = ({ border, isGrid }, ...etc) => mx4("relative", flushPadding, border && "border", border && groupBorder, isGrid && gridCellFocusRing, ...etc);
527
+ var tdContent = (_props, ...etc) => mx4(...etc);
528
+ var tfootRoot = (_props, ...etc) => mx4("sticky block-end-0 z-10", modalSurface, ...etc);
529
+ var tfootTr = (_props, ...etc) => mx4(...etc);
530
+ var tfootTh = ({ border }, ...etc) => mx4(textPadding, modalSurface, border && groupBorder, ...etc);
277
531
 
278
532
  // packages/ui/react-ui-table/src/components/Cell/Cell.tsx
279
533
  import { useFocusableGroup } from "@fluentui/react-tabster";
280
- import React4 from "react";
534
+ import React5 from "react";
281
535
  var CELL_NAME = "Cell";
282
536
  var FocusableCell = ({ cell, children }) => {
283
537
  const tableContext = useTableContext();
@@ -285,7 +539,7 @@ var FocusableCell = ({ cell, children }) => {
285
539
  tabBehavior: "limited"
286
540
  });
287
541
  const className = tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames);
288
- return /* @__PURE__ */ React4.createElement("td", {
542
+ return /* @__PURE__ */ React5.createElement("td", {
289
543
  tabIndex: 0,
290
544
  ...domAttributes,
291
545
  className
@@ -293,14 +547,14 @@ var FocusableCell = ({ cell, children }) => {
293
547
  };
294
548
  var StaticCell = ({ cell, children }) => {
295
549
  const tableContext = useTableContext();
296
- return /* @__PURE__ */ React4.createElement("td", {
550
+ return /* @__PURE__ */ React5.createElement("td", {
297
551
  className: tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames)
298
552
  }, children);
299
553
  };
300
554
  var Cell = ({ cell, children }) => {
301
555
  const { isGrid } = useTableContext();
302
556
  const Root = isGrid ? FocusableCell : StaticCell;
303
- return /* @__PURE__ */ React4.createElement(Root, {
557
+ return /* @__PURE__ */ React5.createElement(Root, {
304
558
  cell
305
559
  }, children);
306
560
  };
@@ -315,14 +569,17 @@ var TableBody = ({ rows }) => {
315
569
  axis: "grid"
316
570
  });
317
571
  const canBeCurrent = !isGrid && !!onDatumClick;
318
- return /* @__PURE__ */ React5.createElement("tbody", isGrid && domAttributes, rows.map((row) => {
572
+ return /* @__PURE__ */ React6.createElement("tbody", isGrid && domAttributes, rows.map((row) => {
319
573
  const isCurrent = currentDatum === row.original;
320
574
  const isSelected = rowSelection?.[row.id];
321
- return /* @__PURE__ */ React5.createElement("tr", {
575
+ const isPinned = row.getIsPinned();
576
+ const classNames = tbodyTr({
577
+ canBeCurrent,
578
+ isPinned: isPinned !== false
579
+ });
580
+ return /* @__PURE__ */ React6.createElement("tr", {
322
581
  key: keyAccessor ? keyAccessor(row.original) : row.id,
323
- className: tbodyTr({
324
- canBeCurrent
325
- }),
582
+ className: classNames,
326
583
  ...isCurrent && {
327
584
  "aria-current": "location"
328
585
  },
@@ -340,57 +597,57 @@ var TableBody = ({ rows }) => {
340
597
  }
341
598
  }
342
599
  }
343
- }, debug && /* @__PURE__ */ React5.createElement("td", null, row.id), row.getVisibleCells().map((cell) => {
344
- return /* @__PURE__ */ React5.createElement(Cell, {
600
+ }, debug && /* @__PURE__ */ React6.createElement("td", null, row.id), row.getVisibleCells().map((cell) => {
601
+ return /* @__PURE__ */ React6.createElement(Cell, {
345
602
  key: cell.id,
346
603
  cell
347
604
  }, flexRender(cell.column.columnDef.cell, {
348
605
  className: "pli-2",
349
606
  ...cell.getContext()
350
607
  }));
351
- }), expand && /* @__PURE__ */ React5.createElement("td", null));
608
+ }), expand && /* @__PURE__ */ React6.createElement("td", null));
352
609
  }));
353
610
  };
354
611
  TableBody.displayName = TABLE_BODY_NAME;
355
612
 
356
613
  // packages/ui/react-ui-table/src/components/Table/TableFooter.tsx
357
614
  import { flexRender as flexRender2 } from "@tanstack/react-table";
358
- import React6 from "react";
615
+ import React7 from "react";
359
616
  var TABLE_FOOT_NAME = "TableFooter";
360
617
  var TableFooter = (props) => {
361
618
  const tableContext = useTableContext();
362
619
  const { table, expand, debug } = tableContext;
363
620
  const footers = table.getFooterGroups();
364
- return /* @__PURE__ */ React6.createElement("tfoot", {
621
+ return /* @__PURE__ */ React7.createElement("tfoot", {
365
622
  className: tfootRoot(props)
366
- }, footers.map((footerGroup) => /* @__PURE__ */ React6.createElement("tr", {
623
+ }, footers.map((footerGroup) => /* @__PURE__ */ React7.createElement("tr", {
367
624
  key: footerGroup.id,
368
625
  className: tfootTr(tableContext)
369
- }, debug && /* @__PURE__ */ React6.createElement("th", null), footerGroup.headers.map((footer) => {
370
- return /* @__PURE__ */ React6.createElement("th", {
626
+ }, debug && /* @__PURE__ */ React7.createElement("th", null), footerGroup.headers.map((footer) => {
627
+ return /* @__PURE__ */ React7.createElement("th", {
371
628
  key: footer.id,
372
629
  className: tfootTh(tableContext, footer.column.columnDef.meta?.footer?.classNames)
373
630
  }, footer.isPlaceholder ? null : flexRender2(footer.column.columnDef.footer, footer.getContext()));
374
- }), expand && /* @__PURE__ */ React6.createElement("th", null))));
631
+ }), expand && /* @__PURE__ */ React7.createElement("th", null))));
375
632
  };
376
633
  TableFooter.displayName = TABLE_FOOT_NAME;
377
634
 
378
635
  // packages/ui/react-ui-table/src/components/Table/TableHead.tsx
379
636
  import { flexRender as flexRender3 } from "@tanstack/react-table";
380
- import React7 from "react";
637
+ import React8 from "react";
381
638
  var TABLE_HEAD_NAME = "TableHeader";
382
639
  var TableHead = (_props) => {
383
640
  const tableContext = useTableContext();
384
641
  const headerGroups = tableContext.table.getHeaderGroups();
385
- return /* @__PURE__ */ React7.createElement("thead", {
642
+ return /* @__PURE__ */ React8.createElement("thead", {
386
643
  className: theadRoot(tableContext)
387
644
  }, headerGroups.map((headerGroup) => {
388
645
  return (
389
646
  // Group element to hover resize handles.
390
- /* @__PURE__ */ React7.createElement("tr", {
647
+ /* @__PURE__ */ React8.createElement("tr", {
391
648
  key: headerGroup.id,
392
649
  className: theadTr(tableContext)
393
- }, tableContext.debug && /* @__PURE__ */ React7.createElement("th", {
650
+ }, tableContext.debug && /* @__PURE__ */ React8.createElement("th", {
394
651
  className: "font-mono",
395
652
  style: {
396
653
  width: 32
@@ -399,13 +656,13 @@ var TableHead = (_props) => {
399
656
  const isResizing = header.column.getIsResizing();
400
657
  const onResize = header.getResizeHandler();
401
658
  const resizable = header.column.columnDef.meta?.resizable;
402
- return /* @__PURE__ */ React7.createElement("th", {
659
+ return /* @__PURE__ */ React8.createElement("th", {
403
660
  key: header.id,
404
661
  style: {
405
662
  width: header.getSize()
406
663
  },
407
664
  className: theadTh(tableContext, header.column.columnDef.meta?.header?.classNames)
408
- }, !header || header.isPlaceholder ? null : flexRender3(header.column.columnDef.header, header.getContext()), resizable && /* @__PURE__ */ React7.createElement("div", {
665
+ }, !header || header.isPlaceholder ? null : flexRender3(header.column.columnDef.header, header.getContext()), resizable && /* @__PURE__ */ React8.createElement("div", {
409
666
  className: theadResizeRoot({
410
667
  isResizing
411
668
  }),
@@ -413,7 +670,7 @@ var TableHead = (_props) => {
413
670
  onMouseDown: onResize,
414
671
  onTouchStart: onResize
415
672
  }));
416
- }), tableContext.expand && /* @__PURE__ */ React7.createElement("th", null))
673
+ }), tableContext.expand && /* @__PURE__ */ React8.createElement("th", null))
417
674
  );
418
675
  }));
419
676
  };
@@ -426,9 +683,9 @@ var Table = (props) => {
426
683
  const columns = useDefaultValue(props.columns, []);
427
684
  const data = useDefaultValue(props.data, []);
428
685
  const TableProvider2 = TableProvider;
429
- const [columnsInitialised, setColumnsInitialised] = useState2(false);
430
- const [columnSizing, setColumnSizing] = useState2({});
431
- useEffect(() => {
686
+ const [columnsInitialised, setColumnsInitialised] = useState6(false);
687
+ const [columnSizing, setColumnSizing] = useState6({});
688
+ useEffect2(() => {
432
689
  if (columnsInitialised) {
433
690
  return;
434
691
  }
@@ -441,8 +698,8 @@ var Table = (props) => {
441
698
  columns,
442
699
  setColumnSizing
443
700
  ]);
444
- const [columnSizingInfo, setColumnSizingInfo] = useState2({});
445
- const notifyColumnResize = useCallback(() => onColumnResize?.(columnSizing), [
701
+ const [columnSizingInfo, setColumnSizingInfo] = useState6({});
702
+ const notifyColumnResize = useCallback4(() => onColumnResize?.(columnSizing), [
446
703
  onColumnResize,
447
704
  columnSizing
448
705
  ]);
@@ -452,7 +709,7 @@ var Table = (props) => {
452
709
  onChange: props.onRowSelectionChange,
453
710
  defaultProp: props.defaultRowSelection
454
711
  });
455
- const handleRowSelectionChange = useCallback((updaterOrValue) => {
712
+ const handleRowSelectionChange = useCallback4((updaterOrValue) => {
456
713
  const nextRowSelection = typeof updaterOrValue === "function" ? updaterOrValue(rowSelection) : updaterOrValue;
457
714
  if (rowsSelectable === "multi") {
458
715
  setRowSelection(nextRowSelection);
@@ -469,8 +726,8 @@ var Table = (props) => {
469
726
  setRowSelection,
470
727
  rowSelection
471
728
  ]);
472
- const [grouping, handleGroupingChange] = useState2(props.grouping ?? []);
473
- useEffect(() => handleGroupingChange(props.grouping ?? []), [
729
+ const [grouping, handleGroupingChange] = useState6(props.grouping ?? []);
730
+ useEffect2(() => handleGroupingChange(props.grouping ?? []), [
474
731
  handleGroupingChange,
475
732
  props.grouping
476
733
  ]);
@@ -512,41 +769,30 @@ var Table = (props) => {
512
769
  // Debug
513
770
  debugTable: debug
514
771
  });
515
- useEffect(() => {
772
+ useEffect2(() => {
516
773
  onDataSelectionChange?.(Object.keys(rowSelection).map((id) => table.getRowModel().rowsById[id].original));
517
774
  }, [
518
775
  onDataSelectionChange,
519
776
  rowSelection,
520
777
  table
521
778
  ]);
522
- useEffect(() => {
523
- if (!pinLastRow) {
524
- return;
525
- }
526
- table.resetRowPinning();
527
- const rows = table.getRowModel().rows;
528
- rows[rows.length - 1].pin("bottom");
529
- }, [
530
- pinLastRow,
531
- table,
532
- data
533
- ]);
779
+ usePinLastRow(pinLastRow, table, data, getScrollElement);
534
780
  const expand = false;
535
781
  if (!getScrollElement) {
536
782
  log.warn("Table: getScrollElement is not set. This is required for virtualized tables.", void 0, {
537
783
  F: __dxlog_file,
538
- L: 168,
784
+ L: 160,
539
785
  S: void 0,
540
786
  C: (f, a) => f(...a)
541
787
  });
542
788
  }
543
- return /* @__PURE__ */ React8.createElement(TableProvider2, {
789
+ return /* @__PURE__ */ React9.createElement(TableProvider2, {
544
790
  ...props,
545
791
  table,
546
792
  header,
547
793
  expand,
548
794
  isGrid: role === "grid" || role === "treegrid"
549
- }, /* @__PURE__ */ React8.createElement(TableImpl, {
795
+ }, /* @__PURE__ */ React9.createElement(TableImpl, {
550
796
  debug: false,
551
797
  getScrollElement,
552
798
  ...props
@@ -555,20 +801,14 @@ var Table = (props) => {
555
801
  var TableImpl = (props) => {
556
802
  const { debug, classNames, getScrollElement, role, footer, grouping, fullWidth } = props;
557
803
  const { table } = useTableContext();
558
- const centerRows = table.getCenterRows();
559
- const bottomRows = table.getBottomRows();
560
- const rows = [
561
- ...centerRows,
562
- ...bottomRows
563
- ];
564
804
  if (debug) {
565
- return /* @__PURE__ */ React8.createElement("pre", {
805
+ return /* @__PURE__ */ React9.createElement("pre", {
566
806
  className: "font-mono text-xs text-neutral-500 m-1 p-2 ring"
567
- }, /* @__PURE__ */ React8.createElement("code", null, JSON.stringify(table.getState(), void 0, 2)));
807
+ }, /* @__PURE__ */ React9.createElement("code", null, JSON.stringify(table.getState(), void 0, 2)));
568
808
  }
569
809
  const virtualisable = getScrollElement !== void 0;
570
810
  const isResizingColumn = table.getState().columnSizingInfo.isResizingColumn;
571
- return /* @__PURE__ */ React8.createElement("table", {
811
+ return /* @__PURE__ */ React9.createElement("table", {
572
812
  role,
573
813
  className: tableRoot(props, classNames),
574
814
  ...!fullWidth && {
@@ -576,15 +816,13 @@ var TableImpl = (props) => {
576
816
  width: table.getTotalSize()
577
817
  }
578
818
  }
579
- }, /* @__PURE__ */ React8.createElement(TableHead, null), grouping?.length !== 0 ? virtualisable ? isResizingColumn ? /* @__PURE__ */ React8.createElement(MemoizedVirtualisedTableContent, {
819
+ }, /* @__PURE__ */ React9.createElement(TableHead, null), grouping?.length !== 0 ? virtualisable ? isResizingColumn ? /* @__PURE__ */ React9.createElement(MemoizedVirtualisedTableContent, {
580
820
  getScrollElement
581
- }) : /* @__PURE__ */ React8.createElement(VirtualizedTableContent, {
821
+ }) : /* @__PURE__ */ React9.createElement(VirtualizedTableContent, {
582
822
  getScrollElement
583
- }) : /* @__PURE__ */ React8.createElement(TableBody, {
584
- rows
585
- }) : /* @__PURE__ */ React8.createElement(GroupedTableContent, null), footer && /* @__PURE__ */ React8.createElement(TableFooter, null));
823
+ }) : /* @__PURE__ */ React9.createElement(UnvirtualizedTableContent, null) : /* @__PURE__ */ React9.createElement(GroupedTableContent, null), footer && /* @__PURE__ */ React9.createElement(TableFooter, null));
586
824
  };
587
- var VirtualizedTableContent = ({ getScrollElement }) => {
825
+ var UnvirtualizedTableContent = () => {
588
826
  const { table } = useTableContext();
589
827
  const centerRows = table.getCenterRows();
590
828
  const pinnedRows = table.getBottomRows();
@@ -592,9 +830,21 @@ var VirtualizedTableContent = ({ getScrollElement }) => {
592
830
  ...centerRows,
593
831
  ...pinnedRows
594
832
  ];
833
+ return /* @__PURE__ */ React9.createElement(TableBody, {
834
+ rows
835
+ });
836
+ };
837
+ var VirtualizedTableContent = ({ getScrollElement }) => {
838
+ const { table } = useTableContext();
839
+ const centerRows = table.getCenterRows();
840
+ let pinnedRows = [];
841
+ try {
842
+ pinnedRows = table.getBottomRows();
843
+ } catch (_) {
844
+ }
595
845
  const { getTotalSize, getVirtualItems } = useVirtualizer({
596
846
  getScrollElement,
597
- count: rows.length,
847
+ count: centerRows.length,
598
848
  overscan: 8,
599
849
  estimateSize: () => 40
600
850
  });
@@ -602,123 +852,58 @@ var VirtualizedTableContent = ({ getScrollElement }) => {
602
852
  const totalSize = getTotalSize();
603
853
  const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
604
854
  const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) : 0;
605
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, paddingTop > 0 && /* @__PURE__ */ React8.createElement("tbody", {
855
+ const rowsToRender = [
856
+ ...virtualRows.map((virtualRow) => centerRows[virtualRow.index]),
857
+ ...pinnedRows
858
+ ];
859
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, paddingTop > 0 && /* @__PURE__ */ React9.createElement("tbody", {
606
860
  role: "none"
607
- }, /* @__PURE__ */ React8.createElement("tr", {
861
+ }, /* @__PURE__ */ React9.createElement("tr", {
608
862
  role: "none"
609
- }, /* @__PURE__ */ React8.createElement("td", {
863
+ }, /* @__PURE__ */ React9.createElement("td", {
610
864
  style: {
611
865
  height: `${paddingTop}px`
612
866
  },
613
867
  role: "none"
614
- }))), /* @__PURE__ */ React8.createElement(TableBody, {
615
- rows: virtualRows.map((virtualRow) => rows[virtualRow.index])
616
- }), paddingBottom > 0 && /* @__PURE__ */ React8.createElement("tbody", {
868
+ }))), /* @__PURE__ */ React9.createElement(TableBody, {
869
+ rows: rowsToRender
870
+ }), paddingBottom > 0 && /* @__PURE__ */ React9.createElement("tbody", {
617
871
  role: "none"
618
- }, /* @__PURE__ */ React8.createElement("tr", {
872
+ }, /* @__PURE__ */ React9.createElement("tr", {
619
873
  role: "none"
620
- }, /* @__PURE__ */ React8.createElement("td", {
874
+ }, /* @__PURE__ */ React9.createElement("td", {
621
875
  style: {
622
876
  height: `${paddingBottom}px`
623
877
  },
624
878
  role: "none"
625
879
  }))));
626
880
  };
627
- var MemoizedVirtualisedTableContent = /* @__PURE__ */ React8.memo(VirtualizedTableContent);
881
+ var MemoizedVirtualisedTableContent = /* @__PURE__ */ React9.memo(VirtualizedTableContent);
628
882
  var GroupedTableContent = () => {
629
883
  const { table: { getGroupedRowModel: getGroupedRowModel2, getHeaderGroups, getState }, debug } = useTableContext();
630
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, getGroupedRowModel2().rows.map((row, i) => {
631
- return /* @__PURE__ */ React8.createElement(Fragment, {
884
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, getGroupedRowModel2().rows.map((row, i) => {
885
+ return /* @__PURE__ */ React9.createElement(Fragment, {
632
886
  key: i
633
- }, /* @__PURE__ */ React8.createElement("thead", null, /* @__PURE__ */ React8.createElement("tr", null, debug && /* @__PURE__ */ React8.createElement("th", null), /* @__PURE__ */ React8.createElement("th", {
887
+ }, /* @__PURE__ */ React9.createElement("thead", null, /* @__PURE__ */ React9.createElement("tr", null, debug && /* @__PURE__ */ React9.createElement("th", null), /* @__PURE__ */ React9.createElement("th", {
634
888
  // TODO(burdon): Calculate row span.
635
889
  colSpan: getHeaderGroups()[0].headers.length,
636
890
  className: groupTh({})
637
- }, getState().grouping[0], "[", String(row.getGroupingValue(getState().grouping[0])), "]"))), /* @__PURE__ */ React8.createElement(TableBody, {
891
+ }, getState().grouping[0], "[", String(row.getGroupingValue(getState().grouping[0])), "]"))), /* @__PURE__ */ React9.createElement(TableBody, {
638
892
  rows: row.subRows
639
893
  }));
640
894
  }));
641
895
  };
642
896
 
643
- // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
644
- import { CaretDown } from "@phosphor-icons/react";
645
- import React9, { useCallback as useCallback2, useState as useState3 } from "react";
646
- import { Popover as Popover2, useTranslation as useTranslation2 } from "@dxos/react-ui";
647
- import { PopoverCombobox } from "@dxos/react-ui-searchlist";
648
- import { descriptionText, getSize as getSize3, mx as mx3, staticPlaceholderText } from "@dxos/react-ui-theme";
649
- var initialItems = (model, value) => value ? {
650
- [model.getId(value)]: {
651
- label: model.getText(value),
652
- data: value
653
- }
654
- } : {};
655
- var CellCombobox = ({ model, value, onValueChange }) => {
656
- const { t } = useTranslation2(translationKey);
657
- const [items, setItems] = useState3(initialItems(model, value));
658
- const [loading, setLoading] = useState3(false);
659
- const [searchInputValue, setSearchInputValue] = useState3("");
660
- const handleSearchInputValueChange = async (text) => {
661
- setSearchInputValue(text ?? "");
662
- setLoading(true);
663
- const items2 = await model.query(text);
664
- setItems(items2.reduce((acc, item) => {
665
- acc[model.getId(item)] = {
666
- label: model.getText(item),
667
- data: item
668
- };
669
- return acc;
670
- }, initialItems(model, value)));
671
- setLoading(false);
672
- };
673
- const handleValueChange = useCallback2((id) => {
674
- onValueChange(items[id]?.data);
675
- }, [
676
- items,
677
- onValueChange
678
- ]);
679
- return /* @__PURE__ */ React9.createElement(PopoverCombobox.Root, {
680
- placeholder: t("no selection label")
681
- }, /* @__PURE__ */ React9.createElement(PopoverCombobox.Trigger, {
682
- variant: "ghost",
683
- classNames: "is-full rounded-none ring-inset"
684
- }, value ? /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement("span", {
685
- className: mx3("font-normal text-start text-base flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
686
- }, model.getText(value)), /* @__PURE__ */ React9.createElement(CaretDown, {
687
- weight: "bold",
688
- className: getSize3(3)
689
- })) : null), /* @__PURE__ */ React9.createElement(PopoverCombobox.Content, {
690
- shouldFilter: false,
691
- classNames: "is-[--radix-popover-trigger-width]"
692
- }, /* @__PURE__ */ React9.createElement(PopoverCombobox.Input, {
693
- value: searchInputValue,
694
- onValueChange: handleSearchInputValueChange
695
- }), /* @__PURE__ */ React9.createElement(PopoverCombobox.List, null, searchInputValue.length < 1 ? /* @__PURE__ */ React9.createElement("p", {
696
- className: mx3("text-center", descriptionText)
697
- }, "Start typing to search") : loading ? /* @__PURE__ */ React9.createElement("p", {
698
- className: mx3("text-center", descriptionText)
699
- }, "Searching\u2026") : /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(PopoverCombobox.Empty, {
700
- classNames: [
701
- "text-center",
702
- descriptionText
703
- ]
704
- }, "No results"), Object.entries(items).map(([id, { label }]) => /* @__PURE__ */ React9.createElement(PopoverCombobox.Item, {
705
- key: id,
706
- value: id,
707
- onSelect: handleValueChange,
708
- classNames: "truncate"
709
- }, label)))), /* @__PURE__ */ React9.createElement(Popover2.Arrow, null)));
710
- };
711
-
712
897
  // packages/ui/react-ui-table/src/helpers.tsx
713
898
  import { useFocusFinders } from "@fluentui/react-tabster";
714
- import { Check as Check2, ClipboardText, X as X2 } from "@phosphor-icons/react";
899
+ import { Check as Check2, ClipboardText, X as X3 } from "@phosphor-icons/react";
715
900
  import { createColumnHelper } from "@tanstack/react-table";
716
901
  import { format } from "date-fns/format";
717
902
  import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
718
- import React10, { useEffect as useEffect2, useRef as useRef2, useState as useState4 } from "react";
903
+ import React10, { useEffect as useEffect3, useRef as useRef3, useState as useState7 } from "react";
719
904
  import { log as log2 } from "@dxos/log";
720
905
  import { Input as Input2, Tooltip } from "@dxos/react-ui";
721
- import { getSize as getSize4, mx as mx4 } from "@dxos/react-ui-theme";
906
+ import { getSize as getSize4, mx as mx5 } from "@dxos/react-ui-theme";
722
907
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/helpers.tsx";
723
908
  var createColumnBuilder = () => ({
724
909
  helper: createColumnHelper(),
@@ -733,11 +918,11 @@ var ComboboxBuilderCell = (cellContext) => {
733
918
  }) : null;
734
919
  };
735
920
  var StringBuilderCell = (cellContext) => {
736
- const ref = useRef2(null);
921
+ const ref = useRef3(null);
737
922
  const { findPrevFocusable } = useFocusFinders();
738
923
  const { onUpdate, cell } = cellContext.column.columnDef.meta;
739
924
  const initialValue = cellContext.getValue();
740
- const [value, setValue] = useState4(() => {
925
+ const [value, setValue] = useState7(() => {
741
926
  if (initialValue?.content) {
742
927
  return initialValue?.content;
743
928
  }
@@ -779,10 +964,10 @@ var displayNumber = (value, digits) => value || value === 0 ? value.toLocaleStri
779
964
  var NumberBuilderCell = (cellContext) => {
780
965
  const { onUpdate, digits } = cellContext.column.columnDef.meta;
781
966
  const value = cellContext.getValue();
782
- const [text, setText] = useState4(displayNumber(value, digits));
967
+ const [text, setText] = useState7(displayNumber(value, digits));
783
968
  const { findPrevFocusable } = useFocusFinders();
784
- const ref = useRef2(null);
785
- useEffect2(() => {
969
+ const ref = useRef3(null);
970
+ useEffect3(() => {
786
971
  (!document.activeElement || document.activeElement !== ref.current) && setText(displayNumber(value, digits));
787
972
  }, [
788
973
  digits,
@@ -869,7 +1054,7 @@ var ColumnBuilder = class {
869
1054
  cell: model && onUpdate ? ComboboxBuilderCell : (cellContext) => {
870
1055
  const cellValue = cellContext.getValue();
871
1056
  return /* @__PURE__ */ React10.createElement("div", {
872
- className: mx4("truncate", classNames)
1057
+ className: mx5("truncate", classNames)
873
1058
  }, cellValue ? model?.getText(cellValue) : "");
874
1059
  },
875
1060
  ...props,
@@ -900,7 +1085,7 @@ var ColumnBuilder = class {
900
1085
  value = value.content;
901
1086
  }
902
1087
  return /* @__PURE__ */ React10.createElement("div", {
903
- className: mx4("truncate", textPadding, classNames)
1088
+ className: mx5("truncate", textPadding, classNames)
904
1089
  }, value);
905
1090
  },
906
1091
  ...props,
@@ -929,7 +1114,6 @@ var ColumnBuilder = class {
929
1114
  onUpdate,
930
1115
  digits,
931
1116
  header: {
932
- classNames: "text-end",
933
1117
  ...props.meta?.header
934
1118
  },
935
1119
  cell: {
@@ -955,7 +1139,7 @@ var ColumnBuilder = class {
955
1139
  addSuffix: true
956
1140
  }) : value.toISOString() : void 0;
957
1141
  return /* @__PURE__ */ React10.createElement("div", {
958
- className: mx4(textPadding, classNames)
1142
+ className: mx5(textPadding, classNames)
959
1143
  }, str);
960
1144
  } catch (err) {
961
1145
  log2.info("formatError", {
@@ -1082,7 +1266,7 @@ var ColumnBuilder = class {
1082
1266
  */
1083
1267
  icon({ label, size, on, off, ...props } = {}) {
1084
1268
  const IconOn = on?.Icon ?? Check2;
1085
- const IconOff = off?.Icon ?? X2;
1269
+ const IconOff = off?.Icon ?? X3;
1086
1270
  return {
1087
1271
  size: size ?? 32,
1088
1272
  // TODO(Zan): Implement sort algorithm
@@ -1094,11 +1278,11 @@ var ColumnBuilder = class {
1094
1278
  const value = cell.getValue();
1095
1279
  if (value) {
1096
1280
  return /* @__PURE__ */ React10.createElement(IconOn, {
1097
- className: mx4("block mli-auto", getSize4(6), on?.className ?? "text-green-700")
1281
+ className: mx5("block mli-auto", getSize4(6), on?.className ?? "text-green-700")
1098
1282
  });
1099
1283
  } else if (value === false) {
1100
1284
  return /* @__PURE__ */ React10.createElement(IconOff, {
1101
- className: mx4("block mli-auto", getSize4(6), off?.className ?? "text-red-700")
1285
+ className: mx5("block mli-auto", getSize4(6), off?.className ?? "text-red-700")
1102
1286
  });
1103
1287
  } else {
1104
1288
  return null;
@@ -1107,13 +1291,165 @@ var ColumnBuilder = class {
1107
1291
  ...props
1108
1292
  };
1109
1293
  }
1294
+ /**
1295
+ * This display column type is for nested/unhandled data to appear as JSON.
1296
+ */
1297
+ display({ label, classNames, ...props } = {}) {
1298
+ return {
1299
+ size: 120,
1300
+ minSize: 120,
1301
+ header: (cell) => label ?? cell.header.id,
1302
+ cell: (cell) => {
1303
+ const value = cell.getValue();
1304
+ return /* @__PURE__ */ React10.createElement("div", {
1305
+ className: "overflow-scroll"
1306
+ }, /* @__PURE__ */ React10.createElement("code", {
1307
+ className: "text-xs"
1308
+ }, JSON.stringify(value)));
1309
+ },
1310
+ ...props,
1311
+ meta: {
1312
+ ...props.meta,
1313
+ cell: {
1314
+ ...props.meta?.cell,
1315
+ classNames: [
1316
+ "font-mono",
1317
+ textPadding,
1318
+ classNames
1319
+ ]
1320
+ }
1321
+ }
1322
+ };
1323
+ }
1324
+ };
1325
+
1326
+ // packages/ui/react-ui-table/src/schema/schema.ts
1327
+ import * as AST from "@effect/schema/AST";
1328
+ var classifySchemaProperties = (schema) => {
1329
+ const recurse = (node, path, acc) => {
1330
+ const properties = AST.getPropertySignatures(node);
1331
+ properties.forEach((prop) => {
1332
+ const propName = prop.name.toString();
1333
+ if (prop.isOptional) {
1334
+ const unwrappedAst = unwrapOptionProperty(prop);
1335
+ if (isStruct(unwrappedAst)) {
1336
+ return recurse(unwrappedAst, [
1337
+ ...path,
1338
+ propName
1339
+ ], acc);
1340
+ }
1341
+ }
1342
+ if (isStruct(prop.type)) {
1343
+ recurse(prop.type, [
1344
+ ...path,
1345
+ propName
1346
+ ], acc);
1347
+ } else {
1348
+ acc.push([
1349
+ path.concat(propName).join("."),
1350
+ propertyToColumn(prop)
1351
+ ]);
1352
+ }
1353
+ });
1354
+ return acc;
1355
+ };
1356
+ return recurse(schema.ast, [], []);
1357
+ };
1358
+ var isStruct = (node) => AST.isTypeLiteral(node);
1359
+ var isOptionalUnion = (prop) => AST.isUnion(prop.type) && prop.isOptional;
1360
+ var unwrapOptionProperty = (prop) => {
1361
+ if (!isOptionalUnion(prop)) {
1362
+ throw new Error(`Not an optional property: ${String(prop.name)}`);
1363
+ }
1364
+ if (!AST.isUnion(prop.type)) {
1365
+ throw new Error(`Not a union type: ${String(prop.name)}`);
1366
+ }
1367
+ const [type, _undefinedCase] = prop.type.types;
1368
+ return type;
1369
+ };
1370
+ var typeToColumn = (type) => {
1371
+ if (AST.isStringKeyword(type)) {
1372
+ return "string";
1373
+ } else if (AST.isNumberKeyword(type)) {
1374
+ return "number";
1375
+ } else if (AST.isBooleanKeyword(type)) {
1376
+ return "boolean";
1377
+ }
1378
+ if (AST.isRefinement(type)) {
1379
+ return typeToColumn(type.from);
1380
+ }
1381
+ if (AST.isTransform(type)) {
1382
+ const identifier = AST.getIdentifierAnnotation(type);
1383
+ if (identifier._tag === "Some") {
1384
+ if (identifier.value === "DateFromString") {
1385
+ return "date";
1386
+ }
1387
+ }
1388
+ }
1389
+ return "display";
1390
+ };
1391
+ var propertyToColumn = (prop) => {
1392
+ let type = prop.type;
1393
+ if (prop.isOptional) {
1394
+ type = unwrapOptionProperty(prop);
1395
+ }
1396
+ return typeToColumn(type);
1397
+ };
1398
+
1399
+ // packages/ui/react-ui-table/src/schema/schemaToColumns.ts
1400
+ var schemaToColumnDefs = (schema) => {
1401
+ const { helper, builder } = createColumnBuilder();
1402
+ const classified = classifySchemaProperties(schema);
1403
+ return classified.map(([name, type]) => {
1404
+ const propertyKey = name.toString();
1405
+ let column;
1406
+ switch (type) {
1407
+ case "string": {
1408
+ column = builder.string({
1409
+ label: propertyKey
1410
+ });
1411
+ break;
1412
+ }
1413
+ case "number": {
1414
+ column = builder.number({
1415
+ label: propertyKey
1416
+ });
1417
+ break;
1418
+ }
1419
+ case "boolean": {
1420
+ column = builder.switch({
1421
+ label: propertyKey
1422
+ });
1423
+ break;
1424
+ }
1425
+ case "date": {
1426
+ column = builder.date({
1427
+ label: propertyKey
1428
+ });
1429
+ break;
1430
+ }
1431
+ case "display": {
1432
+ column = builder.display({
1433
+ label: propertyKey,
1434
+ id: propertyKey
1435
+ });
1436
+ break;
1437
+ }
1438
+ default: {
1439
+ throw new Error(`Unhandled column type: ${type}`);
1440
+ }
1441
+ }
1442
+ return helper.accessor(propertyKey, column);
1443
+ });
1110
1444
  };
1111
1445
  export {
1112
1446
  CellCombobox,
1113
1447
  ColumnBuilder,
1114
1448
  ColumnMenu,
1115
- ColumnPanel,
1449
+ ColumnSettingsForm,
1450
+ ColumnSettingsPanel,
1116
1451
  MemoizedVirtualisedTableContent,
1452
+ SortIndicator,
1117
1453
  Table,
1118
1454
  createColumnBuilder,
1119
1455
  currentRow,
@@ -1121,6 +1457,7 @@ export {
1121
1457
  gridCellFocusRing,
1122
1458
  groupTh,
1123
1459
  headPadding,
1460
+ schemaToColumnDefs,
1124
1461
  selectedRow,
1125
1462
  tableRoot,
1126
1463
  tbodyRoot,
@@ -1135,6 +1472,8 @@ export {
1135
1472
  theadRoot,
1136
1473
  theadTh,
1137
1474
  theadTr,
1138
- translations_default as translations
1475
+ translations_default as translations,
1476
+ useColumnSorting,
1477
+ usePinLastRow
1139
1478
  };
1140
1479
  //# sourceMappingURL=index.mjs.map