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