@dxos/react-ui-table 0.8.4-main.406dc2a → 0.8.4-main.548089c

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 (60) hide show
  1. package/dist/lib/browser/{chunk-4K7JPALT.mjs → chunk-2PFAPQL4.mjs} +3 -3
  2. package/dist/lib/browser/chunk-2PFAPQL4.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-OZTXLZGM.mjs → chunk-GS2UNGJK.mjs} +434 -463
  4. package/dist/lib/browser/chunk-GS2UNGJK.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +41 -38
  6. package/dist/lib/browser/index.mjs.map +3 -3
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +4 -4
  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-MK6OVUF6.mjs → chunk-6POOFFYF.mjs} +3 -3
  12. package/dist/lib/node-esm/chunk-6POOFFYF.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-S56Z4V4X.mjs → chunk-TRR3C5NX.mjs} +434 -463
  14. package/dist/lib/node-esm/chunk-TRR3C5NX.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +41 -38
  16. package/dist/lib/node-esm/index.mjs.map +3 -3
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +4 -4
  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/Relations.stories.d.ts +2 -3
  22. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  24. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +2 -2
  26. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  27. package/dist/types/src/hooks/useTableModel.d.ts +2 -2
  28. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  29. package/dist/types/src/model/table-model.d.ts +3 -3
  30. package/dist/types/src/model/table-model.d.ts.map +1 -1
  31. package/dist/types/src/model/table-sorting.d.ts +2 -2
  32. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  33. package/dist/types/src/testing/useTestTableModel.d.ts +2 -2
  34. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  35. package/dist/types/src/types/schema.d.ts +3 -3
  36. package/dist/types/src/types/schema.d.ts.map +1 -1
  37. package/dist/types/src/util/dynamic-table.d.ts +2 -2
  38. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  39. package/dist/types/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +41 -40
  41. package/src/components/Table/DynamicTable.stories.tsx +3 -3
  42. package/src/components/Table/Relations.stories.tsx +16 -22
  43. package/src/components/Table/RowActionsMenu.tsx +21 -13
  44. package/src/components/Table/Table.stories.tsx +12 -12
  45. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +6 -5
  46. package/src/components/TableToolbar/TableToolbar.tsx +31 -21
  47. package/src/hooks/useTableModel.ts +4 -4
  48. package/src/model/table-model.test.ts +2 -2
  49. package/src/model/table-model.ts +10 -7
  50. package/src/model/table-presentation.test.ts +2 -2
  51. package/src/model/table-sorting.ts +8 -8
  52. package/src/playwright/TableManager.ts +1 -1
  53. package/src/playwright/smoke.spec.ts +7 -5
  54. package/src/testing/useTestTableModel.ts +2 -2
  55. package/src/types/schema.ts +4 -4
  56. package/src/util/dynamic-table.ts +4 -5
  57. package/dist/lib/browser/chunk-4K7JPALT.mjs.map +0 -7
  58. package/dist/lib/browser/chunk-OZTXLZGM.mjs.map +0 -7
  59. package/dist/lib/node-esm/chunk-MK6OVUF6.mjs.map +0 -7
  60. package/dist/lib/node-esm/chunk-S56Z4V4X.mjs.map +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-table",
3
- "version": "0.8.4-main.406dc2a",
3
+ "version": "0.8.4-main.548089c",
4
4
  "description": "A table component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -65,61 +65,62 @@
65
65
  "@radix-ui/react-use-controllable-state": "1.1.0",
66
66
  "date-fns": "^3.3.1",
67
67
  "lodash.orderby": "^4.6.0",
68
- "@dxos/async": "0.8.4-main.406dc2a",
69
- "@dxos/debug": "0.8.4-main.406dc2a",
70
- "@dxos/context": "0.8.4-main.406dc2a",
71
- "@dxos/echo": "0.8.4-main.406dc2a",
72
- "@dxos/effect": "0.8.4-main.406dc2a",
73
- "@dxos/echo-db": "0.8.4-main.406dc2a",
74
- "@dxos/keys": "0.8.4-main.406dc2a",
75
- "@dxos/invariant": "0.8.4-main.406dc2a",
76
- "@dxos/lit-grid": "0.8.4-main.406dc2a",
77
- "@dxos/log": "0.8.4-main.406dc2a",
78
- "@dxos/plugin-search": "0.8.4-main.406dc2a",
79
- "@dxos/random": "0.8.4-main.406dc2a",
80
- "@dxos/react-ui-attention": "0.8.4-main.406dc2a",
81
- "@dxos/live-object": "0.8.4-main.406dc2a",
82
- "@dxos/react-ui-editor": "0.8.4-main.406dc2a",
83
- "@dxos/react-ui-components": "0.8.4-main.406dc2a",
84
- "@dxos/react-ui-form": "0.8.4-main.406dc2a",
85
- "@dxos/react-ui-grid": "0.8.4-main.406dc2a",
86
- "@dxos/react-ui-menu": "0.8.4-main.406dc2a",
87
- "@dxos/react-ui-searchlist": "0.8.4-main.406dc2a",
88
- "@dxos/react-ui-stack": "0.8.4-main.406dc2a",
89
- "@dxos/react-client": "0.8.4-main.406dc2a",
90
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.406dc2a",
91
- "@dxos/react-ui-types": "0.8.4-main.406dc2a",
92
- "@dxos/schema": "0.8.4-main.406dc2a",
93
- "@dxos/util": "0.8.4-main.406dc2a"
68
+ "@dxos/context": "0.8.4-main.548089c",
69
+ "@dxos/async": "0.8.4-main.548089c",
70
+ "@dxos/debug": "0.8.4-main.548089c",
71
+ "@dxos/echo": "0.8.4-main.548089c",
72
+ "@dxos/invariant": "0.8.4-main.548089c",
73
+ "@dxos/effect": "0.8.4-main.548089c",
74
+ "@dxos/keys": "0.8.4-main.548089c",
75
+ "@dxos/lit-grid": "0.8.4-main.548089c",
76
+ "@dxos/echo-db": "0.8.4-main.548089c",
77
+ "@dxos/live-object": "0.8.4-main.548089c",
78
+ "@dxos/log": "0.8.4-main.548089c",
79
+ "@dxos/random": "0.8.4-main.548089c",
80
+ "@dxos/react-client": "0.8.4-main.548089c",
81
+ "@dxos/plugin-search": "0.8.4-main.548089c",
82
+ "@dxos/react-ui-attention": "0.8.4-main.548089c",
83
+ "@dxos/react-ui-editor": "0.8.4-main.548089c",
84
+ "@dxos/react-ui-components": "0.8.4-main.548089c",
85
+ "@dxos/react-ui-form": "0.8.4-main.548089c",
86
+ "@dxos/react-ui-grid": "0.8.4-main.548089c",
87
+ "@dxos/react-ui-menu": "0.8.4-main.548089c",
88
+ "@dxos/react-ui-searchlist": "0.8.4-main.548089c",
89
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.548089c",
90
+ "@dxos/types": "0.8.4-main.548089c",
91
+ "@dxos/react-ui-types": "0.8.4-main.548089c",
92
+ "@dxos/util": "0.8.4-main.548089c",
93
+ "@dxos/react-ui-stack": "0.8.4-main.548089c",
94
+ "@dxos/schema": "0.8.4-main.548089c"
94
95
  },
95
96
  "devDependencies": {
96
- "@effect-rx/rx-react": "0.42.4",
97
+ "@effect-atom/atom-react": "^0.3.4",
97
98
  "@effect/platform": "0.92.1",
98
99
  "@types/lodash.orderby": "^4.6.9",
99
100
  "@types/react": "~19.2.2",
100
- "@types/react-dom": "~19.2.1",
101
+ "@types/react-dom": "~19.2.2",
101
102
  "effect": "3.18.3",
102
103
  "fast-check": "^3.19.0",
103
104
  "react": "~19.2.0",
104
105
  "react-dom": "~19.2.0",
105
106
  "vite": "7.1.9",
106
- "@dxos/echo-signals": "0.8.4-main.406dc2a",
107
- "@dxos/plugin-search": "0.8.4-main.406dc2a",
108
- "@dxos/react-ui": "0.8.4-main.406dc2a",
109
- "@dxos/react-ui-theme": "0.8.4-main.406dc2a",
110
- "@dxos/lit-ui": "0.8.4-main.406dc2a",
111
- "@dxos/random": "0.8.4-main.406dc2a",
112
- "@dxos/storybook-utils": "0.8.4-main.406dc2a",
113
- "@dxos/test-utils": "0.8.4-main.406dc2a"
107
+ "@dxos/lit-ui": "0.8.4-main.548089c",
108
+ "@dxos/plugin-search": "0.8.4-main.548089c",
109
+ "@dxos/echo-signals": "0.8.4-main.548089c",
110
+ "@dxos/random": "0.8.4-main.548089c",
111
+ "@dxos/react-ui": "0.8.4-main.548089c",
112
+ "@dxos/react-ui-theme": "0.8.4-main.548089c",
113
+ "@dxos/storybook-utils": "0.8.4-main.548089c",
114
+ "@dxos/test-utils": "0.8.4-main.548089c"
114
115
  },
115
116
  "peerDependencies": {
116
- "@effect-rx/rx-react": "^0.34.1",
117
+ "@effect-atom/atom-react": "^0.3.4",
117
118
  "@effect/platform": "^0.80.12",
118
119
  "effect": "^3.13.3",
119
120
  "react": "^19.0.0",
120
121
  "react-dom": "^19.0.0",
121
- "@dxos/react-ui": "0.8.4-main.406dc2a",
122
- "@dxos/react-ui-theme": "0.8.4-main.406dc2a"
122
+ "@dxos/react-ui": "0.8.4-main.548089c",
123
+ "@dxos/react-ui-theme": "0.8.4-main.548089c"
123
124
  },
124
125
  "publishConfig": {
125
126
  "access": "public"
@@ -132,7 +132,7 @@ export const WithEchoSchema: StoryObj = {
132
132
  render: () => {
133
133
  const client = useClient();
134
134
  const { space } = useClientProvider();
135
- const schema = useSchema(client, space, Testing.Contact.typename);
135
+ const schema = useSchema(client, space, Testing.Person.typename);
136
136
  const objects = useQuery(space, schema ? Filter.type(schema) : Filter.nothing());
137
137
  if (!schema) {
138
138
  return <div>Loading schema...</div>;
@@ -142,13 +142,13 @@ export const WithEchoSchema: StoryObj = {
142
142
  },
143
143
  decorators: [
144
144
  withClientProvider({
145
- types: [Testing.Contact],
145
+ types: [Testing.Person],
146
146
  createIdentity: true,
147
147
  createSpace: true,
148
148
  onCreateSpace: async ({ space }) => {
149
149
  Array.from({ length: 10 }).forEach(() => {
150
150
  space.db.add(
151
- Obj.make(Testing.Contact, {
151
+ Obj.make(Testing.Person, {
152
152
  name: faker.person.fullName(),
153
153
  email: faker.internet.email(),
154
154
  }),
@@ -15,10 +15,11 @@ import { faker } from '@dxos/random';
15
15
  import { useClient } from '@dxos/react-client';
16
16
  import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
17
17
  import { useAsyncEffect } from '@dxos/react-ui';
18
- import { withTheme } from '@dxos/react-ui/testing';
18
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
19
19
  import { translations as formTranslations } from '@dxos/react-ui-form';
20
- import { DataType } from '@dxos/schema';
20
+ import { View } from '@dxos/schema';
21
21
  import { type ValueGenerator, createAsyncGenerator } from '@dxos/schema/testing';
22
+ import { Organization, Person } from '@dxos/types';
22
23
 
23
24
  import { useTableModel } from '../../hooks';
24
25
  import { type TableFeatures, TablePresentation, type TableRow } from '../../model';
@@ -37,7 +38,7 @@ const generator: ValueGenerator = faker as any;
37
38
  const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
38
39
  const client = useClient();
39
40
  const { space } = useClientProvider();
40
- const [view, setView] = useState<DataType.View>();
41
+ const [view, setView] = useState<View.View>();
41
42
  const [jsonSchema, setJsonSchema] = useState<JsonSchemaType>();
42
43
 
43
44
  const features = useMemo<TableFeatures>(
@@ -87,8 +88,8 @@ const useTestModel = <S extends Type.Obj.Any>(schema: S, count: number) => {
87
88
 
88
89
  const DefaultStory = () => {
89
90
  const client = useClient();
90
- const { model: orgModel, presentation: orgPresentation } = useTestModel(DataType.Organization, 50);
91
- const { model: contactModel, presentation: contactPresentation } = useTestModel(DataType.Person, 50);
91
+ const { model: orgModel, presentation: orgPresentation } = useTestModel(Organization.Organization, 50);
92
+ const { model: contactModel, presentation: contactPresentation } = useTestModel(Person.Person, 50);
92
93
  const { space } = useClientProvider();
93
94
 
94
95
  const handleCreate = useCallback(
@@ -103,7 +104,7 @@ const DefaultStory = () => {
103
104
  <TableComponent.Root>
104
105
  <TableComponent.Main
105
106
  model={orgModel}
106
- schema={DataType.Organization}
107
+ schema={Organization.Organization}
107
108
  presentation={orgPresentation}
108
109
  onCreate={handleCreate}
109
110
  client={client}
@@ -114,7 +115,7 @@ const DefaultStory = () => {
114
115
  <TableComponent.Root>
115
116
  <TableComponent.Main
116
117
  model={contactModel}
117
- schema={DataType.Person}
118
+ schema={Person.Person}
118
119
  presentation={contactPresentation}
119
120
  onCreate={handleCreate}
120
121
  client={client}
@@ -131,8 +132,10 @@ const meta = {
131
132
  render: DefaultStory,
132
133
  decorators: [
133
134
  withTheme,
135
+ // TODO(thure): Shouldn’t `layout: 'fullscreen'` below make this unnecessary?
136
+ withLayout({ classNames: 'fixed inset-0' }),
134
137
  withClientProvider({
135
- types: [DataType.View, DataType.Organization, DataType.Person, Table.Table],
138
+ types: [View.View, Organization.Organization, Person.Person, Table.Table],
136
139
  createIdentity: true,
137
140
  createSpace: true,
138
141
  }),
@@ -149,9 +152,7 @@ export default meta;
149
152
  type Story = StoryObj<typeof meta>;
150
153
 
151
154
  export const Default: Story = {
152
- // TODO(wittjosiah): This test is flaky, especially in CI.
153
- // Most typical failure is `targetCell` returns `null`.
154
- _play: async ({ canvasElement }: any) => {
155
+ play: async ({ canvasElement }: any) => {
155
156
  const canvas = within(canvasElement);
156
157
  const body = within(document.body);
157
158
 
@@ -165,11 +166,8 @@ export const Default: Story = {
165
166
  // Scroll to the relations column (column 4) - this mimics the scrollToColumn call
166
167
  (secondGrid.closest('dx-grid') as DxGrid).scrollToColumn(4);
167
168
 
168
- // Wait for scroll to complete
169
- await new Promise((resolve) => setTimeout(resolve, 1000));
170
-
171
169
  // Find and click the target cell (first row, relations column)
172
- const targetCell = secondGrid.querySelector('[data-dx-grid-plane="grid"] [aria-rowindex="0"][aria-colindex="4"]');
170
+ const targetCell = await within(secondGrid).findByTestId('grid.4.0', undefined, { timeout: 10_000 });
173
171
  await expect(targetCell).toBeVisible();
174
172
 
175
173
  // Click to focus the cell
@@ -185,11 +183,9 @@ export const Default: Story = {
185
183
  await userEvent.click(searchField);
186
184
 
187
185
  // Get the first organization name from the first table to search for
188
- const orgCell = firstGrid.querySelector(
189
- '[data-dx-grid-plane="grid"] [aria-rowindex="0"][aria-colindex="0"] .dx-grid__cell__content',
190
- ) as HTMLElement;
186
+ const orgCell = await within(firstGrid).findByTestId('grid.0.0', undefined, { timeout: 10_000 });
191
187
 
192
- const orgName = orgCell.textContent;
188
+ const orgName = (orgCell.querySelector('.dx-grid__cell__content') as HTMLElement).textContent;
193
189
  // Type the first 4 characters to search
194
190
  await userEvent.type(searchField, orgName.substring(0, 4));
195
191
 
@@ -209,9 +205,7 @@ export const Default: Story = {
209
205
 
210
206
  // Test object creation (new relations) - equivalent to "new relations work as expected" test
211
207
  // Find a different cell to test object creation (second row, relations column)
212
- const newTargetCell = secondGrid.querySelector(
213
- '[data-dx-grid-plane="grid"] [aria-rowindex="1"][aria-colindex="4"]',
214
- );
208
+ const newTargetCell = await within(secondGrid).findByTestId('grid.4.1', undefined, { timeout: 10_000 });
215
209
  await expect(newTargetCell).toBeTruthy();
216
210
 
217
211
  // Click to focus the cell
@@ -23,24 +23,32 @@ export const RowActionsMenu = ({ model, modals }: RowActionsMenuProps) => {
23
23
  <DropdownMenu.VirtualTrigger virtualRef={modals.trigger} />
24
24
  <DropdownMenu.Content>
25
25
  <DropdownMenu.Viewport>
26
+ {/* Custom actions */}
27
+ {model.rowActions?.length > 0 && (
28
+ <>
29
+ <DropdownMenu.Group>
30
+ {model.rowActions?.map((action) => (
31
+ <DropdownMenu.Item
32
+ key={action.id}
33
+ data-testid={`row-action-${action.id}`}
34
+ onClick={() => {
35
+ modals.close();
36
+ model.handleRowAction(action.id, state.rowIndex);
37
+ }}
38
+ >
39
+ {toLocalizedString(action.label, t)}
40
+ </DropdownMenu.Item>
41
+ ))}
42
+ </DropdownMenu.Group>
43
+ <DropdownMenu.Separator />
44
+ </>
45
+ )}
46
+ {/* Default actions */}
26
47
  {model.features.dataEditable !== false && (
27
48
  <DropdownMenu.Item data-testid='row-menu-delete' onClick={() => model.deleteRow(state.rowIndex)}>
28
49
  {t(hasSelection ? 'bulk delete row label' : 'delete row label')}
29
50
  </DropdownMenu.Item>
30
51
  )}
31
- {/* Custom actions */}
32
- {model.rowActions?.map((action) => (
33
- <DropdownMenu.Item
34
- key={action.id}
35
- data-testid={`row-action-${action.id}`}
36
- onClick={() => {
37
- modals.close();
38
- model.handleRowAction(action.id, state.rowIndex);
39
- }}
40
- >
41
- {toLocalizedString(action.label, t)}
42
- </DropdownMenu.Item>
43
- ))}
44
52
  </DropdownMenu.Viewport>
45
53
  <DropdownMenu.Arrow />
46
54
  </DropdownMenu.Content>
@@ -24,7 +24,7 @@ import { withClientProvider } from '@dxos/react-client/testing';
24
24
  import { withTheme } from '@dxos/react-ui/testing';
25
25
  import { ViewEditor } from '@dxos/react-ui-form';
26
26
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
27
- import { DataType, getSchemaFromPropertyDefinitions, getTypenameFromQuery } from '@dxos/schema';
27
+ import { View, getSchemaFromPropertyDefinitions, getTypenameFromQuery } from '@dxos/schema';
28
28
  import { Testing, createObjectFactory } from '@dxos/schema/testing';
29
29
 
30
30
  import { useTestTableModel } from '../../testing';
@@ -70,7 +70,7 @@ const StoryViewEditor = ({
70
70
  space,
71
71
  handleDeleteColumn,
72
72
  }: {
73
- view?: DataType.View;
73
+ view?: View.View;
74
74
  schema?: Schema.Schema.AnyNoContext;
75
75
  space?: Space;
76
76
  handleDeleteColumn: (fieldId: string) => void;
@@ -138,7 +138,7 @@ const DefaultStory = () => {
138
138
  />
139
139
  </TableComponent.Root>
140
140
  </div>
141
- <div className='flex flex-col h-full border-l border-separator overflow-y-auto'>
141
+ <div className='flex flex-col bs-full border-l border-separator overflow-y-auto'>
142
142
  <StoryViewEditor view={view} schema={schema} space={space} handleDeleteColumn={handleDeleteColumn} />
143
143
  <SyntaxHighlighter language='json' className='text-xs'>
144
144
  {JSON.stringify({ view, schema }, null, 2)}
@@ -162,15 +162,15 @@ const meta = {
162
162
  decorators: [
163
163
  withTheme,
164
164
  withClientProvider({
165
- types: [DataType.View, Table.Table],
165
+ types: [View.View, Table.Table],
166
166
  createIdentity: true,
167
167
  createSpace: true,
168
168
  onCreateSpace: async ({ client, space }) => {
169
169
  const [schema] = await space.db.schemaRegistry.register([TestSchema]);
170
170
  const { view } = await Table.makeView({ client, space, typename: schema.typename });
171
171
  view.projection.fields = [
172
- view.projection.fields.find((field) => field.path === 'name')!,
173
- ...view.projection.fields.filter((field) => field.path !== 'name'),
172
+ view.projection.fields.find((field: any) => field.path === 'name')!,
173
+ ...view.projection.fields.filter((field: any) => field.path !== 'name'),
174
174
  ];
175
175
 
176
176
  space.db.add(view);
@@ -206,16 +206,16 @@ export const StaticSchema: StoryObj = {
206
206
  render: DefaultStory,
207
207
  decorators: [
208
208
  withClientProvider({
209
- types: [DataType.View, Table.Table, Testing.Contact, Testing.Organization],
209
+ types: [View.View, Table.Table],
210
210
  createIdentity: true,
211
211
  createSpace: true,
212
212
  onCreateSpace: async ({ client, space }) => {
213
- const { view } = await Table.makeView({ client, space, typename: Testing.Contact.typename });
213
+ const { view } = await Table.makeView({ client, space, typename: Testing.Person.typename });
214
214
  space.db.add(view);
215
215
 
216
216
  const factory = createObjectFactory(space.db, faker as any);
217
217
  await factory([
218
- { type: Testing.Contact, count: 10 },
218
+ { type: Testing.Person, count: 10 },
219
219
  // { type: Testing.Organization, count: 1 },
220
220
  ]);
221
221
  },
@@ -248,7 +248,7 @@ export const ArrayOfObjects: StoryObj = {
248
248
  render: DefaultStory,
249
249
  decorators: [
250
250
  withClientProvider({
251
- types: [DataType.View, Table.Table, Testing.Contact, Testing.Organization, ContactWithArrayOfEmails],
251
+ types: [View.View, Table.Table, Testing.Person, Testing.Organization, ContactWithArrayOfEmails],
252
252
  createIdentity: true,
253
253
  createSpace: true,
254
254
  onCreateSpace: async ({ client, space }) => {
@@ -257,7 +257,7 @@ export const ArrayOfObjects: StoryObj = {
257
257
 
258
258
  const factory = createObjectFactory(space.db, faker as any);
259
259
  await factory([
260
- // { type: Testing.Contact, count: 10 },
260
+ // { type: Testing.Person, count: 10 },
261
261
  // { type: Testing.Organization, count: 1 },
262
262
  { type: ContactWithArrayOfEmails, count: 10 },
263
263
  ]);
@@ -275,7 +275,7 @@ export const Tags: Meta<StoryProps> = {
275
275
  render: DefaultStory,
276
276
  decorators: [
277
277
  withClientProvider({
278
- types: [DataType.View, Table.Table],
278
+ types: [View.View, Table.Table],
279
279
  createIdentity: true,
280
280
  createSpace: true,
281
281
  onCreateSpace: async ({ client, space }) => {
@@ -10,7 +10,8 @@ import { faker } from '@dxos/random';
10
10
  import { withClientProvider } from '@dxos/react-client/testing';
11
11
  import { withTheme } from '@dxos/react-ui/testing';
12
12
  import { Grid, type GridEditing, defaultRowSize } from '@dxos/react-ui-grid';
13
- import { DataType } from '@dxos/schema';
13
+ import { View } from '@dxos/schema';
14
+ import { Task } from '@dxos/types';
14
15
 
15
16
  import { useTestTableModel } from '../../testing';
16
17
  import { translations } from '../../translations';
@@ -32,7 +33,7 @@ const DefaultStory = ({ editing }: StoryProps) => {
32
33
  return (
33
34
  <div className='flex w-[300px] border border-separator' style={{ height: defaultRowSize }}>
34
35
  <Grid.Root id='test' editing={editing}>
35
- <TableCellEditor model={model} schema={DataType.Task} />
36
+ <TableCellEditor model={model} schema={Task.Task} />
36
37
  </Grid.Root>
37
38
  </div>
38
39
  );
@@ -45,15 +46,15 @@ const meta = {
45
46
  decorators: [
46
47
  withTheme,
47
48
  withClientProvider({
48
- types: [DataType.View, DataType.Task, Table.Table],
49
+ types: [View.View, Task.Task, Table.Table],
49
50
  createIdentity: true,
50
51
  createSpace: true,
51
52
  onCreateSpace: async ({ client, space }) => {
52
- const { view } = await Table.makeView({ client, space, typename: DataType.Task.typename });
53
+ const { view } = await Table.makeView({ client, space, typename: Task.Task.typename });
53
54
  space.db.add(view);
54
55
  Array.from({ length: 10 }).forEach(() => {
55
56
  space.db.add(
56
- Obj.make(DataType.Task, {
57
+ Obj.make(Task.Task, {
57
58
  title: faker.person.fullName(),
58
59
  status: faker.helpers.arrayElement(['todo', 'in-progress', 'done'] as const),
59
60
  description: faker.lorem.sentence(),
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
5
+ import { Atom } from '@effect-atom/atom-react';
6
6
  import React, { useMemo } from 'react';
7
7
 
8
8
  import { live } from '@dxos/live-object';
@@ -30,12 +30,14 @@ export type TableToolbarActionType = 'add-row' | 'comment' | 'save-view';
30
30
 
31
31
  type TableToolbarState = Partial<{ viewDirty: boolean }>;
32
32
 
33
+ // TODO(burdon): Radix style layout.
34
+
33
35
  export type TableToolbarProps = ThemedClassName<
34
36
  TableToolbarState & {
35
37
  onAdd: () => void;
36
38
  onSave: () => void;
37
39
  attendableId?: string;
38
- customActions?: Rx.Rx<ActionGraphProps>;
40
+ customActions?: Atom.Atom<ActionGraphProps>;
39
41
  }
40
42
  >;
41
43
 
@@ -46,33 +48,41 @@ const createTableToolbarActions = ({
46
48
  customActions,
47
49
  }: {
48
50
  state: TableToolbarState;
49
- onAdd: () => void;
50
- onSave: () => void;
51
- customActions?: Rx.Rx<ActionGraphProps>;
51
+ onAdd?: () => void;
52
+ onSave?: () => void;
53
+ customActions?: Atom.Atom<ActionGraphProps>;
52
54
  }) =>
53
- Rx.make((get) => {
54
- const add = createMenuAction<TableToolbarActionProperties>('add-row', onAdd, {
55
- type: 'add-row' as const,
56
- icon: 'ph--plus--regular',
57
- label: ['add row', { ns: translationKey }],
58
- testId: 'table.toolbar.add-row',
59
- });
60
- const save = createMenuAction<TableToolbarActionProperties>('save-view', onSave, {
61
- type: 'save-view' as const,
62
- icon: 'ph--floppy-disk--regular',
63
- label: ['save view label', { ns: translationKey }],
64
- testId: 'table.toolbar.save-view',
65
- iconOnly: false,
66
- hidden: get(rxFromSignal(() => !state.viewDirty)),
67
- });
55
+ Atom.make((get) => {
56
+ const nodes: ActionGraphNodes = [];
57
+ if (onAdd) {
58
+ const add = createMenuAction<TableToolbarActionProperties>('add-row', onAdd, {
59
+ type: 'add-row' as const,
60
+ icon: 'ph--plus--regular',
61
+ label: ['add row', { ns: translationKey }],
62
+ testId: 'table.toolbar.add-row',
63
+ });
64
+ nodes.push(add);
65
+ }
66
+ if (onSave) {
67
+ const save = createMenuAction<TableToolbarActionProperties>('save-view', onSave, {
68
+ type: 'save-view' as const,
69
+ icon: 'ph--floppy-disk--regular',
70
+ label: ['save view label', { ns: translationKey }],
71
+ testId: 'table.toolbar.save-view',
72
+ iconOnly: false,
73
+ hidden: get(rxFromSignal(() => !state.viewDirty)),
74
+ });
75
+ nodes.push(save);
76
+ }
68
77
  const gap = createGapSeparator();
69
- const nodes: ActionGraphNodes = [add, save, ...gap.nodes];
78
+ nodes.push(...gap.nodes);
70
79
  const edges: ActionGraphEdges = nodes.map(({ id: target }) => ({ source: 'root', target }));
71
80
  if (customActions) {
72
81
  const custom = get(customActions);
73
82
  nodes.push(...custom.nodes);
74
83
  edges.push(...custom.edges);
75
84
  }
85
+
76
86
  return {
77
87
  nodes,
78
88
  edges,
@@ -6,17 +6,17 @@ import { effect } from '@preact/signals-core';
6
6
  import orderBy from 'lodash.orderby';
7
7
  import { useEffect, useMemo, useState } from 'react';
8
8
 
9
+ import { Obj } from '@dxos/echo';
9
10
  import { type JsonSchemaType } from '@dxos/echo/internal';
10
11
  import { type Live } from '@dxos/live-object';
11
- import { fullyQualifiedId } from '@dxos/react-client/echo';
12
12
  import { useSelected, useSelectionActions } from '@dxos/react-ui-attention';
13
- import { type DataType, type ProjectionModel } from '@dxos/schema';
13
+ import { type ProjectionModel, type View } from '@dxos/schema';
14
14
  import { isNonNullable } from '@dxos/util';
15
15
 
16
16
  import { TableModel, type TableModelProps, type TableRow, type TableRowAction } from '../model';
17
17
 
18
18
  export type UseTableModelParams<T extends TableRow = TableRow> = {
19
- view?: DataType.View;
19
+ view?: View.View;
20
20
  schema?: JsonSchemaType;
21
21
  projection?: ProjectionModel;
22
22
  rows?: Live<T>[];
@@ -39,7 +39,7 @@ export const useTableModel = <T extends TableRow = TableRow>({
39
39
  onRowAction,
40
40
  ...props
41
41
  }: UseTableModelParams<T>): TableModel<T> | undefined => {
42
- const selected = useSelected(view && fullyQualifiedId(view), 'multi');
42
+ const selected = useSelected(view && Obj.getDXN(view).toString(), 'multi');
43
43
  const initialSelection = useMemo(() => selected, [view]);
44
44
 
45
45
  const [model, setModel] = useState<TableModel<T>>();
@@ -12,7 +12,7 @@ import { updateCounter } from '@dxos/echo/testing';
12
12
  import { createEchoSchema } from '@dxos/echo/testing';
13
13
  import { registerSignalsRuntime } from '@dxos/echo-signals';
14
14
  import { live } from '@dxos/live-object';
15
- import { createView } from '@dxos/schema';
15
+ import { View } from '@dxos/schema';
16
16
 
17
17
  import { Table } from '../types';
18
18
 
@@ -113,7 +113,7 @@ class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.
113
113
  const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
114
114
  const schema = createEchoSchema(Test);
115
115
  const table = Table.make();
116
- const view = createView({
116
+ const view = View.make({
117
117
  query: Query.select(Filter.type(schema)),
118
118
  jsonSchema: schema.jsonSchema,
119
119
  presentation: table,
@@ -18,7 +18,6 @@ import {
18
18
  import { invariant } from '@dxos/invariant';
19
19
  import { ObjectId } from '@dxos/keys';
20
20
  import { getSnapshot, isLiveObject } from '@dxos/live-object';
21
- import { fullyQualifiedId } from '@dxos/react-client/echo';
22
21
  import { type Label } from '@dxos/react-ui';
23
22
  import { formatForEditing, parseValue } from '@dxos/react-ui-form';
24
23
  import {
@@ -28,11 +27,11 @@ import {
28
27
  type DxGridPosition,
29
28
  } from '@dxos/react-ui-grid';
30
29
  import {
31
- type DataType,
32
30
  type FieldSortType,
33
31
  ProjectionModel,
34
32
  type PropertyType,
35
33
  type ValidationError,
34
+ type View,
36
35
  validateSchema,
37
36
  } from '@dxos/schema';
38
37
 
@@ -78,7 +77,7 @@ const defaultFeatures: TableFeatures = {
78
77
  export type InsertRowResult = 'draft' | 'final';
79
78
 
80
79
  export type TableModelProps<T extends TableRow = TableRow> = {
81
- view: DataType.View;
80
+ view: View.View;
82
81
  schema: JsonSchemaType;
83
82
  projection?: ProjectionModel;
84
83
  features?: Partial<TableFeatures>;
@@ -96,7 +95,7 @@ export type TableModelProps<T extends TableRow = TableRow> = {
96
95
  };
97
96
 
98
97
  export class TableModel<T extends TableRow = TableRow> extends Resource {
99
- private readonly _view: DataType.View;
98
+ private readonly _view: View.View;
100
99
  private readonly _projection: ProjectionModel;
101
100
  private _table?: Table.Table;
102
101
 
@@ -176,10 +175,10 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
176
175
  }
177
176
 
178
177
  public get id(): string {
179
- return fullyQualifiedId(this._view);
178
+ return Obj.getDXN(this._view).toString();
180
179
  }
181
180
 
182
- public get view(): DataType.View {
181
+ public get view(): View.View {
183
182
  return this._view;
184
183
  }
185
184
 
@@ -480,7 +479,11 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
480
479
  }
481
480
 
482
481
  default: {
483
- return formatForEditing({ type: props.type, format: props.format, value });
482
+ return formatForEditing({
483
+ type: props.type,
484
+ format: props.format,
485
+ value,
486
+ });
484
487
  }
485
488
  }
486
489
  };
@@ -9,7 +9,7 @@ import { Filter, Query } from '@dxos/echo';
9
9
  import { TypedObject } from '@dxos/echo/internal';
10
10
  import { createEchoSchema } from '@dxos/echo/testing';
11
11
  import { live } from '@dxos/live-object';
12
- import { createView } from '@dxos/schema';
12
+ import { View } from '@dxos/schema';
13
13
 
14
14
  import { Table } from '../types';
15
15
 
@@ -96,7 +96,7 @@ class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.
96
96
  const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
97
97
  const schema = createEchoSchema(Test);
98
98
  const table = Table.make();
99
- const view = createView({
99
+ const view = View.make({
100
100
  query: Query.select(Filter.type(schema)),
101
101
  jsonSchema: schema.jsonSchema,
102
102
  presentation: table,