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

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