@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
@@ -6,7 +6,7 @@ import {
6
6
  // src/util/dynamic-table.ts
7
7
  import { Obj } from "@dxos/echo";
8
8
  import { getTypename, toJsonSchema } from "@dxos/echo-schema";
9
- import { createView, getSchemaFromPropertyDefinitions, ProjectionModel } from "@dxos/schema";
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);
@@ -112,6 +112,7 @@ var createTable = async ({ sizes, ...props }) => {
112
112
  }
113
113
  return {
114
114
  jsonSchema,
115
+ schema,
115
116
  view
116
117
  };
117
118
  };
@@ -128,7 +129,7 @@ var BUTTON_IDENTIFIERS = {
128
129
  var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
129
130
  const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
130
131
  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>`;
132
+ 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>`;
132
133
  };
133
134
  var addColumnButton = {
134
135
  attr: BUTTON_IDENTIFIERS.newColumn,
@@ -214,7 +215,8 @@ var saveDraftRowButton = {
214
215
  icon: saveDraftRowButton.icon,
215
216
  disabled,
216
217
  data: {
217
- "data-row-index": rowIndex.toString()
218
+ "data-row-index": rowIndex.toString(),
219
+ "data-variant": "primary"
218
220
  },
219
221
  testId: "table-save-draft-row-button"
220
222
  });
@@ -233,6 +235,7 @@ var tableButtons = {
233
235
  };
234
236
 
235
237
  // src/util/table-controls.ts
238
+ import { accessoryHandlesPointerdownAttrs } from "@dxos/lit-grid";
236
239
  var CONTROL_IDENTIFIERS = {
237
240
  checkbox: "data-table-checkbox",
238
241
  switch: "data-table-switch"
@@ -245,7 +248,7 @@ var renderAttributes = (data) => {
245
248
  return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
246
249
  };
247
250
  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}"/>`;
251
+ 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
252
  };
250
253
  var CheckboxStory = ({ rowIndex, header = false, checked = false, disabled = false }) => {
251
254
  const attrs = {
@@ -261,7 +264,8 @@ var SwitchStory = ({ colIndex, rowIndex, checked = false, disabled = false }) =>
261
264
  const attrs = {
262
265
  [CONTROL_IDENTIFIERS.switch]: "",
263
266
  "data-row-index": rowIndex.toString(),
264
- "data-col-index": colIndex.toString()
267
+ "data-col-index": colIndex.toString(),
268
+ ...accessoryHandlesPointerdownAttrs
265
269
  };
266
270
  return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, "table-switch");
267
271
  };
@@ -288,7 +292,7 @@ var tableControls = {
288
292
 
289
293
  // src/util/schema.ts
290
294
  import { Schema } from "effect";
291
- import { isTypeLiteral, TypeLiteral } from "effect/SchemaAST";
295
+ import { TypeLiteral, isTypeLiteral } from "effect/SchemaAST";
292
296
  var narrowSchema = (schema, paths) => {
293
297
  const ast = schema?.ast;
294
298
  if (isTypeLiteral(ast)) {
@@ -305,7 +309,7 @@ var narrowSchema = (schema, paths) => {
305
309
  import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
306
310
  import { Resource as Resource2 } from "@dxos/context";
307
311
  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";
312
+ import { FormatEnum as FormatEnum2, getSchema, getSnapshot, getValue as getValue2, setValue, toEffectSchema as toEffectSchema2 } from "@dxos/echo-schema";
309
313
  import { invariant } from "@dxos/invariant";
310
314
  import { ObjectId } from "@dxos/keys";
311
315
  import { isLiveObject } from "@dxos/live-object";
@@ -313,10 +317,34 @@ import { fullyQualifiedId } from "@dxos/react-client/echo";
313
317
  import { formatForEditing, parseValue } from "@dxos/react-ui-form";
314
318
  import { ProjectionModel as ProjectionModel2, validateSchema } from "@dxos/schema";
315
319
 
320
+ // src/util/tag.ts
321
+ var TAG_PATTERN_REGEX = /\[([^\]]+)\]\(([^)]+)\)/g;
322
+ var extractTagIds = (value) => {
323
+ if (typeof value !== "string") {
324
+ return void 0;
325
+ }
326
+ const ids = [];
327
+ let match;
328
+ while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
329
+ if (match[2]) {
330
+ ids.push(match[2]);
331
+ }
332
+ }
333
+ return ids.length > 0 ? ids : void 0;
334
+ };
335
+
316
336
  // src/model/selection-model.ts
317
337
  import { computed, effect, signal } from "@preact/signals-core";
318
338
  import { Resource } from "@dxos/context";
319
339
  var SelectionModel = class extends Resource {
340
+ _rows;
341
+ _selectionMode;
342
+ _initialSelection;
343
+ _onSelectionChanged;
344
+ _selection;
345
+ _validSelectedIds;
346
+ _hasSelection;
347
+ _allSelected;
320
348
  constructor(_rows, _selectionMode, _initialSelection, _onSelectionChanged) {
321
349
  super(), this._rows = _rows, this._selectionMode = _selectionMode, this._initialSelection = _initialSelection, this._onSelectionChanged = _onSelectionChanged, this._validSelectedIds = computed(() => {
322
350
  const rows = this._rows.value;
@@ -389,14 +417,29 @@ var SelectionModel = class extends Resource {
389
417
  get selectionMode() {
390
418
  return this._selectionMode;
391
419
  }
420
+ getSelectedRows;
421
+ isRowIndexSelected;
422
+ isObjectSelected;
423
+ //
424
+ // Manipulation
425
+ //
426
+ toggleSelectionForRowIndex;
427
+ setSelection;
392
428
  };
393
429
 
394
430
  // src/model/table-sorting.ts
395
431
  import { computed as computed2, signal as signal2 } from "@preact/signals-core";
396
432
  import orderBy from "lodash.orderby";
397
- import { getValue, FormatEnum, TypeEnum } from "@dxos/echo-schema";
433
+ import { FormatEnum, TypeEnum, getValue } from "@dxos/echo-schema";
398
434
  import { formatForDisplay } from "@dxos/react-ui-form";
399
435
  var TableSorting = class {
436
+ _view;
437
+ _projection;
438
+ _displayToDataIndex;
439
+ _rows;
440
+ _localSort;
441
+ _isDirty;
442
+ sortedRows;
400
443
  constructor(rows, _view, _projection) {
401
444
  this._view = _view;
402
445
  this._projection = _projection;
@@ -556,22 +599,6 @@ var TableSorting = class {
556
599
  }
557
600
  };
558
601
 
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
602
  // src/model/table-model.ts
576
603
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
577
604
  var defaultFeatures = {
@@ -583,222 +610,38 @@ var defaultFeatures = {
583
610
  schemaEditable: false
584
611
  };
585
612
  var TableModel = class extends Resource2 {
613
+ _view;
614
+ _projection;
615
+ _table;
616
+ _visibleRange = signal3({
617
+ start: {
618
+ row: 0,
619
+ col: 0
620
+ },
621
+ end: {
622
+ row: 0,
623
+ col: 0
624
+ }
625
+ });
626
+ _onInsertRow;
627
+ _onDeleteRows;
628
+ _onDeleteColumn;
629
+ _onCellUpdate;
630
+ _onRowOrderChange;
631
+ _onRowAction;
632
+ _rowActions;
633
+ _features;
634
+ _rows = signal3([]);
635
+ _draftRows = signal3([]);
636
+ _sorting;
637
+ _pinnedRows;
638
+ _selection;
639
+ _columnMeta;
586
640
  constructor({ view, schema, projection, features = {}, sorting = [], initialSelection = [], pinnedRows = {
587
641
  top: [],
588
642
  bottom: []
589
643
  }, rowActions = [], onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChange, onRowAction }) {
590
644
  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
645
  this._view = view;
803
646
  this._projection = projection ?? new ProjectionModel2(schema, view.projection);
804
647
  this._features = {
@@ -807,7 +650,7 @@ var TableModel = class extends Resource2 {
807
650
  };
808
651
  invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
809
652
  F: __dxlog_file,
810
- L: 139,
653
+ L: 141,
811
654
  S: this,
812
655
  A: [
813
656
  "!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
@@ -838,7 +681,7 @@ var TableModel = class extends Resource2 {
838
681
  get table() {
839
682
  invariant(this._table, "Model not initialized", {
840
683
  F: __dxlog_file,
841
- L: 177,
684
+ L: 179,
842
685
  S: this,
843
686
  A: [
844
687
  "this._table",
@@ -877,7 +720,7 @@ var TableModel = class extends Resource2 {
877
720
  get columnMeta() {
878
721
  invariant(this._columnMeta, void 0, {
879
722
  F: __dxlog_file,
880
- L: 216,
723
+ L: 218,
881
724
  S: this,
882
725
  A: [
883
726
  "this._columnMeta",
@@ -903,7 +746,7 @@ var TableModel = class extends Resource2 {
903
746
  const presentation = this._view.presentation.target ?? await this._view.presentation.load();
904
747
  invariant(Obj3.instanceOf(TableView, presentation), void 0, {
905
748
  F: __dxlog_file,
906
- L: 239,
749
+ L: 241,
907
750
  S: this,
908
751
  A: [
909
752
  "Obj.instanceOf(TableView, presentation)",
@@ -971,6 +814,17 @@ var TableModel = class extends Resource2 {
971
814
  });
972
815
  this._ctx.onDispose(draftRowsWatcher);
973
816
  }
817
+ //
818
+ // Data
819
+ //
820
+ setRows = (obj) => {
821
+ this._rows.value = obj;
822
+ };
823
+ getRowCount = () => this._rows.value.length;
824
+ /**
825
+ * @reactive
826
+ */
827
+ getDraftRowCount = () => this._draftRows.value.length;
974
828
  // TODO(ZaymonFC): Return .value instead of exposing the signal.
975
829
  get draftRows() {
976
830
  return this._draftRows;
@@ -989,6 +843,13 @@ var TableModel = class extends Resource2 {
989
843
  const validationErrors = draftRow.validationErrors || [];
990
844
  return validationErrors.some((error) => error.path === fieldPath);
991
845
  }
846
+ getColumnCount = () => this._projection?.fields.length ?? 0;
847
+ insertRow = () => {
848
+ const result = this._onInsertRow?.();
849
+ if (result === false && this._draftRows.value.length === 0) {
850
+ this.createDraftRow();
851
+ }
852
+ };
992
853
  createDraftRow() {
993
854
  if (!this._projection) {
994
855
  return;
@@ -1028,6 +889,187 @@ var TableModel = class extends Resource2 {
1028
889
  const schema = toEffectSchema2(this._projection.baseSchema);
1029
890
  return validateSchema(schema, data) || [];
1030
891
  }
892
+ commitDraftRow = (draftRowIndex) => {
893
+ if (draftRowIndex < 0 || draftRowIndex >= this._draftRows.value.length) {
894
+ return false;
895
+ }
896
+ const draftRow = this._draftRows.value[draftRowIndex];
897
+ if (!draftRow.valid) {
898
+ return false;
899
+ }
900
+ const success = this._onInsertRow?.(draftRow.data);
901
+ if (success) {
902
+ const newDraftRows = this._draftRows.value.filter((_, index) => index !== draftRowIndex);
903
+ this._draftRows.value = newDraftRows;
904
+ }
905
+ return success ?? false;
906
+ };
907
+ deleteRow = (rowIndex) => {
908
+ const row = this._sorting.getDataIndex(rowIndex);
909
+ const obj = this._rows.value[row];
910
+ const objectsToDelete = [];
911
+ if (this.features.selection.enabled && this._selection.hasSelection.value) {
912
+ const selectedRows = this._selection.getSelectedRows();
913
+ objectsToDelete.push(...selectedRows);
914
+ } else {
915
+ objectsToDelete.push(obj);
916
+ }
917
+ this._onDeleteRows?.(row, objectsToDelete);
918
+ };
919
+ handleRowAction = (actionId, rowIndex) => {
920
+ if (!this._onRowAction) {
921
+ return;
922
+ }
923
+ const row = this._sorting.getDataIndex(rowIndex);
924
+ const data = this._rows.value[row];
925
+ if (data) {
926
+ this._onRowAction(actionId, data);
927
+ }
928
+ };
929
+ getCellData = (cell) => {
930
+ const { col, row, plane } = cell;
931
+ const fields = this._projection?.fields ?? [];
932
+ if (col < 0 || col >= fields.length) {
933
+ return void 0;
934
+ }
935
+ const field = fields[col];
936
+ let value;
937
+ if (plane === "frozenRowsEnd") {
938
+ if (row >= 0 && row < this._draftRows.value.length) {
939
+ value = getValue2(this._draftRows.value[row].data, field.path);
940
+ } else {
941
+ return void 0;
942
+ }
943
+ } else {
944
+ const dataIndex = this._sorting.getDataIndex(row);
945
+ value = getValue2(this._rows.value[dataIndex], field.path);
946
+ }
947
+ if (value == null) {
948
+ return "";
949
+ }
950
+ const { props } = this._projection.getFieldProjection(field.id);
951
+ switch (props.format) {
952
+ case FormatEnum2.Ref: {
953
+ if (!field.referencePath) {
954
+ return "";
955
+ }
956
+ return getValue2(value.target, field.referencePath);
957
+ }
958
+ default: {
959
+ return formatForEditing({
960
+ type: props.type,
961
+ format: props.format,
962
+ value
963
+ });
964
+ }
965
+ }
966
+ };
967
+ validateCellData = async ({ col, row, plane }, value) => {
968
+ const fields = this._projection?.fields ?? [];
969
+ if (col < 0 || col >= fields.length) {
970
+ return {
971
+ valid: false,
972
+ error: "Invalid column index"
973
+ };
974
+ }
975
+ const field = fields[col];
976
+ const { props } = this._projection.getFieldProjection(field.id);
977
+ const transformedValue = editorTextToCellValue(props, value);
978
+ const isDraftRow = plane === "frozenRowsEnd";
979
+ if (isDraftRow) {
980
+ const isInvalidDraftRowIndex = row < 0 || row >= this._draftRows.value.length;
981
+ if (isInvalidDraftRowIndex) {
982
+ return {
983
+ valid: false,
984
+ error: "Invalid draft row index"
985
+ };
986
+ }
987
+ const draftRow = this._draftRows.value[row];
988
+ const snapshot = {
989
+ ...draftRow.data
990
+ };
991
+ setValue(snapshot, field.path, transformedValue);
992
+ const validationErrors = this.validateDraftRowData(snapshot);
993
+ if (validationErrors.length > 0) {
994
+ const error = validationErrors.find((err) => err.path === field.path);
995
+ if (error) {
996
+ return {
997
+ valid: false,
998
+ error: error.message
999
+ };
1000
+ }
1001
+ }
1002
+ return {
1003
+ valid: true
1004
+ };
1005
+ } else {
1006
+ const rowIdx = this._sorting.getDataIndex(row);
1007
+ const currentRow = this._rows.value[rowIdx];
1008
+ invariant(currentRow, "Invalid row index", {
1009
+ F: __dxlog_file,
1010
+ L: 513,
1011
+ S: this,
1012
+ A: [
1013
+ "currentRow",
1014
+ "'Invalid row index'"
1015
+ ]
1016
+ });
1017
+ const snapshot = getSnapshot(currentRow);
1018
+ setValue(snapshot, field.path, transformedValue);
1019
+ const schema = getSchema(currentRow);
1020
+ invariant(schema, void 0, {
1021
+ F: __dxlog_file,
1022
+ L: 519,
1023
+ S: this,
1024
+ A: [
1025
+ "schema",
1026
+ ""
1027
+ ]
1028
+ });
1029
+ const validationResult = validateSchema(schema, snapshot);
1030
+ if (validationResult && validationResult.length > 0) {
1031
+ const error = validationResult[0];
1032
+ invariant(error.path === field.path, void 0, {
1033
+ F: __dxlog_file,
1034
+ L: 524,
1035
+ S: this,
1036
+ A: [
1037
+ "error.path === field.path",
1038
+ ""
1039
+ ]
1040
+ });
1041
+ return {
1042
+ valid: false,
1043
+ error: error.message
1044
+ };
1045
+ }
1046
+ return {
1047
+ valid: true
1048
+ };
1049
+ }
1050
+ };
1051
+ setCellData = (cell, value) => {
1052
+ const { col, row, plane } = cell;
1053
+ const fields = this._projection?.fields ?? [];
1054
+ if (col < 0 || col >= fields.length) {
1055
+ return;
1056
+ }
1057
+ const field = fields[col];
1058
+ const { props } = this._projection.getFieldProjection(field.id);
1059
+ const transformedValue = editorTextToCellValue(props, value);
1060
+ if (props.format === FormatEnum2.Ref && !isLiveObject(value)) {
1061
+ return;
1062
+ }
1063
+ if (plane === "frozenRowsEnd") {
1064
+ if (row >= 0 && row < this._draftRows.value.length) {
1065
+ setValue(this._draftRows.value[row].data, field.path, transformedValue);
1066
+ this.validateDraftRow(row);
1067
+ }
1068
+ } else {
1069
+ const rowIdx = this._sorting.getDataIndex(row);
1070
+ setValue(this._rows.value[rowIdx], field.path, transformedValue);
1071
+ }
1072
+ };
1031
1073
  /**
1032
1074
  * Updates a cell's value using a transform function.
1033
1075
  * @param {DxGridPlanePosition} position - The position of the cell to update.
@@ -1145,99 +1187,100 @@ import { signal as signal4 } from "@preact/signals-core";
1145
1187
  import { log } from "@dxos/log";
1146
1188
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
1147
1189
  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
- };
1190
+ _state = signal4({
1191
+ type: "closed"
1192
+ });
1193
+ _triggerRef = {
1194
+ current: null
1195
+ };
1196
+ get state() {
1197
+ return this._state;
1198
+ }
1199
+ get trigger() {
1200
+ return this._triggerRef;
1201
+ }
1202
+ setTrigger = (trigger) => {
1203
+ this._triggerRef.current = trigger;
1204
+ };
1205
+ showRowMenu = (rowIndex) => {
1206
+ this._state.value = {
1207
+ type: "row",
1208
+ rowIndex
1177
1209
  };
1178
- this.showReferencePanel = (targetId, schemaId) => {
1179
- this._state.value = {
1180
- type: "refPanel",
1181
- targetId,
1182
- typename: schemaId
1183
- };
1210
+ };
1211
+ showColumnMenu = (fieldId) => {
1212
+ this._state.value = {
1213
+ type: "column",
1214
+ fieldId
1184
1215
  };
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
- });
1216
+ };
1217
+ showColumnCreator = () => {
1218
+ this._state.value = {
1219
+ type: "columnSettings",
1220
+ mode: {
1221
+ type: "create"
1197
1222
  }
1198
1223
  };
1199
- this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1200
- if (anchorCell) {
1201
- this._triggerRef.current = anchorCell;
1224
+ };
1225
+ showReferencePanel = (targetId, schemaId) => {
1226
+ this._state.value = {
1227
+ type: "refPanel",
1228
+ targetId,
1229
+ typename: schemaId
1230
+ };
1231
+ };
1232
+ openColumnSettings = () => {
1233
+ if (this._state.value.type === "column") {
1234
+ const fieldId = this._state.value.fieldId;
1235
+ requestAnimationFrame(() => {
1202
1236
  this._state.value = {
1203
- type: "createRefPanel",
1204
- typename,
1205
- initialValues,
1206
- onCreate
1237
+ type: "columnSettings",
1238
+ mode: {
1239
+ type: "edit",
1240
+ fieldId
1241
+ }
1207
1242
  };
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 = () => {
1243
+ });
1244
+ }
1245
+ };
1246
+ openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
1247
+ if (anchorCell) {
1248
+ this._triggerRef.current = anchorCell;
1218
1249
  this._state.value = {
1219
- type: "closed"
1250
+ type: "createRefPanel",
1251
+ typename,
1252
+ initialValues,
1253
+ onCreate
1220
1254
  };
1255
+ } else {
1256
+ log.warn("anchor cell not found while creating new ref", void 0, {
1257
+ F: __dxlog_file2,
1258
+ L: 86,
1259
+ S: this,
1260
+ C: (f, a) => f(...a)
1261
+ });
1262
+ }
1263
+ };
1264
+ close = () => {
1265
+ this._state.value = {
1266
+ type: "closed"
1221
1267
  };
1222
- }
1223
- get state() {
1224
- return this._state;
1225
- }
1226
- get trigger() {
1227
- return this._triggerRef;
1228
- }
1268
+ };
1229
1269
  };
1230
1270
 
1231
1271
  // src/model/table-presentation.ts
1232
1272
  import { signal as signal5 } from "@preact/signals-core";
1233
1273
  import { isNotNullable } from "effect/Predicate";
1234
1274
  import { Obj as Obj4 } from "@dxos/echo";
1235
- import { FormatEnum as FormatEnum3, getValue as getValue3, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
1275
+ import { FormatEnum as FormatEnum3, TypeEnum as TypeEnum2, getValue as getValue3 } from "@dxos/echo-schema";
1236
1276
  import { cellClassesForFieldType, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
1237
1277
  import { toPlaneCellIndex } from "@dxos/react-ui-grid";
1238
1278
  import { mx } from "@dxos/react-ui-theme";
1239
1279
  import { VIEW_FIELD_LIMIT } from "@dxos/schema";
1240
1280
  var TablePresentation = class {
1281
+ model;
1282
+ _visibleRange;
1283
+ fieldProjectionCache;
1241
1284
  constructor(model, _visibleRange = signal5({
1242
1285
  start: {
1243
1286
  row: 0,
@@ -1278,6 +1321,9 @@ var TablePresentation = class {
1278
1321
  case "frozenRowsEnd":
1279
1322
  cells = this.getDraftRowCells(range);
1280
1323
  break;
1324
+ case "fixedEndStart":
1325
+ cells = this.getDraftSelectCells(range);
1326
+ break;
1281
1327
  case "fixedEndEnd":
1282
1328
  cells = this.getDraftActionCells(range);
1283
1329
  break;
@@ -1381,7 +1427,7 @@ var TablePresentation = class {
1381
1427
  const targetObj = getValue3(obj, field.path)?.target;
1382
1428
  if (targetObj) {
1383
1429
  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>`;
1430
+ 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>`;
1385
1431
  }
1386
1432
  }
1387
1433
  if (props.format === FormatEnum3.Boolean) {
@@ -1446,16 +1492,16 @@ var TablePresentation = class {
1446
1492
  for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1447
1493
  const draftRow = draftRows[row];
1448
1494
  for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
1495
+ const cellIndex = toPlaneCellIndex({
1496
+ col,
1497
+ row
1498
+ });
1449
1499
  const field = fields[col];
1450
1500
  if (!field) {
1451
1501
  continue;
1452
1502
  }
1453
1503
  this.createDataCell(cells, draftRow.data, field, col, row);
1454
1504
  if (this.model.hasDraftRowValidationError(row, field.path)) {
1455
- const cellIndex = toPlaneCellIndex({
1456
- col,
1457
- row
1458
- });
1459
1505
  const cellValue = cells[cellIndex];
1460
1506
  if (cellValue) {
1461
1507
  const existingClasses = cellValue.className || "";
@@ -1463,6 +1509,7 @@ var TablePresentation = class {
1463
1509
  cellValue.className = existingClasses ? `${existingClasses} ${draftClasses}` : draftClasses;
1464
1510
  }
1465
1511
  }
1512
+ cells[cellIndex].className += " !bg-toolbarSurface";
1466
1513
  }
1467
1514
  }
1468
1515
  return cells;
@@ -1594,7 +1641,23 @@ var TablePresentation = class {
1594
1641
  accessoryHtml: tableButtons.saveDraftRow.render({
1595
1642
  rowIndex: row,
1596
1643
  disabled
1597
- })
1644
+ }),
1645
+ className: "!bg-toolbarSurface"
1646
+ };
1647
+ }
1648
+ return cells;
1649
+ }
1650
+ getDraftSelectCells(range) {
1651
+ const cells = {};
1652
+ const draftRows = this.model.draftRows.value;
1653
+ for (let row = range.start.row; row <= range.end.row && row < draftRows.length; row++) {
1654
+ cells[toPlaneCellIndex({
1655
+ col: 0,
1656
+ row
1657
+ })] = {
1658
+ value: "",
1659
+ readonly: true,
1660
+ className: "!bg-toolbarSurface"
1598
1661
  };
1599
1662
  }
1600
1663
  return cells;
@@ -1749,4 +1812,4 @@ export {
1749
1812
  useTableModel,
1750
1813
  useAddRow
1751
1814
  };
1752
- //# sourceMappingURL=chunk-Y66YLSTC.mjs.map
1815
+ //# sourceMappingURL=chunk-ZOFFI3JJ.mjs.map