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

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 (118) 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 +1424 -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 +1429 -1052
  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 +1424 -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 +1 -4
  34. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -2
  36. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  37. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +18 -0
  39. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -0
  40. package/dist/types/src/components/TableToolbar/index.d.ts +2 -0
  41. package/dist/types/src/components/TableToolbar/index.d.ts.map +1 -0
  42. package/dist/types/src/components/index.d.ts +1 -1
  43. package/dist/types/src/components/index.d.ts.map +1 -1
  44. package/dist/types/src/components/testing.d.ts +31 -71
  45. package/dist/types/src/components/testing.d.ts.map +1 -1
  46. package/dist/types/src/index.d.ts +1 -0
  47. package/dist/types/src/index.d.ts.map +1 -1
  48. package/dist/types/src/model/index.d.ts +1 -0
  49. package/dist/types/src/model/index.d.ts.map +1 -1
  50. package/dist/types/src/model/modal-controller.d.ts +6 -2
  51. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  52. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  53. package/dist/types/src/model/table-model.d.ts +19 -31
  54. package/dist/types/src/model/table-model.d.ts.map +1 -1
  55. package/dist/types/src/model/table-presentation.d.ts +22 -0
  56. package/dist/types/src/model/table-presentation.d.ts.map +1 -0
  57. package/dist/types/src/model/table-presentation.test.d.ts +2 -0
  58. package/dist/types/src/model/table-presentation.test.d.ts.map +1 -0
  59. package/dist/types/src/model/table-sorting.d.ts +53 -0
  60. package/dist/types/src/model/table-sorting.d.ts.map +1 -0
  61. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  62. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  63. package/dist/types/src/translations.d.ts +2 -1
  64. package/dist/types/src/translations.d.ts.map +1 -1
  65. package/dist/types/src/types/table.d.ts +46 -154
  66. package/dist/types/src/types/table.d.ts.map +1 -1
  67. package/dist/types/src/util/index.d.ts +1 -0
  68. package/dist/types/src/util/index.d.ts.map +1 -1
  69. package/dist/types/src/util/table-buttons.d.ts +63 -19
  70. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  71. package/dist/types/src/util/table-controls.d.ts +32 -9
  72. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  73. package/dist/types/src/util/table.d.ts +3 -2
  74. package/dist/types/src/util/table.d.ts.map +1 -1
  75. package/dist/types/tsconfig.tsbuildinfo +1 -0
  76. package/package.json +35 -34
  77. package/src/_deprecated/schema/Schema.stories.tsx +1 -1
  78. package/src/components/Table/ColumnActionsMenu.tsx +12 -12
  79. package/src/components/Table/ColumnSettings.tsx +11 -11
  80. package/src/components/Table/CreateRefPanel.tsx +13 -14
  81. package/src/components/Table/RefPanel.tsx +9 -9
  82. package/src/components/Table/RowActionsMenu.tsx +6 -7
  83. package/src/components/Table/Table.stories.tsx +85 -56
  84. package/src/components/Table/Table.tsx +239 -148
  85. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +13 -12
  86. package/src/components/TableCellEditor/TableCellEditor.tsx +6 -4
  87. package/src/components/TableToolbar/TableToolbar.tsx +72 -0
  88. package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
  89. package/src/components/index.ts +1 -1
  90. package/src/components/testing.ts +10 -8
  91. package/src/index.ts +2 -0
  92. package/src/model/index.ts +1 -0
  93. package/src/model/modal-controller.ts +15 -48
  94. package/src/model/selection-model.ts +12 -1
  95. package/src/model/table-model.test.ts +4 -76
  96. package/src/model/table-model.ts +73 -304
  97. package/src/model/table-presentation.test.ts +102 -0
  98. package/src/model/table-presentation.ts +235 -0
  99. package/src/model/table-sorting.ts +215 -0
  100. package/src/playwright/TableManager.ts +5 -1
  101. package/src/playwright/smoke.spec.ts +94 -9
  102. package/src/translations.ts +2 -1
  103. package/src/types/table.ts +4 -4
  104. package/src/util/index.ts +1 -0
  105. package/src/util/table-buttons.ts +127 -48
  106. package/src/util/table-controls.ts +71 -7
  107. package/src/util/table.ts +93 -52
  108. package/dist/lib/browser/chunk-IYCSJDMB.mjs.map +0 -7
  109. package/dist/lib/node/chunk-MHBMVCFZ.cjs.map +0 -7
  110. package/dist/lib/node-esm/chunk-BMWGPXPL.mjs.map +0 -7
  111. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
  112. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  113. package/dist/types/src/components/Toolbar/common.d.ts +0 -14
  114. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  115. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  116. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  117. package/src/components/Toolbar/Toolbar.tsx +0 -87
  118. 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="dx-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] dx-checkbox",
555
+ switch: "absolute inset-block-[.25rem] inline-end-[.25rem] dx-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,166 @@ 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.SingleSelect) {
820
+ const options = props.options;
821
+ if (!options) {
822
+ return void 0;
823
+ }
824
+ const option = options.find((option2) => option2.id === value);
825
+ return option ? options.indexOf(option) : void 0;
826
+ }
827
+ if (format === import_echo_schema5.FormatEnum.Ref && field.referencePath) {
828
+ const refValue = (0, import_echo_schema5.getValue)(value.target, field.referencePath);
829
+ return refValue;
830
+ }
831
+ return (0, import_react_ui_form5.formatForDisplay)({
832
+ type,
833
+ format,
834
+ value
835
+ });
1076
836
  }
1077
837
  };
1078
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
838
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
1079
839
  var TableModel = class extends import_context.Resource {
1080
840
  constructor({ table, projection, sorting = [], pinnedRows = {
1081
841
  top: [],
@@ -1093,203 +853,18 @@ var TableModel = class extends import_context.Resource {
1093
853
  col: 0
1094
854
  }
1095
855
  });
1096
- this._displayToDataIndex = /* @__PURE__ */ new Map();
1097
- this._sorting = (0, import_signals_core.signal)(void 0);
1098
856
  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
857
  this.setRows = (obj) => {
1283
858
  this._rows.value = obj;
1284
859
  };
1285
860
  this.getRowCount = () => this._rows.value.length;
1286
- this.getColumnCount = () => this.table.view?.fields.length ?? 0;
861
+ this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
1287
862
  this.insertRow = (rowIndex) => {
1288
- const row = rowIndex !== void 0 ? this._displayToDataIndex.get(rowIndex) ?? rowIndex : this._rows.value.length;
863
+ const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
1289
864
  this._onInsertRow?.(row);
1290
865
  };
1291
866
  this.deleteRow = (rowIndex) => {
1292
- const row = this._displayToDataIndex.get(rowIndex) ?? rowIndex;
867
+ const row = this._sorting.getDataIndex(rowIndex);
1293
868
  const obj = this._rows.value[row];
1294
869
  const objectsToDelete = [];
1295
870
  if (this._selection.hasSelection.value) {
@@ -1301,23 +876,23 @@ var TableModel = class extends import_context.Resource {
1301
876
  this._onDeleteRows?.(row, objectsToDelete);
1302
877
  };
1303
878
  this.getCellData = ({ col, row }) => {
1304
- const fields = this.table.view?.fields ?? [];
879
+ const fields = this.table.view?.target?.fields ?? [];
1305
880
  if (col < 0 || col >= fields.length) {
1306
881
  return void 0;
1307
882
  }
1308
883
  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);
884
+ const dataIndex = this._sorting.getDataIndex(row);
885
+ const value = (0, import_echo_schema3.getValue)(this._rows.value[dataIndex], field.path);
1311
886
  if (value == null) {
1312
887
  return "";
1313
888
  }
1314
889
  const { props } = this._projection.getFieldProjection(field.id);
1315
890
  switch (props.format) {
1316
- case import_echo_schema4.FormatEnum.Ref: {
891
+ case import_echo_schema3.FormatEnum.Ref: {
1317
892
  if (!field.referencePath) {
1318
893
  return "";
1319
894
  }
1320
- return (0, import_echo_schema4.getValue)(value, field.referencePath);
895
+ return (0, import_echo_schema3.getValue)(value.target, field.referencePath);
1321
896
  }
1322
897
  default: {
1323
898
  return (0, import_react_ui_form4.formatForEditing)({
@@ -1329,20 +904,22 @@ var TableModel = class extends import_context.Resource {
1329
904
  }
1330
905
  };
1331
906
  this.setCellData = ({ col, row }, value) => {
1332
- const rowIdx = this._displayToDataIndex.get(row) ?? row;
1333
- const fields = this.table.view?.fields ?? [];
907
+ const rowIdx = this._sorting.getDataIndex(row);
908
+ const fields = this.table.view?.target?.fields ?? [];
1334
909
  if (col < 0 || col >= fields.length) {
1335
910
  return;
1336
911
  }
1337
912
  const field = fields[col];
1338
913
  const { props } = this._projection.getFieldProjection(field.id);
1339
914
  switch (props.format) {
1340
- case import_echo_schema4.FormatEnum.Ref: {
1341
- (0, import_echo_schema4.setValue)(this._rows.value[rowIdx], field.path, value);
915
+ case import_echo_schema3.FormatEnum.Ref: {
916
+ if ((0, import_live_object.isReactiveObject)(value)) {
917
+ (0, import_echo_schema3.setValue)(this._rows.value[rowIdx], field.path, (0, import_live_object.makeRef)(value));
918
+ }
1342
919
  break;
1343
920
  }
1344
921
  default: {
1345
- (0, import_echo_schema4.setValue)(this._rows.value[rowIdx], field.path, (0, import_react_ui_form4.parseValue)({
922
+ (0, import_echo_schema3.setValue)(this._rows.value[rowIdx], field.path, (0, import_react_ui_form4.parseValue)({
1346
923
  type: props.type,
1347
924
  format: props.format,
1348
925
  value
@@ -1351,28 +928,13 @@ var TableModel = class extends import_context.Resource {
1351
928
  }
1352
929
  }
1353
930
  };
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
931
  this._table = table;
1374
932
  this._projection = projection;
1375
- this._sorting.value = sorting.at(0);
933
+ this._sorting = new TableSorting(this._rows, table.view?.target, projection);
934
+ if (sorting.length > 0) {
935
+ const [sort] = sorting;
936
+ this._sorting.setSort(sort.fieldId, sort.direction);
937
+ }
1376
938
  this._pinnedRows = pinnedRows;
1377
939
  this._onInsertRow = onInsertRow;
1378
940
  this._onDeleteRows = onDeleteRows;
@@ -1386,13 +948,22 @@ var TableModel = class extends import_context.Resource {
1386
948
  get projection() {
1387
949
  return this._projection;
1388
950
  }
951
+ get rows() {
952
+ return this._sorting.sortedRows;
953
+ }
954
+ /**
955
+ * @reactive
956
+ */
957
+ get sorting() {
958
+ return this._sorting;
959
+ }
1389
960
  get pinnedRows() {
1390
961
  return this._pinnedRows;
1391
962
  }
1392
963
  get columnMeta() {
1393
- (0, import_invariant3.invariant)(this._columnMeta, void 0, {
1394
- F: __dxlog_file5,
1395
- L: 126,
964
+ (0, import_invariant2.invariant)(this._columnMeta, void 0, {
965
+ F: __dxlog_file,
966
+ L: 117,
1396
967
  S: this,
1397
968
  A: [
1398
969
  "this._columnMeta",
@@ -1401,28 +972,25 @@ var TableModel = class extends import_context.Resource {
1401
972
  });
1402
973
  return this._columnMeta;
1403
974
  }
1404
- get sorting() {
1405
- return this._sorting.value;
1406
- }
1407
- get modalController() {
1408
- return this._modalController;
1409
- }
1410
975
  get selection() {
1411
976
  return this._selection;
1412
977
  }
978
+ /** @reactive */
979
+ get isViewDirty() {
980
+ return this._sorting.isDirty;
981
+ }
1413
982
  //
1414
983
  // Initialisation
1415
984
  //
1416
985
  async _open() {
1417
986
  this.initializeColumnMeta();
1418
- this.initializeSorting();
1419
987
  this.initializeEffects();
1420
- this._selection = new SelectionModel(this._sortedRows, () => this._onRowOrderChanged?.());
988
+ this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
1421
989
  await this._selection.open(this._ctx);
1422
990
  }
1423
991
  initializeColumnMeta() {
1424
992
  this._columnMeta = (0, import_signals_core.computed)(() => {
1425
- const fields = this._table.view?.fields ?? [];
993
+ const fields = this._table.view?.target?.fields ?? [];
1426
994
  const meta = Object.fromEntries(fields.map((field, index) => [
1427
995
  index,
1428
996
  {
@@ -1447,45 +1015,9 @@ var TableModel = class extends import_context.Resource {
1447
1015
  };
1448
1016
  });
1449
1017
  }
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
1018
  initializeEffects() {
1487
1019
  const rowOrderWatcher = (0, import_signals_core.effect)(() => {
1488
- touch(this._sortedRows.value);
1020
+ touch(this._sorting.sortedRows.value);
1489
1021
  this._onRowOrderChanged?.();
1490
1022
  });
1491
1023
  this._ctx.onDispose(rowOrderWatcher);
@@ -1494,8 +1026,8 @@ var TableModel = class extends import_context.Resource {
1494
1026
  const rowEffects = [];
1495
1027
  for (let row = start.row; row <= end.row; row++) {
1496
1028
  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)));
1029
+ const obj = this._sorting.sortedRows.value[row];
1030
+ this?._table?.view?.target?.fields.forEach((field) => touch((0, import_echo_schema3.getValue)(obj, field.path)));
1499
1031
  this._onCellUpdate?.({
1500
1032
  row,
1501
1033
  col: start.col,
@@ -1507,6 +1039,19 @@ var TableModel = class extends import_context.Resource {
1507
1039
  });
1508
1040
  this._ctx.onDispose(rowEffectManager);
1509
1041
  }
1042
+ /**
1043
+ * Updates a cell's value using a transform function.
1044
+ * @param {DxGridPlanePosition} position - The position of the cell to update.
1045
+ * @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
1046
+ */
1047
+ updateCellData({ col, row }, update) {
1048
+ const dataRow = this._sorting.getDataIndex(row);
1049
+ const fields = this.table.view?.target?.fields ?? [];
1050
+ const field = fields[col];
1051
+ const value = (0, import_echo_schema3.getValue)(this._rows.value[dataRow], field.path);
1052
+ const updatedValue = update(value);
1053
+ (0, import_echo_schema3.setValue)(this._rows.value[dataRow], field.path, updatedValue);
1054
+ }
1510
1055
  //
1511
1056
  // Column Operations
1512
1057
  //
@@ -1514,11 +1059,8 @@ var TableModel = class extends import_context.Resource {
1514
1059
  if (!this.table.view) {
1515
1060
  return;
1516
1061
  }
1517
- const field = this.table.view.fields.find((field2) => field2.id === fieldId);
1062
+ const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
1518
1063
  if (field && this._onDeleteColumn) {
1519
- if (this._sorting.value?.fieldId === fieldId) {
1520
- this.clearSort();
1521
- }
1522
1064
  this._onDeleteColumn(field.id);
1523
1065
  }
1524
1066
  }
@@ -1526,7 +1068,7 @@ var TableModel = class extends import_context.Resource {
1526
1068
  // Resize
1527
1069
  //
1528
1070
  setColumnWidth(columnIndex, width) {
1529
- const fields = this.table.view?.fields ?? [];
1071
+ const fields = this.table.view?.target?.fields ?? [];
1530
1072
  if (columnIndex < fields.length) {
1531
1073
  const newWidth = Math.max(0, width);
1532
1074
  const field = fields[columnIndex];
@@ -1536,19 +1078,7 @@ var TableModel = class extends import_context.Resource {
1536
1078
  }
1537
1079
  }
1538
1080
  //
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
- // Pinning
1081
+ // Pinning
1552
1082
  //
1553
1083
  // TODO(burdon): Change to setPinned(on/off).
1554
1084
  pinRow(rowIndex, side) {
@@ -1558,10 +1088,850 @@ var TableModel = class extends import_context.Resource {
1558
1088
  this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
1559
1089
  this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
1560
1090
  }
1091
+ //
1092
+ // View operations
1093
+ //
1094
+ saveView() {
1095
+ this._sorting.save();
1096
+ }
1097
+ };
1098
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1099
+ var ModalController = class {
1100
+ constructor() {
1101
+ this._state = (0, import_signals_core4.signal)({
1102
+ type: "closed"
1103
+ });
1104
+ this._triggerRef = {
1105
+ current: null
1106
+ };
1107
+ this.setTrigger = (trigger) => {
1108
+ this._triggerRef.current = trigger;
1109
+ };
1110
+ this.showRowMenu = (rowIndex) => {
1111
+ this._state.value = {
1112
+ type: "row",
1113
+ rowIndex
1114
+ };
1115
+ };
1116
+ this.showColumnMenu = (fieldId) => {
1117
+ this._state.value = {
1118
+ type: "column",
1119
+ fieldId
1120
+ };
1121
+ };
1122
+ this.showColumnCreator = () => {
1123
+ this._state.value = {
1124
+ type: "columnSettings",
1125
+ mode: {
1126
+ type: "create"
1127
+ }
1128
+ };
1129
+ };
1130
+ this.showReferencePanel = (targetId, schemaId) => {
1131
+ this._state.value = {
1132
+ type: "refPanel",
1133
+ targetId,
1134
+ typename: schemaId
1135
+ };
1136
+ };
1137
+ this.openColumnSettings = () => {
1138
+ if (this._state.value.type === "column") {
1139
+ const fieldId = this._state.value.fieldId;
1140
+ requestAnimationFrame(() => {
1141
+ this._state.value = {
1142
+ type: "columnSettings",
1143
+ mode: {
1144
+ type: "edit",
1145
+ fieldId
1146
+ }
1147
+ };
1148
+ });
1149
+ }
1150
+ };
1151
+ this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1152
+ if (anchorCell) {
1153
+ this._triggerRef.current = anchorCell;
1154
+ this._state.value = {
1155
+ type: "createRefPanel",
1156
+ typename,
1157
+ initialValues,
1158
+ onCreate
1159
+ };
1160
+ } else {
1161
+ import_log.log.warn("anchor cell not found while creating new ref", void 0, {
1162
+ F: __dxlog_file2,
1163
+ L: 86,
1164
+ S: this,
1165
+ C: (f, a) => f(...a)
1166
+ });
1167
+ }
1168
+ };
1169
+ this.close = () => {
1170
+ this._state.value = {
1171
+ type: "closed"
1172
+ };
1173
+ };
1174
+ }
1175
+ get state() {
1176
+ return this._state;
1177
+ }
1178
+ get trigger() {
1179
+ return this._triggerRef;
1180
+ }
1181
+ };
1182
+ var TablePresentation = class {
1183
+ constructor(model, _visibleRange = (0, import_signals_core5.signal)({
1184
+ start: {
1185
+ row: 0,
1186
+ col: 0
1187
+ },
1188
+ end: {
1189
+ row: 0,
1190
+ col: 0
1191
+ }
1192
+ })) {
1193
+ this.model = model;
1194
+ this._visibleRange = _visibleRange;
1195
+ }
1196
+ getCells(range, plane) {
1197
+ switch (plane) {
1198
+ case "grid":
1199
+ this._visibleRange.value = range;
1200
+ return this.getMainGridCells(range);
1201
+ case "frozenRowsStart":
1202
+ return this.getHeaderCells(range);
1203
+ case "frozenColsStart":
1204
+ return this.getSelectionColumnCells(range);
1205
+ case "frozenColsEnd":
1206
+ return this.getActionColumnCells(range);
1207
+ case "fixedStartStart":
1208
+ return this.getSelectAllCell();
1209
+ case "fixedStartEnd":
1210
+ return this.getNewColumnCell();
1211
+ default:
1212
+ return {};
1213
+ }
1214
+ }
1215
+ getMainGridCells(range) {
1216
+ const cells = {};
1217
+ const fields = this.model.table.view?.target?.fields ?? [];
1218
+ const addCell = (obj, field, colIndex, displayIndex) => {
1219
+ const { props } = this.model.projection.getFieldProjection(field.id);
1220
+ const cell = {
1221
+ get value() {
1222
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1223
+ if (value == null) {
1224
+ return "";
1225
+ }
1226
+ switch (props.format) {
1227
+ case import_echo_schema6.FormatEnum.Boolean:
1228
+ case import_echo_schema6.FormatEnum.SingleSelect: {
1229
+ return "";
1230
+ }
1231
+ case import_echo_schema6.FormatEnum.Ref: {
1232
+ if (!field.referencePath) {
1233
+ return "";
1234
+ }
1235
+ return (0, import_echo_schema6.getValue)(value.target, field.referencePath);
1236
+ }
1237
+ default: {
1238
+ return (0, import_react_ui_form6.formatForDisplay)({
1239
+ type: props.type,
1240
+ format: props.format,
1241
+ value
1242
+ });
1243
+ }
1244
+ }
1245
+ }
1246
+ };
1247
+ const classes = [];
1248
+ const formatClasses = (0, import_react_ui_form6.cellClassesForFieldType)({
1249
+ type: props.type,
1250
+ format: props.format
1251
+ });
1252
+ if (formatClasses) {
1253
+ classes.push(formatClasses);
1254
+ }
1255
+ const rowSelectionClasses = (0, import_react_ui_form6.cellClassesForRowSelection)(this.model.selection.isObjectSelected(obj));
1256
+ if (rowSelectionClasses) {
1257
+ classes.push(rowSelectionClasses);
1258
+ }
1259
+ if (classes.length > 0) {
1260
+ cell.className = (0, import_react_ui_theme2.mx)(classes.flat());
1261
+ }
1262
+ if (props.format === import_echo_schema6.FormatEnum.Ref && props.referenceSchema) {
1263
+ const targetObj = (0, import_echo_schema6.getValue)(obj, field.path)?.target;
1264
+ if (targetObj) {
1265
+ cell.accessoryHtml = tableButtons.referencedCell.render({
1266
+ targetId: targetObj.id,
1267
+ schemaId: props.referenceSchema
1268
+ });
1269
+ }
1270
+ }
1271
+ if (props.format === import_echo_schema6.FormatEnum.Boolean) {
1272
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1273
+ cell.accessoryHtml = tableControls.switch.render({
1274
+ colIndex,
1275
+ rowIndex: displayIndex,
1276
+ checked: value ?? false
1277
+ });
1278
+ cell.readonly = true;
1279
+ }
1280
+ if (props.format === import_echo_schema6.FormatEnum.SingleSelect) {
1281
+ const value = (0, import_echo_schema6.getValue)(obj, field.path);
1282
+ const options = this.model.projection.getFieldProjection(field.id).props.options;
1283
+ if (options) {
1284
+ const option = options.find((o) => o.id === value);
1285
+ if (option) {
1286
+ cell.accessoryHtml = `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
1287
+ }
1288
+ }
1289
+ }
1290
+ const idx = (0, import_react_ui_grid3.toPlaneCellIndex)({
1291
+ col: colIndex,
1292
+ row: displayIndex
1293
+ });
1294
+ cells[idx] = cell;
1295
+ };
1296
+ for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1297
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1298
+ const field = fields[col];
1299
+ if (!field) {
1300
+ continue;
1301
+ }
1302
+ addCell(this.model.rows.value[row], field, col, row);
1303
+ }
1304
+ }
1305
+ return cells;
1306
+ }
1307
+ getHeaderCells(range) {
1308
+ const cells = {};
1309
+ const fields = this.model.table.view?.target?.fields ?? [];
1310
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1311
+ const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
1312
+ const sorting = this.model.sorting?.sorting;
1313
+ const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
1314
+ cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1315
+ col,
1316
+ row: 0
1317
+ })] = {
1318
+ // TODO(burdon): Use same logic as form for fallback title.
1319
+ value: props.title ?? field.path,
1320
+ readonly: true,
1321
+ resizeHandle: "col",
1322
+ accessoryHtml: `
1323
+ ${direction !== void 0 ? tableButtons.sort.render({
1324
+ fieldId: field.id,
1325
+ direction
1326
+ }) : ""}
1327
+ ${tableButtons.columnSettings.render({
1328
+ fieldId: field.id
1329
+ })}
1330
+ `,
1331
+ className: "!bg-gridHeader"
1332
+ };
1333
+ }
1334
+ return cells;
1335
+ }
1336
+ getSelectionColumnCells(range) {
1337
+ const cells = {};
1338
+ for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1339
+ const isSelected = this.model.selection.isRowIndexSelected(row);
1340
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1341
+ cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1342
+ col: 0,
1343
+ row
1344
+ })] = {
1345
+ value: "",
1346
+ readonly: true,
1347
+ className: classes ? (0, import_react_ui_theme2.mx)(classes) : void 0,
1348
+ accessoryHtml: tableControls.checkbox.render({
1349
+ rowIndex: row,
1350
+ checked: isSelected
1351
+ })
1352
+ };
1353
+ }
1354
+ return cells;
1355
+ }
1356
+ getActionColumnCells(range) {
1357
+ const cells = {};
1358
+ for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
1359
+ const isSelected = this.model.selection.isRowIndexSelected(row);
1360
+ const classes = (0, import_react_ui_form6.cellClassesForRowSelection)(isSelected);
1361
+ cells[(0, import_react_ui_grid3.toPlaneCellIndex)({
1362
+ col: 0,
1363
+ row
1364
+ })] = {
1365
+ value: "",
1366
+ readonly: true,
1367
+ className: classes ? (0, import_react_ui_theme2.mx)(classes) : void 0,
1368
+ accessoryHtml: tableButtons.rowMenu.render({
1369
+ rowIndex: row
1370
+ })
1371
+ };
1372
+ }
1373
+ return cells;
1374
+ }
1375
+ getSelectAllCell() {
1376
+ return {
1377
+ [(0, import_react_ui_grid3.toPlaneCellIndex)({
1378
+ col: 0,
1379
+ row: 0
1380
+ })]: {
1381
+ accessoryHtml: tableControls.checkbox.render({
1382
+ rowIndex: 0,
1383
+ header: true,
1384
+ checked: this.model.selection.allRowsSeleted.value
1385
+ }),
1386
+ className: "!bg-gridHeader",
1387
+ readonly: true,
1388
+ value: ""
1389
+ }
1390
+ };
1391
+ }
1392
+ getNewColumnCell() {
1393
+ return {
1394
+ [(0, import_react_ui_grid3.toPlaneCellIndex)({
1395
+ col: 0,
1396
+ row: 0
1397
+ })]: {
1398
+ accessoryHtml: tableButtons.addColumn.render({
1399
+ disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= import_schema2.VIEW_FIELD_LIMIT
1400
+ }),
1401
+ className: "!bg-gridHeader",
1402
+ readonly: true,
1403
+ value: ""
1404
+ }
1405
+ };
1406
+ }
1407
+ };
1408
+ var completion = ({ debug, onQuery, onMatch }) => {
1409
+ return [
1410
+ import_view.EditorView.theme({
1411
+ ".cm-completionDialog": {
1412
+ width: "var(--dx-gridCellWidth)"
1413
+ }
1414
+ }),
1415
+ (0, import_autocomplete.autocompletion)({
1416
+ icons: false,
1417
+ activateOnTyping: true,
1418
+ closeOnBlur: !debug,
1419
+ override: [
1420
+ async (context) => {
1421
+ const text = context.state.doc.toString();
1422
+ return {
1423
+ from: 0,
1424
+ options: await onQuery(text)
1425
+ };
1426
+ }
1427
+ ],
1428
+ // TODO(burdon): Consts from grid (to line-up with grid).
1429
+ tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
1430
+ optionClass: () => "flex h-[33px] items-center"
1431
+ }),
1432
+ // Check for accepted completion metadata in the transaction.
1433
+ import_view.EditorView.updateListener.of((update) => {
1434
+ update.transactions.forEach((tr) => {
1435
+ const completion2 = tr.annotation(import_autocomplete.pickedCompletion);
1436
+ if (completion2) {
1437
+ onMatch(completion2.data);
1438
+ }
1439
+ });
1440
+ })
1441
+ ];
1442
+ };
1443
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
1444
+ var newValue = Symbol.for("newValue");
1445
+ var createOption = (text) => ({
1446
+ [newValue]: true,
1447
+ text
1448
+ });
1449
+ var isCreateOption = (data) => typeof data === "object" && data[newValue];
1450
+ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }) => {
1451
+ const { id: gridId, editing, setEditing } = (0, import_react_ui_grid4.useGridContext)("TableCellEditor", __gridScope);
1452
+ const suppressNextBlur = (0, import_react7.useRef)(false);
1453
+ const fieldProjection = (0, import_react7.useMemo)(() => {
1454
+ if (!model || !editing) {
1455
+ return;
1456
+ }
1457
+ const { col } = (0, import_react_ui_grid4.parseCellIndex)(editing.index);
1458
+ const field = model.projection.view.fields[col];
1459
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
1460
+ (0, import_invariant3.invariant)(fieldProjection2, void 0, {
1461
+ F: __dxlog_file3,
1462
+ L: 67,
1463
+ S: void 0,
1464
+ A: [
1465
+ "fieldProjection",
1466
+ ""
1467
+ ]
1468
+ });
1469
+ return fieldProjection2;
1470
+ }, [
1471
+ model,
1472
+ editing
1473
+ ]);
1474
+ const handleEnter = (0, import_react7.useCallback)((value) => {
1475
+ if (!model || !editing) {
1476
+ return;
1477
+ }
1478
+ const cell = (0, import_react_ui_grid4.parseCellIndex)(editing.index);
1479
+ model.setCellData(cell, value);
1480
+ onEnter?.(cell);
1481
+ onFocus?.();
1482
+ setEditing(null);
1483
+ }, [
1484
+ model,
1485
+ editing
1486
+ ]);
1487
+ const handleBlur = (0, import_react7.useCallback)((value) => {
1488
+ if (!model || !editing) {
1489
+ return;
1490
+ }
1491
+ if (suppressNextBlur.current) {
1492
+ suppressNextBlur.current = false;
1493
+ return;
1494
+ }
1495
+ const cell = (0, import_react_ui_grid4.parseCellIndex)(editing.index);
1496
+ if (value !== void 0) {
1497
+ model.setCellData(cell, value);
1498
+ }
1499
+ }, [
1500
+ model,
1501
+ editing
1502
+ ]);
1503
+ const handleClose = (0, import_react7.useCallback)((value, event) => {
1504
+ if (!model || !editing || !fieldProjection) {
1505
+ return;
1506
+ }
1507
+ const cell = (0, import_react_ui_grid4.parseCellIndex)(editing.index);
1508
+ onEnter?.(cell);
1509
+ if (event && onFocus) {
1510
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
1511
+ }
1512
+ }, [
1513
+ model,
1514
+ editing,
1515
+ onFocus,
1516
+ onEnter,
1517
+ fieldProjection,
1518
+ determineNavigationAxis,
1519
+ determineNavigationDelta
1520
+ ]);
1521
+ const extension = (0, import_react7.useMemo)(() => {
1522
+ if (!fieldProjection) {
1523
+ return [];
1524
+ }
1525
+ const extension2 = [
1526
+ (0, import_react_ui_grid4.editorKeys)({
1527
+ onClose: handleClose,
1528
+ ...editing?.initialContent && {
1529
+ onNav: handleClose
1530
+ }
1531
+ })
1532
+ ];
1533
+ if (onQuery) {
1534
+ switch (fieldProjection.props.format) {
1535
+ case import_echo_schema7.FormatEnum.Ref: {
1536
+ extension2.push([
1537
+ completion({
1538
+ onQuery: (text) => onQuery(fieldProjection, text),
1539
+ onMatch: (data) => {
1540
+ if (model && editing && modals) {
1541
+ if (isCreateOption(data)) {
1542
+ const { field, props } = fieldProjection;
1543
+ if (props.referenceSchema) {
1544
+ suppressNextBlur.current = true;
1545
+ modals.openCreateRef(props.referenceSchema, document.querySelector((0, import_react_ui_grid4.cellQuery)(editing.index, gridId)), {
1546
+ [field.referencePath]: data.text
1547
+ }, (data2) => {
1548
+ handleEnter(data2);
1549
+ });
1550
+ }
1551
+ } else {
1552
+ handleEnter(data);
1553
+ }
1554
+ }
1555
+ }
1556
+ })
1557
+ ]);
1558
+ break;
1559
+ }
1560
+ }
1561
+ }
1562
+ return extension2;
1563
+ }, [
1564
+ model,
1565
+ modals,
1566
+ editing,
1567
+ fieldProjection,
1568
+ handleClose
1569
+ ]);
1570
+ const getCellContent = (0, import_react7.useCallback)(() => {
1571
+ if (model && editing) {
1572
+ const value = model.getCellData((0, import_react_ui_grid4.parseCellIndex)(editing.index));
1573
+ return value !== void 0 ? String(value) : "";
1574
+ }
1575
+ }, [
1576
+ model,
1577
+ editing
1578
+ ]);
1579
+ return /* @__PURE__ */ import_react7.default.createElement(import_react_ui_grid4.GridCellEditor, {
1580
+ extension,
1581
+ getCellContent,
1582
+ onBlur: handleBlur
1583
+ });
1584
+ };
1585
+ var determineNavigationAxis = ({ key }) => {
1586
+ switch (key) {
1587
+ case "ArrowUp":
1588
+ case "ArrowDown":
1589
+ case "Enter": {
1590
+ return "row";
1591
+ }
1592
+ case "ArrowLeft":
1593
+ case "ArrowRight":
1594
+ case "Tab":
1595
+ return "col";
1596
+ }
1597
+ };
1598
+ var determineNavigationDelta = ({ key, shift }) => {
1599
+ switch (key) {
1600
+ case "ArrowUp":
1601
+ case "ArrowLeft":
1602
+ return -1;
1603
+ case "ArrowDown":
1604
+ case "ArrowRight":
1605
+ return 1;
1606
+ }
1607
+ return shift ? -1 : 1;
1608
+ };
1609
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
1610
+ 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";
1611
+ 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";
1612
+ var frozen = {
1613
+ frozenRowsStart: 1,
1614
+ frozenColsStart: 1,
1615
+ frozenColsEnd: 1
1616
+ };
1617
+ var TableRoot = ({ children, role }) => {
1618
+ return /* @__PURE__ */ import_react.default.createElement("div", {
1619
+ role: "none",
1620
+ 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]")
1621
+ }, children);
1622
+ };
1623
+ var TableMain = /* @__PURE__ */ (0, import_react.forwardRef)(({ model, presentation, ignoreAttention }, forwardedRef) => {
1624
+ const [dxGrid, setDxGrid] = (0, import_react.useState)(null);
1625
+ const { hasAttention } = (0, import_react_ui_attention.useAttention)(model?.table ? (0, import_echo.fullyQualifiedId)(model.table) : "table");
1626
+ const { t } = (0, import_react_ui.useTranslation)(translationKey);
1627
+ const modals = (0, import_react.useMemo)(() => new ModalController(), []);
1628
+ (0, import_react.useImperativeHandle)(forwardedRef, () => {
1629
+ if (!presentation || !dxGrid) {
1630
+ return {};
1631
+ }
1632
+ dxGrid.getCells = (range, plane) => presentation.getCells(range, plane);
1633
+ return {
1634
+ update: (cell) => {
1635
+ if (cell) {
1636
+ dxGrid.updateIfWithinBounds(cell);
1637
+ } else {
1638
+ dxGrid.updateCells(true);
1639
+ dxGrid.requestUpdate();
1640
+ }
1641
+ }
1642
+ };
1643
+ }, [
1644
+ presentation,
1645
+ dxGrid
1646
+ ]);
1647
+ const handleGridClick = (0, import_react.useCallback)((event) => {
1648
+ if (!modals) {
1649
+ return;
1650
+ }
1651
+ const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
1652
+ const tableButtonElement = event.target.closest(buttonSelector);
1653
+ if (tableButtonElement) {
1654
+ const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
1655
+ if (!button) {
1656
+ return;
1657
+ }
1658
+ modals.setTrigger(tableButtonElement);
1659
+ const data = button.getData(tableButtonElement);
1660
+ switch (data.type) {
1661
+ case "rowMenu": {
1662
+ modals.showRowMenu(data.rowIndex);
1663
+ break;
1664
+ }
1665
+ case "columnSettings": {
1666
+ modals.showColumnMenu(data.fieldId);
1667
+ break;
1668
+ }
1669
+ case "newColumn": {
1670
+ modals.showColumnCreator();
1671
+ break;
1672
+ }
1673
+ case "referencedCell": {
1674
+ modals.showReferencePanel(data.targetId, data.schemaId);
1675
+ break;
1676
+ }
1677
+ case "sort": {
1678
+ model?.sorting?.toggleSort(data.fieldId);
1679
+ break;
1680
+ }
1681
+ }
1682
+ return;
1683
+ }
1684
+ const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
1685
+ const controlElement = event.target.closest(controlSelector);
1686
+ if (controlElement) {
1687
+ const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
1688
+ if (!control) {
1689
+ return;
1690
+ }
1691
+ const data = control.getData(controlElement);
1692
+ switch (data.type) {
1693
+ case "checkbox": {
1694
+ if (data.header) {
1695
+ model?.selection.setSelection(model.selection.allRowsSeleted.value ? "none" : "all");
1696
+ } else {
1697
+ model?.selection.toggleSelectionForRowIndex(data.rowIndex);
1698
+ }
1699
+ break;
1700
+ }
1701
+ case "switch": {
1702
+ if (model) {
1703
+ model.updateCellData({
1704
+ row: data.rowIndex,
1705
+ col: data.colIndex
1706
+ }, (value) => !value);
1707
+ }
1708
+ break;
1709
+ }
1710
+ }
1711
+ }
1712
+ }, [
1713
+ model,
1714
+ modals
1715
+ ]);
1716
+ const handleFocus = (0, import_react.useCallback)((increment, delta) => {
1717
+ if (dxGrid) {
1718
+ dxGrid.refocus(increment, delta);
1719
+ }
1720
+ }, [
1721
+ dxGrid
1722
+ ]);
1723
+ const handleEnter = (0, import_react.useCallback)((cell) => {
1724
+ if (model && cell.row === model.getRowCount() - 1) {
1725
+ model.insertRow(cell.row);
1726
+ if (dxGrid) {
1727
+ requestAnimationFrame(() => {
1728
+ dxGrid?.scrollToRow(cell.row + 1);
1729
+ dxGrid?.refocus("row", 1);
1730
+ });
1731
+ }
1732
+ }
1733
+ }, [
1734
+ model,
1735
+ dxGrid
1736
+ ]);
1737
+ const handleKeyDown = (0, import_react.useCallback)((event) => {
1738
+ const cell = (0, import_react_ui_grid.closestCell)(event.target);
1739
+ if (!model || !cell) {
1740
+ return;
1741
+ }
1742
+ switch (event.key) {
1743
+ case "Backspace":
1744
+ case "Delete": {
1745
+ model.setCellData(cell, void 0);
1746
+ break;
1747
+ }
1748
+ }
1749
+ }, [
1750
+ model
1751
+ ]);
1752
+ const handleAxisResize = (0, import_react.useCallback)((event) => {
1753
+ if (event.axis === "col") {
1754
+ const columnIndex = parseInt(event.index, 10);
1755
+ model?.setColumnWidth(columnIndex, event.size);
1756
+ }
1757
+ }, [
1758
+ model
1759
+ ]);
1760
+ const handleWheel = (0, import_react.useCallback)((event) => {
1761
+ if (!ignoreAttention && !hasAttention) {
1762
+ event.stopPropagation();
1763
+ }
1764
+ }, [
1765
+ hasAttention,
1766
+ ignoreAttention
1767
+ ]);
1768
+ const handleNewColumn = (0, import_react.useCallback)(() => {
1769
+ const columns = model?.getColumnCount();
1770
+ if (dxGrid && columns) {
1771
+ dxGrid.scrollToColumn(columns - 1);
1772
+ }
1773
+ }, [
1774
+ model,
1775
+ dxGrid
1776
+ ]);
1777
+ const handleQuery = (0, import_react.useCallback)(async ({ field, props }, text) => {
1778
+ if (model && props.referenceSchema && field.referencePath) {
1779
+ const space = (0, import_echo.getSpace)(model.table);
1780
+ (0, import_invariant.invariant)(space, void 0, {
1781
+ F: __dxlog_file4,
1782
+ L: 264,
1783
+ S: void 0,
1784
+ A: [
1785
+ "space",
1786
+ ""
1787
+ ]
1788
+ });
1789
+ const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
1790
+ if (schema) {
1791
+ const { objects } = await space.db.query(import_echo.Filter.schema(schema)).run();
1792
+ const options = objects.map((obj) => {
1793
+ const value = (0, import_echo_schema.getValue)(obj, field.referencePath);
1794
+ if (!value || typeof value !== "string") {
1795
+ return void 0;
1796
+ }
1797
+ return {
1798
+ label: value,
1799
+ data: obj
1800
+ };
1801
+ }).filter(import_util.isNotFalsy);
1802
+ return [
1803
+ ...options,
1804
+ {
1805
+ label: t("create new object label", {
1806
+ text
1807
+ }),
1808
+ data: createOption(text)
1809
+ }
1810
+ ];
1811
+ }
1812
+ }
1813
+ return [];
1814
+ }, [
1815
+ model
1816
+ ]);
1817
+ if (!model || !modals) {
1818
+ return /* @__PURE__ */ import_react.default.createElement("span", {
1819
+ role: "none",
1820
+ className: "attention-surface"
1821
+ });
1822
+ }
1823
+ return /* @__PURE__ */ import_react.default.createElement(import_react_ui_grid.Grid.Root, {
1824
+ id: model.table.id ?? "table-grid"
1825
+ }, /* @__PURE__ */ import_react.default.createElement(TableCellEditor, {
1826
+ model,
1827
+ modals,
1828
+ onEnter: handleEnter,
1829
+ onFocus: handleFocus,
1830
+ onQuery: handleQuery
1831
+ }), /* @__PURE__ */ import_react.default.createElement(import_react_ui_grid.Grid.Content, {
1832
+ onWheelCapture: handleWheel,
1833
+ className: (0, import_react_ui_theme.mx)("[--dx-grid-base:var(--surface-bg)]", inlineEndLine, blockEndLine),
1834
+ frozen,
1835
+ columns: model.columnMeta.value,
1836
+ limitRows: model.getRowCount() ?? 0,
1837
+ limitColumns: model.table.view?.target?.fields?.length ?? 0,
1838
+ onAxisResize: handleAxisResize,
1839
+ onClick: handleGridClick,
1840
+ onKeyDown: handleKeyDown,
1841
+ overscroll: "trap",
1842
+ ref: setDxGrid
1843
+ }), /* @__PURE__ */ import_react.default.createElement(RowActionsMenu, {
1844
+ model,
1845
+ modals
1846
+ }), /* @__PURE__ */ import_react.default.createElement(ColumnActionsMenu, {
1847
+ model,
1848
+ modals
1849
+ }), /* @__PURE__ */ import_react.default.createElement(ColumnSettings, {
1850
+ model,
1851
+ modals,
1852
+ onNewColumn: handleNewColumn
1853
+ }), /* @__PURE__ */ import_react.default.createElement(RefPanel, {
1854
+ model,
1855
+ modals
1856
+ }), /* @__PURE__ */ import_react.default.createElement(CreateRefPanel, {
1857
+ model,
1858
+ modals
1859
+ }));
1860
+ });
1861
+ var Table = {
1862
+ Root: TableRoot,
1863
+ Main: TableMain
1864
+ };
1865
+ var createTableToolbarActions = (state) => {
1866
+ const add = (0, import_react_ui_menu.createMenuAction)("add-row", {
1867
+ type: "add-row",
1868
+ icon: "ph--plus--regular",
1869
+ label: [
1870
+ "add row",
1871
+ {
1872
+ ns: translationKey
1873
+ }
1874
+ ],
1875
+ testId: "table.toolbar.add-row"
1876
+ });
1877
+ const save = (0, import_react_ui_menu.createMenuAction)("save-view", {
1878
+ type: "save-view",
1879
+ icon: "ph--floppy-disk--regular",
1880
+ label: [
1881
+ "save view label",
1882
+ {
1883
+ ns: translationKey
1884
+ }
1885
+ ],
1886
+ testId: "table.toolbar.save-view",
1887
+ iconOnly: false,
1888
+ hidden: !state.viewDirty
1889
+ });
1890
+ const gap = (0, import_react_ui_menu.createGapSeparator)();
1891
+ const comment = (0, import_react_ui_menu.createMenuAction)("comment", {
1892
+ type: "comment",
1893
+ icon: "ph--chat-text--regular",
1894
+ label: [
1895
+ "create comment",
1896
+ {
1897
+ ns: translationKey
1898
+ }
1899
+ ],
1900
+ testId: "table.toolbar.comment"
1901
+ });
1902
+ const nodes = [
1903
+ add,
1904
+ save,
1905
+ ...gap.nodes,
1906
+ comment
1907
+ ];
1908
+ return {
1909
+ nodes,
1910
+ edges: nodes.map(({ id: target }) => ({
1911
+ source: "root",
1912
+ target
1913
+ }))
1914
+ };
1915
+ };
1916
+ var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
1917
+ const state = (0, import_react8.useMemo)(() => (0, import_live_object2.create)({
1918
+ viewDirty
1919
+ }), []);
1920
+ const actionsCreator = (0, import_react8.useCallback)(() => createTableToolbarActions(state), [
1921
+ state
1922
+ ]);
1923
+ const menu = (0, import_react_ui_menu.useMenuActions)(actionsCreator);
1924
+ return /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.MenuProvider, {
1925
+ ...menu,
1926
+ attendableId,
1927
+ onAction
1928
+ }, /* @__PURE__ */ import_react8.default.createElement(import_react_ui_menu.ToolbarMenu, {
1929
+ classNames
1930
+ }));
1561
1931
  };
1562
1932
  var useTableModel = ({ objects, table, projection, ...props }) => {
1563
- const [model, setModel] = (0, import_react10.useState)();
1564
- (0, import_react10.useEffect)(() => {
1933
+ const [model, setModel] = (0, import_react9.useState)();
1934
+ (0, import_react9.useEffect)(() => {
1565
1935
  if (!table || !projection) {
1566
1936
  return;
1567
1937
  }
@@ -1583,7 +1953,7 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1583
1953
  table,
1584
1954
  projection
1585
1955
  ]);
1586
- (0, import_react10.useEffect)(() => {
1956
+ (0, import_react9.useEffect)(() => {
1587
1957
  if (objects) {
1588
1958
  model?.setRows(objects);
1589
1959
  }
@@ -1595,15 +1965,22 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
1595
1965
  };
1596
1966
  // Annotate the CommonJS export names for ESM import in node:
1597
1967
  0 && (module.exports = {
1968
+ BUTTON_IDENTIFIERS,
1969
+ CONTROL_IDENTIFIERS,
1970
+ ModalController,
1598
1971
  Table,
1972
+ TableModel,
1973
+ TablePresentation,
1599
1974
  TableSchema,
1975
+ TableToolbar,
1600
1976
  TableType,
1601
- Toolbar,
1602
1977
  initializeTable,
1978
+ renderCheckbox,
1979
+ renderSwitch,
1603
1980
  tableButtons,
1981
+ tableControls,
1604
1982
  touch,
1605
1983
  translations,
1606
- useTableModel,
1607
- useToolbarContext
1984
+ useTableModel
1608
1985
  });
1609
1986
  //# sourceMappingURL=index.cjs.map