@dxos/react-ui-table 0.8.4-main.c4373fc → 0.8.4-main.d05673bc65

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 (136) hide show
  1. package/dist/lib/browser/chunk-BF54SSNL.mjs +70 -0
  2. package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-PTHMYAAM.mjs +1751 -0
  4. package/dist/lib/browser/chunk-PTHMYAAM.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1158 -1024
  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 +30 -42
  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-GI72MQSG.mjs +1753 -0
  12. package/dist/lib/node-esm/chunk-GI72MQSG.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs +71 -0
  14. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +1158 -1024
  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 +30 -42
  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 -2
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +2 -2
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
  26. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +4 -18
  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 +12 -9
  30. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  32. package/dist/types/src/components/Table/Table.d.ts +11 -11
  33. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  34. package/dist/types/src/components/Table/Table.stories.d.ts +71 -5
  35. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
  37. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +10 -12
  38. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  39. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -7
  40. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  41. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +4 -4
  42. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  43. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +5 -5
  44. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  45. package/dist/types/src/components/testing.d.ts +22 -15
  46. package/dist/types/src/components/testing.d.ts.map +1 -1
  47. package/dist/types/src/hooks/index.d.ts +2 -1
  48. package/dist/types/src/hooks/index.d.ts.map +1 -1
  49. package/dist/types/src/hooks/useAddRow.d.ts +5 -6
  50. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  51. package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
  52. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
  53. package/dist/types/src/hooks/useTableModel.d.ts +9 -9
  54. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  55. package/dist/types/src/model/modal-controller.d.ts +5 -1
  56. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  57. package/dist/types/src/model/selection-model.d.ts +17 -8
  58. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  59. package/dist/types/src/model/table-model.d.ts +105 -25
  60. package/dist/types/src/model/table-model.d.ts.map +1 -1
  61. package/dist/types/src/model/table-presentation.d.ts +3 -1
  62. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  63. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  64. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  65. package/dist/types/src/testing/useTestTableModel.d.ts +18 -15
  66. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  67. package/dist/types/src/translations.d.ts +4 -4
  68. package/dist/types/src/translations.d.ts.map +1 -1
  69. package/dist/types/src/types/Table.d.ts +26 -0
  70. package/dist/types/src/types/Table.d.ts.map +1 -0
  71. package/dist/types/src/types/index.d.ts +1 -1
  72. package/dist/types/src/types/index.d.ts.map +1 -1
  73. package/dist/types/src/util/dynamic-table.d.ts +14 -11
  74. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  75. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  76. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  77. package/dist/types/src/util/index.d.ts +2 -0
  78. package/dist/types/src/util/index.d.ts.map +1 -1
  79. package/dist/types/src/util/query-ast.d.ts +7 -0
  80. package/dist/types/src/util/query-ast.d.ts.map +1 -0
  81. package/dist/types/src/util/sort.d.ts +12 -0
  82. package/dist/types/src/util/sort.d.ts.map +1 -0
  83. package/dist/types/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +54 -54
  85. package/src/components/Table/ColumnActionsMenu.tsx +10 -6
  86. package/src/components/Table/ColumnSettings.tsx +8 -9
  87. package/src/components/Table/DynamicTable.stories.tsx +16 -16
  88. package/src/components/Table/DynamicTable.tsx +30 -22
  89. package/src/components/Table/Relations.stories.tsx +52 -60
  90. package/src/components/Table/RowActionsMenu.tsx +24 -15
  91. package/src/components/Table/Table.stories.tsx +116 -98
  92. package/src/components/Table/Table.tsx +324 -299
  93. package/src/components/TableCellEditor/CellValidationMessage.tsx +5 -5
  94. package/src/components/TableCellEditor/FormCellEditor.tsx +117 -134
  95. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +18 -13
  96. package/src/components/TableCellEditor/TableCellEditor.tsx +31 -31
  97. package/src/components/TableToolbar/TableToolbar.tsx +53 -37
  98. package/src/components/testing.ts +38 -12
  99. package/src/hooks/index.ts +2 -1
  100. package/src/hooks/useAddRow.ts +8 -10
  101. package/src/hooks/useProjectionModel.ts +39 -0
  102. package/src/hooks/useTableModel.ts +36 -34
  103. package/src/model/modal-controller.ts +23 -12
  104. package/src/model/selection-model.ts +75 -44
  105. package/src/model/table-model.test.ts +82 -54
  106. package/src/model/table-model.ts +436 -170
  107. package/src/model/table-presentation.test.ts +59 -49
  108. package/src/model/table-presentation.ts +43 -37
  109. package/src/playwright/TableManager.ts +13 -6
  110. package/src/playwright/playwright.config.ts +1 -1
  111. package/src/playwright/smoke.spec.ts +56 -10
  112. package/src/testing/useTestTableModel.ts +45 -38
  113. package/src/translations.ts +3 -3
  114. package/src/types/Table.ts +79 -0
  115. package/src/types/index.ts +1 -1
  116. package/src/util/dynamic-table.test.ts +70 -0
  117. package/src/util/dynamic-table.ts +41 -28
  118. package/src/util/index.ts +2 -0
  119. package/src/util/query-ast.ts +22 -0
  120. package/src/util/sort.ts +90 -0
  121. package/src/util/table-buttons.ts +1 -1
  122. package/src/util/table-controls.ts +2 -2
  123. package/dist/lib/browser/chunk-4K7JPALT.mjs +0 -66
  124. package/dist/lib/browser/chunk-4K7JPALT.mjs.map +0 -7
  125. package/dist/lib/browser/chunk-OZTXLZGM.mjs +0 -1804
  126. package/dist/lib/browser/chunk-OZTXLZGM.mjs.map +0 -7
  127. package/dist/lib/node-esm/chunk-MK6OVUF6.mjs +0 -67
  128. package/dist/lib/node-esm/chunk-MK6OVUF6.mjs.map +0 -7
  129. package/dist/lib/node-esm/chunk-S56Z4V4X.mjs +0 -1805
  130. package/dist/lib/node-esm/chunk-S56Z4V4X.mjs.map +0 -7
  131. package/dist/types/src/model/table-sorting.d.ts +0 -52
  132. package/dist/types/src/model/table-sorting.d.ts.map +0 -1
  133. package/dist/types/src/types/schema.d.ts +0 -28
  134. package/dist/types/src/types/schema.d.ts.map +0 -1
  135. package/src/model/table-sorting.ts +0 -225
  136. package/src/types/schema.ts +0 -73
@@ -2,90 +2,120 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type ReadonlySignal, type Signal, computed, effect, signal } from '@preact/signals-core';
5
+ import { Atom, type Registry } from '@effect-atom/atom-react';
6
6
 
7
7
  import { Resource } from '@dxos/context';
8
8
 
9
- import { touch } from '../util';
10
-
11
9
  import { type TableRow } from './table-model';
12
10
 
13
11
  export type SelectionMode = 'single' | 'multiple';
14
12
 
15
13
  export class SelectionModel<T extends TableRow> extends Resource {
16
- private readonly _selection: Signal<Set<string>>;
14
+ private readonly _registry: Registry.Registry;
15
+ private readonly _rows: Atom.Atom<T[]>;
16
+ private readonly _selection: Atom.Writable<Set<string>>;
17
+ private readonly _validSelectedIds: Atom.Atom<Set<string>>;
18
+ private readonly _hasSelection: Atom.Atom<boolean>;
19
+ private readonly _allSelected: Atom.Atom<boolean>;
20
+ private readonly _selectionMode: SelectionMode;
21
+ private readonly _onSelectionChanged?: () => void;
17
22
 
18
- private readonly _validSelectedIds = computed<Set<string>>(() => {
19
- const rows = this._rows.value;
20
- if (!rows) {
21
- return new Set<string>();
22
- }
23
+ constructor(
24
+ registry: Registry.Registry,
25
+ rows: Atom.Atom<T[]>,
26
+ selectionMode: SelectionMode,
27
+ initialSelection: string[],
28
+ onSelectionChanged?: () => void,
29
+ ) {
30
+ super();
31
+ this._registry = registry;
32
+ this._rows = rows;
33
+ this._selectionMode = selectionMode;
34
+ this._onSelectionChanged = onSelectionChanged;
23
35
 
24
- const validIds = new Set(rows.map((row) => row.id));
25
- return new Set([...this._selection.value].filter((id) => validIds.has(id)));
26
- });
36
+ this._selection = Atom.make<Set<string>>(new Set(initialSelection));
27
37
 
28
- private readonly _hasSelection = computed<boolean>(() => this._validSelectedIds.value.size > 0);
38
+ this._validSelectedIds = Atom.make((get) => {
39
+ const rows = get(this._rows);
40
+ if (!rows) {
41
+ return new Set<string>();
42
+ }
29
43
 
30
- private readonly _allSelected = computed<boolean>(() => {
31
- const rows = this._rows.value;
32
- if (rows.length === 0) {
33
- return false;
34
- }
44
+ const validIds = new Set(rows.map((row) => row.id));
45
+ const selection = get(this._selection);
46
+ return new Set([...selection].filter((id) => validIds.has(id)));
47
+ });
35
48
 
36
- return rows.every((row) => this._selection.value.has(row.id));
37
- });
49
+ this._hasSelection = Atom.make((get) => get(this._validSelectedIds).size > 0);
38
50
 
39
- constructor(
40
- private readonly _rows: ReadonlySignal<T[]>,
41
- private readonly _selectionMode: SelectionMode,
42
- private readonly _initialSelection: string[],
43
- private readonly _onSelectionChanged?: () => void,
44
- ) {
45
- super();
46
- this._selection = signal(new Set(this._initialSelection));
51
+ this._allSelected = Atom.make((get) => {
52
+ const rows = get(this._rows);
53
+ if (rows.length === 0) {
54
+ return false;
55
+ }
56
+
57
+ const selection = get(this._selection);
58
+ return rows.every((row) => selection.has(row.id));
59
+ });
47
60
  }
48
61
 
49
62
  protected override async _open(): Promise<void> {
50
- const selectionWatcher = effect(() => {
51
- touch(this._selection.value);
63
+ const selectionUnsubscribe = this._registry.subscribe(this._selection, () => {
52
64
  this._onSelectionChanged?.();
53
65
  });
54
- this._ctx.onDispose(selectionWatcher);
66
+ this._ctx.onDispose(selectionUnsubscribe);
55
67
  }
56
68
 
57
69
  //
58
70
  // Getters
59
71
  //
60
72
 
61
- public get selection(): ReadonlySignal<Set<string>> {
73
+ /** Get the selection atom for reactive access. */
74
+ public get selectionAtom(): Atom.Atom<Set<string>> {
62
75
  return this._selection;
63
76
  }
64
77
 
65
- public get hasSelection(): ReadonlySignal<boolean> {
78
+ /** Get the current selection value. */
79
+ public get selection(): Set<string> {
80
+ return this._registry.get(this._selection);
81
+ }
82
+
83
+ /** Get the hasSelection atom for reactive access. */
84
+ public get hasSelectionAtom(): Atom.Atom<boolean> {
66
85
  return this._hasSelection;
67
86
  }
68
87
 
69
- public get allRowsSeleted(): ReadonlySignal<boolean> {
88
+ /** Check if there is any selection. */
89
+ public get hasSelection(): boolean {
90
+ return this._registry.get(this._hasSelection);
91
+ }
92
+
93
+ /** Get the allRowsSelected atom for reactive access. */
94
+ public get allRowsSelectedAtom(): Atom.Atom<boolean> {
70
95
  return this._allSelected;
71
96
  }
72
97
 
98
+ /** Check if all rows are selected. */
99
+ public get allRowsSelected(): boolean {
100
+ return this._registry.get(this._allSelected);
101
+ }
102
+
73
103
  public get selectionMode(): SelectionMode {
74
104
  return this._selectionMode;
75
105
  }
76
106
 
77
107
  public getSelectedRows = (): T[] => {
78
- const selectedIds = this._validSelectedIds.value;
79
- return this._rows.value.filter((row) => selectedIds.has(row.id));
108
+ const selectedIds = this._registry.get(this._validSelectedIds);
109
+ return this._registry.get(this._rows).filter((row) => selectedIds.has(row.id));
80
110
  };
81
111
 
82
112
  public isRowIndexSelected = (rowIndex: number): boolean => {
83
- const row = this._rows.value[rowIndex];
84
- return this._selection.value.has(row.id);
113
+ const row = this._registry.get(this._rows)[rowIndex];
114
+ return this._registry.get(this._selection).has(row.id);
85
115
  };
86
116
 
87
117
  public isObjectSelected = (object: T): boolean => {
88
- return this._selection.value.has(object.id);
118
+ return this._registry.get(this._selection).has(object.id);
89
119
  };
90
120
 
91
121
  //
@@ -93,8 +123,9 @@ export class SelectionModel<T extends TableRow> extends Resource {
93
123
  //
94
124
 
95
125
  public toggleSelectionForRowIndex = (rowIndex: number): void => {
96
- const row = this._rows.value[rowIndex];
97
- const newSelection = new Set(this._selection.value);
126
+ const row = this._registry.get(this._rows)[rowIndex];
127
+ const currentSelection = this._registry.get(this._selection);
128
+ const newSelection = new Set(currentSelection);
98
129
 
99
130
  if (newSelection.has(row.id)) {
100
131
  newSelection.delete(row.id);
@@ -105,17 +136,17 @@ export class SelectionModel<T extends TableRow> extends Resource {
105
136
  newSelection.add(row.id);
106
137
  }
107
138
 
108
- this._selection.value = newSelection;
139
+ this._registry.set(this._selection, newSelection);
109
140
  };
110
141
 
111
142
  public setSelection = (mode: 'all' | 'none'): void => {
112
143
  switch (mode) {
113
144
  case 'all': {
114
- this._selection.value = new Set(this._rows.value.map((row) => row.id));
145
+ this._registry.set(this._selection, new Set(this._registry.get(this._rows).map((row) => row.id)));
115
146
  break;
116
147
  }
117
148
  case 'none': {
118
- this._selection.value = new Set();
149
+ this._registry.set(this._selection, new Set());
119
150
  break;
120
151
  }
121
152
  }
@@ -2,34 +2,34 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { computed } from '@preact/signals-core';
5
+ import { Registry } from '@effect-atom/atom-react';
6
6
  import * as Schema from 'effect/Schema';
7
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
7
+ import { afterEach, beforeEach, describe, expect, test } from 'vitest';
8
8
 
9
- import { Filter, Query } from '@dxos/echo';
10
- import { TypedObject } from '@dxos/echo/internal';
11
- import { updateCounter } from '@dxos/echo/testing';
9
+ import { Filter, JsonSchema, Query, Type } from '@dxos/echo';
12
10
  import { createEchoSchema } from '@dxos/echo/testing';
13
- import { registerSignalsRuntime } from '@dxos/echo-signals';
14
- import { live } from '@dxos/live-object';
15
- import { createView } from '@dxos/schema';
11
+ import { ProjectionModel, ViewModel, createDirectChangeCallback } from '@dxos/schema';
16
12
 
17
13
  import { Table } from '../types';
18
14
 
19
- import { TableModel, type TableModelProps } from './table-model';
15
+ import {
16
+ TableModel,
17
+ type TableModelProps,
18
+ createDirectChangeCallback as createTableDirectChangeCallback,
19
+ } from './table-model';
20
20
 
21
21
  // TODO(burdon): Tests are disabled in project.json since they bring in plugin deps.
22
22
  // Restore once factored out into react-ui-table.
23
23
 
24
- registerSignalsRuntime();
25
-
26
24
  describe('TableModel', () => {
27
25
  let updateCount = 0;
28
26
  let model: any;
27
+ let registry: Registry.Registry;
29
28
 
30
29
  beforeEach(async () => {
31
30
  updateCount = 0;
32
- model = createTableModel({
31
+ registry = Registry.make();
32
+ model = createTableModel(registry, {
33
33
  onCellUpdate: () => updateCount++,
34
34
  });
35
35
  await model.open();
@@ -45,78 +45,106 @@ describe('TableModel', () => {
45
45
  });
46
46
 
47
47
  describe('methods', () => {
48
- it('should pin a row', () => {
48
+ test('should pin a row', () => {
49
49
  model.pinRow(1, 'top');
50
50
  expect(model.pinnedRows.top).toContain(1);
51
51
  });
52
52
 
53
- it('should unpin a row', () => {
53
+ test('should unpin a row', () => {
54
54
  model.pinRow(1, 'top');
55
55
  model.unpinRow(1);
56
56
  expect(model.pinnedRows.top).not.toContain(1);
57
57
  });
58
58
 
59
- it('should toggle row selection', () => {
59
+ test('should toggle row selection', () => {
60
60
  model.selection.toggleSelectionForRowIndex(2);
61
- expect(model.selection.hasSelection.value).toBe(true);
61
+ expect(model.selection.hasSelection).toBe(true);
62
62
  });
63
63
 
64
- it('should deselect a row', () => {
64
+ test('should deselect a row', () => {
65
65
  model.selection.toggleSelectionForRowIndex(2);
66
66
  model.selection.toggleSelectionForRowIndex(2);
67
- expect(model.selection.hasSelection.value).toBe(false);
67
+ expect(model.selection.hasSelection).toBe(false);
68
68
  });
69
69
 
70
- it('should bulk select rows', () => {
70
+ test('should bulk select rows', () => {
71
71
  model.selection.setSelection('all');
72
- expect(model.selection.allRowsSeleted.value).toBe(true);
72
+ expect(model.selection.allRowsSelected).toBe(true);
73
73
  model.selection.setSelection('none');
74
- expect(model.selection.hasSelection.value).toBe(false);
74
+ expect(model.selection.hasSelection).toBe(false);
75
75
  });
76
76
  });
77
77
 
78
78
  describe('reactivity', () => {
79
- it('pure signals should nest', () => {
80
- const signal$ = live({ arr: [{ thingInside: 1 }, { thingInside: 2 }] });
81
- const computed$ = computed(() => {
82
- return signal$.arr.map((row) =>
83
- computed(() => {
84
- return row.thingInside;
85
- }),
86
- );
87
- });
88
-
89
- using outerCounter = updateCounter(() => {
90
- computed$.value.map((c) => c.value);
91
- });
92
-
93
- using innerCounter = updateCounter(() => {
94
- computed$.value[0].value;
95
- });
96
-
97
- expect(computed$.value.map((v) => v.value)).toEqual([1, 2]);
98
-
99
- signal$.arr[0].thingInside = 3;
100
-
101
- expect(computed$.value.map((v) => v.value)).toEqual([3, 2]);
102
- expect(outerCounter.count).toBe(1);
103
- expect(innerCounter.count).toBe(1);
79
+ test('rows should update when setRows is called', () => {
80
+ model.setRows([{ id: '4', title: 'Test 4', completed: false }]);
81
+ expect(model.getRows()).toHaveLength(1);
82
+ expect(model.getRows()[0].id).toBe('4');
83
+
84
+ model.setRows([
85
+ { id: '5', title: 'Test 5', completed: false },
86
+ { id: '6', title: 'Test 6', completed: true },
87
+ ]);
88
+ expect(model.getRows()).toHaveLength(2);
89
+ expect(model.getRows()[0].id).toBe('5');
90
+ expect(model.getRows()[1].id).toBe('6');
91
+ });
92
+
93
+ test('selection should update when toggled', () => {
94
+ model.selection.toggleSelectionForRowIndex(0);
95
+ expect(model.selection.hasSelection).toBe(true);
96
+ expect(model.selection.selection.size).toBe(1);
97
+
98
+ model.selection.toggleSelectionForRowIndex(0);
99
+ expect(model.selection.hasSelection).toBe(false);
100
+ expect(model.selection.selection.size).toBe(0);
101
+ });
102
+
103
+ test('derived atoms should reflect current state', () => {
104
+ // Set initial rows.
105
+ model.setRows([
106
+ { id: '1', title: 'Zebra', completed: false },
107
+ { id: '2', title: 'Apple', completed: true },
108
+ { id: '3', title: 'Mango', completed: false },
109
+ ]);
110
+
111
+ // Verify rows are accessible.
112
+ const rows = model.getRows();
113
+ expect(rows).toHaveLength(3);
114
+ expect(rows[0].id).toBeDefined();
104
115
  });
105
116
  });
106
117
  });
107
118
 
108
- class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
119
+ const Test = Schema.Struct({
109
120
  title: Schema.String,
110
121
  completed: Schema.Boolean,
111
- }) {}
112
-
113
- const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
122
+ }).pipe(
123
+ Type.object({
124
+ typename: 'com.example.type.test',
125
+ version: '0.1.0',
126
+ }),
127
+ );
128
+
129
+ const createTableModel = (registry: Registry.Registry, props: Partial<TableModelProps> = {}): TableModel => {
114
130
  const schema = createEchoSchema(Test);
115
- const table = Table.make();
116
- const view = createView({
131
+ const view = ViewModel.make({
117
132
  query: Query.select(Filter.type(schema)),
118
133
  jsonSchema: schema.jsonSchema,
119
- presentation: table,
120
134
  });
121
- return new TableModel({ view, schema: schema.jsonSchema, ...props });
135
+ const object = Table.make({ view });
136
+ const projection = new ProjectionModel({
137
+ registry,
138
+ view,
139
+ baseSchema: schema.jsonSchema,
140
+ change: createDirectChangeCallback(view.projection, JsonSchema.toJsonSchema(schema)),
141
+ });
142
+ projection.normalizeView();
143
+ return new TableModel({
144
+ registry,
145
+ object,
146
+ projection,
147
+ change: createTableDirectChangeCallback(object),
148
+ ...props,
149
+ });
122
150
  };