@dxos/react-ui-table 0.8.4-main.67995b8 → 0.8.4-main.ae835ea

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 (130) hide show
  1. package/dist/lib/browser/chunk-4K7JPALT.mjs +66 -0
  2. package/dist/lib/browser/chunk-4K7JPALT.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-G7MGPBSR.mjs} +491 -466
  4. package/dist/lib/browser/chunk-G7MGPBSR.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +584 -673
  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 +13 -8
  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-Y66YLSTC.mjs → chunk-LD5JEBA6.mjs} +491 -466
  12. package/dist/lib/node-esm/chunk-LD5JEBA6.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-MK6OVUF6.mjs +67 -0
  14. package/dist/lib/node-esm/chunk-MK6OVUF6.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +584 -673
  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 +13 -8
  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 +108 -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.map +1 -1
  47. package/dist/types/src/components/testing.d.ts +3 -3
  48. package/dist/types/src/components/testing.d.ts.map +1 -1
  49. package/dist/types/src/hooks/useAddRow.d.ts +3 -2
  50. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  51. package/dist/types/src/hooks/useTableModel.d.ts +2 -2
  52. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  53. package/dist/types/src/model/modal-controller.d.ts +0 -7
  54. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  55. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  56. package/dist/types/src/model/table-model.d.ts +9 -7
  57. package/dist/types/src/model/table-model.d.ts.map +1 -1
  58. package/dist/types/src/model/table-presentation.d.ts +2 -1
  59. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  60. package/dist/types/src/model/table-sorting.d.ts +2 -3
  61. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  62. package/dist/types/src/testing/useTestTableModel.d.ts +3 -22
  63. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  64. package/dist/types/src/translations.d.ts +2 -2
  65. package/dist/types/src/types/index.d.ts +1 -1
  66. package/dist/types/src/types/index.d.ts.map +1 -1
  67. package/dist/types/src/types/schema.d.ts +25 -5
  68. package/dist/types/src/types/schema.d.ts.map +1 -1
  69. package/dist/types/src/util/dynamic-table.d.ts +4 -5
  70. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  71. package/dist/types/src/util/index.d.ts +0 -1
  72. package/dist/types/src/util/index.d.ts.map +1 -1
  73. package/dist/types/src/util/schema.d.ts +1 -1
  74. package/dist/types/src/util/schema.d.ts.map +1 -1
  75. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  76. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  77. package/dist/types/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +59 -58
  79. package/src/components/Table/ColumnActionsMenu.tsx +1 -1
  80. package/src/components/Table/ColumnSettings.tsx +1 -1
  81. package/src/components/Table/DynamicTable.stories.tsx +15 -11
  82. package/src/components/Table/DynamicTable.tsx +8 -10
  83. package/src/components/Table/Relations.stories.tsx +241 -0
  84. package/src/components/Table/RowActionsMenu.tsx +3 -3
  85. package/src/components/Table/Table.stories.tsx +68 -56
  86. package/src/components/Table/Table.tsx +140 -115
  87. package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
  88. package/src/components/TableCellEditor/FormCellEditor.tsx +153 -42
  89. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +24 -64
  90. package/src/components/TableCellEditor/TableCellEditor.tsx +74 -224
  91. package/src/components/TableCellEditor/index.ts +1 -0
  92. package/src/components/TableToolbar/TableToolbar.tsx +5 -2
  93. package/src/components/testing.ts +2 -2
  94. package/src/hooks/useAddRow.ts +7 -5
  95. package/src/hooks/useTableModel.ts +2 -2
  96. package/src/model/modal-controller.ts +1 -29
  97. package/src/model/selection-model.ts +3 -2
  98. package/src/model/table-model.test.ts +19 -10
  99. package/src/model/table-model.ts +37 -25
  100. package/src/model/table-presentation.test.ts +23 -21
  101. package/src/model/table-presentation.ts +74 -33
  102. package/src/model/table-sorting.ts +16 -7
  103. package/src/playwright/smoke.spec.ts +129 -37
  104. package/src/testing/useTestTableModel.ts +11 -7
  105. package/src/translations.ts +2 -2
  106. package/src/types/index.ts +1 -1
  107. package/src/types/schema.ts +63 -6
  108. package/src/util/dynamic-table.ts +13 -13
  109. package/src/util/index.ts +0 -1
  110. package/src/util/schema.ts +4 -4
  111. package/src/util/table-buttons.ts +4 -3
  112. package/src/util/table-controls.ts +4 -1
  113. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  114. package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
  115. package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +0 -7
  116. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +0 -20
  117. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +0 -7
  118. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  119. package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
  120. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
  121. package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
  122. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
  123. package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
  124. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
  125. package/dist/types/src/util/table.d.ts +0 -11
  126. package/dist/types/src/util/table.d.ts.map +0 -1
  127. package/src/components/Table/CreateRefPanel.tsx +0 -86
  128. package/src/components/Table/relations.stories.tsx +0 -116
  129. package/src/components/TableCellEditor/extension.ts +0 -61
  130. 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-MK6OVUF6.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, createView, 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
35
  const view = createView({
36
- typename,
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,60 @@ 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";
281
+ import { getSnapshot, isLiveObject } from "@dxos/live-object";
312
282
  import { fullyQualifiedId } from "@dxos/react-client/echo";
313
283
  import { formatForEditing, parseValue } from "@dxos/react-ui-form";
314
284
  import { ProjectionModel as ProjectionModel2, validateSchema } from "@dxos/schema";
315
285
 
286
+ // src/util/tag.ts
287
+ var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
288
+ var extractTagIds = (value) => {
289
+ if (typeof value !== "string") {
290
+ return void 0;
291
+ }
292
+ const ids = [];
293
+ let match;
294
+ while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
295
+ if (match[2]) {
296
+ ids.push(match[2]);
297
+ }
298
+ }
299
+ return ids.length > 0 ? ids : void 0;
300
+ };
301
+
316
302
  // src/model/selection-model.ts
317
303
  import { computed, effect, signal } from "@preact/signals-core";
318
304
  import { Resource } from "@dxos/context";
319
305
  var SelectionModel = class extends Resource {
306
+ _rows;
307
+ _selectionMode;
308
+ _initialSelection;
309
+ _onSelectionChanged;
310
+ _selection;
311
+ _validSelectedIds = computed(() => {
312
+ const rows = this._rows.value;
313
+ if (!rows) {
314
+ return /* @__PURE__ */ new Set();
315
+ }
316
+ const validIds = new Set(rows.map((row) => row.id));
317
+ return new Set([
318
+ ...this._selection.value
319
+ ].filter((id) => validIds.has(id)));
320
+ });
321
+ _hasSelection = computed(() => this._validSelectedIds.value.size > 0);
322
+ _allSelected = computed(() => {
323
+ const rows = this._rows.value;
324
+ if (rows.length === 0) {
325
+ return false;
326
+ }
327
+ return rows.every((row) => this._selection.value.has(row.id));
328
+ });
320
329
  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
- };
330
+ super(), this._rows = _rows, this._selectionMode = _selectionMode, this._initialSelection = _initialSelection, this._onSelectionChanged = _onSelectionChanged;
368
331
  this._selection = signal(new Set(this._initialSelection));
369
332
  }
370
333
  async _open() {
@@ -389,23 +352,67 @@ var SelectionModel = class extends Resource {
389
352
  get selectionMode() {
390
353
  return this._selectionMode;
391
354
  }
355
+ getSelectedRows = () => {
356
+ const selectedIds = this._validSelectedIds.value;
357
+ return this._rows.value.filter((row) => selectedIds.has(row.id));
358
+ };
359
+ isRowIndexSelected = (rowIndex) => {
360
+ const row = this._rows.value[rowIndex];
361
+ return this._selection.value.has(row.id);
362
+ };
363
+ isObjectSelected = (object) => {
364
+ return this._selection.value.has(object.id);
365
+ };
366
+ //
367
+ // Manipulation
368
+ //
369
+ toggleSelectionForRowIndex = (rowIndex) => {
370
+ const row = this._rows.value[rowIndex];
371
+ const newSelection = new Set(this._selection.value);
372
+ if (newSelection.has(row.id)) {
373
+ newSelection.delete(row.id);
374
+ } else {
375
+ if (this._selectionMode === "single") {
376
+ newSelection.clear();
377
+ }
378
+ newSelection.add(row.id);
379
+ }
380
+ this._selection.value = newSelection;
381
+ };
382
+ setSelection = (mode) => {
383
+ switch (mode) {
384
+ case "all": {
385
+ this._selection.value = new Set(this._rows.value.map((row) => row.id));
386
+ break;
387
+ }
388
+ case "none": {
389
+ this._selection.value = /* @__PURE__ */ new Set();
390
+ break;
391
+ }
392
+ }
393
+ };
392
394
  };
393
395
 
394
396
  // src/model/table-sorting.ts
395
397
  import { computed as computed2, signal as signal2 } from "@preact/signals-core";
396
398
  import orderBy from "lodash.orderby";
397
- import { getValue, FormatEnum, TypeEnum } from "@dxos/echo-schema";
399
+ import { FormatEnum, TypeEnum, getValue } from "@dxos/echo/internal";
398
400
  import { formatForDisplay } from "@dxos/react-ui-form";
399
401
  var TableSorting = class {
402
+ _view;
403
+ _projection;
404
+ _displayToDataIndex = /* @__PURE__ */ new Map();
405
+ _rows;
406
+ _localSort = signal2(void 0);
407
+ _isDirty;
408
+ sortedRows;
400
409
  constructor(rows, _view, _projection) {
401
410
  this._view = _view;
402
411
  this._projection = _projection;
403
- this._displayToDataIndex = /* @__PURE__ */ new Map();
404
- this._localSort = signal2(void 0);
405
412
  this._rows = rows;
406
413
  this._isDirty = computed2(() => {
407
414
  const local = this._localSort.value;
408
- const viewSort = this._view.query.sort?.[0];
415
+ const viewSort = this._view.sort?.[0];
409
416
  if (local?.type === "cleared") {
410
417
  return viewSort !== void 0;
411
418
  }
@@ -431,7 +438,7 @@ var TableSorting = class {
431
438
  if (local?.type === "active") {
432
439
  return local.sort;
433
440
  }
434
- return this._view.query.sort?.[0];
441
+ return this._view.sort?.[0];
435
442
  }
436
443
  /**
437
444
  * @reactive
@@ -475,11 +482,11 @@ var TableSorting = class {
475
482
  save() {
476
483
  if (this._localSort.value !== void 0) {
477
484
  if (this._localSort.value.type === "active") {
478
- this._view.query.sort = [
485
+ this._view.sort = [
479
486
  this._localSort.value.sort
480
487
  ];
481
488
  } else {
482
- this._view.query.sort = [];
489
+ this._view.sort = [];
483
490
  }
484
491
  this._localSort.value = void 0;
485
492
  }
@@ -556,22 +563,6 @@ var TableSorting = class {
556
563
  }
557
564
  };
558
565
 
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
566
  // src/model/table-model.ts
576
567
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
577
568
  var defaultFeatures = {
@@ -583,231 +574,48 @@ var defaultFeatures = {
583
574
  schemaEditable: false
584
575
  };
585
576
  var TableModel = class extends Resource2 {
577
+ _view;
578
+ _projection;
579
+ _table;
580
+ _visibleRange = signal3({
581
+ start: {
582
+ row: 0,
583
+ col: 0
584
+ },
585
+ end: {
586
+ row: 0,
587
+ col: 0
588
+ }
589
+ });
590
+ _onInsertRow;
591
+ _onDeleteRows;
592
+ _onDeleteColumn;
593
+ _onCellUpdate;
594
+ _onRowOrderChange;
595
+ _onRowAction;
596
+ _rowActions;
597
+ _features;
598
+ _rows = signal3([]);
599
+ _draftRows = signal3([]);
600
+ _sorting;
601
+ _pinnedRows;
602
+ _selection;
603
+ _columnMeta;
586
604
  constructor({ view, schema, projection, features = {}, sorting = [], initialSelection = [], pinnedRows = {
587
605
  top: [],
588
606
  bottom: []
589
607
  }, rowActions = [], onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
590
608
  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
609
  this._view = view;
803
610
  this._projection = projection ?? new ProjectionModel2(schema, view.projection);
611
+ this._projection.normalizeView();
804
612
  this._features = {
805
613
  ...defaultFeatures,
806
614
  ...features
807
615
  };
808
616
  invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
809
617
  F: __dxlog_file,
810
- L: 139,
618
+ L: 149,
811
619
  S: this,
812
620
  A: [
813
621
  "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
@@ -838,7 +646,7 @@ var TableModel = class extends Resource2 {
838
646
  get table() {
839
647
  invariant(this._table, "Model not initialized", {
840
648
  F: __dxlog_file,
841
- L: 177,
649
+ L: 187,
842
650
  S: this,
843
651
  A: [
844
652
  "this._table",
@@ -877,7 +685,7 @@ var TableModel = class extends Resource2 {
877
685
  get columnMeta() {
878
686
  invariant(this._columnMeta, void 0, {
879
687
  F: __dxlog_file,
880
- L: 216,
688
+ L: 226,
881
689
  S: this,
882
690
  A: [
883
691
  "this._columnMeta",
@@ -901,12 +709,12 @@ var TableModel = class extends Resource2 {
901
709
  //
902
710
  async _open() {
903
711
  const presentation = this._view.presentation.target ?? await this._view.presentation.load();
904
- invariant(Obj3.instanceOf(TableView, presentation), void 0, {
712
+ invariant(Obj2.instanceOf(schema_exports.Table, presentation), void 0, {
905
713
  F: __dxlog_file,
906
- L: 239,
714
+ L: 249,
907
715
  S: this,
908
716
  A: [
909
- "Obj.instanceOf(TableView, presentation)",
717
+ "Obj.instanceOf(Table.Table, presentation)",
910
718
  ""
911
719
  ]
912
720
  });
@@ -935,7 +743,7 @@ var TableModel = class extends Resource2 {
935
743
  },
936
744
  frozenColsEnd: {
937
745
  0: {
938
- size: 40,
746
+ size: 32,
939
747
  resizeable: false
940
748
  }
941
749
  }
@@ -971,6 +779,17 @@ var TableModel = class extends Resource2 {
971
779
  });
972
780
  this._ctx.onDispose(draftRowsWatcher);
973
781
  }
782
+ //
783
+ // Data
784
+ //
785
+ setRows = (obj) => {
786
+ this._rows.value = obj;
787
+ };
788
+ getRowCount = () => this._rows.value.length;
789
+ /**
790
+ * @reactive
791
+ */
792
+ getDraftRowCount = () => this._draftRows.value.length;
974
793
  // TODO(ZaymonFC): Return .value instead of exposing the signal.
975
794
  get draftRows() {
976
795
  return this._draftRows;
@@ -989,6 +808,14 @@ var TableModel = class extends Resource2 {
989
808
  const validationErrors = draftRow.validationErrors || [];
990
809
  return validationErrors.some((error) => error.path === fieldPath);
991
810
  }
811
+ getColumnCount = () => this._projection?.fields.length ?? 0;
812
+ insertRow = () => {
813
+ const result = this._onInsertRow?.();
814
+ if (result === "draft" && this._draftRows.value.length === 0) {
815
+ this.createDraftRow();
816
+ }
817
+ return result ?? "final";
818
+ };
992
819
  createDraftRow() {
993
820
  if (!this._projection) {
994
821
  return;
@@ -1025,9 +852,190 @@ var TableModel = class extends Resource2 {
1025
852
  this._draftRows.value = newDraftRows;
1026
853
  }
1027
854
  validateDraftRowData(data) {
1028
- const schema = toEffectSchema2(this._projection.baseSchema);
855
+ const schema = toEffectSchema(this._projection.baseSchema);
1029
856
  return validateSchema(schema, data) || [];
1030
857
  }
858
+ commitDraftRow = (draftRowIndex) => {
859
+ if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.value.length) {
860
+ return false;
861
+ }
862
+ const draftRow = this._draftRows.value[draftRowIndex];
863
+ if (!draftRow.valid) {
864
+ return false;
865
+ }
866
+ const insertRowResult = this._onInsertRow?.(draftRow.data);
867
+ if (insertRowResult === "final") {
868
+ const newDraftRows = this._draftRows.value.filter((_, index) => index !== draftRowIndex);
869
+ this._draftRows.value = newDraftRows;
870
+ }
871
+ return insertRowResult === "final";
872
+ };
873
+ deleteRow = (rowIndex) => {
874
+ const row = this._sorting.getDataIndex(rowIndex);
875
+ const obj = this._rows.value[row];
876
+ const objectsToDelete = [];
877
+ if (this.features.selection.enabled && this._selection.hasSelection.value) {
878
+ const selectedRows = this._selection.getSelectedRows();
879
+ objectsToDelete.push(...selectedRows);
880
+ } else {
881
+ objectsToDelete.push(obj);
882
+ }
883
+ this._onDeleteRows?.(row, objectsToDelete);
884
+ };
885
+ handleRowAction = (actionId, rowIndex) => {
886
+ if (!this._onRowAction) {
887
+ return;
888
+ }
889
+ const row = this._sorting.getDataIndex(rowIndex);
890
+ const data = this._rows.value[row];
891
+ if (data) {
892
+ this._onRowAction(actionId, data);
893
+ }
894
+ };
895
+ getCellData = (cell) => {
896
+ const { col, row, plane } = cell;
897
+ const fields = this._projection?.fields ?? [];
898
+ if (col < 0 || col >= fields.length) {
899
+ return void 0;
900
+ }
901
+ const field = fields[col];
902
+ let value;
903
+ if (plane === "frozenRowsEnd") {
904
+ if (row >= 0 && row < this._draftRows.value.length) {
905
+ value = getValue2(this._draftRows.value[row].data, field.path);
906
+ } else {
907
+ return void 0;
908
+ }
909
+ } else {
910
+ const dataIndex = this._sorting.getDataIndex(row);
911
+ value = getValue2(this._rows.value[dataIndex], field.path);
912
+ }
913
+ if (value == null) {
914
+ return "";
915
+ }
916
+ const { props } = this._projection.getFieldProjection(field.id);
917
+ switch (props.format) {
918
+ case FormatEnum2.Ref: {
919
+ if (!field.referencePath) {
920
+ return "";
921
+ }
922
+ return getValue2(value.target, field.referencePath);
923
+ }
924
+ default: {
925
+ return formatForEditing({
926
+ type: props.type,
927
+ format: props.format,
928
+ value
929
+ });
930
+ }
931
+ }
932
+ };
933
+ validateCellData = async ({ col, row, plane }, value) => {
934
+ const fields = this._projection?.fields ?? [];
935
+ if (col < 0 || col >= fields.length) {
936
+ return {
937
+ valid: false,
938
+ error: "Invalid column index"
939
+ };
940
+ }
941
+ const field = fields[col];
942
+ const { props } = this._projection.getFieldProjection(field.id);
943
+ const transformedValue = editorTextToCellValue(props, value);
944
+ const isDraftRow = plane === "frozenRowsEnd";
945
+ if (isDraftRow) {
946
+ const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.value.length;
947
+ if (isInvalidDraftRowIndex) {
948
+ return {
949
+ valid: false,
950
+ error: "Invalid draft row index"
951
+ };
952
+ }
953
+ const draftRow = this._draftRows.value[row];
954
+ const snapshot = {
955
+ ...draftRow.data
956
+ };
957
+ setValue(snapshot, field.path, transformedValue);
958
+ const validationErrors = this.validateDraftRowData(snapshot);
959
+ if (validationErrors.length > 0) {
960
+ const error = validationErrors.find((err) => err.path === field.path);
961
+ if (error) {
962
+ return {
963
+ valid: false,
964
+ error: error.message
965
+ };
966
+ }
967
+ }
968
+ return {
969
+ valid: true
970
+ };
971
+ } else {
972
+ const rowIdx = this._sorting.getDataIndex(row);
973
+ const currentRow = this._rows.value[rowIdx];
974
+ invariant(currentRow, "Invalid row index", {
975
+ F: __dxlog_file,
976
+ L: 522,
977
+ S: this,
978
+ A: [
979
+ "currentRow",
980
+ "'Invalid row index'"
981
+ ]
982
+ });
983
+ const snapshot = getSnapshot(currentRow);
984
+ setValue(snapshot, field.path, transformedValue);
985
+ const schema = getSchema(currentRow);
986
+ invariant(schema, void 0, {
987
+ F: __dxlog_file,
988
+ L: 528,
989
+ S: this,
990
+ A: [
991
+ "schema",
992
+ ""
993
+ ]
994
+ });
995
+ const validationResult = validateSchema(schema, snapshot);
996
+ if (validationResult && validationResult.length > 0) {
997
+ const error = validationResult[0];
998
+ invariant(error.path === field.path, void 0, {
999
+ F: __dxlog_file,
1000
+ L: 533,
1001
+ S: this,
1002
+ A: [
1003
+ "error.path === field.path",
1004
+ ""
1005
+ ]
1006
+ });
1007
+ return {
1008
+ valid: false,
1009
+ error: error.message
1010
+ };
1011
+ }
1012
+ return {
1013
+ valid: true
1014
+ };
1015
+ }
1016
+ };
1017
+ setCellData = (cell, value) => {
1018
+ const { col, row, plane } = cell;
1019
+ const fields = this._projection?.fields ?? [];
1020
+ if (col < 0 || col >= fields.length) {
1021
+ return;
1022
+ }
1023
+ const field = fields[col];
1024
+ const { props } = this._projection.getFieldProjection(field.id);
1025
+ const transformedValue = editorTextToCellValue(props, value);
1026
+ if (props.format === FormatEnum2.Ref && !isLiveObject(value)) {
1027
+ return;
1028
+ }
1029
+ if (plane === "frozenRowsEnd") {
1030
+ if (row >= 0 && row < this._draftRows.value.length) {
1031
+ setValue(this._draftRows.value[row].data, field.path, transformedValue);
1032
+ this.validateDraftRow(row);
1033
+ }
1034
+ } else {
1035
+ const rowIdx = this._sorting.getDataIndex(row);
1036
+ setValue(this._rows.value[rowIdx], field.path, transformedValue);
1037
+ }
1038
+ };
1031
1039
  /**
1032
1040
  * Updates a cell's value using a transform function.
1033
1041
  * @param {DxGridPlanePosition} position - The position of the cell to update.
@@ -1142,102 +1150,83 @@ var editorTextToCellValue = (props, value) => {
1142
1150
 
1143
1151
  // src/model/modal-controller.ts
1144
1152
  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
1153
  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
- };
1154
+ _state = signal4({
1155
+ type: "closed"
1156
+ });
1157
+ _triggerRef = {
1158
+ current: null
1159
+ };
1160
+ get state() {
1161
+ return this._state;
1162
+ }
1163
+ get trigger() {
1164
+ return this._triggerRef;
1165
+ }
1166
+ setTrigger = (trigger) => {
1167
+ this._triggerRef.current = trigger;
1168
+ };
1169
+ showRowMenu = (rowIndex) => {
1170
+ this._state.value = {
1171
+ type: "row",
1172
+ rowIndex
1177
1173
  };
1178
- this.showReferencePanel = (targetId, schemaId) => {
1179
- this._state.value = {
1180
- type: "refPanel",
1181
- targetId,
1182
- typename: schemaId
1183
- };
1174
+ };
1175
+ showColumnMenu = (fieldId) => {
1176
+ this._state.value = {
1177
+ type: "column",
1178
+ fieldId
1184
1179
  };
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
- });
1180
+ };
1181
+ showColumnCreator = () => {
1182
+ this._state.value = {
1183
+ type: "columnSettings",
1184
+ mode: {
1185
+ type: "create"
1197
1186
  }
1198
1187
  };
1199
- this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1200
- if (anchorCell) {
1201
- this._triggerRef.current = anchorCell;
1188
+ };
1189
+ showReferencePanel = (targetId, schemaId) => {
1190
+ this._state.value = {
1191
+ type: "refPanel",
1192
+ targetId,
1193
+ typename: schemaId
1194
+ };
1195
+ };
1196
+ openColumnSettings = () => {
1197
+ if (this._state.value.type === "column") {
1198
+ const fieldId = this._state.value.fieldId;
1199
+ requestAnimationFrame(() => {
1202
1200
  this._state.value = {
1203
- type: "createRefPanel",
1204
- typename,
1205
- initialValues,
1206
- onCreate
1201
+ type: "columnSettings",
1202
+ mode: {
1203
+ type: "edit",
1204
+ fieldId
1205
+ }
1207
1206
  };
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
- };
1207
+ });
1208
+ }
1209
+ };
1210
+ close = () => {
1211
+ this._state.value = {
1212
+ type: "closed"
1221
1213
  };
1222
- }
1223
- get state() {
1224
- return this._state;
1225
- }
1226
- get trigger() {
1227
- return this._triggerRef;
1228
- }
1214
+ };
1229
1215
  };
1230
1216
 
1231
1217
  // src/model/table-presentation.ts
1232
1218
  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";
1219
+ import * as Predicate from "effect/Predicate";
1220
+ import { Obj as Obj3 } from "@dxos/echo";
1221
+ import { FormatEnum as FormatEnum3, TypeEnum as TypeEnum2, getValue as getValue3 } from "@dxos/echo/internal";
1236
1222
  import { cellClassesForFieldType, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1237
1223
  import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1238
1224
  import { mx } from "@dxos/react-ui-theme";
1239
1225
  import { VIEW_FIELD_LIMIT } from "@dxos/schema";
1240
1226
  var TablePresentation = class {
1227
+ model;
1228
+ _visibleRange;
1229
+ fieldProjectionCache = /* @__PURE__ */ new Map();
1241
1230
  constructor(model, _visibleRange = signal5({
1242
1231
  start: {
1243
1232
  row: 0,
@@ -1250,7 +1239,6 @@ var TablePresentation = class {
1250
1239
  })) {
1251
1240
  this.model = model;
1252
1241
  this._visibleRange = _visibleRange;
1253
- this.fieldProjectionCache = /* @__PURE__ */ new Map();
1254
1242
  }
1255
1243
  getCells(range, plane) {
1256
1244
  this.fieldProjectionCache.clear();
@@ -1278,6 +1266,9 @@ var TablePresentation = class {
1278
1266
  case "frozenRowsEnd":
1279
1267
  cells = this.getDraftRowCells(range);
1280
1268
  break;
1269
+ case "fixedEndStart":
1270
+ cells = this.getDraftIconCells(range);
1271
+ break;
1281
1272
  case "fixedEndEnd":
1282
1273
  cells = this.getDraftActionCells(range);
1283
1274
  break;
@@ -1336,10 +1327,7 @@ var TablePresentation = class {
1336
1327
  }
1337
1328
  };
1338
1329
  const classes = [];
1339
- const formatClasses = cellClassesForFieldType({
1340
- type: props.type,
1341
- format: props.format
1342
- });
1330
+ const formatClasses = cellClassesForFieldType(props);
1343
1331
  if (formatClasses) {
1344
1332
  classes.push(formatClasses);
1345
1333
  }
@@ -1347,9 +1335,7 @@ var TablePresentation = class {
1347
1335
  if (rowSelectionClasses) {
1348
1336
  classes.push(rowSelectionClasses);
1349
1337
  }
1350
- if (classes.length > 0) {
1351
- cell.className = mx(classes.flat());
1352
- }
1338
+ cell.className = mx(classes);
1353
1339
  if (props.type === TypeEnum2.Array) {
1354
1340
  const targetArray = getValue3(obj, field.path);
1355
1341
  if (targetArray && Array.isArray(targetArray)) {
@@ -1371,7 +1357,7 @@ var TablePresentation = class {
1371
1357
  }
1372
1358
  return "Object";
1373
1359
  };
1374
- const tags = targetArray.map(getLabel).filter(isNotNullable).map((title) => {
1360
+ const tags = targetArray.map(getLabel).filter(Predicate.isNotNullable).map((title) => {
1375
1361
  return `<span class="dx-tag" data-hue="neutral">${title}</span>`;
1376
1362
  }).join("");
1377
1363
  cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
@@ -1380,8 +1366,8 @@ var TablePresentation = class {
1380
1366
  if (props.format === FormatEnum3.Ref && props.referenceSchema) {
1381
1367
  const targetObj = getValue3(obj, field.path)?.target;
1382
1368
  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>`;
1369
+ const dxn = Obj3.getDXN(targetObj)?.toString();
1370
+ 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
1371
  }
1386
1372
  }
1387
1373
  if (props.format === FormatEnum3.Boolean) {
@@ -1443,24 +1429,37 @@ var TablePresentation = class {
1443
1429
  const cells = {};
1444
1430
  const fields = this.model.projection?.fields ?? [];
1445
1431
  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];
1432
+ if (draftRows.length === 0) {
1448
1433
  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)) {
1434
+ cells[toPlaneCellIndex({
1435
+ col,
1436
+ row: 0
1437
+ })] = {
1438
+ value: "",
1439
+ readonly: true,
1440
+ className: "dx-grid__row--cta__cell"
1441
+ };
1442
+ }
1443
+ } else {
1444
+ for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1445
+ const draftRow = draftRows[row];
1446
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1455
1447
  const cellIndex = toPlaneCellIndex({
1456
1448
  col,
1457
1449
  row
1458
1450
  });
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;
1451
+ const field = fields[col];
1452
+ if (!field) {
1453
+ continue;
1454
+ }
1455
+ this.createDataCell(cells, draftRow.data, field, col, row);
1456
+ if (this.model.hasDraftRowValidationError(row, field.path)) {
1457
+ const cellValue = cells[cellIndex];
1458
+ if (cellValue) {
1459
+ const existingClasses = cellValue.className || "";
1460
+ const draftClasses = "dx-grid__cell--flagged";
1461
+ cellValue.className = existingClasses ? `${existingClasses} ${draftClasses}` : draftClasses;
1462
+ }
1464
1463
  }
1465
1464
  }
1466
1465
  }
@@ -1479,10 +1478,10 @@ var TablePresentation = class {
1479
1478
  row: 0
1480
1479
  })] = {
1481
1480
  // TODO(burdon): Use same logic as form for fallback title.
1482
- value: props.title ?? field.path,
1483
- readonly: true,
1481
+ value: "",
1484
1482
  resizeHandle: "col",
1485
1483
  accessoryHtml: `
1484
+ <span class="grow min-is-0 truncate">${props.title ?? field.path}</span>
1486
1485
  ${direction !== void 0 ? tableButtons.sort.render({
1487
1486
  fieldId: field.id,
1488
1487
  direction
@@ -1491,7 +1490,7 @@ var TablePresentation = class {
1491
1490
  fieldId: field.id
1492
1491
  })}
1493
1492
  `,
1494
- className: "!bg-toolbarSurface"
1493
+ className: "!bg-toolbarSurface !text-description [&>div]:flex [&>div]:items-stretch"
1495
1494
  };
1496
1495
  }
1497
1496
  return cells;
@@ -1582,19 +1581,46 @@ var TablePresentation = class {
1582
1581
  getDraftActionCells(range) {
1583
1582
  const cells = {};
1584
1583
  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;
1584
+ if (draftRows.length === 0) {
1585
+ cells[toPlaneCellIndex({
1586
+ col: 0,
1587
+ row: 0
1588
+ })] = {
1589
+ value: "",
1590
+ className: "dx-grid__row--cta__cell",
1591
+ readonly: true
1592
+ };
1593
+ } else {
1594
+ for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1595
+ const draftRow = draftRows[row];
1596
+ const disabled = !draftRow.valid;
1597
+ cells[toPlaneCellIndex({
1598
+ col: 0,
1599
+ row
1600
+ })] = {
1601
+ value: "",
1602
+ readonly: true,
1603
+ accessoryHtml: tableButtons.saveDraftRow.render({
1604
+ rowIndex: row,
1605
+ disabled
1606
+ })
1607
+ };
1608
+ }
1609
+ }
1610
+ return cells;
1611
+ }
1612
+ getDraftIconCells(range) {
1613
+ const cells = {};
1614
+ const draftRows = this.model.draftRows.value;
1615
+ for (let row = range.start.row; row <= range.end.row; row++) {
1588
1616
  cells[toPlaneCellIndex({
1589
1617
  col: 0,
1590
1618
  row
1591
1619
  })] = {
1592
1620
  value: "",
1593
1621
  readonly: true,
1594
- accessoryHtml: tableButtons.saveDraftRow.render({
1595
- rowIndex: row,
1596
- disabled
1597
- })
1622
+ accessoryHtml: '<dx-icon icon="ph--plus--regular" class="contents"></dx-icon>',
1623
+ className: mx("[&>div]:grid [&>div]:place-content-center", draftRows.length < 1 && "dx-grid__row--cta__cell")
1598
1624
  };
1599
1625
  }
1600
1626
  return cells;
@@ -1712,18 +1738,18 @@ var useTableModel = ({ view, schema, projection, rows, rowActions, features, onS
1712
1738
 
1713
1739
  // src/hooks/useAddRow.ts
1714
1740
  import { useCallback } from "react";
1715
- import { Obj as Obj5 } from "@dxos/echo";
1741
+ import { Obj as Obj4 } from "@dxos/echo";
1716
1742
  var useAddRow = ({ space, schema }) => {
1717
1743
  return useCallback((data) => {
1718
1744
  if (space && schema) {
1719
1745
  try {
1720
- space.db.add(Obj5.make(schema, data ?? {}));
1721
- return true;
1746
+ space.db.add(Obj4.make(schema, data ?? {}));
1747
+ return "final";
1722
1748
  } catch (error) {
1723
- return false;
1749
+ return "draft";
1724
1750
  }
1725
1751
  }
1726
- return false;
1752
+ return "final";
1727
1753
  }, [
1728
1754
  space,
1729
1755
  schema
@@ -1734,7 +1760,6 @@ export {
1734
1760
  getBaseSchema,
1735
1761
  makeDynamicTable,
1736
1762
  touch,
1737
- createTable,
1738
1763
  BUTTON_IDENTIFIERS,
1739
1764
  tableButtons,
1740
1765
  CONTROL_IDENTIFIERS,
@@ -1749,4 +1774,4 @@ export {
1749
1774
  useTableModel,
1750
1775
  useAddRow
1751
1776
  };
1752
- //# sourceMappingURL=chunk-Y66YLSTC.mjs.map
1777
+ //# sourceMappingURL=chunk-LD5JEBA6.mjs.map