@dxos/react-ui-table 0.7.4 → 0.7.5-labs.a279d8c

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 (116) hide show
  1. package/dist/lib/browser/{chunk-IYCSJDMB.mjs → chunk-3FR6NHPD.mjs} +7 -5
  2. package/dist/lib/browser/chunk-3FR6NHPD.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1405 -1067
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/types/index.mjs +1 -1
  7. package/dist/lib/node/{chunk-MHBMVCFZ.cjs → chunk-NB3SFHGA.cjs} +9 -7
  8. package/dist/lib/node/chunk-NB3SFHGA.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +1409 -1051
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/types/index.cjs +3 -3
  13. package/dist/lib/node/types/index.cjs.map +1 -1
  14. package/dist/lib/node-esm/{chunk-BMWGPXPL.mjs → chunk-RLVVOZW5.mjs} +7 -5
  15. package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +7 -0
  16. package/dist/lib/node-esm/index.mjs +1405 -1067
  17. package/dist/lib/node-esm/index.mjs.map +4 -4
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/types/index.mjs +1 -1
  20. package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts +1 -1
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +4 -3
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +3 -2
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/CreateRefPanel.d.ts +3 -2
  26. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/RefPanel.d.ts +4 -3
  28. package/dist/types/src/components/Table/RefPanel.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/RowActionsMenu.d.ts +3 -2
  30. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/Table.d.ts +2 -1
  32. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  34. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -2
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  36. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +18 -0
  38. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -0
  39. package/dist/types/src/components/TableToolbar/index.d.ts +2 -0
  40. package/dist/types/src/components/TableToolbar/index.d.ts.map +1 -0
  41. package/dist/types/src/components/index.d.ts +1 -1
  42. package/dist/types/src/components/index.d.ts.map +1 -1
  43. package/dist/types/src/components/testing.d.ts +31 -71
  44. package/dist/types/src/components/testing.d.ts.map +1 -1
  45. package/dist/types/src/index.d.ts +1 -0
  46. package/dist/types/src/index.d.ts.map +1 -1
  47. package/dist/types/src/model/index.d.ts +1 -0
  48. package/dist/types/src/model/index.d.ts.map +1 -1
  49. package/dist/types/src/model/modal-controller.d.ts +6 -2
  50. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  51. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  52. package/dist/types/src/model/table-model.d.ts +19 -31
  53. package/dist/types/src/model/table-model.d.ts.map +1 -1
  54. package/dist/types/src/model/table-presentation.d.ts +22 -0
  55. package/dist/types/src/model/table-presentation.d.ts.map +1 -0
  56. package/dist/types/src/model/table-presentation.test.d.ts +2 -0
  57. package/dist/types/src/model/table-presentation.test.d.ts.map +1 -0
  58. package/dist/types/src/model/table-sorting.d.ts +53 -0
  59. package/dist/types/src/model/table-sorting.d.ts.map +1 -0
  60. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  61. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  62. package/dist/types/src/translations.d.ts +2 -1
  63. package/dist/types/src/translations.d.ts.map +1 -1
  64. package/dist/types/src/types/table.d.ts +46 -154
  65. package/dist/types/src/types/table.d.ts.map +1 -1
  66. package/dist/types/src/util/index.d.ts +1 -0
  67. package/dist/types/src/util/index.d.ts.map +1 -1
  68. package/dist/types/src/util/table-buttons.d.ts +63 -19
  69. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  70. package/dist/types/src/util/table-controls.d.ts +32 -9
  71. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  72. package/dist/types/src/util/table.d.ts +3 -2
  73. package/dist/types/src/util/table.d.ts.map +1 -1
  74. package/dist/types/tsconfig.tsbuildinfo +1 -0
  75. package/package.json +30 -29
  76. package/src/components/Table/ColumnActionsMenu.tsx +12 -12
  77. package/src/components/Table/ColumnSettings.tsx +11 -11
  78. package/src/components/Table/CreateRefPanel.tsx +13 -14
  79. package/src/components/Table/RefPanel.tsx +9 -9
  80. package/src/components/Table/RowActionsMenu.tsx +6 -7
  81. package/src/components/Table/Table.stories.tsx +67 -38
  82. package/src/components/Table/Table.tsx +239 -148
  83. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +13 -12
  84. package/src/components/TableCellEditor/TableCellEditor.tsx +6 -4
  85. package/src/components/TableToolbar/TableToolbar.tsx +72 -0
  86. package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
  87. package/src/components/index.ts +1 -1
  88. package/src/components/testing.ts +10 -8
  89. package/src/index.ts +2 -0
  90. package/src/model/index.ts +1 -0
  91. package/src/model/modal-controller.ts +15 -48
  92. package/src/model/selection-model.ts +12 -1
  93. package/src/model/table-model.test.ts +4 -76
  94. package/src/model/table-model.ts +73 -304
  95. package/src/model/table-presentation.test.ts +102 -0
  96. package/src/model/table-presentation.ts +223 -0
  97. package/src/model/table-sorting.ts +201 -0
  98. package/src/playwright/TableManager.ts +5 -1
  99. package/src/playwright/smoke.spec.ts +94 -9
  100. package/src/translations.ts +2 -1
  101. package/src/types/table.ts +4 -4
  102. package/src/util/index.ts +1 -0
  103. package/src/util/table-buttons.ts +127 -48
  104. package/src/util/table-controls.ts +71 -7
  105. package/src/util/table.ts +93 -52
  106. package/dist/lib/browser/chunk-IYCSJDMB.mjs.map +0 -7
  107. package/dist/lib/node/chunk-MHBMVCFZ.cjs.map +0 -7
  108. package/dist/lib/node-esm/chunk-BMWGPXPL.mjs.map +0 -7
  109. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
  110. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  111. package/dist/types/src/components/Toolbar/common.d.ts +0 -14
  112. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  113. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  114. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  115. package/src/components/Toolbar/Toolbar.tsx +0 -87
  116. package/src/components/Toolbar/common.tsx +0 -71
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TableSchema,
3
3
  TableType
4
- } from "./chunk-IYCSJDMB.mjs";
4
+ } from "./chunk-3FR6NHPD.mjs";
5
5
 
6
6
  // packages/ui/react-ui-table/src/translations.ts
7
7
  var translationKey = "table";
@@ -17,7 +17,7 @@ var translations_default = [
17
17
  "new schema": "New schema",
18
18
  "continue label": "Continue",
19
19
  "create stack section label": "Create table",
20
- "add row": "Add row",
20
+ "add row label": "Add row",
21
21
  "create comment": "Create thread",
22
22
  "column action sort descending": "Sort Descending",
23
23
  "column action sort ascending": "Sort Ascending",
@@ -28,55 +28,56 @@ var translations_default = [
28
28
  "bulk delete row label": "Delete selected rows",
29
29
  "column deleted label": "Column deleted",
30
30
  "new column button label": "Create column",
31
- "create new object label": "Create new object \u201C{{text}}\u201D"
31
+ "create new object label": "Create new object \u201C{{text}}\u201D",
32
+ "save view label": "Save changes to view"
32
33
  }
33
34
  }
34
35
  }
35
36
  ];
36
37
 
37
38
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
38
- import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2 } from "react";
39
- import { getValue } from "@dxos/echo-schema";
40
- import { invariant as invariant2 } from "@dxos/invariant";
39
+ import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2, useMemo as useMemo4 } from "react";
40
+ import { getValue as getValue4 } from "@dxos/echo-schema";
41
+ import { invariant as invariant3 } from "@dxos/invariant";
41
42
  import { Filter, getSpace as getSpace4, fullyQualifiedId } from "@dxos/react-client/echo";
42
43
  import { useTranslation as useTranslation3 } from "@dxos/react-ui";
43
44
  import { useAttention } from "@dxos/react-ui-attention";
44
45
  import { Grid, closestCell } from "@dxos/react-ui-grid";
45
- import { mx } from "@dxos/react-ui-theme";
46
+ import { mx as mx2 } from "@dxos/react-ui-theme";
46
47
  import { isNotFalsy } from "@dxos/util";
47
48
 
48
49
  // packages/ui/react-ui-table/src/components/Table/ColumnActionsMenu.tsx
49
50
  import React from "react";
50
51
  import { DropdownMenu, useTranslation } from "@dxos/react-ui";
51
- var ColumnActionsMenu = ({ model }) => {
52
+ var ColumnActionsMenu = ({ model, modals }) => {
52
53
  const { t } = useTranslation(translationKey);
53
- const state = model?.modalController.state.value;
54
- if (!model || state?.type !== "column") {
54
+ const state = modals.state.value;
55
+ if (state?.type !== "column") {
55
56
  return null;
56
57
  }
57
- const currentSort = model.sorting;
58
+ const currentSort = model.sorting?.sorting;
58
59
  const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
59
60
  return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
60
61
  modal: false,
61
- open: state?.type === "column",
62
- onOpenChange: model.modalController.close
62
+ open: true,
63
+ onOpenChange: modals.close
63
64
  }, /* @__PURE__ */ React.createElement(DropdownMenu.VirtualTrigger, {
64
- virtualRef: model.modalController.trigger
65
+ virtualRef: modals.trigger
65
66
  }), /* @__PURE__ */ React.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
66
67
  "data-testid": "column-sort-descending",
67
- onClick: () => model.setSort(state.fieldId, "desc")
68
+ onClick: () => model.sorting?.setSort(state.fieldId, "desc")
68
69
  }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
69
70
  "data-testid": "column-sort-ascending",
70
- onClick: () => model.setSort(state.fieldId, "asc")
71
+ onClick: () => model.sorting?.setSort(state.fieldId, "asc")
71
72
  }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
72
73
  "data-testid": "column-clear-sort",
73
- onClick: () => model.clearSort()
74
+ onClick: () => model.sorting?.clearSort()
74
75
  }, t("column action clear sorting")), model.getColumnCount() > 1 && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
75
76
  "data-testid": "column-delete",
76
77
  onClick: () => model.deleteColumn(state.fieldId)
77
78
  }, t("column action delete")), /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
78
79
  "data-testid": "column-settings",
79
- onClick: () => model.modalController.openColumnSettings()
80
+ onClick: () => modals.openColumnSettings()
80
81
  }, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
81
82
  };
82
83
 
@@ -85,9 +86,9 @@ import React2, { useCallback, useEffect, useMemo, useState } from "react";
85
86
  import { getSpace } from "@dxos/react-client/echo";
86
87
  import { DropdownMenu as DropdownMenu2 } from "@dxos/react-ui";
87
88
  import { FieldEditor } from "@dxos/react-ui-form";
88
- var ColumnSettings = ({ model, onNewColumn }) => {
89
+ var ColumnSettings = ({ model, modals, onNewColumn }) => {
89
90
  const [newField, setNewField] = useState();
90
- const state = model?.modalController.state.value;
91
+ const state = modals.state.value;
91
92
  const space = getSpace(model?.table);
92
93
  useEffect(() => {
93
94
  if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
@@ -106,19 +107,19 @@ var ColumnSettings = ({ model, onNewColumn }) => {
106
107
  if (state?.type === "columnSettings") {
107
108
  const { mode } = state;
108
109
  if (mode.type === "edit") {
109
- return model?.table?.view?.fields.find((f) => f.id === mode.fieldId);
110
+ return model?.table?.view?.target?.fields.find((f) => f.id === mode.fieldId);
110
111
  }
111
112
  }
112
113
  return void 0;
113
114
  }, [
114
- model?.table?.view?.fields,
115
+ model?.table?.view?.target?.fields,
115
116
  state
116
117
  ]);
117
118
  const field = existingField ?? newField;
118
119
  const handleSave = useCallback(() => {
119
- model?.modalController.close();
120
+ modals.close();
120
121
  }, [
121
- model?.modalController
122
+ modals
122
123
  ]);
123
124
  const handleCancel = useCallback(() => {
124
125
  if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
@@ -129,18 +130,18 @@ var ColumnSettings = ({ model, onNewColumn }) => {
129
130
  state,
130
131
  newField
131
132
  ]);
132
- if (!model?.table?.view || !model.projection || !field) {
133
+ if (!model?.table?.view?.target || !model.projection || !field) {
133
134
  return null;
134
135
  }
135
136
  return /* @__PURE__ */ React2.createElement(DropdownMenu2.Root, {
136
137
  modal: false,
137
138
  open: state?.type === "columnSettings"
138
139
  }, /* @__PURE__ */ React2.createElement(DropdownMenu2.VirtualTrigger, {
139
- virtualRef: model.modalController.trigger
140
+ virtualRef: modals.trigger
140
141
  }), /* @__PURE__ */ React2.createElement(DropdownMenu2.Portal, null, /* @__PURE__ */ React2.createElement(DropdownMenu2.Content, {
141
142
  classNames: "md:is-64"
142
143
  }, /* @__PURE__ */ React2.createElement(DropdownMenu2.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
143
- view: model.table.view,
144
+ view: model.table.view.target,
144
145
  projection: model.projection,
145
146
  field,
146
147
  registry: space?.db.schemaRegistry,
@@ -156,15 +157,17 @@ import { create, getSpace as getSpace2 } from "@dxos/react-client/echo";
156
157
  import { Popover } from "@dxos/react-ui";
157
158
  import { Form } from "@dxos/react-ui-form";
158
159
  import { useGridContext } from "@dxos/react-ui-grid";
159
- var CreateRefPanel = ({ model, __gridScope }) => {
160
+ var CreateRefPanel = ({ model, modals, __gridScope }) => {
160
161
  const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
161
162
  const space = getSpace2(model?.table);
162
- const state = model?.modalController.state.value;
163
+ const state = modals.state.value;
163
164
  const schema = useMemo2(() => {
164
165
  if (!space || state?.type !== "createRefPanel") {
165
166
  return;
166
167
  }
167
- const schema2 = space.db.schemaRegistry.getSchema(state.typename)?.schema;
168
+ const [schema2] = space.db.schemaRegistry.query({
169
+ typename: state.typename
170
+ }).runSync();
168
171
  if (schema2) {
169
172
  const omit = S.omit("id");
170
173
  return omit(schema2);
@@ -177,23 +180,25 @@ var CreateRefPanel = ({ model, __gridScope }) => {
177
180
  if (!model || !space || state?.type !== "createRefPanel") {
178
181
  return;
179
182
  }
180
- const schema2 = space.db.schemaRegistry.getSchema(state.typename)?.schema;
183
+ const [schema2] = space.db.schemaRegistry.query({
184
+ typename: state.typename
185
+ }).runSync();
181
186
  if (schema2) {
182
187
  const obj = space.db.add(create(schema2, values));
183
188
  state.onCreate?.(obj);
184
189
  }
185
- void model.modalController.close();
190
+ void modals.close();
186
191
  }, [
187
- model?.modalController,
192
+ modals,
188
193
  space,
189
194
  state
190
195
  ]);
191
196
  const handleCancel = useCallback2(() => {
192
197
  if (model) {
193
- model.modalController.close();
198
+ modals.close();
194
199
  }
195
200
  }, [
196
- model?.modalController
201
+ modals
197
202
  ]);
198
203
  if (!model?.table?.view || !model.projection) {
199
204
  return null;
@@ -203,11 +208,11 @@ var CreateRefPanel = ({ model, __gridScope }) => {
203
208
  open: state?.type === "createRefPanel" && !!schema,
204
209
  onOpenChange: (nextOpen) => {
205
210
  if (model && !nextOpen) {
206
- return model.modalController.close();
211
+ return modals.close();
207
212
  }
208
213
  }
209
214
  }, /* @__PURE__ */ React3.createElement(Popover.VirtualTrigger, {
210
- virtualRef: model.modalController.trigger
215
+ virtualRef: modals.trigger
211
216
  }), /* @__PURE__ */ React3.createElement(Popover.Portal, null, /* @__PURE__ */ React3.createElement(Popover.Content, {
212
217
  classNames: "md:is-64",
213
218
  "data-grid": gridId
@@ -231,24 +236,24 @@ var getRefTargetObj = (space, id) => {
231
236
  return void 0;
232
237
  }
233
238
  };
234
- var RefPanel = ({ model }) => {
235
- const state = model?.modalController.state.value;
236
- const space = getSpace3(model?.table);
239
+ var RefPanel = ({ model, modals }) => {
240
+ const state = modals.state.value;
241
+ const space = getSpace3(model.table);
237
242
  const targetObj = getRefTargetObj(space, state?.type === "refPanel" ? state.targetId : void 0);
238
243
  const schema = space && state?.type === "refPanel" ? space.db.schemaRegistry.getSchema(state.typename) : void 0;
239
- if (!model?.table?.view || !model.projection) {
244
+ if (!model.table?.view || !model.projection) {
240
245
  return null;
241
246
  }
242
247
  return /* @__PURE__ */ React4.createElement(Popover2.Root, {
243
248
  modal: false,
244
249
  open: state?.type === "refPanel" && !!targetObj && !!schema,
245
250
  onOpenChange: (nextOpen) => {
246
- if (model && !nextOpen) {
247
- return model.modalController.close();
251
+ if (!nextOpen) {
252
+ return modals.close();
248
253
  }
249
254
  }
250
255
  }, /* @__PURE__ */ React4.createElement(Popover2.VirtualTrigger, {
251
- virtualRef: model.modalController.trigger
256
+ virtualRef: modals.trigger
252
257
  }), /* @__PURE__ */ React4.createElement(Popover2.Portal, null, /* @__PURE__ */ React4.createElement(Popover2.Content, {
253
258
  classNames: "md:is-64"
254
259
  }, targetObj && schema && /* @__PURE__ */ React4.createElement(Form2, {
@@ -261,762 +266,319 @@ var RefPanel = ({ model }) => {
261
266
  // packages/ui/react-ui-table/src/components/Table/RowActionsMenu.tsx
262
267
  import React5 from "react";
263
268
  import { DropdownMenu as DropdownMenu3, useTranslation as useTranslation2 } from "@dxos/react-ui";
264
- var RowActionsMenu = ({ model }) => {
269
+ var RowActionsMenu = ({ model, modals }) => {
265
270
  const { t } = useTranslation2(translationKey);
266
271
  const hasSelection = model.selection.hasSelection.value;
267
- const state = model.modalController.state.value;
272
+ const state = modals.state.value;
268
273
  if (state?.type !== "row") {
269
274
  return null;
270
275
  }
271
276
  return /* @__PURE__ */ React5.createElement(DropdownMenu3.Root, {
272
277
  modal: false,
273
278
  open: true,
274
- onOpenChange: model.modalController.close
279
+ onOpenChange: modals.close
275
280
  }, /* @__PURE__ */ React5.createElement(DropdownMenu3.VirtualTrigger, {
276
- virtualRef: model.modalController.trigger
281
+ virtualRef: modals.trigger
277
282
  }), /* @__PURE__ */ React5.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Viewport, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Item, {
278
283
  "data-testid": "row-menu-delete",
279
284
  onClick: () => model.deleteRow(state.rowIndex)
280
285
  }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React5.createElement(DropdownMenu3.Arrow, null)));
281
286
  };
282
287
 
283
- // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
284
- import React6, { useCallback as useCallback3, useMemo as useMemo3, useRef } from "react";
285
- import { FormatEnum } from "@dxos/echo-schema";
288
+ // packages/ui/react-ui-table/src/model/table-model.ts
289
+ import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
290
+ import { Resource as Resource2 } from "@dxos/context";
291
+ import { FormatEnum as FormatEnum3, getValue as getValue2, setValue } from "@dxos/echo-schema";
286
292
  import { invariant } from "@dxos/invariant";
287
- import { cellQuery, editorKeys, parseCellIndex, useGridContext as useGridContext2, GridCellEditor } from "@dxos/react-ui-grid";
293
+ import { isReactiveObject, makeRef as makeRef2 } from "@dxos/live-object";
294
+ import { PublicKey as PublicKey2 } from "@dxos/react-client";
295
+ import { formatForEditing, parseValue } from "@dxos/react-ui-form";
288
296
 
289
- // packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
290
- import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
291
- import { EditorView } from "@codemirror/view";
292
- var completion = ({ debug, onQuery, onMatch }) => {
293
- return [
294
- EditorView.theme({
295
- ".cm-completionDialog": {
296
- width: "var(--dx-gridCellWidth)"
297
- }
298
- }),
299
- autocompletion({
300
- icons: false,
301
- activateOnTyping: true,
302
- closeOnBlur: !debug,
303
- override: [
304
- async (context) => {
305
- const text = context.state.doc.toString();
306
- return {
307
- from: 0,
308
- options: await onQuery(text)
309
- };
310
- }
311
- ],
312
- // TODO(burdon): Consts from grid (to line-up with grid).
313
- tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
314
- optionClass: () => "flex h-[33px] items-center"
315
- }),
316
- // Check for accepted completion metadata in the transaction.
317
- EditorView.updateListener.of((update) => {
318
- update.transactions.forEach((tr) => {
319
- const completion2 = tr.annotation(pickedCompletion);
320
- if (completion2) {
321
- onMatch(completion2.data);
322
- }
323
- });
324
- })
325
- ];
326
- };
297
+ // packages/ui/react-ui-table/src/model/selection-model.ts
298
+ import { computed, effect, signal } from "@preact/signals-core";
299
+ import { Resource } from "@dxos/context";
327
300
 
328
- // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
329
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
330
- var newValue = Symbol.for("newValue");
331
- var createOption = (text) => ({
332
- [newValue]: true,
333
- text
334
- });
335
- var isCreateOption = (data) => typeof data === "object" && data[newValue];
336
- var TableCellEditor = ({ model, onEnter, onFocus, onQuery, __gridScope }) => {
337
- const { id: gridId, editing, setEditing } = useGridContext2("TableCellEditor", __gridScope);
338
- const suppressNextBlur = useRef(false);
339
- const fieldProjection = useMemo3(() => {
340
- if (!model || !editing) {
341
- return;
301
+ // packages/ui/react-ui-table/src/util/signals.ts
302
+ var touch = (value) => value;
303
+
304
+ // packages/ui/react-ui-table/src/util/table.ts
305
+ import { AST, Format, FormatEnum, S as S2, TypedObject, TypeEnum } from "@dxos/echo-schema";
306
+ import { PublicKey } from "@dxos/react-client";
307
+ import { create as create2, makeRef } from "@dxos/react-client/echo";
308
+ import { createFieldId, createView, getSchemaProperties, ViewProjection } from "@dxos/schema";
309
+ var initializeTable = async ({ space, table, initialRow = true, initialSchema }) => {
310
+ if (initialSchema) {
311
+ const schema = await space.db.schemaRegistry.query({
312
+ typename: initialSchema
313
+ }).firstOrUndefined();
314
+ if (!schema) {
315
+ throw new Error(`Schema not found: ${initialSchema}`);
342
316
  }
343
- const { col } = parseCellIndex(editing.index);
344
- const field = model.projection.view.fields[col];
345
- const fieldProjection2 = model.projection.getFieldProjection(field.id);
346
- invariant(fieldProjection2, void 0, {
347
- F: __dxlog_file,
348
- L: 65,
349
- S: void 0,
350
- A: [
351
- "fieldProjection",
352
- ""
317
+ const fields = getSchemaProperties(schema.ast).filter((prop) => prop.type !== "object" || prop.format === FormatEnum.Ref).map((prop) => prop.name);
318
+ table.view = makeRef(createView({
319
+ // TODO(ZaymonFC): Don't hardcode name?
320
+ name: "View",
321
+ typename: schema.typename,
322
+ jsonSchema: schema.jsonSchema,
323
+ fields
324
+ }));
325
+ return schema;
326
+ } else {
327
+ const ContactSchema = TypedObject({
328
+ typename: `example.com/type/${PublicKey.random().truncate()}`,
329
+ version: "0.1.0"
330
+ })({
331
+ name: S2.optional(S2.String).annotations({
332
+ [AST.TitleAnnotationId]: "Name"
333
+ }),
334
+ active: S2.optional(S2.Boolean),
335
+ email: S2.optional(Format.Email),
336
+ salary: S2.optional(Format.Currency()).annotations({
337
+ [AST.TitleAnnotationId]: "Salary"
338
+ })
339
+ });
340
+ const [contactSchema] = await space.db.schemaRegistry.register([
341
+ ContactSchema
342
+ ]);
343
+ table.view = makeRef(createView({
344
+ name: "View",
345
+ typename: contactSchema.typename,
346
+ jsonSchema: contactSchema.jsonSchema,
347
+ fields: [
348
+ "name",
349
+ "email",
350
+ "salary",
351
+ "active"
353
352
  ]
353
+ }));
354
+ const projection = new ViewProjection(contactSchema, table.view.target);
355
+ projection.setFieldProjection({
356
+ field: {
357
+ id: table.view.target.fields.find((f) => f.path === "salary").id,
358
+ path: "salary",
359
+ size: 150
360
+ }
354
361
  });
355
- return fieldProjection2;
356
- }, [
357
- model,
358
- editing
359
- ]);
360
- const handleEnter = useCallback3((value) => {
361
- if (!model || !editing) {
362
- return;
363
- }
364
- const cell = parseCellIndex(editing.index);
365
- model.setCellData(cell, value);
366
- onEnter?.(cell);
367
- onFocus?.();
368
- setEditing(null);
369
- }, [
370
- model,
371
- editing
372
- ]);
373
- const handleBlur = useCallback3((value) => {
374
- if (!model || !editing) {
375
- return;
376
- }
377
- if (suppressNextBlur.current) {
378
- suppressNextBlur.current = false;
379
- return;
380
- }
381
- const cell = parseCellIndex(editing.index);
382
- if (value !== void 0) {
383
- model.setCellData(cell, value);
384
- }
385
- }, [
386
- model,
387
- editing
388
- ]);
389
- const handleClose = useCallback3((value, event) => {
390
- if (!model || !editing || !fieldProjection) {
391
- return;
392
- }
393
- const cell = parseCellIndex(editing.index);
394
- onEnter?.(cell);
395
- if (event && onFocus) {
396
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
397
- }
398
- }, [
399
- model,
400
- editing,
401
- onFocus,
402
- onEnter,
403
- fieldProjection,
404
- determineNavigationAxis,
405
- determineNavigationDelta
406
- ]);
407
- const extension = useMemo3(() => {
408
- if (!fieldProjection) {
409
- return [];
410
- }
411
- const extension2 = [
412
- editorKeys({
413
- onClose: handleClose,
414
- ...editing?.initialContent && {
415
- onNav: handleClose
416
- }
417
- })
418
- ];
419
- if (onQuery) {
420
- switch (fieldProjection.props.format) {
421
- case FormatEnum.Ref: {
422
- extension2.push([
423
- completion({
424
- onQuery: (text) => onQuery(fieldProjection, text),
425
- onMatch: (data) => {
426
- if (model && editing) {
427
- if (isCreateOption(data)) {
428
- const { field, props } = fieldProjection;
429
- if (props.referenceSchema) {
430
- suppressNextBlur.current = true;
431
- model.modalController.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
432
- [field.referencePath]: data.text
433
- }, (data2) => {
434
- handleEnter(data2);
435
- });
436
- }
437
- } else {
438
- handleEnter(data);
439
- }
440
- }
441
- }
442
- })
443
- ]);
444
- break;
445
- }
362
+ projection.setFieldProjection({
363
+ field: {
364
+ id: table.view.target.fields.find((f) => f.path === "active").id,
365
+ path: "active",
366
+ size: 100
446
367
  }
368
+ });
369
+ projection.setFieldProjection({
370
+ field: {
371
+ id: createFieldId(),
372
+ path: "manager",
373
+ referencePath: "name"
374
+ },
375
+ props: {
376
+ property: "manager",
377
+ type: TypeEnum.Ref,
378
+ format: FormatEnum.Ref,
379
+ referenceSchema: contactSchema.typename,
380
+ title: "Manager"
381
+ }
382
+ });
383
+ if (initialRow) {
384
+ space.db.add(create2(contactSchema, {}));
447
385
  }
448
- return extension2;
449
- }, [
450
- model,
451
- editing,
452
- fieldProjection,
453
- handleClose
454
- ]);
455
- const getCellContent = useCallback3(() => {
456
- if (model && editing) {
457
- const value = model.getCellData(parseCellIndex(editing.index));
458
- return value !== void 0 ? String(value) : "";
459
- }
460
- }, [
461
- model,
462
- editing
463
- ]);
464
- return /* @__PURE__ */ React6.createElement(GridCellEditor, {
465
- extension,
466
- getCellContent,
467
- onBlur: handleBlur
468
- });
469
- };
470
- var determineNavigationAxis = ({ key }) => {
471
- switch (key) {
472
- case "ArrowUp":
473
- case "ArrowDown":
474
- case "Enter": {
475
- return "row";
476
- }
477
- case "ArrowLeft":
478
- case "ArrowRight":
479
- case "Tab":
480
- return "col";
481
- }
482
- };
483
- var determineNavigationDelta = ({ key, shift }) => {
484
- switch (key) {
485
- case "ArrowUp":
486
- case "ArrowLeft":
487
- return -1;
488
- case "ArrowDown":
489
- case "ArrowRight":
490
- return 1;
386
+ return contactSchema;
491
387
  }
492
- return shift ? -1 : 1;
493
388
  };
494
389
 
495
- // packages/ui/react-ui-table/src/components/Table/Table.tsx
496
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
497
- var inlineEndLine = "[&>.dx-grid]:relative [&>.dx-grid]:after:absolute [&>.dx-grid]:after:inset-block-0 [&>.dx-grid]:after:-inline-end-px [&>.dx-grid]:after:is-px [&>.dx-grid]:after:bg-separator";
498
- var blockEndLine = "[&>.dx-grid]:before:absolute [&>.dx-grid]:before:inset-inline-0 [&>.dx-grid]:before:-block-end-px [&>.dx-grid]:before:bs-px [&>.dx-grid]:before:bg-separator";
499
- var frozen = {
500
- frozenRowsStart: 1,
501
- frozenColsStart: 1,
502
- frozenColsEnd: 1
390
+ // packages/ui/react-ui-table/src/util/table-buttons.ts
391
+ var BUTTON_IDENTIFIERS = {
392
+ columnSettings: "data-table-column-settings-button",
393
+ newColumn: "data-table-new-column-button",
394
+ referencedCell: "data-table-ref-cell-button",
395
+ rowMenu: "data-table-row-menu-button",
396
+ sort: "data-table-sort-button"
503
397
  };
504
- var TableRoot = ({ children, role }) => {
505
- return /* @__PURE__ */ React7.createElement("div", {
506
- role: "none",
507
- className: mx("relative border-bs !border-separator", role === "section" ? "attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]" : "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]")
508
- }, children);
398
+ var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
399
+ const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
400
+ const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
401
+ return `<button ${attr} data-testid="${testId}" class="ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${icon}"/></svg></button>`;
509
402
  };
510
- var TableMain = /* @__PURE__ */ forwardRef(({ model, ignoreAttention }, forwardedRef) => {
511
- const [dxGrid, setDxGrid] = useState2(null);
512
- const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : "table");
513
- const { t } = useTranslation3(translationKey);
514
- useImperativeHandle(forwardedRef, () => {
515
- if (!model || !dxGrid) {
516
- return {};
517
- }
518
- dxGrid.getCells = model.getCells.bind(model);
519
- return {
520
- update: (cell) => {
521
- if (cell) {
522
- dxGrid.updateIfWithinBounds(cell);
523
- } else {
524
- dxGrid.updateCells(true);
525
- }
526
- }
527
- };
528
- }, [
529
- model,
530
- dxGrid
531
- ]);
532
- const handleFocus = useCallback4((increment, delta) => {
533
- if (dxGrid) {
534
- dxGrid.refocus(increment, delta);
535
- }
536
- }, [
537
- dxGrid
538
- ]);
539
- const handleEnter = useCallback4((cell) => {
540
- if (model && cell.row === model.getRowCount() - 1) {
541
- model.insertRow(cell.row);
542
- if (dxGrid) {
543
- requestAnimationFrame(() => {
544
- dxGrid?.scrollToRow(cell.row + 1);
545
- dxGrid?.refocus("row", 1);
546
- });
547
- }
548
- }
549
- }, [
550
- model,
551
- dxGrid
552
- ]);
553
- const handleKeyDown = useCallback4((event) => {
554
- const cell = closestCell(event.target);
555
- if (!model || !cell) {
556
- return;
557
- }
558
- switch (event.key) {
559
- case "Backspace":
560
- case "Delete": {
561
- model.setCellData(cell, void 0);
562
- break;
563
- }
564
- }
565
- }, [
566
- model
567
- ]);
568
- const handleAxisResize = useCallback4((event) => {
569
- if (event.axis === "col") {
570
- const columnIndex = parseInt(event.index, 10);
571
- model?.setColumnWidth(columnIndex, event.size);
572
- }
573
- }, [
574
- model
575
- ]);
576
- const handleWheel = useCallback4((event) => {
577
- if (!ignoreAttention && !hasAttention) {
578
- event.stopPropagation();
579
- }
580
- }, [
581
- hasAttention,
582
- ignoreAttention
583
- ]);
584
- const handleNewColumn = useCallback4(() => {
585
- const columns = model?.getColumnCount();
586
- if (dxGrid && columns) {
587
- dxGrid.scrollToColumn(columns - 1);
588
- }
589
- }, [
590
- model,
591
- dxGrid
592
- ]);
593
- const handleQuery = useCallback4(async ({ field, props }, text) => {
594
- if (model && props.referenceSchema && field.referencePath) {
595
- const space = getSpace4(model.table);
596
- invariant2(space, void 0, {
597
- F: __dxlog_file2,
598
- L: 180,
599
- S: void 0,
600
- A: [
601
- "space",
602
- ""
603
- ]
604
- });
605
- const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
606
- if (schema) {
607
- const { objects } = await space.db.query(Filter.schema(schema)).run();
608
- const options = objects.map((obj) => {
609
- const value = getValue(obj, field.referencePath);
610
- if (!value || typeof value !== "string") {
611
- return void 0;
612
- }
613
- return {
614
- label: value,
615
- data: obj
616
- };
617
- }).filter(isNotFalsy);
618
- return [
619
- ...options,
620
- {
621
- label: t("create new object label", {
622
- text
623
- }),
624
- data: createOption(text)
625
- }
626
- ];
627
- }
628
- }
629
- return [];
630
- }, [
631
- model
632
- ]);
633
- if (!model) {
634
- return /* @__PURE__ */ React7.createElement("span", {
635
- role: "none",
636
- className: "attention-surface"
403
+ var addColumnButton = {
404
+ attr: BUTTON_IDENTIFIERS.newColumn,
405
+ icon: "ph--plus--regular",
406
+ render: ({ disabled }) => {
407
+ return createButton({
408
+ attr: BUTTON_IDENTIFIERS.newColumn,
409
+ icon: addColumnButton.icon,
410
+ disabled,
411
+ data: {},
412
+ testId: "table-new-column-button"
637
413
  });
638
- }
639
- return /* @__PURE__ */ React7.createElement(Grid.Root, {
640
- id: model.table.id ?? "table-grid"
641
- }, /* @__PURE__ */ React7.createElement(TableCellEditor, {
642
- model,
643
- onEnter: handleEnter,
644
- onFocus: handleFocus,
645
- onQuery: handleQuery
646
- }), /* @__PURE__ */ React7.createElement(Grid.Content, {
647
- onWheelCapture: handleWheel,
648
- className: mx("[--dx-grid-base:var(--surface-bg)]", inlineEndLine, blockEndLine),
649
- frozen,
650
- columns: model.columnMeta.value,
651
- limitRows: model.getRowCount() ?? 0,
652
- limitColumns: model.table.view?.fields?.length ?? 0,
653
- onAxisResize: handleAxisResize,
654
- onClick: model?.handleGridClick,
655
- onKeyDown: handleKeyDown,
656
- overscroll: "trap",
657
- ref: setDxGrid
658
- }), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
659
- model
660
- }), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
661
- model
662
- }), /* @__PURE__ */ React7.createElement(ColumnSettings, {
663
- model,
664
- onNewColumn: handleNewColumn
665
- }), /* @__PURE__ */ React7.createElement(RefPanel, {
666
- model
667
- }), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
668
- model
669
- }));
670
- });
671
- var Table = {
672
- Root: TableRoot,
673
- Main: TableMain
674
- };
675
-
676
- // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
677
- import { createContext } from "@radix-ui/react-context";
678
- import React9 from "react";
679
- import { Toolbar as NaturalToolbar2, useTranslation as useTranslation4 } from "@dxos/react-ui";
680
-
681
- // packages/ui/react-ui-table/src/components/Toolbar/common.tsx
682
- import React8 from "react";
683
- import { Icon, Toolbar as NaturalToolbar, Tooltip } from "@dxos/react-ui";
684
- var buttonStyles = "min-bs-0 p-2";
685
- var tooltipProps = {
686
- side: "top",
687
- classNames: "z-10"
414
+ },
415
+ getData: (_el) => ({
416
+ type: "newColumn"
417
+ })
688
418
  };
689
- var ToolbarSeparator = () => /* @__PURE__ */ React8.createElement("div", {
690
- role: "separator",
691
- className: "grow"
692
- });
693
- var ToolbarButton = ({ icon, children, ...props }) => {
694
- return /* @__PURE__ */ React8.createElement(Tooltip.Root, null, /* @__PURE__ */ React8.createElement(Tooltip.Trigger, {
695
- asChild: true
696
- }, /* @__PURE__ */ React8.createElement(NaturalToolbar.Button, {
697
- variant: "ghost",
698
- ...props,
699
- classNames: buttonStyles
700
- }, /* @__PURE__ */ React8.createElement(Icon, {
701
- icon,
702
- size: 5
703
- }), /* @__PURE__ */ React8.createElement("span", {
704
- className: "sr-only"
705
- }, children))), /* @__PURE__ */ React8.createElement(Tooltip.Portal, null, /* @__PURE__ */ React8.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React8.createElement(Tooltip.Arrow, null))));
419
+ var columnSettingsButton = {
420
+ attr: BUTTON_IDENTIFIERS.columnSettings,
421
+ icon: "ph--caret-down--regular",
422
+ render: ({ fieldId }) => {
423
+ return createButton({
424
+ attr: BUTTON_IDENTIFIERS.columnSettings,
425
+ icon: columnSettingsButton.icon,
426
+ data: {
427
+ "data-field-id": fieldId
428
+ },
429
+ testId: "table-column-settings-button"
430
+ });
431
+ },
432
+ getData: (el) => ({
433
+ type: "columnSettings",
434
+ fieldId: el.getAttribute("data-field-id")
435
+ })
706
436
  };
707
-
708
- // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
709
- var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
710
- var ToolbarRoot = ({ classNames, children, onAction }) => {
711
- return /* @__PURE__ */ React9.createElement(ToolbarContextProvider, {
712
- onAction
713
- }, /* @__PURE__ */ React9.createElement(NaturalToolbar2.Root, {
714
- classNames: [
715
- "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1 attention-surface",
716
- classNames
717
- ]
718
- }, children));
437
+ var referencedCellButton = {
438
+ attr: BUTTON_IDENTIFIERS.referencedCell,
439
+ icon: "ph--link-simple-horizontal--regular",
440
+ render: ({ targetId, schemaId }) => {
441
+ return createButton({
442
+ attr: BUTTON_IDENTIFIERS.referencedCell,
443
+ icon: referencedCellButton.icon,
444
+ data: {
445
+ "data-target-id": targetId,
446
+ "data-schema-id": schemaId
447
+ },
448
+ testId: "table-ref-cell-button"
449
+ });
450
+ },
451
+ getData: (el) => ({
452
+ type: "referencedCell",
453
+ targetId: el.getAttribute("data-target-id"),
454
+ schemaId: el.getAttribute("data-schema-id")
455
+ })
719
456
  };
720
- var Editing = () => {
721
- const { onAction } = useToolbarContext("Editing");
722
- const { t } = useTranslation4(translationKey);
723
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(ToolbarButton, {
724
- value: "add-row",
725
- icon: "ph--plus--regular",
726
- "data-testid": "table.toolbar.add-row",
727
- onClick: () => onAction?.({
728
- type: "add-row"
729
- })
730
- }, t("add row")));
457
+ var rowMenuButton = {
458
+ attr: BUTTON_IDENTIFIERS.rowMenu,
459
+ icon: "ph--dots-three--regular",
460
+ render: ({ rowIndex }) => {
461
+ return createButton({
462
+ attr: BUTTON_IDENTIFIERS.rowMenu,
463
+ icon: rowMenuButton.icon,
464
+ data: {
465
+ "data-row-index": rowIndex.toString()
466
+ },
467
+ testId: "table-row-menu-button"
468
+ });
469
+ },
470
+ getData: (el) => ({
471
+ type: "rowMenu",
472
+ rowIndex: Number(el.getAttribute("data-row-index"))
473
+ })
731
474
  };
732
- var Actions = () => {
733
- const { onAction } = useToolbarContext("Actions");
734
- const { t } = useTranslation4(translationKey);
735
- return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(ToolbarButton, {
736
- value: "comment",
737
- icon: "ph--chat-text--regular",
738
- "data-testid": "table.toolbar.comment",
739
- onClick: () => onAction?.({
740
- type: "comment"
741
- })
742
- }, t("create comment")));
475
+ var sortButton = {
476
+ attr: BUTTON_IDENTIFIERS.sort,
477
+ icon: "ph--sort-ascending--regular",
478
+ render: ({ fieldId, direction }) => {
479
+ return createButton({
480
+ attr: BUTTON_IDENTIFIERS.sort,
481
+ icon: direction === "desc" ? "ph--sort-descending--regular" : "ph--sort-ascending--regular",
482
+ data: {
483
+ "data-field-id": fieldId,
484
+ "data-direction": direction ?? ""
485
+ },
486
+ testId: "table-sort-button",
487
+ // TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
488
+ // This is a bit hacky.
489
+ type: "secondary"
490
+ });
491
+ },
492
+ getData: (el) => ({
493
+ type: "sort",
494
+ fieldId: el.getAttribute("data-field-id"),
495
+ direction: el.getAttribute("data-direction")
496
+ })
743
497
  };
744
- var Toolbar = {
745
- Root: ToolbarRoot,
746
- Editing,
747
- Actions,
748
- Separator: ToolbarSeparator
498
+ var tableButtons = {
499
+ addColumn: addColumnButton,
500
+ columnSettings: columnSettingsButton,
501
+ referencedCell: referencedCellButton,
502
+ rowMenu: rowMenuButton,
503
+ sort: sortButton
749
504
  };
750
505
 
751
- // packages/ui/react-ui-table/src/hooks/useTableModel.ts
752
- import { useEffect as useEffect2, useState as useState3 } from "react";
753
-
754
- // packages/ui/react-ui-table/src/model/table-model.ts
755
- import { computed as computed2, effect as effect2, signal as signal3 } from "@preact/signals-core";
756
- import orderBy from "lodash.orderby";
757
- import { Resource as Resource2 } from "@dxos/context";
758
- import { getValue as getValue2, setValue, FormatEnum as FormatEnum3 } from "@dxos/echo-schema";
759
- import { invariant as invariant3 } from "@dxos/invariant";
760
- import { PublicKey as PublicKey2 } from "@dxos/react-client";
761
- import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay, formatForEditing, parseValue } from "@dxos/react-ui-form";
762
- import { toPlaneCellIndex } from "@dxos/react-ui-grid";
763
- import { mx as mx2 } from "@dxos/react-ui-theme";
764
- import { VIEW_FIELD_LIMIT } from "@dxos/schema";
765
-
766
- // packages/ui/react-ui-table/src/model/modal-controller.ts
767
- import { signal } from "@preact/signals-core";
768
- import { log as log2 } from "@dxos/log";
769
-
770
- // packages/ui/react-ui-table/src/util/signals.ts
771
- var touch = (value) => value;
772
-
773
- // packages/ui/react-ui-table/src/util/table.ts
774
- import { AST, Format, FormatEnum as FormatEnum2, S as S2, TypedObject, TypeEnum } from "@dxos/echo-schema";
775
- import { log } from "@dxos/log";
776
- import { PublicKey } from "@dxos/react-client";
777
- import { create as create2 } from "@dxos/react-client/echo";
778
- import { createFieldId, createView, ViewProjection } from "@dxos/schema";
779
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
780
- var initializeTable = ({ space, table, initialRow = true }) => {
781
- log.info("initializeTable", {
782
- table
783
- }, {
784
- F: __dxlog_file3,
785
- L: 32,
786
- S: void 0,
787
- C: (f, a) => f(...a)
788
- });
789
- const ContactSchema = TypedObject({
790
- typename: `example.com/type/${PublicKey.random().truncate()}`,
791
- version: "0.1.0"
792
- })({
793
- name: S2.optional(S2.String).annotations({
794
- [AST.TitleAnnotationId]: "Name"
795
- }),
796
- email: S2.optional(Format.Email),
797
- salary: S2.optional(Format.Currency()).annotations({
798
- [AST.TitleAnnotationId]: "Salary"
799
- })
800
- });
801
- const contactSchema = space.db.schemaRegistry.addSchema(ContactSchema);
802
- table.view = createView({
803
- name: "Test",
804
- typename: contactSchema.typename,
805
- jsonSchema: contactSchema.jsonSchema,
806
- fields: [
807
- "name",
808
- "email",
809
- "salary"
810
- ]
811
- });
812
- const projection = new ViewProjection(contactSchema, table.view);
813
- projection.setFieldProjection({
814
- field: {
815
- id: table.view.fields[2].id,
816
- path: "salary",
817
- size: 150
818
- }
819
- });
820
- projection.setFieldProjection({
821
- field: {
822
- id: createFieldId(),
823
- path: "manager",
824
- referencePath: "name"
825
- },
826
- props: {
827
- property: "manager",
828
- type: TypeEnum.Ref,
829
- format: FormatEnum2.Ref,
830
- referenceSchema: contactSchema.typename,
831
- title: "Manager"
832
- }
833
- });
834
- if (initialRow) {
835
- space.db.add(create2(contactSchema, {}));
836
- }
837
- return contactSchema;
506
+ // packages/ui/react-ui-table/src/util/table-controls.ts
507
+ var CONTROL_IDENTIFIERS = {
508
+ checkbox: "data-table-checkbox",
509
+ switch: "data-table-switch"
838
510
  };
839
-
840
- // packages/ui/react-ui-table/src/util/table-buttons.ts
841
- var TABLE_ATTRS = {
842
- referencedCell: "data-table-ref-cell-button",
843
- columnSettings: "data-table-column-settings-button",
844
- rowMenu: "data-table-row-menu-button",
845
- newColumn: "data-table-new-column-button"
511
+ var BASE_CLASSES = {
512
+ checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] ch-checkbox",
513
+ switch: "absolute inset-block-[.25rem] inline-end-[.25rem] ch-checkbox--switch"
846
514
  };
847
- var ICONS = {
848
- referencedCell: "ph--link-simple-horizontal--regular",
849
- columnSettings: "ph--caret-down--regular",
850
- rowMenu: "ph--dots-three--regular",
851
- newColumn: "ph--plus--regular"
515
+ var renderAttributes = (data) => {
516
+ return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
852
517
  };
853
- var createButtonHtml = ({ button, value = "", disabled = false, testId }) => {
854
- const buttonClasses = "ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 inline-end-2";
855
- return `<button class="${buttonClasses}" ${TABLE_ATTRS[button]}="${value}" data-testid="${testId}" ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${ICONS[button]}"/></svg></button>`;
518
+ var renderInput = (baseClass, attrs, checked = false, disabled = false, preventToggle = false, testId) => {
519
+ return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}"/>`;
856
520
  };
857
- var tableButtons = {
858
- referencedCell: {
859
- attr: TABLE_ATTRS.referencedCell,
860
- icon: ICONS.referencedCell,
861
- render: ({ targetId, schemaId }) => createButtonHtml({
862
- button: "referencedCell",
863
- value: `${schemaId}#${targetId}`,
864
- testId: "table-ref-cell-button"
865
- })
866
- },
867
- columnSettings: {
868
- attr: TABLE_ATTRS.columnSettings,
869
- icon: ICONS.columnSettings,
870
- render: ({ fieldId }) => createButtonHtml({
871
- button: "columnSettings",
872
- value: fieldId,
873
- testId: "table-column-settings-button"
874
- })
875
- },
876
- rowMenu: {
877
- attr: TABLE_ATTRS.rowMenu,
878
- icon: ICONS.rowMenu,
879
- render: ({ rowIndex }) => createButtonHtml({
880
- button: "rowMenu",
881
- value: rowIndex.toString(),
882
- testId: "table-row-menu-button"
521
+ var renderCheckbox = ({ rowIndex, header = false, checked = false, disabled = false }) => {
522
+ const attrs = {
523
+ [CONTROL_IDENTIFIERS.checkbox]: "",
524
+ "data-row-index": rowIndex.toString(),
525
+ ...header && {
526
+ "data-header": ""
527
+ }
528
+ };
529
+ return renderInput(BASE_CLASSES.checkbox, attrs, checked, disabled, true, "table-selection");
530
+ };
531
+ var renderSwitch = ({ colIndex, rowIndex, checked = false, disabled = false }) => {
532
+ const attrs = {
533
+ [CONTROL_IDENTIFIERS.switch]: "",
534
+ "data-row-index": rowIndex.toString(),
535
+ "data-col-index": colIndex.toString()
536
+ };
537
+ return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, "table-switch");
538
+ };
539
+ var tableControls = {
540
+ checkbox: {
541
+ attr: CONTROL_IDENTIFIERS.checkbox,
542
+ render: renderCheckbox,
543
+ getData: (el) => ({
544
+ type: "checkbox",
545
+ rowIndex: Number(el.getAttribute("data-row-index")),
546
+ header: el.hasAttribute("data-header")
883
547
  })
884
548
  },
885
- addColumn: {
886
- attr: TABLE_ATTRS.newColumn,
887
- icon: ICONS.newColumn,
888
- render: ({ disabled } = {}) => createButtonHtml({
889
- button: "newColumn",
890
- disabled,
891
- testId: "table-new-column-button"
549
+ switch: {
550
+ attr: CONTROL_IDENTIFIERS.switch,
551
+ render: renderSwitch,
552
+ getData: (el) => ({
553
+ type: "switch",
554
+ rowIndex: Number(el.getAttribute("data-row-index")),
555
+ colIndex: Number(el.getAttribute("data-col-index"))
892
556
  })
893
557
  }
894
558
  };
895
559
 
896
- // packages/ui/react-ui-table/src/model/modal-controller.ts
897
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
898
- var ModalController = class {
899
- constructor() {
900
- this._state = signal({
901
- type: "closed"
902
- });
903
- this._triggerRef = {
904
- current: null
905
- };
906
- this.handleClick = (event) => {
907
- const target = event.target;
908
- const rowButton = target.closest(`button[${tableButtons.rowMenu.attr}]`);
909
- if (rowButton) {
910
- this._triggerRef.current = rowButton;
911
- this._state.value = {
912
- type: "row",
913
- rowIndex: Number(rowButton.getAttribute(tableButtons.rowMenu.attr))
914
- };
915
- return true;
916
- }
917
- const columnButton = target.closest(`button[${tableButtons.columnSettings.attr}]`);
918
- if (columnButton) {
919
- const fieldId = columnButton.getAttribute(tableButtons.columnSettings.attr);
920
- this._triggerRef.current = columnButton;
921
- this._state.value = {
922
- type: "column",
923
- fieldId
924
- };
925
- return true;
926
- }
927
- const addColumnButton = target.closest(`button[${tableButtons.addColumn.attr}]`);
928
- if (addColumnButton) {
929
- this._triggerRef.current = addColumnButton;
930
- this._state.value = {
931
- type: "columnSettings",
932
- mode: {
933
- type: "create"
934
- }
935
- };
936
- return true;
560
+ // packages/ui/react-ui-table/src/model/selection-model.ts
561
+ var SelectionModel = class extends Resource {
562
+ constructor(_rows, _onSelectionChanged) {
563
+ super();
564
+ this._rows = _rows;
565
+ this._onSelectionChanged = _onSelectionChanged;
566
+ this._selection = signal(/* @__PURE__ */ new Set());
567
+ this._validSelectedIds = computed(() => {
568
+ const rows = this._rows.value;
569
+ if (!rows) {
570
+ return /* @__PURE__ */ new Set();
937
571
  }
938
- const refButton = target.closest(`button[${tableButtons.referencedCell.attr}]`);
939
- if (refButton) {
940
- this._triggerRef.current = refButton;
941
- const [schemaId, targetId] = refButton.getAttribute(tableButtons.referencedCell.attr).split("#");
942
- this._state.value = {
943
- type: "refPanel",
944
- targetId,
945
- typename: schemaId
946
- };
947
- }
948
- return false;
949
- };
950
- this.openColumnSettings = () => {
951
- if (this._state.value.type === "column") {
952
- const fieldId = this._state.value.fieldId;
953
- requestAnimationFrame(() => {
954
- this._state.value = {
955
- type: "columnSettings",
956
- mode: {
957
- type: "edit",
958
- fieldId
959
- }
960
- };
961
- });
962
- }
963
- };
964
- this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
965
- if (anchorCell) {
966
- this._triggerRef.current = anchorCell;
967
- this._state.value = {
968
- type: "createRefPanel",
969
- typename,
970
- initialValues,
971
- onCreate
972
- };
973
- } else {
974
- log2.warn("anchor cell not found while creating new ref", void 0, {
975
- F: __dxlog_file4,
976
- L: 119,
977
- S: this,
978
- C: (f, a) => f(...a)
979
- });
980
- }
981
- };
982
- this.close = () => {
983
- this._state.value = {
984
- type: "closed"
985
- };
986
- };
987
- }
988
- get state() {
989
- return this._state;
990
- }
991
- get trigger() {
992
- return this._triggerRef;
993
- }
994
- };
995
-
996
- // packages/ui/react-ui-table/src/model/selection-model.ts
997
- import { computed, effect, signal as signal2 } from "@preact/signals-core";
998
- import { Resource } from "@dxos/context";
999
- var SelectionModel = class extends Resource {
1000
- constructor(_rows, _onSelectionChanged) {
1001
- super();
1002
- this._rows = _rows;
1003
- this._onSelectionChanged = _onSelectionChanged;
1004
- this._selection = signal2(/* @__PURE__ */ new Set());
1005
- this._validSelectedIds = computed(() => {
1006
- const rows = this._rows.value;
1007
- if (!rows) {
1008
- return /* @__PURE__ */ new Set();
1009
- }
1010
- const validIds = new Set(rows.map((row) => row.id));
1011
- return new Set([
1012
- ...this._selection.value
1013
- ].filter((id) => validIds.has(id)));
1014
- });
1015
- this._hasSelection = computed(() => this._validSelectedIds.value.size > 0);
1016
- this._allSelected = computed(() => {
1017
- const rows = this._rows.value;
1018
- if (rows.length === 0) {
1019
- return false;
572
+ const validIds = new Set(rows.map((row) => row.id));
573
+ return new Set([
574
+ ...this._selection.value
575
+ ].filter((id) => validIds.has(id)));
576
+ });
577
+ this._hasSelection = computed(() => this._validSelectedIds.value.size > 0);
578
+ this._allSelected = computed(() => {
579
+ const rows = this._rows.value;
580
+ if (rows.length === 0) {
581
+ return false;
1020
582
  }
1021
583
  return rows.every((row) => this._selection.value.has(row.id));
1022
584
  });
@@ -1042,7 +604,16 @@ var SelectionModel = class extends Resource {
1042
604
  this._selection.value = newSelection;
1043
605
  };
1044
606
  this.setSelection = (mode) => {
1045
- this._selection.value = mode === "all" ? new Set(this._rows.value.map((row) => row.id)) : /* @__PURE__ */ new Set();
607
+ switch (mode) {
608
+ case "all": {
609
+ this._selection.value = new Set(this._rows.value.map((row) => row.id));
610
+ break;
611
+ }
612
+ case "none": {
613
+ this._selection.value = /* @__PURE__ */ new Set();
614
+ break;
615
+ }
616
+ }
1046
617
  };
1047
618
  }
1048
619
  async _open() {
@@ -1066,25 +637,165 @@ var SelectionModel = class extends Resource {
1066
637
  }
1067
638
  };
1068
639
 
1069
- // packages/ui/react-ui-table/src/util/table-controls.ts
1070
- var checkboxAttributes = {
1071
- checkbox: "data-table-checkbox",
1072
- header: "data-table-header"
1073
- };
1074
- var renderCheckbox = ({ rowIndex, header = false, checked = false, disabled = false }) => {
1075
- const baseClasses = "absolute inset-block-[6px] inline-end-[6px] ch-checkbox";
1076
- const { attributes } = tableControls.checkbox;
1077
- return `<input type="checkbox" class="${baseClasses}" ${attributes.checkbox}="${rowIndex}" ${header ? attributes.header : ""} ${checked ? "checked" : ""} ${disabled ? "disabled" : ""} data-testid="table-selection"/>`;
1078
- };
1079
- var tableControls = {
1080
- checkbox: {
1081
- attributes: checkboxAttributes,
1082
- render: renderCheckbox
640
+ // packages/ui/react-ui-table/src/model/table-sorting.ts
641
+ import { computed as computed2, signal as signal2 } from "@preact/signals-core";
642
+ import orderBy from "lodash.orderby";
643
+ import { getValue, FormatEnum as FormatEnum2, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
644
+ import { formatForDisplay } from "@dxos/react-ui-form";
645
+ var TableSorting = class {
646
+ constructor(rows, _view, _projection) {
647
+ this._view = _view;
648
+ this._projection = _projection;
649
+ this._displayToDataIndex = /* @__PURE__ */ new Map();
650
+ this._localSort = signal2(void 0);
651
+ this._rows = rows;
652
+ this._isDirty = computed2(() => {
653
+ const local = this._localSort.value;
654
+ const viewSort = this._view?.query.sort?.[0];
655
+ if (local?.type === "cleared") {
656
+ return viewSort !== void 0;
657
+ }
658
+ if (local?.type === "active") {
659
+ if (!viewSort) {
660
+ return true;
661
+ }
662
+ return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
663
+ }
664
+ return false;
665
+ });
666
+ this.sortedRows = this.initialiseSortedRows();
667
+ }
668
+ /**
669
+ * @reactive
670
+ * @returns Local sort if present, falls back to view sort.
671
+ */
672
+ get sorting() {
673
+ const local = this._localSort.value;
674
+ if (local?.type === "cleared") {
675
+ return void 0;
676
+ }
677
+ if (local?.type === "active") {
678
+ return local.sort;
679
+ }
680
+ return this._view?.query.sort?.[0];
681
+ }
682
+ /**
683
+ * @reactive
684
+ * @returns Whether local sort differs from view sort.
685
+ */
686
+ get isDirty() {
687
+ return this._isDirty.value;
688
+ }
689
+ getDataIndex(displayIndex) {
690
+ return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
691
+ }
692
+ setSort(fieldId, direction) {
693
+ this._localSort.value = {
694
+ type: "active",
695
+ sort: {
696
+ fieldId,
697
+ direction
698
+ }
699
+ };
700
+ }
701
+ toggleSort(fieldId) {
702
+ if (!this._view || !this.sorting || this.sorting.fieldId !== fieldId) {
703
+ return;
704
+ }
705
+ switch (this.sorting.direction) {
706
+ case "asc": {
707
+ this.setSort(fieldId, "desc");
708
+ break;
709
+ }
710
+ case "desc": {
711
+ this.setSort(fieldId, "asc");
712
+ break;
713
+ }
714
+ }
715
+ }
716
+ clearSort() {
717
+ this._localSort.value = {
718
+ type: "cleared"
719
+ };
720
+ }
721
+ save() {
722
+ if (this._view && this._localSort.value !== void 0) {
723
+ if (this._localSort.value.type === "active") {
724
+ this._view.query.sort = [
725
+ this._localSort.value.sort
726
+ ];
727
+ } else {
728
+ this._view.query.sort = [];
729
+ }
730
+ this._localSort.value = void 0;
731
+ }
732
+ }
733
+ //
734
+ // Initialisation.
735
+ //
736
+ initialiseSortedRows() {
737
+ return computed2(() => {
738
+ this._displayToDataIndex.clear();
739
+ const sort = this.sorting;
740
+ if (!sort || !this._view) {
741
+ return this._rows.value;
742
+ }
743
+ const field = this._view.fields.find((f) => f.id === sort.fieldId);
744
+ if (!field) {
745
+ return this._rows.value;
746
+ }
747
+ const { props } = this._projection.getFieldProjection(field.id);
748
+ const dataWithIndices = this._rows.value.map((item, index) => {
749
+ const sortValue = this.getSortValue(props, field, item);
750
+ const isEmpty = !(props.type === TypeEnum2.Boolean) && (sortValue == null || sortValue === "");
751
+ return {
752
+ item,
753
+ index,
754
+ value: sortValue,
755
+ isEmpty
756
+ };
757
+ });
758
+ const ordered = orderBy(dataWithIndices, [
759
+ "isEmpty",
760
+ "value"
761
+ ], [
762
+ "asc",
763
+ sort.direction
764
+ ]);
765
+ ordered.forEach(({ index: dataIndex }, displayIndex) => {
766
+ if (displayIndex !== dataIndex) {
767
+ this._displayToDataIndex.set(displayIndex, dataIndex);
768
+ }
769
+ });
770
+ return ordered.map(({ item }) => item);
771
+ });
772
+ }
773
+ getSortValue(props, field, item) {
774
+ const { type, format } = props;
775
+ const value = getValue(item, field.path);
776
+ if (type === TypeEnum2.Boolean) {
777
+ return !!value;
778
+ }
779
+ if (type === TypeEnum2.Number) {
780
+ return value;
781
+ }
782
+ if (value == null) {
783
+ return value;
784
+ }
785
+ if (format === FormatEnum2.Ref && field.referencePath) {
786
+ const refValue = getValue(value.target, field.referencePath);
787
+ return refValue;
788
+ }
789
+ return formatForDisplay({
790
+ type,
791
+ format,
792
+ value
793
+ });
1083
794
  }
1084
795
  };
1085
796
 
1086
797
  // packages/ui/react-ui-table/src/model/table-model.ts
1087
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
798
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
1088
799
  var TableModel = class extends Resource2 {
1089
800
  constructor({ table, projection, sorting = [], pinnedRows = {
1090
801
  top: [],
@@ -1102,200 +813,7 @@ var TableModel = class extends Resource2 {
1102
813
  col: 0
1103
814
  }
1104
815
  });
1105
- /**
1106
- * Maps display indices to data indices.
1107
- * Used for translating between sorted/displayed order and original data order.
1108
- * Keys are display indices, values are corresponding data indices.
1109
- */
1110
- this._displayToDataIndex = /* @__PURE__ */ new Map();
1111
- this._sorting = signal3(void 0);
1112
816
  this._rows = signal3([]);
1113
- this._modalController = new ModalController();
1114
- //
1115
- // Get Cells
1116
- //
1117
- this.getCells = (range, plane) => {
1118
- switch (plane) {
1119
- case "grid": {
1120
- this._visibleRange.value = range;
1121
- return this.getMainGridCells(range);
1122
- }
1123
- case "frozenRowsStart": {
1124
- return this.getHeaderCells(range);
1125
- }
1126
- case "frozenColsStart": {
1127
- return this.getSelectionColumnCells(range);
1128
- }
1129
- case "frozenColsEnd": {
1130
- return this.getActionColumnCells(range);
1131
- }
1132
- case "fixedStartStart": {
1133
- return this.getSelectAllCell();
1134
- }
1135
- case "fixedStartEnd": {
1136
- return this.getNewColumnCell();
1137
- }
1138
- default: {
1139
- return {};
1140
- }
1141
- }
1142
- };
1143
- this.getMainGridCells = (range) => {
1144
- const cells = {};
1145
- const fields = this._table.view?.fields ?? [];
1146
- const addCell = (obj, field, colIndex, displayIndex) => {
1147
- const { props } = this._projection.getFieldProjection(field.id);
1148
- const cell = {
1149
- get value() {
1150
- const value = getValue2(obj, field.path);
1151
- if (value == null) {
1152
- return "";
1153
- }
1154
- switch (props.format) {
1155
- case FormatEnum3.Ref: {
1156
- if (!field.referencePath) {
1157
- return "";
1158
- }
1159
- return getValue2(value, field.referencePath);
1160
- }
1161
- default: {
1162
- return formatForDisplay({
1163
- type: props.type,
1164
- format: props.format,
1165
- value
1166
- });
1167
- }
1168
- }
1169
- }
1170
- };
1171
- const classes = [];
1172
- const formatClasses = cellClassesForFieldType({
1173
- type: props.type,
1174
- format: props.format
1175
- });
1176
- if (formatClasses) {
1177
- classes.push(formatClasses);
1178
- }
1179
- const rowSelectionClasses = cellClassesForRowSelection(this._selection.isObjectSelected(obj));
1180
- if (rowSelectionClasses) {
1181
- classes.push(rowSelectionClasses);
1182
- }
1183
- if (classes.length > 0) {
1184
- cell.className = mx2(classes.flat());
1185
- }
1186
- if (cell.value && props.format === FormatEnum3.Ref && props.referenceSchema) {
1187
- const targetObj = getValue2(obj, field.path);
1188
- cell.accessoryHtml = tableButtons.referencedCell.render({
1189
- targetId: targetObj.id,
1190
- schemaId: props.referenceSchema
1191
- });
1192
- }
1193
- const idx = toPlaneCellIndex({
1194
- col: colIndex,
1195
- row: displayIndex
1196
- });
1197
- cells[idx] = cell;
1198
- };
1199
- for (let row = range.start.row; row <= range.end.row && row < this._sortedRows.value.length; row++) {
1200
- for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1201
- const field = fields[col];
1202
- if (!field) {
1203
- continue;
1204
- }
1205
- addCell(this._sortedRows.value[row], field, col, row);
1206
- }
1207
- }
1208
- return cells;
1209
- };
1210
- this.getHeaderCells = (range) => {
1211
- const cells = {};
1212
- const fields = this.table.view?.fields ?? [];
1213
- for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1214
- const { field, props } = this._projection.getFieldProjection(fields[col].id);
1215
- cells[toPlaneCellIndex({
1216
- col,
1217
- row: 0
1218
- })] = {
1219
- // TODO(burdon): Use same logic as form for fallback title.
1220
- value: props.title ?? field.path,
1221
- readonly: true,
1222
- resizeHandle: "col",
1223
- accessoryHtml: tableButtons.columnSettings.render({
1224
- fieldId: field.id
1225
- })
1226
- };
1227
- }
1228
- return cells;
1229
- };
1230
- this.getSelectionColumnCells = (range) => {
1231
- const cells = {};
1232
- for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
1233
- const isSelected = this._selection.isRowIndexSelected(row);
1234
- const classes = cellClassesForRowSelection(isSelected);
1235
- cells[toPlaneCellIndex({
1236
- col: 0,
1237
- row
1238
- })] = {
1239
- value: "",
1240
- readonly: true,
1241
- className: classes ? mx2(classes) : void 0,
1242
- accessoryHtml: tableControls.checkbox.render({
1243
- rowIndex: row,
1244
- checked: isSelected
1245
- })
1246
- };
1247
- }
1248
- return cells;
1249
- };
1250
- this.getActionColumnCells = (range) => {
1251
- const cells = {};
1252
- for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
1253
- const isSelected = this._selection.isRowIndexSelected(row);
1254
- const classes = cellClassesForRowSelection(isSelected);
1255
- cells[toPlaneCellIndex({
1256
- col: 0,
1257
- row
1258
- })] = {
1259
- value: "",
1260
- readonly: true,
1261
- className: classes ? mx2(classes) : void 0,
1262
- accessoryHtml: tableButtons.rowMenu.render({
1263
- rowIndex: row
1264
- })
1265
- };
1266
- }
1267
- return cells;
1268
- };
1269
- this.getSelectAllCell = () => {
1270
- return {
1271
- [toPlaneCellIndex({
1272
- col: 0,
1273
- row: 0
1274
- })]: {
1275
- value: "",
1276
- accessoryHtml: tableControls.checkbox.render({
1277
- rowIndex: 0,
1278
- header: true,
1279
- checked: this._selection.allRowsSeleted.value
1280
- }),
1281
- readonly: true
1282
- }
1283
- };
1284
- };
1285
- this.getNewColumnCell = () => {
1286
- return {
1287
- [toPlaneCellIndex({
1288
- col: 0,
1289
- row: 0
1290
- })]: {
1291
- value: "",
1292
- accessoryHtml: tableButtons.addColumn.render({
1293
- disabled: (this._table.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
1294
- }),
1295
- readonly: true
1296
- }
1297
- };
1298
- };
1299
817
  //
1300
818
  // Data
1301
819
  //
@@ -1303,13 +821,13 @@ var TableModel = class extends Resource2 {
1303
821
  this._rows.value = obj;
1304
822
  };
1305
823
  this.getRowCount = () => this._rows.value.length;
1306
- this.getColumnCount = () => this.table.view?.fields.length ?? 0;
824
+ this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
1307
825
  this.insertRow = (rowIndex) => {
1308
- const row = rowIndex !== void 0 ? this._displayToDataIndex.get(rowIndex) ?? rowIndex : this._rows.value.length;
826
+ const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
1309
827
  this._onInsertRow?.(row);
1310
828
  };
1311
829
  this.deleteRow = (rowIndex) => {
1312
- const row = this._displayToDataIndex.get(rowIndex) ?? rowIndex;
830
+ const row = this._sorting.getDataIndex(rowIndex);
1313
831
  const obj = this._rows.value[row];
1314
832
  const objectsToDelete = [];
1315
833
  if (this._selection.hasSelection.value) {
@@ -1321,12 +839,12 @@ var TableModel = class extends Resource2 {
1321
839
  this._onDeleteRows?.(row, objectsToDelete);
1322
840
  };
1323
841
  this.getCellData = ({ col, row }) => {
1324
- const fields = this.table.view?.fields ?? [];
842
+ const fields = this.table.view?.target?.fields ?? [];
1325
843
  if (col < 0 || col >= fields.length) {
1326
844
  return void 0;
1327
845
  }
1328
846
  const field = fields[col];
1329
- const dataIndex = this._displayToDataIndex.get(row) ?? row;
847
+ const dataIndex = this._sorting.getDataIndex(row);
1330
848
  const value = getValue2(this._rows.value[dataIndex], field.path);
1331
849
  if (value == null) {
1332
850
  return "";
@@ -1337,7 +855,7 @@ var TableModel = class extends Resource2 {
1337
855
  if (!field.referencePath) {
1338
856
  return "";
1339
857
  }
1340
- return getValue2(value, field.referencePath);
858
+ return getValue2(value.target, field.referencePath);
1341
859
  }
1342
860
  default: {
1343
861
  return formatForEditing({
@@ -1349,8 +867,8 @@ var TableModel = class extends Resource2 {
1349
867
  }
1350
868
  };
1351
869
  this.setCellData = ({ col, row }, value) => {
1352
- const rowIdx = this._displayToDataIndex.get(row) ?? row;
1353
- const fields = this.table.view?.fields ?? [];
870
+ const rowIdx = this._sorting.getDataIndex(row);
871
+ const fields = this.table.view?.target?.fields ?? [];
1354
872
  if (col < 0 || col >= fields.length) {
1355
873
  return;
1356
874
  }
@@ -1358,7 +876,9 @@ var TableModel = class extends Resource2 {
1358
876
  const { props } = this._projection.getFieldProjection(field.id);
1359
877
  switch (props.format) {
1360
878
  case FormatEnum3.Ref: {
1361
- setValue(this._rows.value[rowIdx], field.path, value);
879
+ if (isReactiveObject(value)) {
880
+ setValue(this._rows.value[rowIdx], field.path, makeRef2(value));
881
+ }
1362
882
  break;
1363
883
  }
1364
884
  default: {
@@ -1371,31 +891,13 @@ var TableModel = class extends Resource2 {
1371
891
  }
1372
892
  }
1373
893
  };
1374
- //
1375
- // Interactions
1376
- //
1377
- this.handleGridClick = (event) => {
1378
- if (!this._modalController.handleClick(event)) {
1379
- const target = event.target;
1380
- const selectionCheckbox = target.closest(`input[${tableControls.checkbox.attributes.checkbox}]`);
1381
- if (selectionCheckbox) {
1382
- const isHeader = selectionCheckbox.hasAttribute(tableControls.checkbox.attributes.header);
1383
- if (isHeader) {
1384
- if (this._selection.allRowsSeleted.value) {
1385
- this._selection.setSelection("none");
1386
- } else {
1387
- this._selection.setSelection("all");
1388
- }
1389
- } else {
1390
- const rowIndex = Number(selectionCheckbox.getAttribute(tableControls.checkbox.attributes.checkbox));
1391
- this._selection.toggleSelectionForRowIndex(rowIndex);
1392
- }
1393
- }
1394
- }
1395
- };
1396
894
  this._table = table;
1397
895
  this._projection = projection;
1398
- this._sorting.value = sorting.at(0);
896
+ this._sorting = new TableSorting(this._rows, table.view?.target, projection);
897
+ if (sorting.length > 0) {
898
+ const [sort] = sorting;
899
+ this._sorting.setSort(sort.fieldId, sort.direction);
900
+ }
1399
901
  this._pinnedRows = pinnedRows;
1400
902
  this._onInsertRow = onInsertRow;
1401
903
  this._onDeleteRows = onDeleteRows;
@@ -1409,13 +911,22 @@ var TableModel = class extends Resource2 {
1409
911
  get projection() {
1410
912
  return this._projection;
1411
913
  }
914
+ get rows() {
915
+ return this._sorting.sortedRows;
916
+ }
917
+ /**
918
+ * @reactive
919
+ */
920
+ get sorting() {
921
+ return this._sorting;
922
+ }
1412
923
  get pinnedRows() {
1413
924
  return this._pinnedRows;
1414
925
  }
1415
926
  get columnMeta() {
1416
- invariant3(this._columnMeta, void 0, {
1417
- F: __dxlog_file5,
1418
- L: 126,
927
+ invariant(this._columnMeta, void 0, {
928
+ F: __dxlog_file,
929
+ L: 117,
1419
930
  S: this,
1420
931
  A: [
1421
932
  "this._columnMeta",
@@ -1424,28 +935,25 @@ var TableModel = class extends Resource2 {
1424
935
  });
1425
936
  return this._columnMeta;
1426
937
  }
1427
- get sorting() {
1428
- return this._sorting.value;
1429
- }
1430
- get modalController() {
1431
- return this._modalController;
1432
- }
1433
938
  get selection() {
1434
939
  return this._selection;
1435
940
  }
941
+ /** @reactive */
942
+ get isViewDirty() {
943
+ return this._sorting.isDirty;
944
+ }
1436
945
  //
1437
946
  // Initialisation
1438
947
  //
1439
948
  async _open() {
1440
949
  this.initializeColumnMeta();
1441
- this.initializeSorting();
1442
950
  this.initializeEffects();
1443
- this._selection = new SelectionModel(this._sortedRows, () => this._onRowOrderChanged?.());
951
+ this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
1444
952
  await this._selection.open(this._ctx);
1445
953
  }
1446
954
  initializeColumnMeta() {
1447
- this._columnMeta = computed2(() => {
1448
- const fields = this._table.view?.fields ?? [];
955
+ this._columnMeta = computed3(() => {
956
+ const fields = this._table.view?.target?.fields ?? [];
1449
957
  const meta = Object.fromEntries(fields.map((field, index) => [
1450
958
  index,
1451
959
  {
@@ -1470,45 +978,9 @@ var TableModel = class extends Resource2 {
1470
978
  };
1471
979
  });
1472
980
  }
1473
- initializeSorting() {
1474
- this._sortedRows = computed2(() => {
1475
- this._displayToDataIndex.clear();
1476
- const sort = this._sorting.value;
1477
- if (!sort) {
1478
- return this._rows.value;
1479
- }
1480
- const field = this._table.view?.fields.find((field2) => field2.id === sort.fieldId);
1481
- if (!field) {
1482
- return this._rows.value;
1483
- }
1484
- const dataWithIndices = this._rows.value.map((item, index) => {
1485
- const value = getValue2(item, field.path);
1486
- return {
1487
- item,
1488
- index,
1489
- value,
1490
- isEmpty: value == null || value === ""
1491
- };
1492
- });
1493
- const sorted = orderBy(dataWithIndices, [
1494
- "isEmpty",
1495
- "value"
1496
- ], [
1497
- "asc",
1498
- sort.direction
1499
- ]);
1500
- for (let displayIndex = 0; displayIndex < sorted.length; displayIndex++) {
1501
- const { index: dataIndex } = sorted[displayIndex];
1502
- if (displayIndex !== dataIndex) {
1503
- this._displayToDataIndex.set(displayIndex, dataIndex);
1504
- }
1505
- }
1506
- return sorted.map(({ item }) => item);
1507
- });
1508
- }
1509
981
  initializeEffects() {
1510
982
  const rowOrderWatcher = effect2(() => {
1511
- touch(this._sortedRows.value);
983
+ touch(this._sorting.sortedRows.value);
1512
984
  this._onRowOrderChanged?.();
1513
985
  });
1514
986
  this._ctx.onDispose(rowOrderWatcher);
@@ -1517,8 +989,8 @@ var TableModel = class extends Resource2 {
1517
989
  const rowEffects = [];
1518
990
  for (let row = start.row; row <= end.row; row++) {
1519
991
  rowEffects.push(effect2(() => {
1520
- const obj = this._sortedRows.value[row];
1521
- this?._table?.view?.fields.forEach((field) => touch(getValue2(obj, field.path)));
992
+ const obj = this._sorting.sortedRows.value[row];
993
+ this?._table?.view?.target?.fields.forEach((field) => touch(getValue2(obj, field.path)));
1522
994
  this._onCellUpdate?.({
1523
995
  row,
1524
996
  col: start.col,
@@ -1530,6 +1002,19 @@ var TableModel = class extends Resource2 {
1530
1002
  });
1531
1003
  this._ctx.onDispose(rowEffectManager);
1532
1004
  }
1005
+ /**
1006
+ * Updates a cell's value using a transform function.
1007
+ * @param {DxGridPlanePosition} position - The position of the cell to update.
1008
+ * @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
1009
+ */
1010
+ updateCellData({ col, row }, update) {
1011
+ const dataRow = this._sorting.getDataIndex(row);
1012
+ const fields = this.table.view?.target?.fields ?? [];
1013
+ const field = fields[col];
1014
+ const value = getValue2(this._rows.value[dataRow], field.path);
1015
+ const updatedValue = update(value);
1016
+ setValue(this._rows.value[dataRow], field.path, updatedValue);
1017
+ }
1533
1018
  //
1534
1019
  // Column Operations
1535
1020
  //
@@ -1537,11 +1022,8 @@ var TableModel = class extends Resource2 {
1537
1022
  if (!this.table.view) {
1538
1023
  return;
1539
1024
  }
1540
- const field = this.table.view.fields.find((field2) => field2.id === fieldId);
1025
+ const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
1541
1026
  if (field && this._onDeleteColumn) {
1542
- if (this._sorting.value?.fieldId === fieldId) {
1543
- this.clearSort();
1544
- }
1545
1027
  this._onDeleteColumn(field.id);
1546
1028
  }
1547
1029
  }
@@ -1549,7 +1031,7 @@ var TableModel = class extends Resource2 {
1549
1031
  // Resize
1550
1032
  //
1551
1033
  setColumnWidth(columnIndex, width) {
1552
- const fields = this.table.view?.fields ?? [];
1034
+ const fields = this.table.view?.target?.fields ?? [];
1553
1035
  if (columnIndex < fields.length) {
1554
1036
  const newWidth = Math.max(0, width);
1555
1037
  const field = fields[columnIndex];
@@ -1559,18 +1041,6 @@ var TableModel = class extends Resource2 {
1559
1041
  }
1560
1042
  }
1561
1043
  //
1562
- // Sorting
1563
- //
1564
- setSort(fieldId, direction) {
1565
- this._sorting.value = {
1566
- fieldId,
1567
- direction
1568
- };
1569
- }
1570
- clearSort() {
1571
- this._sorting.value = void 0;
1572
- }
1573
- //
1574
1044
  // Pinning
1575
1045
  //
1576
1046
  // TODO(burdon): Change to setPinned(on/off).
@@ -1581,9 +1051,870 @@ var TableModel = class extends Resource2 {
1581
1051
  this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
1582
1052
  this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
1583
1053
  }
1054
+ //
1055
+ // View operations
1056
+ //
1057
+ saveView() {
1058
+ this._sorting.save();
1059
+ }
1584
1060
  };
1585
1061
 
1586
- // packages/ui/react-ui-table/src/hooks/useTableModel.ts
1062
+ // packages/ui/react-ui-table/src/model/modal-controller.ts
1063
+ import { signal as signal4 } from "@preact/signals-core";
1064
+ import { log } from "@dxos/log";
1065
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1066
+ var ModalController = class {
1067
+ constructor() {
1068
+ this._state = signal4({
1069
+ type: "closed"
1070
+ });
1071
+ this._triggerRef = {
1072
+ current: null
1073
+ };
1074
+ this.setTrigger = (trigger) => {
1075
+ this._triggerRef.current = trigger;
1076
+ };
1077
+ this.showRowMenu = (rowIndex) => {
1078
+ this._state.value = {
1079
+ type: "row",
1080
+ rowIndex
1081
+ };
1082
+ };
1083
+ this.showColumnMenu = (fieldId) => {
1084
+ this._state.value = {
1085
+ type: "column",
1086
+ fieldId
1087
+ };
1088
+ };
1089
+ this.showColumnCreator = () => {
1090
+ this._state.value = {
1091
+ type: "columnSettings",
1092
+ mode: {
1093
+ type: "create"
1094
+ }
1095
+ };
1096
+ };
1097
+ this.showReferencePanel = (targetId, schemaId) => {
1098
+ this._state.value = {
1099
+ type: "refPanel",
1100
+ targetId,
1101
+ typename: schemaId
1102
+ };
1103
+ };
1104
+ this.openColumnSettings = () => {
1105
+ if (this._state.value.type === "column") {
1106
+ const fieldId = this._state.value.fieldId;
1107
+ requestAnimationFrame(() => {
1108
+ this._state.value = {
1109
+ type: "columnSettings",
1110
+ mode: {
1111
+ type: "edit",
1112
+ fieldId
1113
+ }
1114
+ };
1115
+ });
1116
+ }
1117
+ };
1118
+ this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1119
+ if (anchorCell) {
1120
+ this._triggerRef.current = anchorCell;
1121
+ this._state.value = {
1122
+ type: "createRefPanel",
1123
+ typename,
1124
+ initialValues,
1125
+ onCreate
1126
+ };
1127
+ } else {
1128
+ log.warn("anchor cell not found while creating new ref", void 0, {
1129
+ F: __dxlog_file2,
1130
+ L: 86,
1131
+ S: this,
1132
+ C: (f, a) => f(...a)
1133
+ });
1134
+ }
1135
+ };
1136
+ this.close = () => {
1137
+ this._state.value = {
1138
+ type: "closed"
1139
+ };
1140
+ };
1141
+ }
1142
+ get state() {
1143
+ return this._state;
1144
+ }
1145
+ get trigger() {
1146
+ return this._triggerRef;
1147
+ }
1148
+ };
1149
+
1150
+ // packages/ui/react-ui-table/src/model/table-presentation.ts
1151
+ import { signal as signal5 } from "@preact/signals-core";
1152
+ import { FormatEnum as FormatEnum4, getValue as getValue3 } from "@dxos/echo-schema";
1153
+ import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1154
+ import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1155
+ import { mx } from "@dxos/react-ui-theme";
1156
+ import { VIEW_FIELD_LIMIT } from "@dxos/schema";
1157
+ var TablePresentation = class {
1158
+ constructor(model, _visibleRange = signal5({
1159
+ start: {
1160
+ row: 0,
1161
+ col: 0
1162
+ },
1163
+ end: {
1164
+ row: 0,
1165
+ col: 0
1166
+ }
1167
+ })) {
1168
+ this.model = model;
1169
+ this._visibleRange = _visibleRange;
1170
+ }
1171
+ getCells(range, plane) {
1172
+ switch (plane) {
1173
+ case "grid":
1174
+ this._visibleRange.value = range;
1175
+ return this.getMainGridCells(range);
1176
+ case "frozenRowsStart":
1177
+ return this.getHeaderCells(range);
1178
+ case "frozenColsStart":
1179
+ return this.getSelectionColumnCells(range);
1180
+ case "frozenColsEnd":
1181
+ return this.getActionColumnCells(range);
1182
+ case "fixedStartStart":
1183
+ return this.getSelectAllCell();
1184
+ case "fixedStartEnd":
1185
+ return this.getNewColumnCell();
1186
+ default:
1187
+ return {};
1188
+ }
1189
+ }
1190
+ getMainGridCells(range) {
1191
+ const cells = {};
1192
+ const fields = this.model.table.view?.target?.fields ?? [];
1193
+ const addCell = (obj, field, colIndex, displayIndex) => {
1194
+ const { props } = this.model.projection.getFieldProjection(field.id);
1195
+ const cell = {
1196
+ get value() {
1197
+ const value = getValue3(obj, field.path);
1198
+ if (value == null) {
1199
+ return "";
1200
+ }
1201
+ switch (props.format) {
1202
+ case FormatEnum4.Boolean: {
1203
+ return "";
1204
+ }
1205
+ case FormatEnum4.Ref: {
1206
+ if (!field.referencePath) {
1207
+ return "";
1208
+ }
1209
+ return getValue3(value.target, field.referencePath);
1210
+ }
1211
+ default: {
1212
+ return formatForDisplay2({
1213
+ type: props.type,
1214
+ format: props.format,
1215
+ value
1216
+ });
1217
+ }
1218
+ }
1219
+ }
1220
+ };
1221
+ const classes = [];
1222
+ const formatClasses = cellClassesForFieldType({
1223
+ type: props.type,
1224
+ format: props.format
1225
+ });
1226
+ if (formatClasses) {
1227
+ classes.push(formatClasses);
1228
+ }
1229
+ const rowSelectionClasses = cellClassesForRowSelection(this.model.selection.isObjectSelected(obj));
1230
+ if (rowSelectionClasses) {
1231
+ classes.push(rowSelectionClasses);
1232
+ }
1233
+ if (classes.length > 0) {
1234
+ cell.className = mx(classes.flat());
1235
+ }
1236
+ if (props.format === FormatEnum4.Ref && props.referenceSchema) {
1237
+ const targetObj = getValue3(obj, field.path)?.target;
1238
+ if (targetObj) {
1239
+ cell.accessoryHtml = tableButtons.referencedCell.render({
1240
+ targetId: targetObj.id,
1241
+ schemaId: props.referenceSchema
1242
+ });
1243
+ }
1244
+ }
1245
+ if (props.format === FormatEnum4.Boolean) {
1246
+ const value = getValue3(obj, field.path);
1247
+ cell.accessoryHtml = tableControls.switch.render({
1248
+ colIndex,
1249
+ rowIndex: displayIndex,
1250
+ checked: value ?? false
1251
+ });
1252
+ cell.readonly = true;
1253
+ }
1254
+ const idx = toPlaneCellIndex({
1255
+ col: colIndex,
1256
+ row: displayIndex
1257
+ });
1258
+ cells[idx] = cell;
1259
+ };
1260
+ for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1261
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1262
+ const field = fields[col];
1263
+ if (!field) {
1264
+ continue;
1265
+ }
1266
+ addCell(this.model.rows.value[row], field, col, row);
1267
+ }
1268
+ }
1269
+ return cells;
1270
+ }
1271
+ getHeaderCells(range) {
1272
+ const cells = {};
1273
+ const fields = this.model.table.view?.target?.fields ?? [];
1274
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1275
+ const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1276
+ const sorting = this.model.sorting?.sorting;
1277
+ const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
1278
+ cells[toPlaneCellIndex({
1279
+ col,
1280
+ row: 0
1281
+ })] = {
1282
+ // TODO(burdon): Use same logic as form for fallback title.
1283
+ value: props.title ?? field.path,
1284
+ readonly: true,
1285
+ resizeHandle: "col",
1286
+ accessoryHtml: `
1287
+ ${direction !== void 0 ? tableButtons.sort.render({
1288
+ fieldId: field.id,
1289
+ direction
1290
+ }) : ""}
1291
+ ${tableButtons.columnSettings.render({
1292
+ fieldId: field.id
1293
+ })}
1294
+ `,
1295
+ className: "!bg-gridHeader"
1296
+ };
1297
+ }
1298
+ return cells;
1299
+ }
1300
+ getSelectionColumnCells(range) {
1301
+ const cells = {};
1302
+ for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1303
+ const isSelected = this.model.selection.isRowIndexSelected(row);
1304
+ const classes = cellClassesForRowSelection(isSelected);
1305
+ cells[toPlaneCellIndex({
1306
+ col: 0,
1307
+ row
1308
+ })] = {
1309
+ value: "",
1310
+ readonly: true,
1311
+ className: classes ? mx(classes) : void 0,
1312
+ accessoryHtml: tableControls.checkbox.render({
1313
+ rowIndex: row,
1314
+ checked: isSelected
1315
+ })
1316
+ };
1317
+ }
1318
+ return cells;
1319
+ }
1320
+ getActionColumnCells(range) {
1321
+ const cells = {};
1322
+ for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1323
+ const isSelected = this.model.selection.isRowIndexSelected(row);
1324
+ const classes = cellClassesForRowSelection(isSelected);
1325
+ cells[toPlaneCellIndex({
1326
+ col: 0,
1327
+ row
1328
+ })] = {
1329
+ value: "",
1330
+ readonly: true,
1331
+ className: classes ? mx(classes) : void 0,
1332
+ accessoryHtml: tableButtons.rowMenu.render({
1333
+ rowIndex: row
1334
+ })
1335
+ };
1336
+ }
1337
+ return cells;
1338
+ }
1339
+ getSelectAllCell() {
1340
+ return {
1341
+ [toPlaneCellIndex({
1342
+ col: 0,
1343
+ row: 0
1344
+ })]: {
1345
+ accessoryHtml: tableControls.checkbox.render({
1346
+ rowIndex: 0,
1347
+ header: true,
1348
+ checked: this.model.selection.allRowsSeleted.value
1349
+ }),
1350
+ className: "!bg-gridHeader",
1351
+ readonly: true,
1352
+ value: ""
1353
+ }
1354
+ };
1355
+ }
1356
+ getNewColumnCell() {
1357
+ return {
1358
+ [toPlaneCellIndex({
1359
+ col: 0,
1360
+ row: 0
1361
+ })]: {
1362
+ accessoryHtml: tableButtons.addColumn.render({
1363
+ disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
1364
+ }),
1365
+ className: "!bg-gridHeader",
1366
+ readonly: true,
1367
+ value: ""
1368
+ }
1369
+ };
1370
+ }
1371
+ };
1372
+
1373
+ // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
1374
+ import React6, { useCallback as useCallback3, useMemo as useMemo3, useRef } from "react";
1375
+ import { FormatEnum as FormatEnum5 } from "@dxos/echo-schema";
1376
+ import { invariant as invariant2 } from "@dxos/invariant";
1377
+ import { cellQuery, editorKeys, parseCellIndex, useGridContext as useGridContext2, GridCellEditor } from "@dxos/react-ui-grid";
1378
+
1379
+ // packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
1380
+ import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
1381
+ import { EditorView } from "@codemirror/view";
1382
+ var completion = ({ debug, onQuery, onMatch }) => {
1383
+ return [
1384
+ EditorView.theme({
1385
+ ".cm-completionDialog": {
1386
+ width: "var(--dx-gridCellWidth)"
1387
+ }
1388
+ }),
1389
+ autocompletion({
1390
+ icons: false,
1391
+ activateOnTyping: true,
1392
+ closeOnBlur: !debug,
1393
+ override: [
1394
+ async (context) => {
1395
+ const text = context.state.doc.toString();
1396
+ return {
1397
+ from: 0,
1398
+ options: await onQuery(text)
1399
+ };
1400
+ }
1401
+ ],
1402
+ // TODO(burdon): Consts from grid (to line-up with grid).
1403
+ tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
1404
+ optionClass: () => "flex h-[33px] items-center"
1405
+ }),
1406
+ // Check for accepted completion metadata in the transaction.
1407
+ EditorView.updateListener.of((update) => {
1408
+ update.transactions.forEach((tr) => {
1409
+ const completion2 = tr.annotation(pickedCompletion);
1410
+ if (completion2) {
1411
+ onMatch(completion2.data);
1412
+ }
1413
+ });
1414
+ })
1415
+ ];
1416
+ };
1417
+
1418
+ // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
1419
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1420
+ var newValue = Symbol.for("newValue");
1421
+ var createOption = (text) => ({
1422
+ [newValue]: true,
1423
+ text
1424
+ });
1425
+ var isCreateOption = (data) => typeof data === "object" && data[newValue];
1426
+ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }) => {
1427
+ const { id: gridId, editing, setEditing } = useGridContext2("TableCellEditor", __gridScope);
1428
+ const suppressNextBlur = useRef(false);
1429
+ const fieldProjection = useMemo3(() => {
1430
+ if (!model || !editing) {
1431
+ return;
1432
+ }
1433
+ const { col } = parseCellIndex(editing.index);
1434
+ const field = model.projection.view.fields[col];
1435
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
1436
+ invariant2(fieldProjection2, void 0, {
1437
+ F: __dxlog_file3,
1438
+ L: 67,
1439
+ S: void 0,
1440
+ A: [
1441
+ "fieldProjection",
1442
+ ""
1443
+ ]
1444
+ });
1445
+ return fieldProjection2;
1446
+ }, [
1447
+ model,
1448
+ editing
1449
+ ]);
1450
+ const handleEnter = useCallback3((value) => {
1451
+ if (!model || !editing) {
1452
+ return;
1453
+ }
1454
+ const cell = parseCellIndex(editing.index);
1455
+ model.setCellData(cell, value);
1456
+ onEnter?.(cell);
1457
+ onFocus?.();
1458
+ setEditing(null);
1459
+ }, [
1460
+ model,
1461
+ editing
1462
+ ]);
1463
+ const handleBlur = useCallback3((value) => {
1464
+ if (!model || !editing) {
1465
+ return;
1466
+ }
1467
+ if (suppressNextBlur.current) {
1468
+ suppressNextBlur.current = false;
1469
+ return;
1470
+ }
1471
+ const cell = parseCellIndex(editing.index);
1472
+ if (value !== void 0) {
1473
+ model.setCellData(cell, value);
1474
+ }
1475
+ }, [
1476
+ model,
1477
+ editing
1478
+ ]);
1479
+ const handleClose = useCallback3((value, event) => {
1480
+ if (!model || !editing || !fieldProjection) {
1481
+ return;
1482
+ }
1483
+ const cell = parseCellIndex(editing.index);
1484
+ onEnter?.(cell);
1485
+ if (event && onFocus) {
1486
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
1487
+ }
1488
+ }, [
1489
+ model,
1490
+ editing,
1491
+ onFocus,
1492
+ onEnter,
1493
+ fieldProjection,
1494
+ determineNavigationAxis,
1495
+ determineNavigationDelta
1496
+ ]);
1497
+ const extension = useMemo3(() => {
1498
+ if (!fieldProjection) {
1499
+ return [];
1500
+ }
1501
+ const extension2 = [
1502
+ editorKeys({
1503
+ onClose: handleClose,
1504
+ ...editing?.initialContent && {
1505
+ onNav: handleClose
1506
+ }
1507
+ })
1508
+ ];
1509
+ if (onQuery) {
1510
+ switch (fieldProjection.props.format) {
1511
+ case FormatEnum5.Ref: {
1512
+ extension2.push([
1513
+ completion({
1514
+ onQuery: (text) => onQuery(fieldProjection, text),
1515
+ onMatch: (data) => {
1516
+ if (model && editing && modals) {
1517
+ if (isCreateOption(data)) {
1518
+ const { field, props } = fieldProjection;
1519
+ if (props.referenceSchema) {
1520
+ suppressNextBlur.current = true;
1521
+ modals.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
1522
+ [field.referencePath]: data.text
1523
+ }, (data2) => {
1524
+ handleEnter(data2);
1525
+ });
1526
+ }
1527
+ } else {
1528
+ handleEnter(data);
1529
+ }
1530
+ }
1531
+ }
1532
+ })
1533
+ ]);
1534
+ break;
1535
+ }
1536
+ }
1537
+ }
1538
+ return extension2;
1539
+ }, [
1540
+ model,
1541
+ modals,
1542
+ editing,
1543
+ fieldProjection,
1544
+ handleClose
1545
+ ]);
1546
+ const getCellContent = useCallback3(() => {
1547
+ if (model && editing) {
1548
+ const value = model.getCellData(parseCellIndex(editing.index));
1549
+ return value !== void 0 ? String(value) : "";
1550
+ }
1551
+ }, [
1552
+ model,
1553
+ editing
1554
+ ]);
1555
+ return /* @__PURE__ */ React6.createElement(GridCellEditor, {
1556
+ extension,
1557
+ getCellContent,
1558
+ onBlur: handleBlur
1559
+ });
1560
+ };
1561
+ var determineNavigationAxis = ({ key }) => {
1562
+ switch (key) {
1563
+ case "ArrowUp":
1564
+ case "ArrowDown":
1565
+ case "Enter": {
1566
+ return "row";
1567
+ }
1568
+ case "ArrowLeft":
1569
+ case "ArrowRight":
1570
+ case "Tab":
1571
+ return "col";
1572
+ }
1573
+ };
1574
+ var determineNavigationDelta = ({ key, shift }) => {
1575
+ switch (key) {
1576
+ case "ArrowUp":
1577
+ case "ArrowLeft":
1578
+ return -1;
1579
+ case "ArrowDown":
1580
+ case "ArrowRight":
1581
+ return 1;
1582
+ }
1583
+ return shift ? -1 : 1;
1584
+ };
1585
+
1586
+ // packages/ui/react-ui-table/src/components/Table/Table.tsx
1587
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1588
+ var inlineEndLine = "[&>.dx-grid]:relative [&>.dx-grid]:after:absolute [&>.dx-grid]:after:inset-block-0 [&>.dx-grid]:after:-inline-end-px [&>.dx-grid]:after:is-px [&>.dx-grid]:after:bg-separator";
1589
+ var blockEndLine = "[&>.dx-grid]:before:absolute [&>.dx-grid]:before:inset-inline-0 [&>.dx-grid]:before:-block-end-px [&>.dx-grid]:before:bs-px [&>.dx-grid]:before:bg-separator";
1590
+ var frozen = {
1591
+ frozenRowsStart: 1,
1592
+ frozenColsStart: 1,
1593
+ frozenColsEnd: 1
1594
+ };
1595
+ var TableRoot = ({ children, role }) => {
1596
+ return /* @__PURE__ */ React7.createElement("div", {
1597
+ role: "none",
1598
+ className: mx2("relative border-bs !border-separator", role === "section" ? "attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]" : "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]")
1599
+ }, children);
1600
+ };
1601
+ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention }, forwardedRef) => {
1602
+ const [dxGrid, setDxGrid] = useState2(null);
1603
+ const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : "table");
1604
+ const { t } = useTranslation3(translationKey);
1605
+ const modals = useMemo4(() => new ModalController(), []);
1606
+ useImperativeHandle(forwardedRef, () => {
1607
+ if (!presentation || !dxGrid) {
1608
+ return {};
1609
+ }
1610
+ dxGrid.getCells = (range, plane) => presentation.getCells(range, plane);
1611
+ return {
1612
+ update: (cell) => {
1613
+ if (cell) {
1614
+ dxGrid.updateIfWithinBounds(cell);
1615
+ } else {
1616
+ dxGrid.updateCells(true);
1617
+ dxGrid.requestUpdate();
1618
+ }
1619
+ }
1620
+ };
1621
+ }, [
1622
+ presentation,
1623
+ dxGrid
1624
+ ]);
1625
+ const handleGridClick = useCallback4((event) => {
1626
+ if (!modals) {
1627
+ return;
1628
+ }
1629
+ const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
1630
+ const tableButtonElement = event.target.closest(buttonSelector);
1631
+ if (tableButtonElement) {
1632
+ const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
1633
+ if (!button) {
1634
+ return;
1635
+ }
1636
+ modals.setTrigger(tableButtonElement);
1637
+ const data = button.getData(tableButtonElement);
1638
+ switch (data.type) {
1639
+ case "rowMenu": {
1640
+ modals.showRowMenu(data.rowIndex);
1641
+ break;
1642
+ }
1643
+ case "columnSettings": {
1644
+ modals.showColumnMenu(data.fieldId);
1645
+ break;
1646
+ }
1647
+ case "newColumn": {
1648
+ modals.showColumnCreator();
1649
+ break;
1650
+ }
1651
+ case "referencedCell": {
1652
+ modals.showReferencePanel(data.targetId, data.schemaId);
1653
+ break;
1654
+ }
1655
+ case "sort": {
1656
+ model?.sorting?.toggleSort(data.fieldId);
1657
+ break;
1658
+ }
1659
+ }
1660
+ return;
1661
+ }
1662
+ const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
1663
+ const controlElement = event.target.closest(controlSelector);
1664
+ if (controlElement) {
1665
+ const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
1666
+ if (!control) {
1667
+ return;
1668
+ }
1669
+ const data = control.getData(controlElement);
1670
+ switch (data.type) {
1671
+ case "checkbox": {
1672
+ if (data.header) {
1673
+ model?.selection.setSelection(model.selection.allRowsSeleted.value ? "none" : "all");
1674
+ } else {
1675
+ model?.selection.toggleSelectionForRowIndex(data.rowIndex);
1676
+ }
1677
+ break;
1678
+ }
1679
+ case "switch": {
1680
+ if (model) {
1681
+ model.updateCellData({
1682
+ row: data.rowIndex,
1683
+ col: data.colIndex
1684
+ }, (value) => !value);
1685
+ }
1686
+ break;
1687
+ }
1688
+ }
1689
+ }
1690
+ }, [
1691
+ model,
1692
+ modals
1693
+ ]);
1694
+ const handleFocus = useCallback4((increment, delta) => {
1695
+ if (dxGrid) {
1696
+ dxGrid.refocus(increment, delta);
1697
+ }
1698
+ }, [
1699
+ dxGrid
1700
+ ]);
1701
+ const handleEnter = useCallback4((cell) => {
1702
+ if (model && cell.row === model.getRowCount() - 1) {
1703
+ model.insertRow(cell.row);
1704
+ if (dxGrid) {
1705
+ requestAnimationFrame(() => {
1706
+ dxGrid?.scrollToRow(cell.row + 1);
1707
+ dxGrid?.refocus("row", 1);
1708
+ });
1709
+ }
1710
+ }
1711
+ }, [
1712
+ model,
1713
+ dxGrid
1714
+ ]);
1715
+ const handleKeyDown = useCallback4((event) => {
1716
+ const cell = closestCell(event.target);
1717
+ if (!model || !cell) {
1718
+ return;
1719
+ }
1720
+ switch (event.key) {
1721
+ case "Backspace":
1722
+ case "Delete": {
1723
+ model.setCellData(cell, void 0);
1724
+ break;
1725
+ }
1726
+ }
1727
+ }, [
1728
+ model
1729
+ ]);
1730
+ const handleAxisResize = useCallback4((event) => {
1731
+ if (event.axis === "col") {
1732
+ const columnIndex = parseInt(event.index, 10);
1733
+ model?.setColumnWidth(columnIndex, event.size);
1734
+ }
1735
+ }, [
1736
+ model
1737
+ ]);
1738
+ const handleWheel = useCallback4((event) => {
1739
+ if (!ignoreAttention && !hasAttention) {
1740
+ event.stopPropagation();
1741
+ }
1742
+ }, [
1743
+ hasAttention,
1744
+ ignoreAttention
1745
+ ]);
1746
+ const handleNewColumn = useCallback4(() => {
1747
+ const columns = model?.getColumnCount();
1748
+ if (dxGrid && columns) {
1749
+ dxGrid.scrollToColumn(columns - 1);
1750
+ }
1751
+ }, [
1752
+ model,
1753
+ dxGrid
1754
+ ]);
1755
+ const handleQuery = useCallback4(async ({ field, props }, text) => {
1756
+ if (model && props.referenceSchema && field.referencePath) {
1757
+ const space = getSpace4(model.table);
1758
+ invariant3(space, void 0, {
1759
+ F: __dxlog_file4,
1760
+ L: 264,
1761
+ S: void 0,
1762
+ A: [
1763
+ "space",
1764
+ ""
1765
+ ]
1766
+ });
1767
+ const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
1768
+ if (schema) {
1769
+ const { objects } = await space.db.query(Filter.schema(schema)).run();
1770
+ const options = objects.map((obj) => {
1771
+ const value = getValue4(obj, field.referencePath);
1772
+ if (!value || typeof value !== "string") {
1773
+ return void 0;
1774
+ }
1775
+ return {
1776
+ label: value,
1777
+ data: obj
1778
+ };
1779
+ }).filter(isNotFalsy);
1780
+ return [
1781
+ ...options,
1782
+ {
1783
+ label: t("create new object label", {
1784
+ text
1785
+ }),
1786
+ data: createOption(text)
1787
+ }
1788
+ ];
1789
+ }
1790
+ }
1791
+ return [];
1792
+ }, [
1793
+ model
1794
+ ]);
1795
+ if (!model || !modals) {
1796
+ return /* @__PURE__ */ React7.createElement("span", {
1797
+ role: "none",
1798
+ className: "attention-surface"
1799
+ });
1800
+ }
1801
+ return /* @__PURE__ */ React7.createElement(Grid.Root, {
1802
+ id: model.table.id ?? "table-grid"
1803
+ }, /* @__PURE__ */ React7.createElement(TableCellEditor, {
1804
+ model,
1805
+ modals,
1806
+ onEnter: handleEnter,
1807
+ onFocus: handleFocus,
1808
+ onQuery: handleQuery
1809
+ }), /* @__PURE__ */ React7.createElement(Grid.Content, {
1810
+ onWheelCapture: handleWheel,
1811
+ className: mx2("[--dx-grid-base:var(--surface-bg)]", inlineEndLine, blockEndLine),
1812
+ frozen,
1813
+ columns: model.columnMeta.value,
1814
+ limitRows: model.getRowCount() ?? 0,
1815
+ limitColumns: model.table.view?.target?.fields?.length ?? 0,
1816
+ onAxisResize: handleAxisResize,
1817
+ onClick: handleGridClick,
1818
+ onKeyDown: handleKeyDown,
1819
+ overscroll: "trap",
1820
+ ref: setDxGrid
1821
+ }), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
1822
+ model,
1823
+ modals
1824
+ }), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
1825
+ model,
1826
+ modals
1827
+ }), /* @__PURE__ */ React7.createElement(ColumnSettings, {
1828
+ model,
1829
+ modals,
1830
+ onNewColumn: handleNewColumn
1831
+ }), /* @__PURE__ */ React7.createElement(RefPanel, {
1832
+ model,
1833
+ modals
1834
+ }), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
1835
+ model,
1836
+ modals
1837
+ }));
1838
+ });
1839
+ var Table = {
1840
+ Root: TableRoot,
1841
+ Main: TableMain
1842
+ };
1843
+
1844
+ // packages/ui/react-ui-table/src/components/TableToolbar/TableToolbar.tsx
1845
+ import React8, { useCallback as useCallback5, useMemo as useMemo5 } from "react";
1846
+ import { create as create3 } from "@dxos/live-object";
1847
+ import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
1848
+ var createTableToolbarActions = (state) => {
1849
+ const add = createMenuAction("add-row", {
1850
+ type: "add-row",
1851
+ icon: "ph--plus--regular",
1852
+ label: [
1853
+ "add row",
1854
+ {
1855
+ ns: translationKey
1856
+ }
1857
+ ],
1858
+ testId: "table.toolbar.add-row"
1859
+ });
1860
+ const save = createMenuAction("save-view", {
1861
+ type: "save-view",
1862
+ icon: "ph--floppy-disk--regular",
1863
+ label: [
1864
+ "save view label",
1865
+ {
1866
+ ns: translationKey
1867
+ }
1868
+ ],
1869
+ testId: "table.toolbar.save-view",
1870
+ iconOnly: false,
1871
+ hidden: !state.viewDirty
1872
+ });
1873
+ const gap = createGapSeparator();
1874
+ const comment = createMenuAction("comment", {
1875
+ type: "comment",
1876
+ icon: "ph--chat-text--regular",
1877
+ label: [
1878
+ "create comment",
1879
+ {
1880
+ ns: translationKey
1881
+ }
1882
+ ],
1883
+ testId: "table.toolbar.comment"
1884
+ });
1885
+ const nodes = [
1886
+ add,
1887
+ save,
1888
+ ...gap.nodes,
1889
+ comment
1890
+ ];
1891
+ return {
1892
+ nodes,
1893
+ edges: nodes.map(({ id: target }) => ({
1894
+ source: "root",
1895
+ target
1896
+ }))
1897
+ };
1898
+ };
1899
+ var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
1900
+ const state = useMemo5(() => create3({
1901
+ viewDirty
1902
+ }), []);
1903
+ const actionsCreator = useCallback5(() => createTableToolbarActions(state), [
1904
+ state
1905
+ ]);
1906
+ const menu = useMenuActions(actionsCreator);
1907
+ return /* @__PURE__ */ React8.createElement(MenuProvider, {
1908
+ ...menu,
1909
+ attendableId,
1910
+ onAction
1911
+ }, /* @__PURE__ */ React8.createElement(ToolbarMenu, {
1912
+ classNames
1913
+ }));
1914
+ };
1915
+
1916
+ // packages/ui/react-ui-table/src/hooks/useTableModel.ts
1917
+ import { useEffect as useEffect2, useState as useState3 } from "react";
1587
1918
  var useTableModel = ({ objects, table, projection, ...props }) => {
1588
1919
  const [model, setModel] = useState3();
1589
1920
  useEffect2(() => {
@@ -1619,15 +1950,22 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1619
1950
  return model;
1620
1951
  };
1621
1952
  export {
1953
+ BUTTON_IDENTIFIERS,
1954
+ CONTROL_IDENTIFIERS,
1955
+ ModalController,
1622
1956
  Table,
1957
+ TableModel,
1958
+ TablePresentation,
1623
1959
  TableSchema,
1960
+ TableToolbar,
1624
1961
  TableType,
1625
- Toolbar,
1626
1962
  initializeTable,
1963
+ renderCheckbox,
1964
+ renderSwitch,
1627
1965
  tableButtons,
1966
+ tableControls,
1628
1967
  touch,
1629
1968
  translations_default as translations,
1630
- useTableModel,
1631
- useToolbarContext
1969
+ useTableModel
1632
1970
  };
1633
1971
  //# sourceMappingURL=index.mjs.map