@dxos/react-ui-table 0.8.4-main.9735255 → 0.8.4-main.abd8ff62ef

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 (137) hide show
  1. package/dist/lib/browser/{chunk-OZBLY7XM.mjs → chunk-FBURZBPH.mjs} +17 -23
  2. package/dist/lib/browser/chunk-FBURZBPH.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  4. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-I5IFW7UF.mjs → chunk-YGC7LZJN.mjs} +39 -90
  6. package/dist/lib/browser/chunk-YGC7LZJN.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +198 -235
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/testing/index.mjs +7 -6
  11. package/dist/lib/browser/testing/index.mjs.map +3 -3
  12. package/dist/lib/browser/translations.mjs +36 -0
  13. package/dist/lib/browser/translations.mjs.map +7 -0
  14. package/dist/lib/browser/types/index.mjs +2 -1
  15. package/dist/lib/node-esm/{chunk-WNZSKIRF.mjs → chunk-DKKMSVKP.mjs} +17 -23
  16. package/dist/lib/node-esm/chunk-DKKMSVKP.mjs.map +7 -0
  17. package/dist/lib/node-esm/{chunk-DDJKYJFY.mjs → chunk-GKIWDEZ7.mjs} +39 -90
  18. package/dist/lib/node-esm/chunk-GKIWDEZ7.mjs.map +7 -0
  19. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  20. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  21. package/dist/lib/node-esm/index.mjs +198 -235
  22. package/dist/lib/node-esm/index.mjs.map +4 -4
  23. package/dist/lib/node-esm/meta.json +1 -1
  24. package/dist/lib/node-esm/testing/index.mjs +7 -6
  25. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  26. package/dist/lib/node-esm/translations.mjs +37 -0
  27. package/dist/lib/node-esm/translations.mjs.map +7 -0
  28. package/dist/lib/node-esm/types/index.mjs +2 -1
  29. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/DynamicTable.d.ts +5 -4
  32. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +20 -22
  34. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/Table/Relations.stories.d.ts +82 -82
  36. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  38. package/dist/types/src/components/Table/Table.d.ts +20 -21
  39. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  40. package/dist/types/src/components/Table/Table.stories.d.ts +84 -84
  41. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/Table/TableContent.d.ts +17 -0
  43. package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
  44. package/dist/types/src/components/Table/TableToolbar.d.ts +21 -0
  45. package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
  46. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  47. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +3 -3
  48. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  49. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +2 -2
  50. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  51. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +22 -24
  52. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  53. package/dist/types/src/components/index.d.ts +0 -1
  54. package/dist/types/src/components/index.d.ts.map +1 -1
  55. package/dist/types/src/components/testing.d.ts.map +1 -1
  56. package/dist/types/src/hooks/useAddRow.d.ts +1 -1
  57. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  58. package/dist/types/src/hooks/useProjectionModel.d.ts +1 -1
  59. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -1
  60. package/dist/types/src/hooks/useTableModel.d.ts +1 -1
  61. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  62. package/dist/types/src/index.d.ts +0 -2
  63. package/dist/types/src/index.d.ts.map +1 -1
  64. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  65. package/dist/types/src/model/selection-model.d.ts +1 -1
  66. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  67. package/dist/types/src/model/table-model.d.ts +7 -6
  68. package/dist/types/src/model/table-model.d.ts.map +1 -1
  69. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  70. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  71. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  72. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -1
  73. package/dist/types/src/testing/useTestTableModel.d.ts +2 -2
  74. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  75. package/dist/types/src/translations.d.ts +19 -21
  76. package/dist/types/src/translations.d.ts.map +1 -1
  77. package/dist/types/src/types/Table.d.ts +1 -6
  78. package/dist/types/src/types/Table.d.ts.map +1 -1
  79. package/dist/types/src/util/dynamic-table.d.ts +6 -5
  80. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  81. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  82. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  83. package/dist/types/src/util/query-ast.d.ts.map +1 -1
  84. package/dist/types/src/util/schema.d.ts.map +1 -1
  85. package/dist/types/src/util/signals.d.ts.map +1 -1
  86. package/dist/types/src/util/sort.d.ts.map +1 -1
  87. package/dist/types/src/util/table-buttons.d.ts +20 -20
  88. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  89. package/dist/types/src/util/table-controls.d.ts +4 -4
  90. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  91. package/dist/types/src/util/tag.d.ts.map +1 -1
  92. package/dist/types/tsconfig.tsbuildinfo +1 -1
  93. package/package.json +59 -62
  94. package/src/components/Table/ColumnActionsMenu.tsx +7 -6
  95. package/src/components/Table/ColumnSettings.tsx +3 -4
  96. package/src/components/Table/DynamicTable.stories.tsx +19 -18
  97. package/src/components/Table/DynamicTable.tsx +13 -20
  98. package/src/components/Table/Relations.stories.tsx +78 -34
  99. package/src/components/Table/RowActionsMenu.tsx +3 -2
  100. package/src/components/Table/Table.stories.tsx +72 -52
  101. package/src/components/Table/Table.tsx +41 -435
  102. package/src/components/Table/TableContent.tsx +421 -0
  103. package/src/components/{TableToolbar → Table}/TableToolbar.tsx +36 -43
  104. package/src/components/TableCellEditor/CellValidationMessage.tsx +4 -4
  105. package/src/components/TableCellEditor/FormCellEditor.tsx +14 -7
  106. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +13 -12
  107. package/src/components/TableCellEditor/TableCellEditor.tsx +12 -10
  108. package/src/components/index.ts +0 -1
  109. package/src/components/testing.ts +10 -10
  110. package/src/hooks/useAddRow.ts +1 -1
  111. package/src/hooks/useProjectionModel.ts +3 -3
  112. package/src/hooks/useTableModel.ts +1 -1
  113. package/src/index.ts +0 -4
  114. package/src/model/table-model.test.ts +5 -6
  115. package/src/model/table-model.ts +18 -17
  116. package/src/model/table-presentation.test.ts +13 -7
  117. package/src/model/table-presentation.ts +12 -12
  118. package/src/playwright/TableManager.ts +10 -3
  119. package/src/playwright/playwright.config.ts +1 -1
  120. package/src/playwright/smoke.spec.ts +48 -5
  121. package/src/testing/useTestTableModel.ts +6 -6
  122. package/src/translations.ts +19 -21
  123. package/src/types/Table.ts +12 -23
  124. package/src/util/dynamic-table.test.ts +77 -0
  125. package/src/util/dynamic-table.ts +17 -16
  126. package/src/util/query-ast.ts +3 -0
  127. package/src/util/table-buttons.ts +1 -1
  128. package/src/util/table-controls.ts +2 -2
  129. package/dist/lib/browser/chunk-I5IFW7UF.mjs.map +0 -7
  130. package/dist/lib/browser/chunk-OZBLY7XM.mjs.map +0 -7
  131. package/dist/lib/node-esm/chunk-DDJKYJFY.mjs.map +0 -7
  132. package/dist/lib/node-esm/chunk-WNZSKIRF.mjs.map +0 -7
  133. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +0 -21
  134. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +0 -1
  135. package/dist/types/src/components/TableToolbar/index.d.ts +0 -2
  136. package/dist/types/src/components/TableToolbar/index.d.ts.map +0 -1
  137. package/src/components/TableToolbar/index.ts +0 -5
@@ -6,25 +6,26 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
8
  import { Obj } from '@dxos/echo';
9
- import { faker } from '@dxos/random';
9
+ import { View } from '@dxos/echo';
10
+ import { random } from '@dxos/random';
10
11
  import { withClientProvider } from '@dxos/react-client/testing';
11
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
12
  import { Grid, type GridEditing, defaultRowSize } from '@dxos/react-ui-grid';
13
- import { View } from '@dxos/schema';
13
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
14
+ import { ViewModel } from '@dxos/schema';
14
15
  import { Task } from '@dxos/types';
15
16
 
17
+ import { translations } from '#translations';
18
+
16
19
  import { useTestTableModel } from '../../testing';
17
- import { translations } from '../../translations';
18
20
  import { Table } from '../../types';
19
-
20
21
  import { TableCellEditor } from './TableCellEditor';
21
22
 
22
- type StoryProps = {
23
+ type DefaultStoryProps = {
23
24
  editing: GridEditing;
24
25
  };
25
26
 
26
27
  // TODO(burdon): Broken layout.
27
- const DefaultStory = ({ editing }: StoryProps) => {
28
+ const DefaultStory = ({ editing }: DefaultStoryProps) => {
28
29
  const { model, table } = useTestTableModel();
29
30
 
30
31
  if (!model || !table) {
@@ -45,22 +46,22 @@ const meta = {
45
46
  component: DefaultStory,
46
47
  render: DefaultStory,
47
48
  decorators: [
48
- withTheme,
49
+ withTheme(),
49
50
  withLayout({ layout: 'column' }),
50
51
  withClientProvider({
51
52
  types: [View.View, Task.Task, Table.Table],
52
53
  createIdentity: true,
53
54
  createSpace: true,
54
55
  onCreateSpace: async ({ space }) => {
55
- const { view, jsonSchema } = await View.makeFromDatabase({ db: space.db, typename: Task.Task.typename });
56
+ const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename: Task.Task.typename });
56
57
  const table = Table.make({ view, jsonSchema });
57
58
  space.db.add(table);
58
59
  Array.from({ length: 10 }).forEach(() => {
59
60
  space.db.add(
60
61
  Obj.make(Task.Task, {
61
- title: faker.person.fullName(),
62
- status: faker.helpers.arrayElement(['todo', 'in-progress', 'done'] as const),
63
- description: faker.lorem.sentence(),
62
+ title: random.person.fullName(),
63
+ status: random.helpers.arrayElement(['todo', 'in-progress', 'done'] as const),
64
+ description: random.lorem.sentence(),
64
65
  }),
65
66
  );
66
67
  });
@@ -25,16 +25,9 @@ import {
25
25
  import { type FieldProjection } from '@dxos/schema';
26
26
 
27
27
  import { type ModalController, type TableModel } from '../../model';
28
-
29
28
  import { CellValidationMessage } from './CellValidationMessage';
30
29
  import { FormCellEditor, type OnCreateHandler } from './FormCellEditor';
31
30
 
32
- const editorSlots = {
33
- scroll: {
34
- className: '!plb-[--dx-grid-cell-editor-padding-block]',
35
- },
36
- };
37
-
38
31
  /**
39
32
  * Option to create new object/value.
40
33
  */
@@ -42,7 +35,7 @@ export type QueryResult = Pick<Completion, 'label'> & {
42
35
  data: any;
43
36
  };
44
37
 
45
- export type TableCellEditorProps<T extends Type.Entity.Any = Type.Entity.Any> = {
38
+ export type TableCellEditorProps<T extends Type.AnyEntity = Type.AnyEntity> = {
46
39
  schema?: T;
47
40
  model?: TableModel;
48
41
  modals?: ModalController;
@@ -51,7 +44,7 @@ export type TableCellEditorProps<T extends Type.Entity.Any = Type.Entity.Any> =
51
44
  onSave?: () => void;
52
45
  };
53
46
 
54
- export const TableValueEditor = <T extends Type.Entity.Any = Type.Entity.Any>({
47
+ export const TableValueEditor = <T extends Type.AnyEntity = Type.AnyEntity>({
55
48
  __gridScope,
56
49
  schema,
57
50
  model,
@@ -250,7 +243,16 @@ export const TableCellEditor = ({
250
243
  return (
251
244
  <>
252
245
  <CellValidationMessage validationError={validationError} variant={validationVariant} __gridScope={__gridScope} />
253
- <GridCellEditor extensions={extensions} getCellContent={getCellContent} onBlur={handleBlur} slots={editorSlots} />
246
+ <GridCellEditor
247
+ extensions={extensions}
248
+ slots={{
249
+ content: {
250
+ className: '!py-(--dx-grid-cell-editor-padding-block)',
251
+ },
252
+ }}
253
+ getCellContent={getCellContent}
254
+ onBlur={handleBlur}
255
+ />
254
256
  </>
255
257
  );
256
258
  };
@@ -3,4 +3,3 @@
3
3
  //
4
4
 
5
5
  export * from './Table';
6
- export * from './TableToolbar';
@@ -9,7 +9,7 @@ import { useEffect } from 'react';
9
9
  import { Format, Type } from '@dxos/echo';
10
10
  import { TypeEnum } from '@dxos/echo/internal';
11
11
  import { setValue } from '@dxos/effect';
12
- import { faker } from '@dxos/random';
12
+ import { random } from '@dxos/random';
13
13
  import { type ProjectionModel } from '@dxos/schema';
14
14
 
15
15
  export const TestSchema = Schema.Struct({
@@ -19,7 +19,7 @@ export const TestSchema = Schema.Struct({
19
19
  netWorth: Schema.optional(Schema.Number),
20
20
  }).pipe(
21
21
  Type.object({
22
- typename: 'example.com/type/Test',
22
+ typename: 'com.example.type.test',
23
23
  version: '0.1.0',
24
24
  }),
25
25
  );
@@ -37,10 +37,10 @@ export type TestItem = {
37
37
  export const createItemsAtom = (n: number) => {
38
38
  return Atom.make<{ data: TestItem[] }>({
39
39
  data: Array.from({ length: n }, () => ({
40
- name: faker.person.fullName(),
41
- age: faker.number.int({ min: 20, max: 70 }),
42
- active: faker.datatype.boolean(),
43
- netWorth: faker.number.int(),
40
+ name: random.person.fullName(),
41
+ age: random.number.int({ min: 20, max: 70 }),
42
+ active: random.datatype.boolean(),
43
+ netWorth: random.number.int(),
44
44
  })),
45
45
  }).pipe(Atom.keepAlive);
46
46
  };
@@ -50,10 +50,10 @@ export const createItemsAtom = (n: number) => {
50
50
  */
51
51
  export const createItems = (n: number): TestItem[] => {
52
52
  return Array.from({ length: n }, () => ({
53
- name: faker.person.fullName(),
54
- age: faker.number.int({ min: 20, max: 70 }),
55
- active: faker.datatype.boolean(),
56
- netWorth: faker.number.int(),
53
+ name: random.person.fullName(),
54
+ age: random.number.int({ min: 20, max: 70 }),
55
+ active: random.datatype.boolean(),
56
+ netWorth: random.number.int(),
57
57
  }));
58
58
  };
59
59
 
@@ -10,7 +10,7 @@ import { type InsertRowResult } from '../model';
10
10
 
11
11
  export type UseAddRowProps = {
12
12
  db?: Database.Database;
13
- schema?: Type.Obj.Any;
13
+ schema?: Type.AnyObj;
14
14
  };
15
15
 
16
16
  /**
@@ -5,13 +5,13 @@
5
5
  import { type Registry } from '@effect-atom/atom-react';
6
6
  import { useState } from 'react';
7
7
 
8
- import { Type } from '@dxos/echo';
8
+ import { JsonSchema, Type } from '@dxos/echo';
9
9
  import { useAsyncEffect } from '@dxos/react-ui';
10
10
  import { ProjectionModel, createEchoChangeCallback } from '@dxos/schema';
11
11
 
12
12
  import { type Table } from '../types';
13
13
 
14
- export const useProjectionModel = <S extends Type.Entity.Any>(
14
+ export const useProjectionModel = <S extends Type.AnyEntity>(
15
15
  schema: S | undefined,
16
16
  table: Table.Table | undefined,
17
17
  registry: Registry.Registry,
@@ -23,7 +23,7 @@ export const useProjectionModel = <S extends Type.Entity.Any>(
23
23
  const view = await table.view.load();
24
24
  // For mutable schemas (EchoSchema), use the live jsonSchema reference for reactivity.
25
25
  // For immutable schemas, create a snapshot.
26
- const jsonSchema = Type.isMutable(schema) ? schema.jsonSchema : Type.toJsonSchema(schema);
26
+ const jsonSchema = Type.isMutable(schema) ? schema.jsonSchema : JsonSchema.toJsonSchema(schema);
27
27
 
28
28
  // Always use createEchoChangeCallback since the view is ECHO-backed.
29
29
  // Pass schema only when mutable to allow schema mutations.
@@ -29,7 +29,7 @@ export type UseTableModelProps<T extends TableRow = TableRow> = {
29
29
  onRowAction?: (actionId: string, data: T) => void;
30
30
  } & Pick<
31
31
  TableModelProps<T>,
32
- 'features' | 'onInsertRow' | 'onDeleteRows' | 'onDeleteColumn' | 'onCellUpdate' | 'onRowOrderChange'
32
+ 'features' | 'onInsertRow' | 'onDeleteRows' | 'onColumnDelete' | 'onCellUpdate' | 'onRowOrderChange'
33
33
  >;
34
34
 
35
35
  export const useTableModel = <T extends TableRow = TableRow>({
package/src/index.ts CHANGED
@@ -2,11 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { translations } from './translations';
6
-
7
5
  export * from './components';
8
6
  export * from './hooks';
9
7
  export * from './model';
10
8
  export * from './util';
11
-
12
- export { translations };
@@ -6,12 +6,11 @@ import { Registry } from '@effect-atom/atom-react';
6
6
  import * as Schema from 'effect/Schema';
7
7
  import { afterEach, beforeEach, describe, expect, test } from 'vitest';
8
8
 
9
- import { Filter, Query, Type } from '@dxos/echo';
9
+ import { Filter, JsonSchema, Query, Type } from '@dxos/echo';
10
10
  import { createEchoSchema } from '@dxos/echo/testing';
11
- import { ProjectionModel, View, createDirectChangeCallback } from '@dxos/schema';
11
+ import { ProjectionModel, ViewModel, createDirectChangeCallback } from '@dxos/schema';
12
12
 
13
13
  import { Table } from '../types';
14
-
15
14
  import {
16
15
  TableModel,
17
16
  type TableModelProps,
@@ -121,14 +120,14 @@ const Test = Schema.Struct({
121
120
  completed: Schema.Boolean,
122
121
  }).pipe(
123
122
  Type.object({
124
- typename: 'example.com/type/Test',
123
+ typename: 'com.example.type.test',
125
124
  version: '0.1.0',
126
125
  }),
127
126
  );
128
127
 
129
128
  const createTableModel = (registry: Registry.Registry, props: Partial<TableModelProps> = {}): TableModel => {
130
129
  const schema = createEchoSchema(Test);
131
- const view = View.make({
130
+ const view = ViewModel.make({
132
131
  query: Query.select(Filter.type(schema)),
133
132
  jsonSchema: schema.jsonSchema,
134
133
  });
@@ -137,7 +136,7 @@ const createTableModel = (registry: Registry.Registry, props: Partial<TableModel
137
136
  registry,
138
137
  view,
139
138
  baseSchema: schema.jsonSchema,
140
- change: createDirectChangeCallback(view.projection, schema.jsonSchema),
139
+ change: createDirectChangeCallback(view.projection, JsonSchema.toJsonSchema(schema)),
141
140
  });
142
141
  projection.normalizeView();
143
142
  return new TableModel({
@@ -6,6 +6,7 @@ import { Atom, type Registry } from '@effect-atom/atom-react';
6
6
 
7
7
  import { Resource } from '@dxos/context';
8
8
  import { type Database, Format, Obj, Order, Query, type QueryAST, Ref } from '@dxos/echo';
9
+ import { type View } from '@dxos/echo';
9
10
  import { type JsonProp, type JsonSchemaType, type Mutable, toEffectSchema } from '@dxos/echo/internal';
10
11
  import { getSnapshot } from '@dxos/echo/internal';
11
12
  import { getValue, setValue } from '@dxos/effect';
@@ -19,7 +20,7 @@ import {
19
20
  type DxGridPlaneRange,
20
21
  type DxGridPosition,
21
22
  } from '@dxos/react-ui-grid';
22
- import { type ProjectionModel, type PropertyType, type ValidationError, type View, validateSchema } from '@dxos/schema';
23
+ import { type ProjectionModel, type PropertyType, type ValidationError, validateSchema } from '@dxos/schema';
23
24
 
24
25
  import { type Table } from '../types';
25
26
  import { extractOrder } from '../util';
@@ -37,7 +38,7 @@ export type FieldSortType = {
37
38
  import { type SelectionMode, SelectionModel } from './selection-model';
38
39
 
39
40
  /**
40
- * Callback type for wrapping mutations in Obj.change().
41
+ * Callback type for wrapping mutations in Obj.update().
41
42
  * Contains separate callbacks for table object and row mutations.
42
43
  */
43
44
  export type TableChangeCallback<T extends TableRow> = {
@@ -52,10 +53,10 @@ export type TableChangeCallback<T extends TableRow> = {
52
53
  * Use this when the table and rows are stored in the ECHO database.
53
54
  */
54
55
  export const createEchoChangeCallback = <T extends TableRow>(table: Table.Table): TableChangeCallback<T> => ({
55
- table: (mutate) => Obj.change(table, (mutableTable) => mutate(mutableTable as unknown as Table.Table)),
56
+ table: (mutate) => Obj.update(table, (table) => mutate(table as unknown as Table.Table)),
56
57
  row: (row, mutate) => {
57
58
  if (Obj.isObject(row)) {
58
- Obj.change(row, (mutableRow) => mutate(mutableRow as T));
59
+ Obj.update(row, (row) => mutate(row as T));
59
60
  } else {
60
61
  mutate(row);
61
62
  }
@@ -111,7 +112,7 @@ export type TableModelProps<T extends TableRow = TableRow> = {
111
112
  projection: ProjectionModel;
112
113
  db?: Database.Database;
113
114
  /**
114
- * Callbacks to wrap mutations in Obj.change().
115
+ * Callbacks to wrap mutations in Obj.update().
115
116
  * Use createEchoChangeCallback() for ECHO-backed objects or createDirectChangeCallback() for plain objects.
116
117
  */
117
118
  change?: TableChangeCallback<T>;
@@ -122,7 +123,7 @@ export type TableModelProps<T extends TableRow = TableRow> = {
122
123
  onResolveSchema?: (typename: string) => Promise<JsonSchemaType>;
123
124
  onInsertRow?: (data?: any) => InsertRowResult;
124
125
  onDeleteRows?: (index: number, obj: T[]) => void;
125
- onDeleteColumn?: (fieldId: string) => void;
126
+ onColumnDelete?: (fieldId: string) => void;
126
127
  onCellUpdate?: (cell: DxGridPosition) => void;
127
128
  onRowOrderChange?: () => void;
128
129
  onRowAction?: (actionId: string, data: T) => void;
@@ -139,7 +140,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
139
140
 
140
141
  private readonly _onInsertRow?: (data?: any) => InsertRowResult;
141
142
  private readonly _onDeleteRows?: TableModelProps<T>['onDeleteRows'];
142
- private readonly _onDeleteColumn?: TableModelProps<T>['onDeleteColumn'];
143
+ private readonly _onColumnDelete?: TableModelProps<T>['onColumnDelete'];
143
144
  private readonly _onCellUpdate?: TableModelProps<T>['onCellUpdate'];
144
145
  private readonly _onRowOrderChange?: TableModelProps<T>['onRowOrderChange'];
145
146
  private readonly _onRowAction?: TableModelProps<T>['onRowAction'];
@@ -176,7 +177,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
176
177
  pinnedRows = { top: [], bottom: [] },
177
178
  rowActions = [],
178
179
  onCellUpdate,
179
- onDeleteColumn,
180
+ onColumnDelete,
180
181
  onDeleteRows,
181
182
  onInsertRow,
182
183
  onRowOrderChange,
@@ -292,7 +293,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
292
293
  this._rowActions = rowActions;
293
294
  this._onInsertRow = onInsertRow;
294
295
  this._onDeleteRows = onDeleteRows;
295
- this._onDeleteColumn = onDeleteColumn;
296
+ this._onColumnDelete = onColumnDelete;
296
297
  this._onCellUpdate = onCellUpdate;
297
298
  this._onRowOrderChange = onRowOrderChange;
298
299
  this._onRowAction = onRowAction;
@@ -691,10 +692,10 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
691
692
  const currentRow = this._registry.get(this._rows)[row];
692
693
  invariant(currentRow, 'Invalid row index');
693
694
 
694
- const snapshot = getSnapshot(currentRow);
695
+ const snapshot = { ...getSnapshot(currentRow) };
695
696
  setValue(snapshot, field.path, transformedValue);
696
697
 
697
- const schema = Obj.getSchema(currentRow);
698
+ const schema = Obj.getSchema(currentRow as unknown as Obj.Unknown);
698
699
  invariant(schema);
699
700
 
700
701
  const validationResult = validateSchema(schema, snapshot);
@@ -796,8 +797,8 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
796
797
  }
797
798
 
798
799
  const field = this._projection?.getFields().find((field) => field.id === fieldId);
799
- if (field && this._onDeleteColumn) {
800
- this._onDeleteColumn(field.id);
800
+ if (field && this._onColumnDelete) {
801
+ this._onColumnDelete(field.id);
801
802
  }
802
803
  }
803
804
 
@@ -893,14 +894,14 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
893
894
  if (field) {
894
895
  // Persist sort to view.query.ast
895
896
  const newQuery = baseQuery.orderBy(Order.property<any>(field.path as string, inMemorySort.direction));
896
- Obj.change(view, (v) => {
897
- v.query.ast = newQuery.ast as Mutable<typeof newQuery.ast>;
897
+ Obj.update(view, (view) => {
898
+ view.query.ast = newQuery.ast as Mutable<typeof newQuery.ast>;
898
899
  });
899
900
  }
900
901
  } else {
901
902
  // Clear sort from view.query.ast
902
- Obj.change(view, (v) => {
903
- v.query.ast = baseQuery.ast as Mutable<typeof baseQuery.ast>;
903
+ Obj.update(view, (view) => {
904
+ view.query.ast = baseQuery.ast as Mutable<typeof baseQuery.ast>;
904
905
  });
905
906
  }
906
907
 
@@ -6,16 +6,22 @@ import { Registry } from '@effect-atom/atom-react';
6
6
  import * as Schema from 'effect/Schema';
7
7
  import { beforeEach, describe, expect, it } from 'vitest';
8
8
 
9
- import { Filter, Query, Type } from '@dxos/echo';
9
+ import { Filter, JsonSchema, Query, Type } from '@dxos/echo';
10
10
  import { createEchoSchema } from '@dxos/echo/testing';
11
- import { ProjectionModel, View, createDirectChangeCallback } from '@dxos/schema';
11
+ import { ProjectionModel, ViewModel, createDirectChangeCallback } from '@dxos/schema';
12
12
 
13
13
  import { Table } from '../types';
14
-
15
14
  import { TableModel, type TableModelProps } from './table-model';
16
15
  import { TablePresentation } from './table-presentation';
17
16
 
18
- describe('TablePresentation', () => {
17
+ // Quarantined in CI only — vite resolves `@dxos/react-ui-grid` to the hoisted
18
+ // node_modules copy, which fails the `node` export condition under the
19
+ // workflow's `--no-file-parallelism` runner. Tests pass locally so the suite
20
+ // still runs during development.
21
+ // Trunk.io tracking:
22
+ // https://app.trunk.io/dxos/flaky-tests/test/e027ed98-4aea-5a63-b5ed-10baf76fb11e
23
+ const describeOutsideCI = process.env.CI ? describe.skip : describe;
24
+ describeOutsideCI('TablePresentation', () => {
19
25
  describe('getCells', () => {
20
26
  let registry: Registry.Registry;
21
27
  let data: any[];
@@ -92,14 +98,14 @@ const Test = Schema.Struct({
92
98
  count: Schema.Number,
93
99
  }).pipe(
94
100
  Type.object({
95
- typename: 'example.com/type/Test',
101
+ typename: 'com.example.type.test',
96
102
  version: '0.1.0',
97
103
  }),
98
104
  );
99
105
 
100
106
  const createTableModel = (registry: Registry.Registry, props: Partial<TableModelProps> = {}): TableModel => {
101
107
  const schema = createEchoSchema(Test);
102
- const view = View.make({
108
+ const view = ViewModel.make({
103
109
  query: Query.select(Filter.type(schema)),
104
110
  jsonSchema: schema.jsonSchema,
105
111
  });
@@ -108,7 +114,7 @@ const createTableModel = (registry: Registry.Registry, props: Partial<TableModel
108
114
  registry,
109
115
  view,
110
116
  baseSchema: schema.jsonSchema,
111
- change: createDirectChangeCallback(view.projection, schema.jsonSchema),
117
+ change: createDirectChangeCallback(view.projection, JsonSchema.toJsonSchema(schema)),
112
118
  });
113
119
  projection.normalizeView();
114
120
  return new TableModel({ registry, object, projection, ...props });
@@ -6,6 +6,7 @@ import { Atom, type Registry } from '@effect-atom/atom-react';
6
6
  import * as Predicate from 'effect/Predicate';
7
7
 
8
8
  import { Obj } from '@dxos/echo';
9
+ import { type View } from '@dxos/echo';
9
10
  import { Format, TypeEnum, getValue } from '@dxos/echo/internal';
10
11
  import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
11
12
  import {
@@ -15,11 +16,10 @@ import {
15
16
  type DxGridPlaneRange,
16
17
  toPlaneCellIndex,
17
18
  } from '@dxos/react-ui-grid';
18
- import { type FieldType, VIEW_FIELD_LIMIT } from '@dxos/schema';
19
+ import { VIEW_FIELD_LIMIT } from '@dxos/schema';
19
20
  import { mx } from '@dxos/ui-theme';
20
21
 
21
22
  import { tableButtons, tableControls } from '../util';
22
-
23
23
  import { type SelectionMode } from './selection-model';
24
24
  import { type TableModel, type TableRow } from './table-model';
25
25
 
@@ -107,7 +107,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
107
107
  private createDataCell(
108
108
  cells: DxGridPlaneCells,
109
109
  obj: T,
110
- field: FieldType,
110
+ field: View.FieldType,
111
111
  colIndex: number,
112
112
  displayIndex: number,
113
113
  ): void {
@@ -210,7 +210,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
210
210
  const targetObj = getValue(obj, field.path)?.target;
211
211
  if (targetObj) {
212
212
  const dxn = Obj.getDXN(targetObj)?.toString();
213
- 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>`;
213
+ cell.accessoryHtml = `<div role="none" class="absolute end-0 inset-y-0 p-(--dx-grid-cell-content-padding-block)"><dx-anchor dxn=${dxn} class="dx-button w-6 aspect-square min-h-0" data-dx-grid-action="accessory"><dx-icon icon="ph--link-simple--regular"/></dx-anchor></div>`;
214
214
  }
215
215
  }
216
216
 
@@ -335,11 +335,11 @@ export class TablePresentation<T extends TableRow = TableRow> {
335
335
  value: '',
336
336
  resizeHandle: 'col',
337
337
  accessoryHtml: `
338
- <span class="grow min-is-0 truncate">${props.title ?? field.path}</span>
338
+ <span class="grow min-w-0 truncate">${props.title ?? field.path}</span>
339
339
  ${direction !== undefined ? tableButtons.sort.render({ fieldId: field.id, direction }) : ''}
340
340
  ${tableButtons.columnSettings.render({ fieldId: field.id })}
341
341
  `,
342
- className: '!bg-toolbarSurface !text-description [&>div]:flex [&>div]:items-stretch',
342
+ className: '!bg-toolbar-surface text-description! [&>div]:flex [&>div]:items-stretch',
343
343
  };
344
344
  }
345
345
 
@@ -382,7 +382,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
382
382
  if (!this.model.features.selection.enabled || this.model.selection.selectionMode === 'single') {
383
383
  return {
384
384
  [toPlaneCellIndex({ col: 0, row: 0 })]: {
385
- className: '!bg-toolbarSurface',
385
+ className: '!bg-toolbar-surface',
386
386
  readonly: true,
387
387
  value: '',
388
388
  },
@@ -396,7 +396,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
396
396
  header: true,
397
397
  checked: this.model.selection.allRowsSelected,
398
398
  }),
399
- className: '!bg-toolbarSurface',
399
+ className: '!bg-toolbar-surface',
400
400
  readonly: true,
401
401
  value: '',
402
402
  },
@@ -411,7 +411,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
411
411
  disabled: (this.model.projection?.getFields()?.length ?? 0) >= VIEW_FIELD_LIMIT,
412
412
  })
413
413
  : undefined,
414
- className: '!bg-toolbarSurface',
414
+ className: '!bg-toolbar-surface',
415
415
  readonly: true,
416
416
  value: '',
417
417
  },
@@ -465,7 +465,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
465
465
  export const cellClassesForRowSelection = (selected: boolean, selectionMode: SelectionMode) => {
466
466
  if (!selected) {
467
467
  if (selectionMode === 'single') {
468
- return ['!cursor-pointer'];
468
+ return ['cursor-pointer!'];
469
469
  } else {
470
470
  return undefined;
471
471
  }
@@ -473,8 +473,8 @@ export const cellClassesForRowSelection = (selected: boolean, selectionMode: Sel
473
473
 
474
474
  switch (selectionMode) {
475
475
  case 'single':
476
- return ['!bg-currentRelated dx-grid__cell--no-focus-unfurl hover:bg-hoverSurface !cursor-pointer'];
476
+ return ['dx-grid__cell--no-focus-unfurl !bg-current-surface hover:bg-hover-surface cursor-pointer!'];
477
477
  case 'multiple':
478
- return ['!bg-gridCellSelected'];
478
+ return ['!bg-grid-cell-selected'];
479
479
  }
480
480
  };
@@ -17,6 +17,7 @@ const TABLE_SELECTORS = {
17
17
  },
18
18
  columnDelete: 'column-delete',
19
19
  rowDelete: 'row-menu-delete',
20
+ addRow: 'table.toolbar.add-row',
20
21
  } as const;
21
22
 
22
23
  export class TableManager {
@@ -53,10 +54,16 @@ export class TableManager {
53
54
  await this.page.getByTestId(TABLE_SELECTORS.columnSort[direction]).click();
54
55
  }
55
56
 
56
- public async addColumn({ label, format }: { label: string; format: string }): Promise<void> {
57
+ public async addRow(): Promise<void> {
58
+ await this.page.getByTestId(TABLE_SELECTORS.addRow).click();
59
+ }
60
+
61
+ public async addColumn({ label, format }: { label: string; format?: string }): Promise<void> {
57
62
  await this.page.getByTestId(TABLE_SELECTORS.newColumnButton).click();
58
- await this.page.getByRole('combobox').click();
59
- await this.page.getByLabel(format).click();
63
+ if (format) {
64
+ await this.page.getByRole('combobox').click();
65
+ await this.page.getByLabel(format).click();
66
+ }
60
67
  await this.page.getByPlaceholder('Property label').click();
61
68
  await this.page.getByPlaceholder('Property label').fill(label);
62
69
  await this.page.getByRole('button', { name: 'Save' }).click();
@@ -10,7 +10,7 @@ export default defineConfig({
10
10
  ...e2ePreset(import.meta.dirname),
11
11
  // TODO(wittjosiah): Avoid hard-coding ports.
12
12
  webServer: {
13
- command: 'moon run storybook-react:serve-e2e -- --port=9004',
13
+ command: 'pnpm storybook dev --ci --quiet --port=9004 --config-dir=.storybook',
14
14
  port: 9004,
15
15
  reuseExistingServer: false,
16
16
  },