@dxos/react-ui-table 0.8.4-main.5ea62a8 → 0.8.4-main.ae835ea

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/lib/browser/{chunk-63UUF4IG.mjs → chunk-4K7JPALT.mjs} +5 -5
  2. package/dist/lib/browser/chunk-4K7JPALT.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-RQYXNWWN.mjs → chunk-G7MGPBSR.mjs} +444 -490
  4. package/dist/lib/browser/chunk-G7MGPBSR.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +132 -283
  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 +9 -6
  9. package/dist/lib/browser/testing/index.mjs.map +3 -3
  10. package/dist/lib/browser/types/index.mjs +1 -1
  11. package/dist/lib/node-esm/{chunk-QNDUGIS7.mjs → chunk-LD5JEBA6.mjs} +444 -490
  12. package/dist/lib/node-esm/chunk-LD5JEBA6.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-K734DJB7.mjs → chunk-MK6OVUF6.mjs} +5 -5
  14. package/dist/lib/node-esm/chunk-MK6OVUF6.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +132 -283
  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 +9 -6
  19. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/types/index.mjs +1 -1
  21. package/dist/types/src/components/Table/DynamicTable.d.ts +2 -2
  22. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +3 -3
  24. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/Relations.stories.d.ts +71 -7
  26. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/Table.d.ts +5 -2
  28. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Table.stories.d.ts +5 -6
  30. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +7 -5
  32. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  33. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -3
  34. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +1 -2
  36. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
  38. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -1
  39. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  40. package/dist/types/src/components/testing.d.ts +3 -3
  41. package/dist/types/src/components/testing.d.ts.map +1 -1
  42. package/dist/types/src/hooks/useAddRow.d.ts +1 -1
  43. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useTableModel.d.ts +1 -1
  45. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  46. package/dist/types/src/model/modal-controller.d.ts +0 -7
  47. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  48. package/dist/types/src/model/table-model.d.ts +2 -2
  49. package/dist/types/src/model/table-model.d.ts.map +1 -1
  50. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  51. package/dist/types/src/model/table-sorting.d.ts +1 -2
  52. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  53. package/dist/types/src/testing/useTestTableModel.d.ts +3 -17
  54. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  55. package/dist/types/src/types/schema.d.ts +3 -3
  56. package/dist/types/src/types/schema.d.ts.map +1 -1
  57. package/dist/types/src/util/dynamic-table.d.ts +4 -5
  58. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  59. package/dist/types/src/util/schema.d.ts +1 -1
  60. package/dist/types/src/util/schema.d.ts.map +1 -1
  61. package/dist/types/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +51 -51
  63. package/src/components/Table/DynamicTable.stories.tsx +8 -7
  64. package/src/components/Table/DynamicTable.tsx +4 -7
  65. package/src/components/Table/Relations.stories.tsx +119 -11
  66. package/src/components/Table/Table.stories.tsx +36 -35
  67. package/src/components/Table/Table.tsx +13 -9
  68. package/src/components/TableCellEditor/FormCellEditor.tsx +51 -41
  69. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +17 -45
  70. package/src/components/TableCellEditor/TableCellEditor.tsx +17 -112
  71. package/src/components/TableCellEditor/index.ts +1 -0
  72. package/src/components/TableToolbar/TableToolbar.tsx +3 -0
  73. package/src/components/testing.ts +2 -2
  74. package/src/hooks/useAddRow.ts +1 -1
  75. package/src/hooks/useTableModel.ts +1 -1
  76. package/src/model/modal-controller.ts +0 -28
  77. package/src/model/table-model.test.ts +16 -6
  78. package/src/model/table-model.ts +10 -3
  79. package/src/model/table-presentation.test.ts +19 -17
  80. package/src/model/table-presentation.ts +4 -5
  81. package/src/model/table-sorting.ts +15 -6
  82. package/src/playwright/smoke.spec.ts +3 -3
  83. package/src/testing/useTestTableModel.ts +7 -4
  84. package/src/types/schema.ts +4 -4
  85. package/src/util/dynamic-table.ts +8 -8
  86. package/src/util/schema.ts +4 -4
  87. package/dist/lib/browser/chunk-63UUF4IG.mjs.map +0 -7
  88. package/dist/lib/browser/chunk-RQYXNWWN.mjs.map +0 -7
  89. package/dist/lib/node-esm/chunk-K734DJB7.mjs.map +0 -7
  90. package/dist/lib/node-esm/chunk-QNDUGIS7.mjs.map +0 -7
  91. package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
  92. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
  93. package/src/components/Table/CreateRefPanel.tsx +0 -103
@@ -5,21 +5,12 @@
5
5
  import { signal } from '@preact/signals-core';
6
6
  import { type MutableRefObject, type RefObject } from 'react';
7
7
 
8
- import { type Live } from '@dxos/live-object';
9
- import { log } from '@dxos/log';
10
-
11
8
  export type ColumnSettingsMode = { type: 'create' } | { type: 'edit'; fieldId: string };
12
9
 
13
10
  export type ModalState =
14
11
  | { type: 'row'; rowIndex: number }
15
12
  | { type: 'column'; fieldId: string }
16
13
  | { type: 'refPanel'; targetId: string; typename: string }
17
- | {
18
- type: 'createRefPanel';
19
- typename: string;
20
- initialValues?: Record<string, string>;
21
- onCreate?: (obj: Live<any>) => void;
22
- }
23
14
  | { type: 'columnSettings'; mode: ColumnSettingsMode }
24
15
  | { type: 'closed' };
25
16
 
@@ -68,25 +59,6 @@ export class ModalController {
68
59
  }
69
60
  };
70
61
 
71
- public openCreateRef = (
72
- typename: string,
73
- anchorCell: Element | null,
74
- initialValues?: Record<string, string>,
75
- onCreate?: (obj: Live<any>) => void,
76
- ) => {
77
- if (anchorCell) {
78
- this._triggerRef.current = anchorCell as HTMLElement;
79
- this._state.value = {
80
- type: 'createRefPanel',
81
- typename,
82
- initialValues,
83
- onCreate,
84
- };
85
- } else {
86
- log.warn('anchor cell not found while creating new ref');
87
- }
88
- };
89
-
90
62
  public close = () => {
91
63
  this._state.value = { type: 'closed' };
92
64
  };
@@ -3,14 +3,15 @@
3
3
  //
4
4
 
5
5
  import { computed } from '@preact/signals-core';
6
- import { Schema } from 'effect';
6
+ import * as Schema from 'effect/Schema';
7
7
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
8
8
 
9
- import { TypedObject } from '@dxos/echo-schema';
10
- import { updateCounter } from '@dxos/echo-schema/testing';
9
+ import { Filter, Query } from '@dxos/echo';
10
+ import { TypedObject } from '@dxos/echo/internal';
11
+ import { updateCounter } from '@dxos/echo/testing';
12
+ import { createEchoSchema } from '@dxos/echo/testing';
11
13
  import { registerSignalsRuntime } from '@dxos/echo-signals';
12
14
  import { live } from '@dxos/live-object';
13
- import { createEchoSchema } from '@dxos/live-object/testing';
14
15
  import { createView } from '@dxos/schema';
15
16
 
16
17
  import { Table } from '../types';
@@ -24,7 +25,7 @@ registerSignalsRuntime();
24
25
 
25
26
  describe('TableModel', () => {
26
27
  let updateCount = 0;
27
- let model: TableModel;
28
+ let model: any;
28
29
 
29
30
  beforeEach(async () => {
30
31
  updateCount = 0;
@@ -32,6 +33,11 @@ describe('TableModel', () => {
32
33
  onCellUpdate: () => updateCount++,
33
34
  });
34
35
  await model.open();
36
+ model.setRows([
37
+ { id: '1', title: 'Test', completed: false },
38
+ { id: '2', title: 'Test 2', completed: true },
39
+ { id: '3', title: 'Test 3', completed: false },
40
+ ]);
35
41
  });
36
42
 
37
43
  afterEach(async () => {
@@ -107,6 +113,10 @@ class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.
107
113
  const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
108
114
  const schema = createEchoSchema(Test);
109
115
  const table = Table.make();
110
- const view = createView({ typename: schema.typename, jsonSchema: schema.jsonSchema, presentation: table });
116
+ const view = createView({
117
+ query: Query.select(Filter.type(schema)),
118
+ jsonSchema: schema.jsonSchema,
119
+ presentation: table,
120
+ });
111
121
  return new TableModel({ view, schema: schema.jsonSchema, ...props });
112
122
  };
@@ -7,7 +7,6 @@ import { type ReadonlySignal, computed, effect, signal } from '@preact/signals-c
7
7
  import { Resource } from '@dxos/context';
8
8
  import { Obj, Ref } from '@dxos/echo';
9
9
  import {
10
- type FieldSortType,
11
10
  FormatEnum,
12
11
  type JsonProp,
13
12
  type JsonSchemaType,
@@ -15,7 +14,7 @@ import {
15
14
  getValue,
16
15
  setValue,
17
16
  toEffectSchema,
18
- } from '@dxos/echo-schema';
17
+ } from '@dxos/echo/internal';
19
18
  import { invariant } from '@dxos/invariant';
20
19
  import { ObjectId } from '@dxos/keys';
21
20
  import { getSnapshot, isLiveObject } from '@dxos/live-object';
@@ -28,7 +27,14 @@ import {
28
27
  type DxGridPlaneRange,
29
28
  type DxGridPosition,
30
29
  } from '@dxos/react-ui-grid';
31
- import { type DataType, ProjectionModel, type PropertyType, type ValidationError, validateSchema } from '@dxos/schema';
30
+ import {
31
+ type DataType,
32
+ type FieldSortType,
33
+ ProjectionModel,
34
+ type PropertyType,
35
+ type ValidationError,
36
+ validateSchema,
37
+ } from '@dxos/schema';
32
38
 
33
39
  import { Table } from '../types';
34
40
  import { touch } from '../util';
@@ -135,6 +141,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
135
141
  super();
136
142
  this._view = view;
137
143
  this._projection = projection ?? new ProjectionModel(schema, view.projection);
144
+ this._projection.normalizeView();
138
145
 
139
146
  // TODO(ZaymonFC): Use our more robust config merging module?
140
147
  this._features = { ...defaultFeatures, ...features };
@@ -2,12 +2,13 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
  import { beforeEach, describe, expect, it } from 'vitest';
7
7
 
8
- import { TypedObject } from '@dxos/echo-schema';
8
+ import { Filter, Query } from '@dxos/echo';
9
+ import { TypedObject } from '@dxos/echo/internal';
10
+ import { createEchoSchema } from '@dxos/echo/testing';
9
11
  import { live } from '@dxos/live-object';
10
- import { createEchoSchema } from '@dxos/live-object/testing';
11
12
  import { createView } from '@dxos/schema';
12
13
 
13
14
  import { Table } from '../types';
@@ -26,8 +27,8 @@ describe('TablePresentation', () => {
26
27
  updateCount = 0;
27
28
  ({ data } = live({
28
29
  data: [
29
- { col1: 'A', col2: 1, col3: true },
30
- { col1: 'B', col2: 2, col3: false },
30
+ { title: 'A', count: 1 },
31
+ { title: 'B', count: 2 },
31
32
  ],
32
33
  }));
33
34
 
@@ -44,8 +45,8 @@ describe('TablePresentation', () => {
44
45
  presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 1, col: 2 } }, 'grid');
45
46
 
46
47
  // Trigger a row update.
47
- data[0].col1 = 'New Value';
48
- expect(updateCount).toBe(1);
48
+ data[0].title = 'New Value';
49
+ expect(updateCount).toBe(2);
49
50
 
50
51
  // Verify the new value through getCells.
51
52
  const cells = presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 0, col: 0 } }, 'grid');
@@ -56,15 +57,14 @@ describe('TablePresentation', () => {
56
57
  // Set up visible range to include our test data.
57
58
  presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 2, col: 2 } }, 'grid');
58
59
 
59
- data.push({ col1: 'C', col2: 3, col3: true });
60
- expect(updateCount).toBe(1);
60
+ data.push({ title: 'C', count: 3 });
61
+ expect(updateCount).toBe(2);
61
62
 
62
63
  const cells = presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 2, col: 2 } }, 'grid');
63
64
 
64
65
  // Verify the new row's data.
65
66
  expect(cells['0,2']?.value).toBe('C');
66
67
  expect(cells['1,2']?.value).toBe('3');
67
- expect(cells['2,2']?.value).toBe('true');
68
68
  });
69
69
 
70
70
  it('should handle combined operations reactively', () => {
@@ -72,32 +72,34 @@ describe('TablePresentation', () => {
72
72
  presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 2, col: 2 } }, 'grid');
73
73
 
74
74
  // Multiple operations.
75
- data[0].col1 = 'Updated A';
76
- data.push({ col1: 'C', col2: 3, col3: true });
75
+ data[0].title = 'Updated A';
76
+ data.push({ title: 'C', count: 3, completed: true });
77
77
  data.splice(1, 1);
78
78
 
79
79
  // We expect one update per operation affecting visible rows.
80
- expect(updateCount).toBe(3);
80
+ expect(updateCount).toBe(4);
81
81
 
82
82
  const cells = presentation.getCells({ start: { row: 0, col: 0 }, end: { row: 1, col: 2 } }, 'grid');
83
83
 
84
84
  // Verify final state.
85
85
  expect(cells['0,0']?.value).toBe('Updated A');
86
86
  expect(cells['0,1']?.value).toBe('C');
87
- expect(cells['1,1']?.value).toBe('3');
88
- expect(cells['2,1']?.value).toBe('true');
89
87
  });
90
88
  });
91
89
  });
92
90
 
93
91
  class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
94
92
  title: Schema.String,
95
- completed: Schema.Boolean,
93
+ count: Schema.Number,
96
94
  }) {}
97
95
 
98
96
  const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
99
97
  const schema = createEchoSchema(Test);
100
98
  const table = Table.make();
101
- const view = createView({ typename: schema.typename, jsonSchema: schema.jsonSchema, presentation: table });
99
+ const view = createView({
100
+ query: Query.select(Filter.type(schema)),
101
+ jsonSchema: schema.jsonSchema,
102
+ presentation: table,
103
+ });
102
104
  return new TableModel({ view, schema: schema.jsonSchema, ...props });
103
105
  };
@@ -3,10 +3,10 @@
3
3
  //
4
4
 
5
5
  import { signal } from '@preact/signals-core';
6
- import { isNotNullable } from 'effect/Predicate';
6
+ import * as Predicate from 'effect/Predicate';
7
7
 
8
8
  import { Obj } from '@dxos/echo';
9
- import { FormatEnum, TypeEnum, getValue } from '@dxos/echo-schema';
9
+ import { FormatEnum, TypeEnum, getValue } from '@dxos/echo/internal';
10
10
  import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
11
11
  import {
12
12
  type DxGridCellValue,
@@ -190,7 +190,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
190
190
 
191
191
  const tags = targetArray
192
192
  .map(getLabel)
193
- .filter(isNotNullable)
193
+ .filter(Predicate.isNotNullable)
194
194
  .map((title) => {
195
195
  return `<span class="dx-tag" data-hue="neutral">${title}</span>`;
196
196
  })
@@ -205,7 +205,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
205
205
  const targetObj = getValue(obj, field.path)?.target;
206
206
  if (targetObj) {
207
207
  const dxn = Obj.getDXN(targetObj)?.toString();
208
- 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>`;
208
+ cell.accessoryHtml = `<div role="none" class="absolute inline-end-0 inset-block-0 p-[--dx-grid-cell-content-padding-block]"><dx-anchor refId=${dxn} class="dx-button is-6 aspect-square min-bs-0" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-anchor></div>`;
209
209
  }
210
210
  }
211
211
 
@@ -468,7 +468,6 @@ export const cellClassesForRowSelection = (selected: boolean, selectionMode: Sel
468
468
 
469
469
  switch (selectionMode) {
470
470
  case 'single':
471
- // TODO(ZaymonFC): @thure, do we need a grid version of 'currentRelated'?
472
471
  return ['!bg-currentRelated dx-grid__cell--no-focus-unfurl hover:bg-hoverSurface !cursor-pointer'];
473
472
  case 'multiple':
474
473
  return ['!bg-gridCellSelected'];
@@ -5,12 +5,21 @@
5
5
  import { type ReadonlySignal, type Signal, computed, signal } from '@preact/signals-core';
6
6
  import orderBy from 'lodash.orderby';
7
7
 
8
- import { type FieldSortType, FormatEnum, type SortDirectionType, TypeEnum, getValue } from '@dxos/echo-schema';
8
+ import { FormatEnum, TypeEnum, getValue } from '@dxos/echo/internal';
9
9
  import { formatForDisplay } from '@dxos/react-ui-form';
10
- import type { DataType, FieldType, ProjectionModel, PropertyType } from '@dxos/schema';
10
+ import type {
11
+ DataType,
12
+ FieldSortType,
13
+ FieldType,
14
+ ProjectionModel,
15
+ PropertyType,
16
+ SortDirectionType,
17
+ } from '@dxos/schema';
11
18
 
12
19
  import { type TableRow } from './table-model';
13
20
 
21
+ // TODO(wittjosiah): Remove. Use ordering in queries instead.
22
+
14
23
  /**
15
24
  * Represents the local sort state.
16
25
  * - undefined: No local sort set, fallback to view sort.
@@ -55,7 +64,7 @@ export class TableSorting<T extends TableRow> {
55
64
  this._rows = rows;
56
65
  this._isDirty = computed(() => {
57
66
  const local = this._localSort.value;
58
- const viewSort = this._view.query.sort?.[0];
67
+ const viewSort = this._view.sort?.[0];
59
68
  if (local?.type === 'cleared') {
60
69
  return viewSort !== undefined;
61
70
  }
@@ -83,7 +92,7 @@ export class TableSorting<T extends TableRow> {
83
92
  return local.sort;
84
93
  }
85
94
 
86
- return this._view.query.sort?.[0];
95
+ return this._view.sort?.[0];
87
96
  }
88
97
 
89
98
  /**
@@ -129,9 +138,9 @@ export class TableSorting<T extends TableRow> {
129
138
  public save(): void {
130
139
  if (this._localSort.value !== undefined) {
131
140
  if (this._localSort.value.type === 'active') {
132
- this._view.query.sort = [this._localSort.value.sort];
141
+ this._view.sort = [this._localSort.value.sort];
133
142
  } else {
134
- this._view.query.sort = [];
143
+ this._view.sort = [];
135
144
  }
136
145
  this._localSort.value = undefined;
137
146
  }
@@ -187,7 +187,7 @@ test.describe('Table', () => {
187
187
  // Click on the combobox to open options
188
188
  await page.getByRole('combobox').click();
189
189
  await page.pause();
190
- await page.getByPlaceholder('Search...').focus();
190
+ await page.getByPlaceholder('Search…').focus();
191
191
 
192
192
  // Type the first few letters of an org name.
193
193
  const orgName =
@@ -240,7 +240,7 @@ test.describe('Table', () => {
240
240
 
241
241
  // Click on the combobox to open options
242
242
  await page.getByRole('combobox').click();
243
- await page.getByPlaceholder('Search...').focus();
243
+ await page.getByPlaceholder('Search…').focus();
244
244
 
245
245
  // Type the first few letters of an org name.
246
246
  const orgName = 'Sally';
@@ -254,7 +254,7 @@ test.describe('Table', () => {
254
254
  await page.pause();
255
255
 
256
256
  // Click the save button in the popover
257
- await page.getByTestId('save-button').click();
257
+ await page.getByTestId('create-referenced-object-form').getByTestId('save-button').click();
258
258
 
259
259
  // Assert that the cell element has the org name
260
260
  await expect(targetCell).toHaveText(orgName);
@@ -4,13 +4,13 @@
4
4
 
5
5
  import { useCallback, useMemo, useRef } from 'react';
6
6
 
7
- import { isMutable, toJsonSchema } from '@dxos/echo-schema';
7
+ import { isMutable, toJsonSchema } from '@dxos/echo/internal';
8
8
  import { useGlobalFilteredObjects } from '@dxos/plugin-search';
9
9
  import { faker } from '@dxos/random';
10
10
  import { useClient } from '@dxos/react-client';
11
11
  import { Filter, useQuery, useSchema } from '@dxos/react-client/echo';
12
12
  import { useClientProvider } from '@dxos/react-client/testing';
13
- import { DataType, ProjectionModel } from '@dxos/schema';
13
+ import { DataType, ProjectionModel, getTypenameFromQuery } from '@dxos/schema';
14
14
 
15
15
  import { type TableController } from '../components';
16
16
  import { useAddRow, useTableModel } from '../hooks';
@@ -28,12 +28,15 @@ export const useTestTableModel = () => {
28
28
 
29
29
  const views = useQuery(space, Filter.type(DataType.View));
30
30
  const view = useMemo(() => views.at(0), [views]);
31
- const schema = useSchema(client, space, view?.query.typename);
31
+ const typename = view?.query ? getTypenameFromQuery(view.query.ast) : undefined;
32
+ const schema = useSchema(client, space, typename);
32
33
  const jsonSchema = useMemo(() => (schema ? toJsonSchema(schema) : undefined), [schema]);
33
34
 
34
35
  const projection = useMemo(() => {
35
36
  if (schema && view?.projection) {
36
- return new ProjectionModel(toJsonSchema(schema), view.projection);
37
+ const projection = new ProjectionModel(toJsonSchema(schema), view.projection);
38
+ projection.normalizeView();
39
+ return projection;
37
40
  }
38
41
  }, [schema, view?.projection]);
39
42
 
@@ -2,12 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
6
- import { Match } from 'effect';
5
+ import * as Match from 'effect/Match';
6
+ import * as Schema from 'effect/Schema';
7
7
 
8
8
  import { Obj, Type } from '@dxos/echo';
9
- import { JsonPath, type JsonSchemaType, toEffectSchema } from '@dxos/echo-schema';
10
- import { ViewAnnotation } from '@dxos/echo-schema';
9
+ import { JsonPath, type JsonSchemaType, toEffectSchema } from '@dxos/echo/internal';
10
+ import { ViewAnnotation } from '@dxos/echo/internal';
11
11
  import { type SimpleType } from '@dxos/effect';
12
12
  import { type CreateViewFromSpaceProps, type DataType, createViewFromSpace, getSchemaProperties } from '@dxos/schema';
13
13
 
@@ -2,15 +2,16 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Schema } from 'effect';
5
+ import type * as Schema from 'effect/Schema';
6
6
 
7
- import { Obj } from '@dxos/echo';
8
- import { getTypename, toJsonSchema } from '@dxos/echo-schema';
9
- import type { JsonSchemaType, SortDirectionType } from '@dxos/echo-schema';
7
+ import { Filter, Obj, Query } from '@dxos/echo';
8
+ import { getTypename, toJsonSchema } from '@dxos/echo/internal';
9
+ import type { JsonSchemaType } from '@dxos/echo/internal';
10
10
  import {
11
11
  type DataType,
12
12
  ProjectionModel,
13
13
  type SchemaPropertyDefinition,
14
+ type SortDirectionType,
14
15
  createView,
15
16
  getSchemaFromPropertyDefinitions,
16
17
  } from '@dxos/schema';
@@ -54,23 +55,22 @@ export const getBaseSchema = ({
54
55
  };
55
56
 
56
57
  export const makeDynamicTable = ({
57
- typename,
58
58
  jsonSchema,
59
59
  properties,
60
60
  }: {
61
- typename: string;
62
61
  jsonSchema: JsonSchemaType;
63
62
  properties?: TablePropertyDefinition[];
64
63
  }): { projection: ProjectionModel; view: DataType.View } => {
65
64
  const table = Obj.make(Table.Table, { sizes: {} });
66
65
  const view = createView({
67
- typename,
66
+ query: Query.select(Filter.everything()),
68
67
  jsonSchema,
69
68
  presentation: table,
70
69
  ...(properties && { fields: properties.map((property) => property.name) }),
71
70
  });
72
71
 
73
72
  const projection = new ProjectionModel(jsonSchema, view.projection);
73
+ projection.normalizeView();
74
74
  if (properties && projection.fields) {
75
75
  setProperties(view, projection, table, properties);
76
76
  }
@@ -101,7 +101,7 @@ const setProperties = (
101
101
 
102
102
  if (property.sort) {
103
103
  const fieldId = field.id;
104
- view.query.sort = [{ fieldId, direction: property.sort }];
104
+ view.sort = [{ fieldId, direction: property.sort }];
105
105
  }
106
106
  }
107
107
  }
@@ -2,8 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
6
- import { TypeLiteral, isTypeLiteral } from 'effect/SchemaAST';
5
+ import * as Schema from 'effect/Schema';
6
+ import * as SchemaAST from 'effect/SchemaAST';
7
7
 
8
8
  /**
9
9
  * Creates a narrowed schema from an original schema that only includes
@@ -20,14 +20,14 @@ export const narrowSchema = <S extends Schema.Schema.AnyNoContext>(
20
20
  ): Schema.Schema<unknown, unknown> | undefined => {
21
21
  const ast = (schema as any)?.ast;
22
22
 
23
- if (isTypeLiteral(ast)) {
23
+ if (SchemaAST.isTypeLiteral(ast)) {
24
24
  // Filter property signatures that match any of the provided paths
25
25
  const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
26
26
 
27
27
  // If we found at least one matching property
28
28
  if (propertySignatures.length > 0) {
29
29
  // Create a new TypeLiteral with only the matching properties
30
- const narrowType = new TypeLiteral(propertySignatures, []);
30
+ const narrowType = new SchemaAST.TypeLiteral(propertySignatures, []);
31
31
  return Schema.make(narrowType);
32
32
  }
33
33
  }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/schema.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Schema } from 'effect';\nimport { Match } from 'effect';\n\nimport { Obj, Type } from '@dxos/echo';\nimport { JsonPath, type JsonSchemaType, toEffectSchema } from '@dxos/echo-schema';\nimport { ViewAnnotation } from '@dxos/echo-schema';\nimport { type SimpleType } from '@dxos/effect';\nimport { type CreateViewFromSpaceProps, type DataType, createViewFromSpace, getSchemaProperties } from '@dxos/schema';\n\nexport const Table = Schema.Struct({\n sizes: Schema.Record({\n key: JsonPath,\n value: Schema.Number,\n }).pipe(Schema.mutable),\n}).pipe(\n Type.Obj({\n typename: 'dxos.org/type/Table',\n version: '0.1.0',\n }),\n ViewAnnotation.set(true),\n);\n\nexport type Table = Schema.Schema.Type<typeof Table>;\n\n/**\n * Make a table view.\n */\nexport const make = (props: Partial<Obj.MakeProps<typeof Table>> = {}) => Obj.make(Table, { sizes: {}, ...props });\n\ntype MakeViewProps = Omit<CreateViewFromSpaceProps, 'presentation'> & {\n sizes?: Record<string, number>;\n};\n\nexport const makeView = async ({\n sizes,\n ...props\n}: MakeViewProps): Promise<{\n jsonSchema: JsonSchemaType;\n view: DataType.View;\n schema: ReturnType<typeof toEffectSchema>;\n}> => {\n const table = Obj.make(Table, { sizes: {} });\n const { jsonSchema, view } = await createViewFromSpace({ ...props, presentation: table });\n\n // Preset sizes.\n const schema = toEffectSchema(jsonSchema);\n const shouldIncludeId = props.fields?.find((field) => field === 'id') !== undefined;\n const properties = getSchemaProperties(schema.ast, {}, shouldIncludeId);\n for (const property of properties) {\n if (sizes?.[property.name]) {\n table.sizes[property.name as JsonPath] = sizes[property.name];\n continue;\n }\n\n Match.type<SimpleType>().pipe(\n Match.when('boolean', () => {\n table.sizes[property.name as JsonPath] = 100;\n }),\n Match.when('number', () => {\n table.sizes[property.name as JsonPath] = 100;\n }),\n Match.orElse(() => {\n // Noop.\n }),\n )(property.type);\n }\n\n return { jsonSchema, schema, view };\n};\n"],
5
- "mappings": ";;;;;;;AAAA;;;;;;AAIA,SAASA,cAAc;AACvB,SAASC,aAAa;AAEtB,SAASC,KAAKC,YAAY;AAC1B,SAASC,UAA+BC,sBAAsB;AAC9D,SAASC,sBAAsB;AAE/B,SAAuDC,qBAAqBC,2BAA2B;AAEhG,IAAMC,QAAQC,OAAOC,OAAO;EACjCC,OAAOF,OAAOG,OAAO;IACnBC,KAAKC;IACLC,OAAON,OAAOO;EAChB,CAAA,EAAGC,KAAKR,OAAOS,OAAO;AACxB,CAAA,EAAGD,KACDE,KAAKC,IAAI;EACPC,UAAU;EACVC,SAAS;AACX,CAAA,GACAC,eAAeC,IAAI,IAAA,CAAA;AAQd,IAAMC,OAAO,CAACC,QAA8C,CAAC,MAAMN,IAAIK,KAAKjB,OAAO;EAAEG,OAAO,CAAC;EAAG,GAAGe;AAAM,CAAA;AAMzG,IAAMC,WAAW,OAAO,EAC7BhB,OACA,GAAGe,MAAAA,MACW;AAKd,QAAME,QAAQR,IAAIK,KAAKjB,OAAO;IAAEG,OAAO,CAAC;EAAE,CAAA;AAC1C,QAAM,EAAEkB,YAAYC,KAAI,IAAK,MAAMC,oBAAoB;IAAE,GAAGL;IAAOM,cAAcJ;EAAM,CAAA;AAGvF,QAAMK,SAASC,eAAeL,UAAAA;AAC9B,QAAMM,kBAAkBT,MAAMU,QAAQC,KAAK,CAACC,UAAUA,UAAU,IAAA,MAAUC;AAC1E,QAAMC,aAAaC,oBAAoBR,OAAOS,KAAK,CAAC,GAAGP,eAAAA;AACvD,aAAWQ,YAAYH,YAAY;AACjC,QAAI7B,QAAQgC,SAASC,IAAI,GAAG;AAC1BhB,YAAMjB,MAAMgC,SAASC,IAAI,IAAgBjC,MAAMgC,SAASC,IAAI;AAC5D;IACF;AAEAC,UAAMC,KAAI,EAAe7B,KACvB4B,MAAME,KAAK,WAAW,MAAA;AACpBnB,YAAMjB,MAAMgC,SAASC,IAAI,IAAgB;IAC3C,CAAA,GACAC,MAAME,KAAK,UAAU,MAAA;AACnBnB,YAAMjB,MAAMgC,SAASC,IAAI,IAAgB;IAC3C,CAAA,GACAC,MAAMG,OAAO,MAAA;IAEb,CAAA,CAAA,EACAL,SAASG,IAAI;EACjB;AAEA,SAAO;IAAEjB;IAAYI;IAAQH;EAAK;AACpC;",
6
- "names": ["Schema", "Match", "Obj", "Type", "JsonPath", "toEffectSchema", "ViewAnnotation", "createViewFromSpace", "getSchemaProperties", "Table", "Schema", "Struct", "sizes", "Record", "key", "JsonPath", "value", "Number", "pipe", "mutable", "Type", "Obj", "typename", "version", "ViewAnnotation", "set", "make", "props", "makeView", "table", "jsonSchema", "view", "createViewFromSpace", "presentation", "schema", "toEffectSchema", "shouldIncludeId", "fields", "find", "field", "undefined", "properties", "getSchemaProperties", "ast", "property", "name", "Match", "type", "when", "orElse"]
7
- }