@dxos/react-ui-table 0.8.4-main.2e9d522 → 0.8.4-main.548089c

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 (132) hide show
  1. package/dist/lib/browser/chunk-2PFAPQL4.mjs +66 -0
  2. package/dist/lib/browser/chunk-2PFAPQL4.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-GS2UNGJK.mjs} +493 -469
  4. package/dist/lib/browser/chunk-GS2UNGJK.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +614 -696
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +14 -9
  9. package/dist/lib/browser/testing/index.mjs.map +3 -3
  10. package/dist/lib/browser/types/index.mjs +3 -3
  11. package/dist/lib/node-esm/chunk-6POOFFYF.mjs +67 -0
  12. package/dist/lib/node-esm/chunk-6POOFFYF.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-Y66YLSTC.mjs → chunk-TRR3C5NX.mjs} +493 -469
  14. package/dist/lib/node-esm/chunk-TRR3C5NX.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +614 -696
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +14 -9
  19. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/types/index.mjs +3 -3
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -1
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +1 -1
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts +2 -2
  26. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +51 -3
  28. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Relations.stories.d.ts +107 -0
  30. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  31. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  32. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/Table.d.ts +8 -4
  34. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  35. package/dist/types/src/components/Table/Table.stories.d.ts +42 -4
  36. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  38. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +12 -6
  39. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  40. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +12 -17
  41. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  42. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +39 -4
  43. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
  45. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -1
  46. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +2 -2
  47. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  48. package/dist/types/src/components/testing.d.ts +3 -3
  49. package/dist/types/src/components/testing.d.ts.map +1 -1
  50. package/dist/types/src/hooks/useAddRow.d.ts +3 -2
  51. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  52. package/dist/types/src/hooks/useTableModel.d.ts +4 -4
  53. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  54. package/dist/types/src/model/modal-controller.d.ts +0 -7
  55. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  56. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  57. package/dist/types/src/model/table-model.d.ts +11 -9
  58. package/dist/types/src/model/table-model.d.ts.map +1 -1
  59. package/dist/types/src/model/table-presentation.d.ts +2 -1
  60. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  61. package/dist/types/src/model/table-sorting.d.ts +3 -4
  62. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  63. package/dist/types/src/testing/useTestTableModel.d.ts +3 -22
  64. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  65. package/dist/types/src/translations.d.ts +2 -2
  66. package/dist/types/src/types/index.d.ts +1 -1
  67. package/dist/types/src/types/index.d.ts.map +1 -1
  68. package/dist/types/src/types/schema.d.ts +25 -5
  69. package/dist/types/src/types/schema.d.ts.map +1 -1
  70. package/dist/types/src/util/dynamic-table.d.ts +5 -6
  71. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  72. package/dist/types/src/util/index.d.ts +0 -1
  73. package/dist/types/src/util/index.d.ts.map +1 -1
  74. package/dist/types/src/util/schema.d.ts +1 -1
  75. package/dist/types/src/util/schema.d.ts.map +1 -1
  76. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  77. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  78. package/dist/types/tsconfig.tsbuildinfo +1 -1
  79. package/package.json +57 -51
  80. package/src/components/Table/ColumnActionsMenu.tsx +1 -1
  81. package/src/components/Table/ColumnSettings.tsx +1 -1
  82. package/src/components/Table/DynamicTable.stories.tsx +18 -14
  83. package/src/components/Table/DynamicTable.tsx +8 -10
  84. package/src/components/Table/Relations.stories.tsx +242 -0
  85. package/src/components/Table/RowActionsMenu.tsx +23 -15
  86. package/src/components/Table/Table.stories.tsx +72 -60
  87. package/src/components/Table/Table.tsx +147 -117
  88. package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
  89. package/src/components/TableCellEditor/FormCellEditor.tsx +153 -42
  90. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +25 -64
  91. package/src/components/TableCellEditor/TableCellEditor.tsx +74 -224
  92. package/src/components/TableCellEditor/index.ts +1 -0
  93. package/src/components/TableToolbar/TableToolbar.tsx +33 -23
  94. package/src/components/testing.ts +2 -2
  95. package/src/hooks/useAddRow.ts +7 -5
  96. package/src/hooks/useTableModel.ts +6 -6
  97. package/src/model/modal-controller.ts +1 -29
  98. package/src/model/selection-model.ts +3 -2
  99. package/src/model/table-model.test.ts +20 -11
  100. package/src/model/table-model.ts +46 -31
  101. package/src/model/table-presentation.test.ts +24 -22
  102. package/src/model/table-presentation.ts +74 -33
  103. package/src/model/table-sorting.ts +17 -8
  104. package/src/playwright/TableManager.ts +1 -1
  105. package/src/playwright/smoke.spec.ts +131 -37
  106. package/src/testing/useTestTableModel.ts +12 -8
  107. package/src/translations.ts +2 -2
  108. package/src/types/index.ts +1 -1
  109. package/src/types/schema.ts +63 -6
  110. package/src/util/dynamic-table.ts +16 -17
  111. package/src/util/index.ts +0 -1
  112. package/src/util/schema.ts +4 -4
  113. package/src/util/table-buttons.ts +4 -3
  114. package/src/util/table-controls.ts +4 -1
  115. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  116. package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
  117. package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +0 -7
  118. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +0 -20
  119. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +0 -7
  120. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  121. package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
  122. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
  123. package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
  124. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
  125. package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
  126. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
  127. package/dist/types/src/util/table.d.ts +0 -11
  128. package/dist/types/src/util/table.d.ts.map +0 -1
  129. package/src/components/Table/CreateRefPanel.tsx +0 -86
  130. package/src/components/Table/relations.stories.tsx +0 -116
  131. package/src/components/TableCellEditor/extension.ts +0 -61
  132. package/src/util/table.ts +0 -49
@@ -1,12 +1,12 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
  import {
3
- TableView
4
- } from "./chunk-NXZ4CJYX.mjs";
3
+ schema_exports
4
+ } from "./chunk-6POOFFYF.mjs";
5
5
 
6
6
  // src/util/dynamic-table.ts
7
- import { Obj } from "@dxos/echo";
8
- import { getTypename, toJsonSchema } from "@dxos/echo-schema";
9
- import { createView, getSchemaFromPropertyDefinitions, ProjectionModel } from "@dxos/schema";
7
+ import { Filter, Obj, Query } from "@dxos/echo";
8
+ import { getTypename, toJsonSchema } from "@dxos/echo/internal";
9
+ import { ProjectionModel, View, getSchemaFromPropertyDefinitions } from "@dxos/schema";
10
10
  var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
11
11
  if (typename && properties) {
12
12
  const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
@@ -28,12 +28,12 @@ var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
28
28
  throw new Error("invalid properties");
29
29
  }
30
30
  };
31
- var makeDynamicTable = ({ typename, jsonSchema, properties }) => {
32
- const table = Obj.make(TableView, {
31
+ var makeDynamicTable = ({ jsonSchema, properties }) => {
32
+ const table = Obj.make(schema_exports.Table, {
33
33
  sizes: {}
34
34
  });
35
- const view = createView({
36
- typename,
35
+ const view = View.make({
36
+ query: Query.select(Filter.everything()),
37
37
  jsonSchema,
38
38
  presentation: table,
39
39
  ...properties && {
@@ -41,6 +41,7 @@ var makeDynamicTable = ({ typename, jsonSchema, properties }) => {
41
41
  }
42
42
  });
43
43
  const projection = new ProjectionModel(jsonSchema, view.projection);
44
+ projection.normalizeView();
44
45
  if (properties && projection.fields) {
45
46
  setProperties(view, projection, table, properties);
46
47
  }
@@ -68,7 +69,7 @@ var setProperties = (view, projection, table, properties) => {
68
69
  }
69
70
  if (property.sort) {
70
71
  const fieldId = field.id;
71
- view.query.sort = [
72
+ view.sort = [
72
73
  {
73
74
  fieldId,
74
75
  direction: property.sort
@@ -82,40 +83,6 @@ var setProperties = (view, projection, table, properties) => {
82
83
  // src/util/signals.ts
83
84
  var touch = (value) => value;
84
85
 
85
- // src/util/table.ts
86
- import { Match } from "effect";
87
- import { Obj as Obj2 } from "@dxos/echo";
88
- import { toEffectSchema } from "@dxos/echo-schema";
89
- import { createViewFromSpace, getSchemaProperties } from "@dxos/schema";
90
- var createTable = async ({ sizes, ...props }) => {
91
- const table = Obj2.make(TableView, {
92
- sizes: {}
93
- });
94
- const { jsonSchema, view } = await createViewFromSpace({
95
- ...props,
96
- presentation: table
97
- });
98
- const schema = toEffectSchema(jsonSchema);
99
- const shouldIncludeId = props.fields?.find((field) => field === "id") !== void 0;
100
- const properties = getSchemaProperties(schema.ast, {}, shouldIncludeId);
101
- for (const property of properties) {
102
- if (sizes?.[property.name]) {
103
- table.sizes[property.name] = sizes[property.name];
104
- continue;
105
- }
106
- Match.type().pipe(Match.when("boolean", () => {
107
- table.sizes[property.name] = 100;
108
- }), Match.when("number", () => {
109
- table.sizes[property.name] = 100;
110
- }), Match.orElse(() => {
111
- }))(property.type);
112
- }
113
- return {
114
- jsonSchema,
115
- view
116
- };
117
- };
118
-
119
86
  // src/util/table-buttons.ts
120
87
  var BUTTON_IDENTIFIERS = {
121
88
  columnSettings: "data-table-column-settings-button",
@@ -125,10 +92,9 @@ var BUTTON_IDENTIFIERS = {
125
92
  saveDraftRow: "data-table-save-draft-row-button",
126
93
  sort: "data-table-sort-button"
127
94
  };
128
- var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
95
+ var createButton = ({ attr, data, disabled = false, icon, testId, type: _type = "primary" }) => {
129
96
  const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
130
- const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
131
- 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 data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
97
+ return `<button ${attr} data-testid="${testId}" class="dx-button is-6 aspect-square pli-0.5 min-bs-0" ${dataAttrs} ${disabled ? "disabled" : ""} data-dx-grid-action="accessory"><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
132
98
  };
133
99
  var addColumnButton = {
134
100
  attr: BUTTON_IDENTIFIERS.newColumn,
@@ -154,7 +120,8 @@ var columnSettingsButton = {
154
120
  attr: BUTTON_IDENTIFIERS.columnSettings,
155
121
  icon: columnSettingsButton.icon,
156
122
  data: {
157
- "data-field-id": fieldId
123
+ "data-field-id": fieldId,
124
+ "data-variant": "ghost"
158
125
  },
159
126
  testId: "table-column-settings-button"
160
127
  });
@@ -214,7 +181,8 @@ var saveDraftRowButton = {
214
181
  icon: saveDraftRowButton.icon,
215
182
  disabled,
216
183
  data: {
217
- "data-row-index": rowIndex.toString()
184
+ "data-row-index": rowIndex.toString(),
185
+ "data-variant": "primary"
218
186
  },
219
187
  testId: "table-save-draft-row-button"
220
188
  });
@@ -233,6 +201,7 @@ var tableButtons = {
233
201
  };
234
202
 
235
203
  // src/util/table-controls.ts
204
+ import { accessoryHandlesPointerdownAttrs } from "@dxos/lit-grid";
236
205
  var CONTROL_IDENTIFIERS = {
237
206
  checkbox: "data-table-checkbox",
238
207
  switch: "data-table-switch"
@@ -245,7 +214,7 @@ var renderAttributes = (data) => {
245
214
  return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
246
215
  };
247
216
  var renderInput = (baseClass, attrs, checked = false, disabled = false, preventToggle = false, testId) => {
248
- return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}"/>`;
217
+ return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}" data-dx-grid-action="accessory"/>`;
249
218
  };
250
219
  var CheckboxStory = ({ rowIndex, header = false, checked = false, disabled = false }) => {
251
220
  const attrs = {
@@ -261,7 +230,8 @@ var SwitchStory = ({ colIndex, rowIndex, checked = false, disabled = false }) =>
261
230
  const attrs = {
262
231
  [CONTROL_IDENTIFIERS.switch]: "",
263
232
  "data-row-index": rowIndex.toString(),
264
- "data-col-index": colIndex.toString()
233
+ "data-col-index": colIndex.toString(),
234
+ ...accessoryHandlesPointerdownAttrs
265
235
  };
266
236
  return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, "table-switch");
267
237
  };
@@ -287,14 +257,14 @@ var tableControls = {
287
257
  };
288
258
 
289
259
  // src/util/schema.ts
290
- import { Schema } from "effect";
291
- import { isTypeLiteral, TypeLiteral } from "effect/SchemaAST";
260
+ import * as Schema from "effect/Schema";
261
+ import * as SchemaAST from "effect/SchemaAST";
292
262
  var narrowSchema = (schema, paths) => {
293
263
  const ast = schema?.ast;
294
- if (isTypeLiteral(ast)) {
264
+ if (SchemaAST.isTypeLiteral(ast)) {
295
265
  const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
296
266
  if (propertySignatures.length > 0) {
297
- const narrowType = new TypeLiteral(propertySignatures, []);
267
+ const narrowType = new SchemaAST.TypeLiteral(propertySignatures, []);
298
268
  return Schema.make(narrowType);
299
269
  }
300
270
  }
@@ -304,67 +274,59 @@ var narrowSchema = (schema, paths) => {
304
274
  // src/model/table-model.ts
305
275
  import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
306
276
  import { Resource as Resource2 } from "@dxos/context";
307
- import { Obj as Obj3, Ref } from "@dxos/echo";
308
- import { FormatEnum as FormatEnum2, getValue as getValue2, setValue, getSnapshot, getSchema, toEffectSchema as toEffectSchema2 } from "@dxos/echo-schema";
277
+ import { Obj as Obj2, Ref } from "@dxos/echo";
278
+ import { FormatEnum as FormatEnum2, getSchema, getValue as getValue2, setValue, toEffectSchema } from "@dxos/echo/internal";
309
279
  import { invariant } from "@dxos/invariant";
310
280
  import { ObjectId } from "@dxos/keys";
311
- import { isLiveObject } from "@dxos/live-object";
312
- import { fullyQualifiedId } from "@dxos/react-client/echo";
281
+ import { getSnapshot, isLiveObject } from "@dxos/live-object";
313
282
  import { formatForEditing, parseValue } from "@dxos/react-ui-form";
314
283
  import { ProjectionModel as ProjectionModel2, validateSchema } from "@dxos/schema";
315
284
 
285
+ // src/util/tag.ts
286
+ var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
287
+ var extractTagIds = (value) => {
288
+ if (typeof value !== "string") {
289
+ return void 0;
290
+ }
291
+ const ids = [];
292
+ let match;
293
+ while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
294
+ if (match[2]) {
295
+ ids.push(match[2]);
296
+ }
297
+ }
298
+ return ids.length > 0 ? ids : void 0;
299
+ };
300
+
316
301
  // src/model/selection-model.ts
317
302
  import { computed, effect, signal } from "@preact/signals-core";
318
303
  import { Resource } from "@dxos/context";
319
304
  var SelectionModel = class extends Resource {
305
+ _rows;
306
+ _selectionMode;
307
+ _initialSelection;
308
+ _onSelectionChanged;
309
+ _selection;
310
+ _validSelectedIds = computed(() => {
311
+ const rows = this._rows.value;
312
+ if (!rows) {
313
+ return /* @__PURE__ */ new Set();
314
+ }
315
+ const validIds = new Set(rows.map((row) => row.id));
316
+ return new Set([
317
+ ...this._selection.value
318
+ ].filter((id) => validIds.has(id)));
319
+ });
320
+ _hasSelection = computed(() => this._validSelectedIds.value.size > 0);
321
+ _allSelected = computed(() => {
322
+ const rows = this._rows.value;
323
+ if (rows.length === 0) {
324
+ return false;
325
+ }
326
+ return rows.every((row) => this._selection.value.has(row.id));
327
+ });
320
328
  constructor(_rows, _selectionMode, _initialSelection, _onSelectionChanged) {
321
- super(), this._rows = _rows, this._selectionMode = _selectionMode, this._initialSelection = _initialSelection, this._onSelectionChanged = _onSelectionChanged, this._validSelectedIds = computed(() => {
322
- const rows = this._rows.value;
323
- if (!rows) {
324
- return /* @__PURE__ */ new Set();
325
- }
326
- const validIds = new Set(rows.map((row) => row.id));
327
- return new Set([
328
- ...this._selection.value
329
- ].filter((id) => validIds.has(id)));
330
- }), this._hasSelection = computed(() => this._validSelectedIds.value.size > 0), this._allSelected = computed(() => {
331
- const rows = this._rows.value;
332
- if (rows.length === 0) {
333
- return false;
334
- }
335
- return rows.every((row) => this._selection.value.has(row.id));
336
- }), this.getSelectedRows = () => {
337
- const selectedIds = this._validSelectedIds.value;
338
- return this._rows.value.filter((row) => selectedIds.has(row.id));
339
- }, this.isRowIndexSelected = (rowIndex) => {
340
- const row = this._rows.value[rowIndex];
341
- return this._selection.value.has(row.id);
342
- }, this.isObjectSelected = (object) => {
343
- return this._selection.value.has(object.id);
344
- }, this.toggleSelectionForRowIndex = (rowIndex) => {
345
- const row = this._rows.value[rowIndex];
346
- const newSelection = new Set(this._selection.value);
347
- if (newSelection.has(row.id)) {
348
- newSelection.delete(row.id);
349
- } else {
350
- if (this._selectionMode === "single") {
351
- newSelection.clear();
352
- }
353
- newSelection.add(row.id);
354
- }
355
- this._selection.value = newSelection;
356
- }, this.setSelection = (mode) => {
357
- switch (mode) {
358
- case "all": {
359
- this._selection.value = new Set(this._rows.value.map((row) => row.id));
360
- break;
361
- }
362
- case "none": {
363
- this._selection.value = /* @__PURE__ */ new Set();
364
- break;
365
- }
366
- }
367
- };
329
+ super(), this._rows = _rows, this._selectionMode = _selectionMode, this._initialSelection = _initialSelection, this._onSelectionChanged = _onSelectionChanged;
368
330
  this._selection = signal(new Set(this._initialSelection));
369
331
  }
370
332
  async _open() {
@@ -389,23 +351,67 @@ var SelectionModel = class extends Resource {
389
351
  get selectionMode() {
390
352
  return this._selectionMode;
391
353
  }
354
+ getSelectedRows = () => {
355
+ const selectedIds = this._validSelectedIds.value;
356
+ return this._rows.value.filter((row) => selectedIds.has(row.id));
357
+ };
358
+ isRowIndexSelected = (rowIndex) => {
359
+ const row = this._rows.value[rowIndex];
360
+ return this._selection.value.has(row.id);
361
+ };
362
+ isObjectSelected = (object) => {
363
+ return this._selection.value.has(object.id);
364
+ };
365
+ //
366
+ // Manipulation
367
+ //
368
+ toggleSelectionForRowIndex = (rowIndex) => {
369
+ const row = this._rows.value[rowIndex];
370
+ const newSelection = new Set(this._selection.value);
371
+ if (newSelection.has(row.id)) {
372
+ newSelection.delete(row.id);
373
+ } else {
374
+ if (this._selectionMode === "single") {
375
+ newSelection.clear();
376
+ }
377
+ newSelection.add(row.id);
378
+ }
379
+ this._selection.value = newSelection;
380
+ };
381
+ setSelection = (mode) => {
382
+ switch (mode) {
383
+ case "all": {
384
+ this._selection.value = new Set(this._rows.value.map((row) => row.id));
385
+ break;
386
+ }
387
+ case "none": {
388
+ this._selection.value = /* @__PURE__ */ new Set();
389
+ break;
390
+ }
391
+ }
392
+ };
392
393
  };
393
394
 
394
395
  // src/model/table-sorting.ts
395
396
  import { computed as computed2, signal as signal2 } from "@preact/signals-core";
396
397
  import orderBy from "lodash.orderby";
397
- import { getValue, FormatEnum, TypeEnum } from "@dxos/echo-schema";
398
+ import { FormatEnum, TypeEnum, getValue } from "@dxos/echo/internal";
398
399
  import { formatForDisplay } from "@dxos/react-ui-form";
399
400
  var TableSorting = class {
401
+ _view;
402
+ _projection;
403
+ _displayToDataIndex = /* @__PURE__ */ new Map();
404
+ _rows;
405
+ _localSort = signal2(void 0);
406
+ _isDirty;
407
+ sortedRows;
400
408
  constructor(rows, _view, _projection) {
401
409
  this._view = _view;
402
410
  this._projection = _projection;
403
- this._displayToDataIndex = /* @__PURE__ */ new Map();
404
- this._localSort = signal2(void 0);
405
411
  this._rows = rows;
406
412
  this._isDirty = computed2(() => {
407
413
  const local = this._localSort.value;
408
- const viewSort = this._view.query.sort?.[0];
414
+ const viewSort = this._view.sort?.[0];
409
415
  if (local?.type === "cleared") {
410
416
  return viewSort !== void 0;
411
417
  }
@@ -431,7 +437,7 @@ var TableSorting = class {
431
437
  if (local?.type === "active") {
432
438
  return local.sort;
433
439
  }
434
- return this._view.query.sort?.[0];
440
+ return this._view.sort?.[0];
435
441
  }
436
442
  /**
437
443
  * @reactive
@@ -475,11 +481,11 @@ var TableSorting = class {
475
481
  save() {
476
482
  if (this._localSort.value !== void 0) {
477
483
  if (this._localSort.value.type === "active") {
478
- this._view.query.sort = [
484
+ this._view.sort = [
479
485
  this._localSort.value.sort
480
486
  ];
481
487
  } else {
482
- this._view.query.sort = [];
488
+ this._view.sort = [];
483
489
  }
484
490
  this._localSort.value = void 0;
485
491
  }
@@ -556,22 +562,6 @@ var TableSorting = class {
556
562
  }
557
563
  };
558
564
 
559
- // src/util/tag.ts
560
- var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
561
- var extractTagIds = (value) => {
562
- if (typeof value !== "string") {
563
- return void 0;
564
- }
565
- const ids = [];
566
- let match;
567
- while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
568
- if (match[2]) {
569
- ids.push(match[2]);
570
- }
571
- }
572
- return ids.length > 0 ? ids : void 0;
573
- };
574
-
575
565
  // src/model/table-model.ts
576
566
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
577
567
  var defaultFeatures = {
@@ -583,231 +573,48 @@ var defaultFeatures = {
583
573
  schemaEditable: false
584
574
  };
585
575
  var TableModel = class extends Resource2 {
576
+ _view;
577
+ _projection;
578
+ _table;
579
+ _visibleRange = signal3({
580
+ start: {
581
+ row: 0,
582
+ col: 0
583
+ },
584
+ end: {
585
+ row: 0,
586
+ col: 0
587
+ }
588
+ });
589
+ _onInsertRow;
590
+ _onDeleteRows;
591
+ _onDeleteColumn;
592
+ _onCellUpdate;
593
+ _onRowOrderChange;
594
+ _onRowAction;
595
+ _rowActions;
596
+ _features;
597
+ _rows = signal3([]);
598
+ _draftRows = signal3([]);
599
+ _sorting;
600
+ _pinnedRows;
601
+ _selection;
602
+ _columnMeta;
586
603
  constructor({ view, schema, projection, features = {}, sorting = [], initialSelection = [], pinnedRows = {
587
604
  top: [],
588
605
  bottom: []
589
606
  }, rowActions = [], onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
590
607
  super();
591
- this._visibleRange = signal3({
592
- start: {
593
- row: 0,
594
- col: 0
595
- },
596
- end: {
597
- row: 0,
598
- col: 0
599
- }
600
- });
601
- this._rows = signal3([]);
602
- this._draftRows = signal3([]);
603
- //
604
- // Data
605
- //
606
- this.setRows = (obj) => {
607
- this._rows.value = obj;
608
- };
609
- this.getRowCount = () => this._rows.value.length;
610
- /**
611
- * @reactive
612
- */
613
- this.getDraftRowCount = () => this._draftRows.value.length;
614
- this.getColumnCount = () => this._projection?.fields.length ?? 0;
615
- this.insertRow = () => {
616
- const result = this._onInsertRow?.();
617
- if (result === false && this._draftRows.value.length === 0) {
618
- this.createDraftRow();
619
- }
620
- };
621
- this.commitDraftRow = (draftRowIndex) => {
622
- if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.value.length) {
623
- return false;
624
- }
625
- const draftRow = this._draftRows.value[draftRowIndex];
626
- if (!draftRow.valid) {
627
- return false;
628
- }
629
- const success = this._onInsertRow?.(draftRow.data);
630
- if (success) {
631
- const newDraftRows = this._draftRows.value.filter((_, index) => index !== draftRowIndex);
632
- this._draftRows.value = newDraftRows;
633
- }
634
- return success ?? false;
635
- };
636
- this.deleteRow = (rowIndex) => {
637
- const row = this._sorting.getDataIndex(rowIndex);
638
- const obj = this._rows.value[row];
639
- const objectsToDelete = [];
640
- if (this.features.selection.enabled && this._selection.hasSelection.value) {
641
- const selectedRows = this._selection.getSelectedRows();
642
- objectsToDelete.push(...selectedRows);
643
- } else {
644
- objectsToDelete.push(obj);
645
- }
646
- this._onDeleteRows?.(row, objectsToDelete);
647
- };
648
- this.handleRowAction = (actionId, rowIndex) => {
649
- if (!this._onRowAction) {
650
- return;
651
- }
652
- const row = this._sorting.getDataIndex(rowIndex);
653
- const data = this._rows.value[row];
654
- if (data) {
655
- this._onRowAction(actionId, data);
656
- }
657
- };
658
- this.getCellData = (cell) => {
659
- const { col, row, plane } = cell;
660
- const fields = this._projection?.fields ?? [];
661
- if (col < 0 || col >= fields.length) {
662
- return void 0;
663
- }
664
- const field = fields[col];
665
- let value;
666
- if (plane === "frozenRowsEnd") {
667
- if (row >= 0 && row < this._draftRows.value.length) {
668
- value = getValue2(this._draftRows.value[row].data, field.path);
669
- } else {
670
- return void 0;
671
- }
672
- } else {
673
- const dataIndex = this._sorting.getDataIndex(row);
674
- value = getValue2(this._rows.value[dataIndex], field.path);
675
- }
676
- if (value == null) {
677
- return "";
678
- }
679
- const { props } = this._projection.getFieldProjection(field.id);
680
- switch (props.format) {
681
- case FormatEnum2.Ref: {
682
- if (!field.referencePath) {
683
- return "";
684
- }
685
- return getValue2(value.target, field.referencePath);
686
- }
687
- default: {
688
- return formatForEditing({
689
- type: props.type,
690
- format: props.format,
691
- value
692
- });
693
- }
694
- }
695
- };
696
- this.validateCellData = async ({ col, row, plane }, value) => {
697
- const fields = this._projection?.fields ?? [];
698
- if (col < 0 || col >= fields.length) {
699
- return {
700
- valid: false,
701
- error: "Invalid column index"
702
- };
703
- }
704
- const field = fields[col];
705
- const { props } = this._projection.getFieldProjection(field.id);
706
- const transformedValue = editorTextToCellValue(props, value);
707
- const isDraftRow = plane === "frozenRowsEnd";
708
- if (isDraftRow) {
709
- const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.value.length;
710
- if (isInvalidDraftRowIndex) {
711
- return {
712
- valid: false,
713
- error: "Invalid draft row index"
714
- };
715
- }
716
- const draftRow = this._draftRows.value[row];
717
- const snapshot = {
718
- ...draftRow.data
719
- };
720
- setValue(snapshot, field.path, transformedValue);
721
- const validationErrors = this.validateDraftRowData(snapshot);
722
- if (validationErrors.length > 0) {
723
- const error = validationErrors.find((err) => err.path === field.path);
724
- if (error) {
725
- return {
726
- valid: false,
727
- error: error.message
728
- };
729
- }
730
- }
731
- return {
732
- valid: true
733
- };
734
- } else {
735
- const rowIdx = this._sorting.getDataIndex(row);
736
- const currentRow = this._rows.value[rowIdx];
737
- invariant(currentRow, "Invalid row index", {
738
- F: __dxlog_file,
739
- L: 510,
740
- S: this,
741
- A: [
742
- "currentRow",
743
- "'Invalid row index'"
744
- ]
745
- });
746
- const snapshot = getSnapshot(currentRow);
747
- setValue(snapshot, field.path, transformedValue);
748
- const schema = getSchema(currentRow);
749
- invariant(schema, void 0, {
750
- F: __dxlog_file,
751
- L: 516,
752
- S: this,
753
- A: [
754
- "schema",
755
- ""
756
- ]
757
- });
758
- const validationResult = validateSchema(schema, snapshot);
759
- if (validationResult && validationResult.length > 0) {
760
- const error = validationResult[0];
761
- invariant(error.path === field.path, void 0, {
762
- F: __dxlog_file,
763
- L: 521,
764
- S: this,
765
- A: [
766
- "error.path === field.path",
767
- ""
768
- ]
769
- });
770
- return {
771
- valid: false,
772
- error: error.message
773
- };
774
- }
775
- return {
776
- valid: true
777
- };
778
- }
779
- };
780
- this.setCellData = (cell, value) => {
781
- const { col, row, plane } = cell;
782
- const fields = this._projection?.fields ?? [];
783
- if (col < 0 || col >= fields.length) {
784
- return;
785
- }
786
- const field = fields[col];
787
- const { props } = this._projection.getFieldProjection(field.id);
788
- const transformedValue = editorTextToCellValue(props, value);
789
- if (props.format === FormatEnum2.Ref && !isLiveObject(value)) {
790
- return;
791
- }
792
- if (plane === "frozenRowsEnd") {
793
- if (row >= 0 && row < this._draftRows.value.length) {
794
- setValue(this._draftRows.value[row].data, field.path, transformedValue);
795
- this.validateDraftRow(row);
796
- }
797
- } else {
798
- const rowIdx = this._sorting.getDataIndex(row);
799
- setValue(this._rows.value[rowIdx], field.path, transformedValue);
800
- }
801
- };
802
608
  this._view = view;
803
609
  this._projection = projection ?? new ProjectionModel2(schema, view.projection);
610
+ this._projection.normalizeView();
804
611
  this._features = {
805
612
  ...defaultFeatures,
806
613
  ...features
807
614
  };
808
615
  invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
809
616
  F: __dxlog_file,
810
- L: 139,
617
+ L: 148,
811
618
  S: this,
812
619
  A: [
813
620
  "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
@@ -830,7 +637,7 @@ var TableModel = class extends Resource2 {
830
637
  this._onRowAction = onRowAction;
831
638
  }
832
639
  get id() {
833
- return fullyQualifiedId(this._view);
640
+ return Obj2.getDXN(this._view).toString();
834
641
  }
835
642
  get view() {
836
643
  return this._view;
@@ -838,7 +645,7 @@ var TableModel = class extends Resource2 {
838
645
  get table() {
839
646
  invariant(this._table, "Model not initialized", {
840
647
  F: __dxlog_file,
841
- L: 177,
648
+ L: 186,
842
649
  S: this,
843
650
  A: [
844
651
  "this._table",
@@ -877,7 +684,7 @@ var TableModel = class extends Resource2 {
877
684
  get columnMeta() {
878
685
  invariant(this._columnMeta, void 0, {
879
686
  F: __dxlog_file,
880
- L: 216,
687
+ L: 225,
881
688
  S: this,
882
689
  A: [
883
690
  "this._columnMeta",
@@ -901,12 +708,12 @@ var TableModel = class extends Resource2 {
901
708
  //
902
709
  async _open() {
903
710
  const presentation = this._view.presentation.target ?? await this._view.presentation.load();
904
- invariant(Obj3.instanceOf(TableView, presentation), void 0, {
711
+ invariant(Obj2.instanceOf(schema_exports.Table, presentation), void 0, {
905
712
  F: __dxlog_file,
906
- L: 239,
713
+ L: 248,
907
714
  S: this,
908
715
  A: [
909
- "Obj.instanceOf(TableView, presentation)",
716
+ "Obj.instanceOf(Table.Table, presentation)",
910
717
  ""
911
718
  ]
912
719
  });
@@ -935,7 +742,7 @@ var TableModel = class extends Resource2 {
935
742
  },
936
743
  frozenColsEnd: {
937
744
  0: {
938
- size: 40,
745
+ size: 32,
939
746
  resizeable: false
940
747
  }
941
748
  }
@@ -971,6 +778,17 @@ var TableModel = class extends Resource2 {
971
778
  });
972
779
  this._ctx.onDispose(draftRowsWatcher);
973
780
  }
781
+ //
782
+ // Data
783
+ //
784
+ setRows = (obj) => {
785
+ this._rows.value = obj;
786
+ };
787
+ getRowCount = () => this._rows.value.length;
788
+ /**
789
+ * @reactive
790
+ */
791
+ getDraftRowCount = () => this._draftRows.value.length;
974
792
  // TODO(ZaymonFC): Return .value instead of exposing the signal.
975
793
  get draftRows() {
976
794
  return this._draftRows;
@@ -989,6 +807,14 @@ var TableModel = class extends Resource2 {
989
807
  const validationErrors = draftRow.validationErrors || [];
990
808
  return validationErrors.some((error) => error.path === fieldPath);
991
809
  }
810
+ getColumnCount = () => this._projection?.fields.length ?? 0;
811
+ insertRow = () => {
812
+ const result = this._onInsertRow?.();
813
+ if (result === "draft" && this._draftRows.value.length === 0) {
814
+ this.createDraftRow();
815
+ }
816
+ return result ?? "final";
817
+ };
992
818
  createDraftRow() {
993
819
  if (!this._projection) {
994
820
  return;
@@ -1025,9 +851,190 @@ var TableModel = class extends Resource2 {
1025
851
  this._draftRows.value = newDraftRows;
1026
852
  }
1027
853
  validateDraftRowData(data) {
1028
- const schema = toEffectSchema2(this._projection.baseSchema);
854
+ const schema = toEffectSchema(this._projection.baseSchema);
1029
855
  return validateSchema(schema, data) || [];
1030
856
  }
857
+ commitDraftRow = (draftRowIndex) => {
858
+ if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.value.length) {
859
+ return false;
860
+ }
861
+ const draftRow = this._draftRows.value[draftRowIndex];
862
+ if (!draftRow.valid) {
863
+ return false;
864
+ }
865
+ const insertRowResult = this._onInsertRow?.(draftRow.data);
866
+ if (insertRowResult === "final") {
867
+ const newDraftRows = this._draftRows.value.filter((_, index) => index !== draftRowIndex);
868
+ this._draftRows.value = newDraftRows;
869
+ }
870
+ return insertRowResult === "final";
871
+ };
872
+ deleteRow = (rowIndex) => {
873
+ const row = this._sorting.getDataIndex(rowIndex);
874
+ const obj = this._rows.value[row];
875
+ const objectsToDelete = [];
876
+ if (this.features.selection.enabled && this._selection.hasSelection.value) {
877
+ const selectedRows = this._selection.getSelectedRows();
878
+ objectsToDelete.push(...selectedRows);
879
+ } else {
880
+ objectsToDelete.push(obj);
881
+ }
882
+ this._onDeleteRows?.(row, objectsToDelete);
883
+ };
884
+ handleRowAction = (actionId, rowIndex) => {
885
+ if (!this._onRowAction) {
886
+ return;
887
+ }
888
+ const row = this._sorting.getDataIndex(rowIndex);
889
+ const data = this._rows.value[row];
890
+ if (data) {
891
+ this._onRowAction(actionId, data);
892
+ }
893
+ };
894
+ getCellData = (cell) => {
895
+ const { col, row, plane } = cell;
896
+ const fields = this._projection?.fields ?? [];
897
+ if (col < 0 || col >= fields.length) {
898
+ return void 0;
899
+ }
900
+ const field = fields[col];
901
+ let value;
902
+ if (plane === "frozenRowsEnd") {
903
+ if (row >= 0 && row < this._draftRows.value.length) {
904
+ value = getValue2(this._draftRows.value[row].data, field.path);
905
+ } else {
906
+ return void 0;
907
+ }
908
+ } else {
909
+ const dataIndex = this._sorting.getDataIndex(row);
910
+ value = getValue2(this._rows.value[dataIndex], field.path);
911
+ }
912
+ if (value == null) {
913
+ return "";
914
+ }
915
+ const { props } = this._projection.getFieldProjection(field.id);
916
+ switch (props.format) {
917
+ case FormatEnum2.Ref: {
918
+ if (!field.referencePath) {
919
+ return "";
920
+ }
921
+ return getValue2(value.target, field.referencePath);
922
+ }
923
+ default: {
924
+ return formatForEditing({
925
+ type: props.type,
926
+ format: props.format,
927
+ value
928
+ });
929
+ }
930
+ }
931
+ };
932
+ validateCellData = async ({ col, row, plane }, value) => {
933
+ const fields = this._projection?.fields ?? [];
934
+ if (col < 0 || col >= fields.length) {
935
+ return {
936
+ valid: false,
937
+ error: "Invalid column index"
938
+ };
939
+ }
940
+ const field = fields[col];
941
+ const { props } = this._projection.getFieldProjection(field.id);
942
+ const transformedValue = editorTextToCellValue(props, value);
943
+ const isDraftRow = plane === "frozenRowsEnd";
944
+ if (isDraftRow) {
945
+ const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.value.length;
946
+ if (isInvalidDraftRowIndex) {
947
+ return {
948
+ valid: false,
949
+ error: "Invalid draft row index"
950
+ };
951
+ }
952
+ const draftRow = this._draftRows.value[row];
953
+ const snapshot = {
954
+ ...draftRow.data
955
+ };
956
+ setValue(snapshot, field.path, transformedValue);
957
+ const validationErrors = this.validateDraftRowData(snapshot);
958
+ if (validationErrors.length > 0) {
959
+ const error = validationErrors.find((err) => err.path === field.path);
960
+ if (error) {
961
+ return {
962
+ valid: false,
963
+ error: error.message
964
+ };
965
+ }
966
+ }
967
+ return {
968
+ valid: true
969
+ };
970
+ } else {
971
+ const rowIdx = this._sorting.getDataIndex(row);
972
+ const currentRow = this._rows.value[rowIdx];
973
+ invariant(currentRow, "Invalid row index", {
974
+ F: __dxlog_file,
975
+ L: 525,
976
+ S: this,
977
+ A: [
978
+ "currentRow",
979
+ "'Invalid row index'"
980
+ ]
981
+ });
982
+ const snapshot = getSnapshot(currentRow);
983
+ setValue(snapshot, field.path, transformedValue);
984
+ const schema = getSchema(currentRow);
985
+ invariant(schema, void 0, {
986
+ F: __dxlog_file,
987
+ L: 531,
988
+ S: this,
989
+ A: [
990
+ "schema",
991
+ ""
992
+ ]
993
+ });
994
+ const validationResult = validateSchema(schema, snapshot);
995
+ if (validationResult && validationResult.length > 0) {
996
+ const error = validationResult[0];
997
+ invariant(error.path === field.path, void 0, {
998
+ F: __dxlog_file,
999
+ L: 536,
1000
+ S: this,
1001
+ A: [
1002
+ "error.path === field.path",
1003
+ ""
1004
+ ]
1005
+ });
1006
+ return {
1007
+ valid: false,
1008
+ error: error.message
1009
+ };
1010
+ }
1011
+ return {
1012
+ valid: true
1013
+ };
1014
+ }
1015
+ };
1016
+ setCellData = (cell, value) => {
1017
+ const { col, row, plane } = cell;
1018
+ const fields = this._projection?.fields ?? [];
1019
+ if (col < 0 || col >= fields.length) {
1020
+ return;
1021
+ }
1022
+ const field = fields[col];
1023
+ const { props } = this._projection.getFieldProjection(field.id);
1024
+ const transformedValue = editorTextToCellValue(props, value);
1025
+ if (props.format === FormatEnum2.Ref && !isLiveObject(value)) {
1026
+ return;
1027
+ }
1028
+ if (plane === "frozenRowsEnd") {
1029
+ if (row >= 0 && row < this._draftRows.value.length) {
1030
+ setValue(this._draftRows.value[row].data, field.path, transformedValue);
1031
+ this.validateDraftRow(row);
1032
+ }
1033
+ } else {
1034
+ const rowIdx = this._sorting.getDataIndex(row);
1035
+ setValue(this._rows.value[rowIdx], field.path, transformedValue);
1036
+ }
1037
+ };
1031
1038
  /**
1032
1039
  * Updates a cell's value using a transform function.
1033
1040
  * @param {DxGridPlanePosition} position - The position of the cell to update.
@@ -1142,102 +1149,83 @@ var editorTextToCellValue = (props, value) => {
1142
1149
 
1143
1150
  // src/model/modal-controller.ts
1144
1151
  import { signal as signal4 } from "@preact/signals-core";
1145
- import { log } from "@dxos/log";
1146
- var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1147
1152
  var ModalController = class {
1148
- constructor() {
1149
- this._state = signal4({
1150
- type: "closed"
1151
- });
1152
- this._triggerRef = {
1153
- current: null
1154
- };
1155
- this.setTrigger = (trigger) => {
1156
- this._triggerRef.current = trigger;
1157
- };
1158
- this.showRowMenu = (rowIndex) => {
1159
- this._state.value = {
1160
- type: "row",
1161
- rowIndex
1162
- };
1163
- };
1164
- this.showColumnMenu = (fieldId) => {
1165
- this._state.value = {
1166
- type: "column",
1167
- fieldId
1168
- };
1169
- };
1170
- this.showColumnCreator = () => {
1171
- this._state.value = {
1172
- type: "columnSettings",
1173
- mode: {
1174
- type: "create"
1175
- }
1176
- };
1153
+ _state = signal4({
1154
+ type: "closed"
1155
+ });
1156
+ _triggerRef = {
1157
+ current: null
1158
+ };
1159
+ get state() {
1160
+ return this._state;
1161
+ }
1162
+ get trigger() {
1163
+ return this._triggerRef;
1164
+ }
1165
+ setTrigger = (trigger) => {
1166
+ this._triggerRef.current = trigger;
1167
+ };
1168
+ showRowMenu = (rowIndex) => {
1169
+ this._state.value = {
1170
+ type: "row",
1171
+ rowIndex
1177
1172
  };
1178
- this.showReferencePanel = (targetId, schemaId) => {
1179
- this._state.value = {
1180
- type: "refPanel",
1181
- targetId,
1182
- typename: schemaId
1183
- };
1173
+ };
1174
+ showColumnMenu = (fieldId) => {
1175
+ this._state.value = {
1176
+ type: "column",
1177
+ fieldId
1184
1178
  };
1185
- this.openColumnSettings = () => {
1186
- if (this._state.value.type === "column") {
1187
- const fieldId = this._state.value.fieldId;
1188
- requestAnimationFrame(() => {
1189
- this._state.value = {
1190
- type: "columnSettings",
1191
- mode: {
1192
- type: "edit",
1193
- fieldId
1194
- }
1195
- };
1196
- });
1179
+ };
1180
+ showColumnCreator = () => {
1181
+ this._state.value = {
1182
+ type: "columnSettings",
1183
+ mode: {
1184
+ type: "create"
1197
1185
  }
1198
1186
  };
1199
- this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1200
- if (anchorCell) {
1201
- this._triggerRef.current = anchorCell;
1187
+ };
1188
+ showReferencePanel = (targetId, schemaId) => {
1189
+ this._state.value = {
1190
+ type: "refPanel",
1191
+ targetId,
1192
+ typename: schemaId
1193
+ };
1194
+ };
1195
+ openColumnSettings = () => {
1196
+ if (this._state.value.type === "column") {
1197
+ const fieldId = this._state.value.fieldId;
1198
+ requestAnimationFrame(() => {
1202
1199
  this._state.value = {
1203
- type: "createRefPanel",
1204
- typename,
1205
- initialValues,
1206
- onCreate
1200
+ type: "columnSettings",
1201
+ mode: {
1202
+ type: "edit",
1203
+ fieldId
1204
+ }
1207
1205
  };
1208
- } else {
1209
- log.warn("anchor cell not found while creating new ref", void 0, {
1210
- F: __dxlog_file2,
1211
- L: 86,
1212
- S: this,
1213
- C: (f, a) => f(...a)
1214
- });
1215
- }
1216
- };
1217
- this.close = () => {
1218
- this._state.value = {
1219
- type: "closed"
1220
- };
1206
+ });
1207
+ }
1208
+ };
1209
+ close = () => {
1210
+ this._state.value = {
1211
+ type: "closed"
1221
1212
  };
1222
- }
1223
- get state() {
1224
- return this._state;
1225
- }
1226
- get trigger() {
1227
- return this._triggerRef;
1228
- }
1213
+ };
1229
1214
  };
1230
1215
 
1231
1216
  // src/model/table-presentation.ts
1232
1217
  import { signal as signal5 } from "@preact/signals-core";
1233
- import { isNotNullable } from "effect/Predicate";
1234
- import { Obj as Obj4 } from "@dxos/echo";
1235
- import { FormatEnum as FormatEnum3, getValue as getValue3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1218
+ import * as Predicate from "effect/Predicate";
1219
+ import { Obj as Obj3 } from "@dxos/echo";
1220
+ import { FormatEnum as FormatEnum3, TypeEnum as TypeEnum2, getValue as getValue3 } from "@dxos/echo/internal";
1236
1221
  import { cellClassesForFieldType, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1237
1222
  import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1238
1223
  import { mx } from "@dxos/react-ui-theme";
1239
1224
  import { VIEW_FIELD_LIMIT } from "@dxos/schema";
1240
1225
  var TablePresentation = class {
1226
+ model;
1227
+ _visibleRange;
1228
+ fieldProjectionCache = /* @__PURE__ */ new Map();
1241
1229
  constructor(model, _visibleRange = signal5({
1242
1230
  start: {
1243
1231
  row: 0,
@@ -1250,7 +1238,6 @@ var TablePresentation = class {
1250
1238
  })) {
1251
1239
  this.model = model;
1252
1240
  this._visibleRange = _visibleRange;
1253
- this.fieldProjectionCache = /* @__PURE__ */ new Map();
1254
1241
  }
1255
1242
  getCells(range, plane) {
1256
1243
  this.fieldProjectionCache.clear();
@@ -1278,6 +1265,9 @@ var TablePresentation = class {
1278
1265
  case "frozenRowsEnd":
1279
1266
  cells = this.getDraftRowCells(range);
1280
1267
  break;
1268
+ case "fixedEndStart":
1269
+ cells = this.getDraftIconCells(range);
1270
+ break;
1281
1271
  case "fixedEndEnd":
1282
1272
  cells = this.getDraftActionCells(range);
1283
1273
  break;
@@ -1336,10 +1326,7 @@ var TablePresentation = class {
1336
1326
  }
1337
1327
  };
1338
1328
  const classes = [];
1339
- const formatClasses = cellClassesForFieldType({
1340
- type: props.type,
1341
- format: props.format
1342
- });
1329
+ const formatClasses = cellClassesForFieldType(props);
1343
1330
  if (formatClasses) {
1344
1331
  classes.push(formatClasses);
1345
1332
  }
@@ -1347,9 +1334,7 @@ var TablePresentation = class {
1347
1334
  if (rowSelectionClasses) {
1348
1335
  classes.push(rowSelectionClasses);
1349
1336
  }
1350
- if (classes.length > 0) {
1351
- cell.className = mx(classes.flat());
1352
- }
1337
+ cell.className = mx(classes);
1353
1338
  if (props.type === TypeEnum2.Array) {
1354
1339
  const targetArray = getValue3(obj, field.path);
1355
1340
  if (targetArray && Array.isArray(targetArray)) {
@@ -1371,7 +1356,7 @@ var TablePresentation = class {
1371
1356
  }
1372
1357
  return "Object";
1373
1358
  };
1374
- const tags = targetArray.map(getLabel).filter(isNotNullable).map((title) => {
1359
+ const tags = targetArray.map(getLabel).filter(Predicate.isNotNullable).map((title) => {
1375
1360
  return `<span class="dx-tag" data-hue="neutral">${title}</span>`;
1376
1361
  }).join("");
1377
1362
  cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
@@ -1380,8 +1365,8 @@ var TablePresentation = class {
1380
1365
  if (props.format === FormatEnum3.Ref && props.referenceSchema) {
1381
1366
  const targetObj = getValue3(obj, field.path)?.target;
1382
1367
  if (targetObj) {
1383
- const dxn = Obj4.getDXN(targetObj)?.toString();
1384
- cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button is-6 pli-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
1368
+ const dxn = Obj3.getDXN(targetObj)?.toString();
1369
+ cell.accessoryHtml = `<div role="none" class="absolute inline-end-0 inset-block-0 p-[--dx-grid-cell-content-padding-block]"><dx-anchor refId=${dxn} class="dx-button is-6 aspect-square min-bs-0" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-anchor></div>`;
1385
1370
  }
1386
1371
  }
1387
1372
  if (props.format === FormatEnum3.Boolean) {
@@ -1443,24 +1428,37 @@ var TablePresentation = class {
1443
1428
  const cells = {};
1444
1429
  const fields = this.model.projection?.fields ?? [];
1445
1430
  const draftRows = this.model.draftRows.value;
1446
- for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1447
- const draftRow = draftRows[row];
1431
+ if (draftRows.length === 0) {
1448
1432
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1449
- const field = fields[col];
1450
- if (!field) {
1451
- continue;
1452
- }
1453
- this.createDataCell(cells, draftRow.data, field, col, row);
1454
- if (this.model.hasDraftRowValidationError(row, field.path)) {
1433
+ cells[toPlaneCellIndex({
1434
+ col,
1435
+ row: 0
1436
+ })] = {
1437
+ value: "",
1438
+ readonly: true,
1439
+ className: "dx-grid__row--cta__cell"
1440
+ };
1441
+ }
1442
+ } else {
1443
+ for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1444
+ const draftRow = draftRows[row];
1445
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1455
1446
  const cellIndex = toPlaneCellIndex({
1456
1447
  col,
1457
1448
  row
1458
1449
  });
1459
- const cellValue = cells[cellIndex];
1460
- if (cellValue) {
1461
- const existingClasses = cellValue.className || "";
1462
- const draftClasses = "dx-grid__cell--flagged";
1463
- cellValue.className = existingClasses ? `${existingClasses} ${draftClasses}` : draftClasses;
1450
+ const field = fields[col];
1451
+ if (!field) {
1452
+ continue;
1453
+ }
1454
+ this.createDataCell(cells, draftRow.data, field, col, row);
1455
+ if (this.model.hasDraftRowValidationError(row, field.path)) {
1456
+ const cellValue = cells[cellIndex];
1457
+ if (cellValue) {
1458
+ const existingClasses = cellValue.className || "";
1459
+ const draftClasses = "dx-grid__cell--flagged";
1460
+ cellValue.className = existingClasses ? `${existingClasses} ${draftClasses}` : draftClasses;
1461
+ }
1464
1462
  }
1465
1463
  }
1466
1464
  }
@@ -1479,10 +1477,10 @@ var TablePresentation = class {
1479
1477
  row: 0
1480
1478
  })] = {
1481
1479
  // TODO(burdon): Use same logic as form for fallback title.
1482
- value: props.title ?? field.path,
1483
- readonly: true,
1480
+ value: "",
1484
1481
  resizeHandle: "col",
1485
1482
  accessoryHtml: `
1483
+ <span class="grow min-is-0 truncate">${props.title ?? field.path}</span>
1486
1484
  ${direction !== void 0 ? tableButtons.sort.render({
1487
1485
  fieldId: field.id,
1488
1486
  direction
@@ -1491,7 +1489,7 @@ var TablePresentation = class {
1491
1489
  fieldId: field.id
1492
1490
  })}
1493
1491
  `,
1494
- className: "!bg-toolbarSurface"
1492
+ className: "!bg-toolbarSurface !text-description [&>div]:flex [&>div]:items-stretch"
1495
1493
  };
1496
1494
  }
1497
1495
  return cells;
@@ -1582,19 +1580,46 @@ var TablePresentation = class {
1582
1580
  getDraftActionCells(range) {
1583
1581
  const cells = {};
1584
1582
  const draftRows = this.model.draftRows.value;
1585
- for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1586
- const draftRow = draftRows[row];
1587
- const disabled = !draftRow.valid;
1583
+ if (draftRows.length === 0) {
1584
+ cells[toPlaneCellIndex({
1585
+ col: 0,
1586
+ row: 0
1587
+ })] = {
1588
+ value: "",
1589
+ className: "dx-grid__row--cta__cell",
1590
+ readonly: true
1591
+ };
1592
+ } else {
1593
+ for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1594
+ const draftRow = draftRows[row];
1595
+ const disabled = !draftRow.valid;
1596
+ cells[toPlaneCellIndex({
1597
+ col: 0,
1598
+ row
1599
+ })] = {
1600
+ value: "",
1601
+ readonly: true,
1602
+ accessoryHtml: tableButtons.saveDraftRow.render({
1603
+ rowIndex: row,
1604
+ disabled
1605
+ })
1606
+ };
1607
+ }
1608
+ }
1609
+ return cells;
1610
+ }
1611
+ getDraftIconCells(range) {
1612
+ const cells = {};
1613
+ const draftRows = this.model.draftRows.value;
1614
+ for (let row = range.start.row; row <= range.end.row; row++) {
1588
1615
  cells[toPlaneCellIndex({
1589
1616
  col: 0,
1590
1617
  row
1591
1618
  })] = {
1592
1619
  value: "",
1593
1620
  readonly: true,
1594
- accessoryHtml: tableButtons.saveDraftRow.render({
1595
- rowIndex: row,
1596
- disabled
1597
- })
1621
+ accessoryHtml: '<dx-icon icon="ph--plus--regular" class="contents"></dx-icon>',
1622
+ className: mx("[&>div]:grid [&>div]:place-content-center", draftRows.length < 1 && "dx-grid__row--cta__cell")
1598
1623
  };
1599
1624
  }
1600
1625
  return cells;
@@ -1627,13 +1652,13 @@ import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
1627
1652
  import { effect as effect3 } from "@preact/signals-core";
1628
1653
  import orderBy2 from "lodash.orderby";
1629
1654
  import { useEffect, useMemo, useState } from "react";
1630
- import { fullyQualifiedId as fullyQualifiedId2 } from "@dxos/react-client/echo";
1655
+ import { Obj as Obj4 } from "@dxos/echo";
1631
1656
  import { useSelected, useSelectionActions } from "@dxos/react-ui-attention";
1632
1657
  import { isNonNullable } from "@dxos/util";
1633
1658
  var useTableModel = ({ view, schema, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
1634
1659
  var _effect = _useSignals();
1635
1660
  try {
1636
- const selected = useSelected(view && fullyQualifiedId2(view), "multi");
1661
+ const selected = useSelected(view && Obj4.getDXN(view).toString(), "multi");
1637
1662
  const initialSelection = useMemo(() => selected, [
1638
1663
  view
1639
1664
  ]);
@@ -1718,12 +1743,12 @@ var useAddRow = ({ space, schema }) => {
1718
1743
  if (space && schema) {
1719
1744
  try {
1720
1745
  space.db.add(Obj5.make(schema, data ?? {}));
1721
- return true;
1746
+ return "final";
1722
1747
  } catch (error) {
1723
- return false;
1748
+ return "draft";
1724
1749
  }
1725
1750
  }
1726
- return false;
1751
+ return "final";
1727
1752
  }, [
1728
1753
  space,
1729
1754
  schema
@@ -1734,7 +1759,6 @@ export {
1734
1759
  getBaseSchema,
1735
1760
  makeDynamicTable,
1736
1761
  touch,
1737
- createTable,
1738
1762
  BUTTON_IDENTIFIERS,
1739
1763
  tableButtons,
1740
1764
  CONTROL_IDENTIFIERS,
@@ -1749,4 +1773,4 @@ export {
1749
1773
  useTableModel,
1750
1774
  useAddRow
1751
1775
  };
1752
- //# sourceMappingURL=chunk-Y66YLSTC.mjs.map
1776
+ //# sourceMappingURL=chunk-TRR3C5NX.mjs.map