@dxos/react-ui-table 0.7.4 → 0.7.5-main.937ce75

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