@dxos/react-ui-table 0.7.4-staging.f7e8224 → 0.7.5-main.499c70c

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