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

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