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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-ZAOSIG3L.mjs} +382 -319
  2. package/dist/lib/browser/chunk-ZAOSIG3L.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +399 -380
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +4 -2
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/{chunk-Y66YLSTC.mjs → chunk-ZOFFI3JJ.mjs} +382 -319
  9. package/dist/lib/node-esm/chunk-ZOFFI3JJ.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +399 -380
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +4 -2
  14. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  15. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -1
  16. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  17. package/dist/types/src/components/Table/ColumnSettings.d.ts +1 -1
  18. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  19. package/dist/types/src/components/Table/CreateRefPanel.d.ts +1 -1
  20. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +1 -1
  23. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/{relations.stories.d.ts → Relations.stories.d.ts} +2 -2
  25. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  27. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/Table.d.ts +1 -0
  29. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/Table.stories.d.ts +1 -1
  31. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  33. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -5
  34. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +1 -1
  37. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  38. package/dist/types/src/hooks/useTableModel.d.ts +1 -1
  39. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  40. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  41. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  42. package/dist/types/src/model/table-model.d.ts +3 -2
  43. package/dist/types/src/model/table-model.d.ts.map +1 -1
  44. package/dist/types/src/model/table-presentation.d.ts +2 -1
  45. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  46. package/dist/types/src/model/table-sorting.d.ts +2 -2
  47. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  48. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  49. package/dist/types/src/translations.d.ts +2 -2
  50. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  51. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  52. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  53. package/dist/types/src/util/table.d.ts +2 -1
  54. package/dist/types/src/util/table.d.ts.map +1 -1
  55. package/dist/types/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +46 -46
  57. package/src/components/Table/ColumnActionsMenu.tsx +1 -1
  58. package/src/components/Table/ColumnSettings.tsx +1 -1
  59. package/src/components/Table/CreateRefPanel.tsx +1 -1
  60. package/src/components/Table/DynamicTable.stories.tsx +3 -2
  61. package/src/components/Table/DynamicTable.tsx +4 -3
  62. package/src/components/Table/{relations.stories.tsx → Relations.stories.tsx} +12 -4
  63. package/src/components/Table/RowActionsMenu.tsx +3 -3
  64. package/src/components/Table/Table.stories.tsx +12 -7
  65. package/src/components/Table/Table.tsx +49 -43
  66. package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
  67. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +4 -3
  68. package/src/components/TableCellEditor/TableCellEditor.tsx +16 -20
  69. package/src/components/TableCellEditor/extension.ts +2 -2
  70. package/src/components/TableToolbar/TableToolbar.tsx +2 -2
  71. package/src/components/testing.ts +1 -1
  72. package/src/hooks/useTableModel.ts +1 -1
  73. package/src/model/modal-controller.ts +1 -1
  74. package/src/model/selection-model.ts +3 -2
  75. package/src/model/table-model.test.ts +2 -1
  76. package/src/model/table-model.ts +13 -10
  77. package/src/model/table-presentation.test.ts +3 -2
  78. package/src/model/table-presentation.ts +28 -6
  79. package/src/model/table-sorting.ts +3 -3
  80. package/src/playwright/smoke.spec.ts +92 -0
  81. package/src/testing/useTestTableModel.ts +3 -2
  82. package/src/translations.ts +2 -2
  83. package/src/util/dynamic-table.ts +2 -2
  84. package/src/util/schema.ts +1 -1
  85. package/src/util/table-buttons.ts +2 -1
  86. package/src/util/table-controls.ts +4 -1
  87. package/src/util/table.ts +7 -3
  88. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  89. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  90. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
@@ -5,7 +5,7 @@ import {
5
5
  // src/util/dynamic-table.ts
6
6
  import { Obj } from "@dxos/echo";
7
7
  import { getTypename, toJsonSchema } from "@dxos/echo-schema";
8
- import { createView, getSchemaFromPropertyDefinitions, ProjectionModel } from "@dxos/schema";
8
+ import { ProjectionModel, createView, getSchemaFromPropertyDefinitions } from "@dxos/schema";
9
9
  var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
10
10
  if (typename && properties) {
11
11
  const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
@@ -111,6 +111,7 @@ var createTable = async ({ sizes, ...props }) => {
111
111
  }
112
112
  return {
113
113
  jsonSchema,
114
+ schema,
114
115
  view
115
116
  };
116
117
  };
@@ -127,7 +128,7 @@ var BUTTON_IDENTIFIERS = {
127
128
  var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
128
129
  const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
129
130
  const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
130
- 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>`;
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" : ""} data-dx-grid-action="accessory"><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
131
132
  };
132
133
  var addColumnButton = {
133
134
  attr: BUTTON_IDENTIFIERS.newColumn,
@@ -213,7 +214,8 @@ var saveDraftRowButton = {
213
214
  icon: saveDraftRowButton.icon,
214
215
  disabled,
215
216
  data: {
216
- "data-row-index": rowIndex.toString()
217
+ "data-row-index": rowIndex.toString(),
218
+ "data-variant": "primary"
217
219
  },
218
220
  testId: "table-save-draft-row-button"
219
221
  });
@@ -232,6 +234,7 @@ var tableButtons = {
232
234
  };
233
235
 
234
236
  // src/util/table-controls.ts
237
+ import { accessoryHandlesPointerdownAttrs } from "@dxos/lit-grid";
235
238
  var CONTROL_IDENTIFIERS = {
236
239
  checkbox: "data-table-checkbox",
237
240
  switch: "data-table-switch"
@@ -244,7 +247,7 @@ var renderAttributes = (data) => {
244
247
  return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
245
248
  };
246
249
  var renderInput = (baseClass, attrs, checked = false, disabled = false, preventToggle = false, testId) => {
247
- return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}"/>`;
250
+ return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}" data-dx-grid-action="accessory"/>`;
248
251
  };
249
252
  var CheckboxStory = ({ rowIndex, header = false, checked = false, disabled = false }) => {
250
253
  const attrs = {
@@ -260,7 +263,8 @@ var SwitchStory = ({ colIndex, rowIndex, checked = false, disabled = false }) =>
260
263
  const attrs = {
261
264
  [CONTROL_IDENTIFIERS.switch]: "",
262
265
  "data-row-index": rowIndex.toString(),
263
- "data-col-index": colIndex.toString()
266
+ "data-col-index": colIndex.toString(),
267
+ ...accessoryHandlesPointerdownAttrs
264
268
  };
265
269
  return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, "table-switch");
266
270
  };
@@ -287,7 +291,7 @@ var tableControls = {
287
291
 
288
292
  // src/util/schema.ts
289
293
  import { Schema } from "effect";
290
- import { isTypeLiteral, TypeLiteral } from "effect/SchemaAST";
294
+ import { TypeLiteral, isTypeLiteral } from "effect/SchemaAST";
291
295
  var narrowSchema = (schema, paths) => {
292
296
  const ast = schema?.ast;
293
297
  if (isTypeLiteral(ast)) {
@@ -304,7 +308,7 @@ var narrowSchema = (schema, paths) => {
304
308
  import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
305
309
  import { Resource as Resource2 } from "@dxos/context";
306
310
  import { Obj as Obj3, Ref } from "@dxos/echo";
307
- import { FormatEnum as FormatEnum2, getValue as getValue2, setValue, getSnapshot, getSchema, toEffectSchema as toEffectSchema2 } from "@dxos/echo-schema";
311
+ import { FormatEnum as FormatEnum2, getSchema, getSnapshot, getValue as getValue2, setValue, toEffectSchema as toEffectSchema2 } from "@dxos/echo-schema";
308
312
  import { invariant } from "@dxos/invariant";
309
313
  import { ObjectId } from "@dxos/keys";
310
314
  import { isLiveObject } from "@dxos/live-object";
@@ -312,10 +316,34 @@ import { fullyQualifiedId } from "@dxos/react-client/echo";
312
316
  import { formatForEditing, parseValue } from "@dxos/react-ui-form";
313
317
  import { ProjectionModel as ProjectionModel2, validateSchema } from "@dxos/schema";
314
318
 
319
+ // src/util/tag.ts
320
+ var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
321
+ var extractTagIds = (value) => {
322
+ if (typeof value !== "string") {
323
+ return void 0;
324
+ }
325
+ const ids = [];
326
+ let match;
327
+ while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
328
+ if (match[2]) {
329
+ ids.push(match[2]);
330
+ }
331
+ }
332
+ return ids.length > 0 ? ids : void 0;
333
+ };
334
+
315
335
  // src/model/selection-model.ts
316
336
  import { computed, effect, signal } from "@preact/signals-core";
317
337
  import { Resource } from "@dxos/context";
318
338
  var SelectionModel = class extends Resource {
339
+ _rows;
340
+ _selectionMode;
341
+ _initialSelection;
342
+ _onSelectionChanged;
343
+ _selection;
344
+ _validSelectedIds;
345
+ _hasSelection;
346
+ _allSelected;
319
347
  constructor(_rows, _selectionMode, _initialSelection, _onSelectionChanged) {
320
348
  super(), this._rows = _rows, this._selectionMode = _selectionMode, this._initialSelection = _initialSelection, this._onSelectionChanged = _onSelectionChanged, this._validSelectedIds = computed(() => {
321
349
  const rows = this._rows.value;
@@ -388,14 +416,29 @@ var SelectionModel = class extends Resource {
388
416
  get selectionMode() {
389
417
  return this._selectionMode;
390
418
  }
419
+ getSelectedRows;
420
+ isRowIndexSelected;
421
+ isObjectSelected;
422
+ //
423
+ // Manipulation
424
+ //
425
+ toggleSelectionForRowIndex;
426
+ setSelection;
391
427
  };
392
428
 
393
429
  // src/model/table-sorting.ts
394
430
  import { computed as computed2, signal as signal2 } from "@preact/signals-core";
395
431
  import orderBy from "lodash.orderby";
396
- import { getValue, FormatEnum, TypeEnum } from "@dxos/echo-schema";
432
+ import { FormatEnum, TypeEnum, getValue } from "@dxos/echo-schema";
397
433
  import { formatForDisplay } from "@dxos/react-ui-form";
398
434
  var TableSorting = class {
435
+ _view;
436
+ _projection;
437
+ _displayToDataIndex;
438
+ _rows;
439
+ _localSort;
440
+ _isDirty;
441
+ sortedRows;
399
442
  constructor(rows, _view, _projection) {
400
443
  this._view = _view;
401
444
  this._projection = _projection;
@@ -555,22 +598,6 @@ var TableSorting = class {
555
598
  }
556
599
  };
557
600
 
558
- // src/util/tag.ts
559
- var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
560
- var extractTagIds = (value) => {
561
- if (typeof value !== "string") {
562
- return void 0;
563
- }
564
- const ids = [];
565
- let match;
566
- while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
567
- if (match[2]) {
568
- ids.push(match[2]);
569
- }
570
- }
571
- return ids.length > 0 ? ids : void 0;
572
- };
573
-
574
601
  // src/model/table-model.ts
575
602
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
576
603
  var defaultFeatures = {
@@ -582,222 +609,38 @@ var defaultFeatures = {
582
609
  schemaEditable: false
583
610
  };
584
611
  var TableModel = class extends Resource2 {
612
+ _view;
613
+ _projection;
614
+ _table;
615
+ _visibleRange = signal3({
616
+ start: {
617
+ row: 0,
618
+ col: 0
619
+ },
620
+ end: {
621
+ row: 0,
622
+ col: 0
623
+ }
624
+ });
625
+ _onInsertRow;
626
+ _onDeleteRows;
627
+ _onDeleteColumn;
628
+ _onCellUpdate;
629
+ _onRowOrderChange;
630
+ _onRowAction;
631
+ _rowActions;
632
+ _features;
633
+ _rows = signal3([]);
634
+ _draftRows = signal3([]);
635
+ _sorting;
636
+ _pinnedRows;
637
+ _selection;
638
+ _columnMeta;
585
639
  constructor({ view, schema, projection, features = {}, sorting = [], initialSelection = [], pinnedRows = {
586
640
  top: [],
587
641
  bottom: []
588
642
  }, rowActions = [], onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
589
643
  super();
590
- this._visibleRange = signal3({
591
- start: {
592
- row: 0,
593
- col: 0
594
- },
595
- end: {
596
- row: 0,
597
- col: 0
598
- }
599
- });
600
- this._rows = signal3([]);
601
- this._draftRows = signal3([]);
602
- //
603
- // Data
604
- //
605
- this.setRows = (obj) => {
606
- this._rows.value = obj;
607
- };
608
- this.getRowCount = () => this._rows.value.length;
609
- /**
610
- * @reactive
611
- */
612
- this.getDraftRowCount = () => this._draftRows.value.length;
613
- this.getColumnCount = () => this._projection?.fields.length ?? 0;
614
- this.insertRow = () => {
615
- const result = this._onInsertRow?.();
616
- if (result === false && this._draftRows.value.length === 0) {
617
- this.createDraftRow();
618
- }
619
- };
620
- this.commitDraftRow = (draftRowIndex) => {
621
- if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.value.length) {
622
- return false;
623
- }
624
- const draftRow = this._draftRows.value[draftRowIndex];
625
- if (!draftRow.valid) {
626
- return false;
627
- }
628
- const success = this._onInsertRow?.(draftRow.data);
629
- if (success) {
630
- const newDraftRows = this._draftRows.value.filter((_, index) => index !== draftRowIndex);
631
- this._draftRows.value = newDraftRows;
632
- }
633
- return success ?? false;
634
- };
635
- this.deleteRow = (rowIndex) => {
636
- const row = this._sorting.getDataIndex(rowIndex);
637
- const obj = this._rows.value[row];
638
- const objectsToDelete = [];
639
- if (this.features.selection.enabled && this._selection.hasSelection.value) {
640
- const selectedRows = this._selection.getSelectedRows();
641
- objectsToDelete.push(...selectedRows);
642
- } else {
643
- objectsToDelete.push(obj);
644
- }
645
- this._onDeleteRows?.(row, objectsToDelete);
646
- };
647
- this.handleRowAction = (actionId, rowIndex) => {
648
- if (!this._onRowAction) {
649
- return;
650
- }
651
- const row = this._sorting.getDataIndex(rowIndex);
652
- const data = this._rows.value[row];
653
- if (data) {
654
- this._onRowAction(actionId, data);
655
- }
656
- };
657
- this.getCellData = (cell) => {
658
- const { col, row, plane } = cell;
659
- const fields = this._projection?.fields ?? [];
660
- if (col < 0 || col >= fields.length) {
661
- return void 0;
662
- }
663
- const field = fields[col];
664
- let value;
665
- if (plane === "frozenRowsEnd") {
666
- if (row >= 0 && row < this._draftRows.value.length) {
667
- value = getValue2(this._draftRows.value[row].data, field.path);
668
- } else {
669
- return void 0;
670
- }
671
- } else {
672
- const dataIndex = this._sorting.getDataIndex(row);
673
- value = getValue2(this._rows.value[dataIndex], field.path);
674
- }
675
- if (value == null) {
676
- return "";
677
- }
678
- const { props } = this._projection.getFieldProjection(field.id);
679
- switch (props.format) {
680
- case FormatEnum2.Ref: {
681
- if (!field.referencePath) {
682
- return "";
683
- }
684
- return getValue2(value.target, field.referencePath);
685
- }
686
- default: {
687
- return formatForEditing({
688
- type: props.type,
689
- format: props.format,
690
- value
691
- });
692
- }
693
- }
694
- };
695
- this.validateCellData = async ({ col, row, plane }, value) => {
696
- const fields = this._projection?.fields ?? [];
697
- if (col < 0 || col >= fields.length) {
698
- return {
699
- valid: false,
700
- error: "Invalid column index"
701
- };
702
- }
703
- const field = fields[col];
704
- const { props } = this._projection.getFieldProjection(field.id);
705
- const transformedValue = editorTextToCellValue(props, value);
706
- const isDraftRow = plane === "frozenRowsEnd";
707
- if (isDraftRow) {
708
- const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.value.length;
709
- if (isInvalidDraftRowIndex) {
710
- return {
711
- valid: false,
712
- error: "Invalid draft row index"
713
- };
714
- }
715
- const draftRow = this._draftRows.value[row];
716
- const snapshot = {
717
- ...draftRow.data
718
- };
719
- setValue(snapshot, field.path, transformedValue);
720
- const validationErrors = this.validateDraftRowData(snapshot);
721
- if (validationErrors.length > 0) {
722
- const error = validationErrors.find((err) => err.path === field.path);
723
- if (error) {
724
- return {
725
- valid: false,
726
- error: error.message
727
- };
728
- }
729
- }
730
- return {
731
- valid: true
732
- };
733
- } else {
734
- const rowIdx = this._sorting.getDataIndex(row);
735
- const currentRow = this._rows.value[rowIdx];
736
- invariant(currentRow, "Invalid row index", {
737
- F: __dxlog_file,
738
- L: 510,
739
- S: this,
740
- A: [
741
- "currentRow",
742
- "'Invalid row index'"
743
- ]
744
- });
745
- const snapshot = getSnapshot(currentRow);
746
- setValue(snapshot, field.path, transformedValue);
747
- const schema = getSchema(currentRow);
748
- invariant(schema, void 0, {
749
- F: __dxlog_file,
750
- L: 516,
751
- S: this,
752
- A: [
753
- "schema",
754
- ""
755
- ]
756
- });
757
- const validationResult = validateSchema(schema, snapshot);
758
- if (validationResult && validationResult.length > 0) {
759
- const error = validationResult[0];
760
- invariant(error.path === field.path, void 0, {
761
- F: __dxlog_file,
762
- L: 521,
763
- S: this,
764
- A: [
765
- "error.path === field.path",
766
- ""
767
- ]
768
- });
769
- return {
770
- valid: false,
771
- error: error.message
772
- };
773
- }
774
- return {
775
- valid: true
776
- };
777
- }
778
- };
779
- this.setCellData = (cell, value) => {
780
- const { col, row, plane } = cell;
781
- const fields = this._projection?.fields ?? [];
782
- if (col < 0 || col >= fields.length) {
783
- return;
784
- }
785
- const field = fields[col];
786
- const { props } = this._projection.getFieldProjection(field.id);
787
- const transformedValue = editorTextToCellValue(props, value);
788
- if (props.format === FormatEnum2.Ref && !isLiveObject(value)) {
789
- return;
790
- }
791
- if (plane === "frozenRowsEnd") {
792
- if (row >= 0 && row < this._draftRows.value.length) {
793
- setValue(this._draftRows.value[row].data, field.path, transformedValue);
794
- this.validateDraftRow(row);
795
- }
796
- } else {
797
- const rowIdx = this._sorting.getDataIndex(row);
798
- setValue(this._rows.value[rowIdx], field.path, transformedValue);
799
- }
800
- };
801
644
  this._view = view;
802
645
  this._projection = projection ?? new ProjectionModel2(schema, view.projection);
803
646
  this._features = {
@@ -806,7 +649,7 @@ var TableModel = class extends Resource2 {
806
649
  };
807
650
  invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
808
651
  F: __dxlog_file,
809
- L: 139,
652
+ L: 141,
810
653
  S: this,
811
654
  A: [
812
655
  "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
@@ -837,7 +680,7 @@ var TableModel = class extends Resource2 {
837
680
  get table() {
838
681
  invariant(this._table, "Model not initialized", {
839
682
  F: __dxlog_file,
840
- L: 177,
683
+ L: 179,
841
684
  S: this,
842
685
  A: [
843
686
  "this._table",
@@ -876,7 +719,7 @@ var TableModel = class extends Resource2 {
876
719
  get columnMeta() {
877
720
  invariant(this._columnMeta, void 0, {
878
721
  F: __dxlog_file,
879
- L: 216,
722
+ L: 218,
880
723
  S: this,
881
724
  A: [
882
725
  "this._columnMeta",
@@ -902,7 +745,7 @@ var TableModel = class extends Resource2 {
902
745
  const presentation = this._view.presentation.target ?? await this._view.presentation.load();
903
746
  invariant(Obj3.instanceOf(TableView, presentation), void 0, {
904
747
  F: __dxlog_file,
905
- L: 239,
748
+ L: 241,
906
749
  S: this,
907
750
  A: [
908
751
  "Obj.instanceOf(TableView, presentation)",
@@ -970,6 +813,17 @@ var TableModel = class extends Resource2 {
970
813
  });
971
814
  this._ctx.onDispose(draftRowsWatcher);
972
815
  }
816
+ //
817
+ // Data
818
+ //
819
+ setRows = (obj) => {
820
+ this._rows.value = obj;
821
+ };
822
+ getRowCount = () => this._rows.value.length;
823
+ /**
824
+ * @reactive
825
+ */
826
+ getDraftRowCount = () => this._draftRows.value.length;
973
827
  // TODO(ZaymonFC): Return .value instead of exposing the signal.
974
828
  get draftRows() {
975
829
  return this._draftRows;
@@ -988,6 +842,13 @@ var TableModel = class extends Resource2 {
988
842
  const validationErrors = draftRow.validationErrors || [];
989
843
  return validationErrors.some((error) => error.path === fieldPath);
990
844
  }
845
+ getColumnCount = () => this._projection?.fields.length ?? 0;
846
+ insertRow = () => {
847
+ const result = this._onInsertRow?.();
848
+ if (result === false && this._draftRows.value.length === 0) {
849
+ this.createDraftRow();
850
+ }
851
+ };
991
852
  createDraftRow() {
992
853
  if (!this._projection) {
993
854
  return;
@@ -1027,6 +888,187 @@ var TableModel = class extends Resource2 {
1027
888
  const schema = toEffectSchema2(this._projection.baseSchema);
1028
889
  return validateSchema(schema, data) || [];
1029
890
  }
891
+ commitDraftRow = (draftRowIndex) => {
892
+ if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.value.length) {
893
+ return false;
894
+ }
895
+ const draftRow = this._draftRows.value[draftRowIndex];
896
+ if (!draftRow.valid) {
897
+ return false;
898
+ }
899
+ const success = this._onInsertRow?.(draftRow.data);
900
+ if (success) {
901
+ const newDraftRows = this._draftRows.value.filter((_, index) => index !== draftRowIndex);
902
+ this._draftRows.value = newDraftRows;
903
+ }
904
+ return success ?? false;
905
+ };
906
+ deleteRow = (rowIndex) => {
907
+ const row = this._sorting.getDataIndex(rowIndex);
908
+ const obj = this._rows.value[row];
909
+ const objectsToDelete = [];
910
+ if (this.features.selection.enabled && this._selection.hasSelection.value) {
911
+ const selectedRows = this._selection.getSelectedRows();
912
+ objectsToDelete.push(...selectedRows);
913
+ } else {
914
+ objectsToDelete.push(obj);
915
+ }
916
+ this._onDeleteRows?.(row, objectsToDelete);
917
+ };
918
+ handleRowAction = (actionId, rowIndex) => {
919
+ if (!this._onRowAction) {
920
+ return;
921
+ }
922
+ const row = this._sorting.getDataIndex(rowIndex);
923
+ const data = this._rows.value[row];
924
+ if (data) {
925
+ this._onRowAction(actionId, data);
926
+ }
927
+ };
928
+ getCellData = (cell) => {
929
+ const { col, row, plane } = cell;
930
+ const fields = this._projection?.fields ?? [];
931
+ if (col < 0 || col >= fields.length) {
932
+ return void 0;
933
+ }
934
+ const field = fields[col];
935
+ let value;
936
+ if (plane === "frozenRowsEnd") {
937
+ if (row >= 0 && row < this._draftRows.value.length) {
938
+ value = getValue2(this._draftRows.value[row].data, field.path);
939
+ } else {
940
+ return void 0;
941
+ }
942
+ } else {
943
+ const dataIndex = this._sorting.getDataIndex(row);
944
+ value = getValue2(this._rows.value[dataIndex], field.path);
945
+ }
946
+ if (value == null) {
947
+ return "";
948
+ }
949
+ const { props } = this._projection.getFieldProjection(field.id);
950
+ switch (props.format) {
951
+ case FormatEnum2.Ref: {
952
+ if (!field.referencePath) {
953
+ return "";
954
+ }
955
+ return getValue2(value.target, field.referencePath);
956
+ }
957
+ default: {
958
+ return formatForEditing({
959
+ type: props.type,
960
+ format: props.format,
961
+ value
962
+ });
963
+ }
964
+ }
965
+ };
966
+ validateCellData = async ({ col, row, plane }, value) => {
967
+ const fields = this._projection?.fields ?? [];
968
+ if (col < 0 || col >= fields.length) {
969
+ return {
970
+ valid: false,
971
+ error: "Invalid column index"
972
+ };
973
+ }
974
+ const field = fields[col];
975
+ const { props } = this._projection.getFieldProjection(field.id);
976
+ const transformedValue = editorTextToCellValue(props, value);
977
+ const isDraftRow = plane === "frozenRowsEnd";
978
+ if (isDraftRow) {
979
+ const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.value.length;
980
+ if (isInvalidDraftRowIndex) {
981
+ return {
982
+ valid: false,
983
+ error: "Invalid draft row index"
984
+ };
985
+ }
986
+ const draftRow = this._draftRows.value[row];
987
+ const snapshot = {
988
+ ...draftRow.data
989
+ };
990
+ setValue(snapshot, field.path, transformedValue);
991
+ const validationErrors = this.validateDraftRowData(snapshot);
992
+ if (validationErrors.length > 0) {
993
+ const error = validationErrors.find((err) => err.path === field.path);
994
+ if (error) {
995
+ return {
996
+ valid: false,
997
+ error: error.message
998
+ };
999
+ }
1000
+ }
1001
+ return {
1002
+ valid: true
1003
+ };
1004
+ } else {
1005
+ const rowIdx = this._sorting.getDataIndex(row);
1006
+ const currentRow = this._rows.value[rowIdx];
1007
+ invariant(currentRow, "Invalid row index", {
1008
+ F: __dxlog_file,
1009
+ L: 513,
1010
+ S: this,
1011
+ A: [
1012
+ "currentRow",
1013
+ "'Invalid row index'"
1014
+ ]
1015
+ });
1016
+ const snapshot = getSnapshot(currentRow);
1017
+ setValue(snapshot, field.path, transformedValue);
1018
+ const schema = getSchema(currentRow);
1019
+ invariant(schema, void 0, {
1020
+ F: __dxlog_file,
1021
+ L: 519,
1022
+ S: this,
1023
+ A: [
1024
+ "schema",
1025
+ ""
1026
+ ]
1027
+ });
1028
+ const validationResult = validateSchema(schema, snapshot);
1029
+ if (validationResult && validationResult.length > 0) {
1030
+ const error = validationResult[0];
1031
+ invariant(error.path === field.path, void 0, {
1032
+ F: __dxlog_file,
1033
+ L: 524,
1034
+ S: this,
1035
+ A: [
1036
+ "error.path === field.path",
1037
+ ""
1038
+ ]
1039
+ });
1040
+ return {
1041
+ valid: false,
1042
+ error: error.message
1043
+ };
1044
+ }
1045
+ return {
1046
+ valid: true
1047
+ };
1048
+ }
1049
+ };
1050
+ setCellData = (cell, value) => {
1051
+ const { col, row, plane } = cell;
1052
+ const fields = this._projection?.fields ?? [];
1053
+ if (col < 0 || col >= fields.length) {
1054
+ return;
1055
+ }
1056
+ const field = fields[col];
1057
+ const { props } = this._projection.getFieldProjection(field.id);
1058
+ const transformedValue = editorTextToCellValue(props, value);
1059
+ if (props.format === FormatEnum2.Ref && !isLiveObject(value)) {
1060
+ return;
1061
+ }
1062
+ if (plane === "frozenRowsEnd") {
1063
+ if (row >= 0 && row < this._draftRows.value.length) {
1064
+ setValue(this._draftRows.value[row].data, field.path, transformedValue);
1065
+ this.validateDraftRow(row);
1066
+ }
1067
+ } else {
1068
+ const rowIdx = this._sorting.getDataIndex(row);
1069
+ setValue(this._rows.value[rowIdx], field.path, transformedValue);
1070
+ }
1071
+ };
1030
1072
  /**
1031
1073
  * Updates a cell's value using a transform function.
1032
1074
  * @param {DxGridPlanePosition} position - The position of the cell to update.
@@ -1144,99 +1186,100 @@ import { signal as signal4 } from "@preact/signals-core";
1144
1186
  import { log } from "@dxos/log";
1145
1187
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1146
1188
  var ModalController = class {
1147
- constructor() {
1148
- this._state = signal4({
1149
- type: "closed"
1150
- });
1151
- this._triggerRef = {
1152
- current: null
1153
- };
1154
- this.setTrigger = (trigger) => {
1155
- this._triggerRef.current = trigger;
1156
- };
1157
- this.showRowMenu = (rowIndex) => {
1158
- this._state.value = {
1159
- type: "row",
1160
- rowIndex
1161
- };
1162
- };
1163
- this.showColumnMenu = (fieldId) => {
1164
- this._state.value = {
1165
- type: "column",
1166
- fieldId
1167
- };
1168
- };
1169
- this.showColumnCreator = () => {
1170
- this._state.value = {
1171
- type: "columnSettings",
1172
- mode: {
1173
- type: "create"
1174
- }
1175
- };
1189
+ _state = signal4({
1190
+ type: "closed"
1191
+ });
1192
+ _triggerRef = {
1193
+ current: null
1194
+ };
1195
+ get state() {
1196
+ return this._state;
1197
+ }
1198
+ get trigger() {
1199
+ return this._triggerRef;
1200
+ }
1201
+ setTrigger = (trigger) => {
1202
+ this._triggerRef.current = trigger;
1203
+ };
1204
+ showRowMenu = (rowIndex) => {
1205
+ this._state.value = {
1206
+ type: "row",
1207
+ rowIndex
1176
1208
  };
1177
- this.showReferencePanel = (targetId, schemaId) => {
1178
- this._state.value = {
1179
- type: "refPanel",
1180
- targetId,
1181
- typename: schemaId
1182
- };
1209
+ };
1210
+ showColumnMenu = (fieldId) => {
1211
+ this._state.value = {
1212
+ type: "column",
1213
+ fieldId
1183
1214
  };
1184
- this.openColumnSettings = () => {
1185
- if (this._state.value.type === "column") {
1186
- const fieldId = this._state.value.fieldId;
1187
- requestAnimationFrame(() => {
1188
- this._state.value = {
1189
- type: "columnSettings",
1190
- mode: {
1191
- type: "edit",
1192
- fieldId
1193
- }
1194
- };
1195
- });
1215
+ };
1216
+ showColumnCreator = () => {
1217
+ this._state.value = {
1218
+ type: "columnSettings",
1219
+ mode: {
1220
+ type: "create"
1196
1221
  }
1197
1222
  };
1198
- this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1199
- if (anchorCell) {
1200
- this._triggerRef.current = anchorCell;
1223
+ };
1224
+ showReferencePanel = (targetId, schemaId) => {
1225
+ this._state.value = {
1226
+ type: "refPanel",
1227
+ targetId,
1228
+ typename: schemaId
1229
+ };
1230
+ };
1231
+ openColumnSettings = () => {
1232
+ if (this._state.value.type === "column") {
1233
+ const fieldId = this._state.value.fieldId;
1234
+ requestAnimationFrame(() => {
1201
1235
  this._state.value = {
1202
- type: "createRefPanel",
1203
- typename,
1204
- initialValues,
1205
- onCreate
1236
+ type: "columnSettings",
1237
+ mode: {
1238
+ type: "edit",
1239
+ fieldId
1240
+ }
1206
1241
  };
1207
- } else {
1208
- log.warn("anchor cell not found while creating new ref", void 0, {
1209
- F: __dxlog_file2,
1210
- L: 86,
1211
- S: this,
1212
- C: (f, a) => f(...a)
1213
- });
1214
- }
1215
- };
1216
- this.close = () => {
1242
+ });
1243
+ }
1244
+ };
1245
+ openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1246
+ if (anchorCell) {
1247
+ this._triggerRef.current = anchorCell;
1217
1248
  this._state.value = {
1218
- type: "closed"
1249
+ type: "createRefPanel",
1250
+ typename,
1251
+ initialValues,
1252
+ onCreate
1219
1253
  };
1254
+ } else {
1255
+ log.warn("anchor cell not found while creating new ref", void 0, {
1256
+ F: __dxlog_file2,
1257
+ L: 86,
1258
+ S: this,
1259
+ C: (f, a) => f(...a)
1260
+ });
1261
+ }
1262
+ };
1263
+ close = () => {
1264
+ this._state.value = {
1265
+ type: "closed"
1220
1266
  };
1221
- }
1222
- get state() {
1223
- return this._state;
1224
- }
1225
- get trigger() {
1226
- return this._triggerRef;
1227
- }
1267
+ };
1228
1268
  };
1229
1269
 
1230
1270
  // src/model/table-presentation.ts
1231
1271
  import { signal as signal5 } from "@preact/signals-core";
1232
1272
  import { isNotNullable } from "effect/Predicate";
1233
1273
  import { Obj as Obj4 } from "@dxos/echo";
1234
- import { FormatEnum as FormatEnum3, getValue as getValue3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1274
+ import { FormatEnum as FormatEnum3, TypeEnum as TypeEnum2, getValue as getValue3 } from "@dxos/echo-schema";
1235
1275
  import { cellClassesForFieldType, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1236
1276
  import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1237
1277
  import { mx } from "@dxos/react-ui-theme";
1238
1278
  import { VIEW_FIELD_LIMIT } from "@dxos/schema";
1239
1279
  var TablePresentation = class {
1280
+ model;
1281
+ _visibleRange;
1282
+ fieldProjectionCache;
1240
1283
  constructor(model, _visibleRange = signal5({
1241
1284
  start: {
1242
1285
  row: 0,
@@ -1277,6 +1320,9 @@ var TablePresentation = class {
1277
1320
  case "frozenRowsEnd":
1278
1321
  cells = this.getDraftRowCells(range);
1279
1322
  break;
1323
+ case "fixedEndStart":
1324
+ cells = this.getDraftSelectCells(range);
1325
+ break;
1280
1326
  case "fixedEndEnd":
1281
1327
  cells = this.getDraftActionCells(range);
1282
1328
  break;
@@ -1380,7 +1426,7 @@ var TablePresentation = class {
1380
1426
  const targetObj = getValue3(obj, field.path)?.target;
1381
1427
  if (targetObj) {
1382
1428
  const dxn = Obj4.getDXN(targetObj)?.toString();
1383
- 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>`;
1429
+ cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button is-6 pli-[3px] pbe-[2px] min-bs-0 absolute inline-end-2 block-start-[.2rem]" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
1384
1430
  }
1385
1431
  }
1386
1432
  if (props.format === FormatEnum3.Boolean) {
@@ -1445,16 +1491,16 @@ var TablePresentation = class {
1445
1491
  for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1446
1492
  const draftRow = draftRows[row];
1447
1493
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1494
+ const cellIndex = toPlaneCellIndex({
1495
+ col,
1496
+ row
1497
+ });
1448
1498
  const field = fields[col];
1449
1499
  if (!field) {
1450
1500
  continue;
1451
1501
  }
1452
1502
  this.createDataCell(cells, draftRow.data, field, col, row);
1453
1503
  if (this.model.hasDraftRowValidationError(row, field.path)) {
1454
- const cellIndex = toPlaneCellIndex({
1455
- col,
1456
- row
1457
- });
1458
1504
  const cellValue = cells[cellIndex];
1459
1505
  if (cellValue) {
1460
1506
  const existingClasses = cellValue.className || "";
@@ -1462,6 +1508,7 @@ var TablePresentation = class {
1462
1508
  cellValue.className = existingClasses ? `${existingClasses} ${draftClasses}` : draftClasses;
1463
1509
  }
1464
1510
  }
1511
+ cells[cellIndex].className += " !bg-toolbarSurface";
1465
1512
  }
1466
1513
  }
1467
1514
  return cells;
@@ -1593,7 +1640,23 @@ var TablePresentation = class {
1593
1640
  accessoryHtml: tableButtons.saveDraftRow.render({
1594
1641
  rowIndex: row,
1595
1642
  disabled
1596
- })
1643
+ }),
1644
+ className: "!bg-toolbarSurface"
1645
+ };
1646
+ }
1647
+ return cells;
1648
+ }
1649
+ getDraftSelectCells(range) {
1650
+ const cells = {};
1651
+ const draftRows = this.model.draftRows.value;
1652
+ for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1653
+ cells[toPlaneCellIndex({
1654
+ col: 0,
1655
+ row
1656
+ })] = {
1657
+ value: "",
1658
+ readonly: true,
1659
+ className: "!bg-toolbarSurface"
1597
1660
  };
1598
1661
  }
1599
1662
  return cells;
@@ -1748,4 +1811,4 @@ export {
1748
1811
  useTableModel,
1749
1812
  useAddRow
1750
1813
  };
1751
- //# sourceMappingURL=chunk-5XLSHLOG.mjs.map
1814
+ //# sourceMappingURL=chunk-ZAOSIG3L.mjs.map