@dxos/react-ui-table 0.7.4 → 0.7.5-main.9cb18ac

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/lib/browser/{chunk-IYCSJDMB.mjs → chunk-AT7O4RAD.mjs} +4 -4
  2. package/dist/lib/browser/{chunk-IYCSJDMB.mjs.map → chunk-AT7O4RAD.mjs.map} +2 -2
  3. package/dist/lib/browser/index.mjs +1407 -1218
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/types/index.mjs +1 -1
  7. package/dist/lib/node/{chunk-MHBMVCFZ.cjs → chunk-YSBXNBDJ.cjs} +6 -6
  8. package/dist/lib/node/{chunk-MHBMVCFZ.cjs.map → chunk-YSBXNBDJ.cjs.map} +2 -2
  9. package/dist/lib/node/index.cjs +1139 -936
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/types/index.cjs +3 -3
  13. package/dist/lib/node/types/index.cjs.map +1 -1
  14. package/dist/lib/node-esm/{chunk-BMWGPXPL.mjs → chunk-6OH2NHUX.mjs} +4 -4
  15. package/dist/lib/node-esm/{chunk-BMWGPXPL.mjs.map → chunk-6OH2NHUX.mjs.map} +2 -2
  16. package/dist/lib/node-esm/index.mjs +1407 -1218
  17. package/dist/lib/node-esm/index.mjs.map +4 -4
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/types/index.mjs +1 -1
  20. package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts +1 -1
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +4 -3
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +3 -2
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/CreateRefPanel.d.ts +3 -2
  26. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/RefPanel.d.ts +4 -3
  28. package/dist/types/src/components/Table/RefPanel.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/RowActionsMenu.d.ts +3 -2
  30. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/Table.d.ts +2 -1
  32. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  34. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -2
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  36. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/testing.d.ts +55 -71
  38. package/dist/types/src/components/testing.d.ts.map +1 -1
  39. package/dist/types/src/index.d.ts +1 -0
  40. package/dist/types/src/index.d.ts.map +1 -1
  41. package/dist/types/src/model/index.d.ts +1 -0
  42. package/dist/types/src/model/index.d.ts.map +1 -1
  43. package/dist/types/src/model/modal-controller.d.ts +6 -2
  44. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  45. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  46. package/dist/types/src/model/table-model.d.ts +8 -12
  47. package/dist/types/src/model/table-model.d.ts.map +1 -1
  48. package/dist/types/src/model/table-presentation.d.ts +22 -0
  49. package/dist/types/src/model/table-presentation.d.ts.map +1 -0
  50. package/dist/types/src/model/table-presentation.test.d.ts +2 -0
  51. package/dist/types/src/model/table-presentation.test.d.ts.map +1 -0
  52. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  53. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  54. package/dist/types/src/types/table.d.ts +118 -154
  55. package/dist/types/src/types/table.d.ts.map +1 -1
  56. package/dist/types/src/util/index.d.ts +1 -0
  57. package/dist/types/src/util/index.d.ts.map +1 -1
  58. package/dist/types/src/util/table-buttons.d.ts +50 -20
  59. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  60. package/dist/types/src/util/table-controls.d.ts +32 -9
  61. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  62. package/dist/types/src/util/table.d.ts +2 -2
  63. package/dist/types/src/util/table.d.ts.map +1 -1
  64. package/dist/types/tsconfig.tsbuildinfo +1 -0
  65. package/package.json +29 -29
  66. package/src/components/Table/ColumnActionsMenu.tsx +8 -8
  67. package/src/components/Table/ColumnSettings.tsx +11 -11
  68. package/src/components/Table/CreateRefPanel.tsx +13 -14
  69. package/src/components/Table/RefPanel.tsx +9 -9
  70. package/src/components/Table/RowActionsMenu.tsx +6 -7
  71. package/src/components/Table/Table.stories.tsx +40 -23
  72. package/src/components/Table/Table.tsx +235 -148
  73. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +13 -12
  74. package/src/components/TableCellEditor/TableCellEditor.tsx +6 -4
  75. package/src/components/testing.ts +10 -8
  76. package/src/index.ts +2 -0
  77. package/src/model/index.ts +1 -0
  78. package/src/model/modal-controller.ts +15 -48
  79. package/src/model/selection-model.ts +12 -1
  80. package/src/model/table-model.test.ts +4 -71
  81. package/src/model/table-model.ts +59 -232
  82. package/src/model/table-presentation.test.ts +102 -0
  83. package/src/model/table-presentation.ts +217 -0
  84. package/src/playwright/TableManager.ts +5 -1
  85. package/src/playwright/smoke.spec.ts +79 -1
  86. package/src/types/table.ts +3 -3
  87. package/src/util/index.ts +1 -0
  88. package/src/util/table-buttons.ts +97 -48
  89. package/src/util/table-controls.ts +71 -7
  90. package/src/util/table.ts +21 -13
@@ -9,6 +9,8 @@ import React, {
9
9
  useImperativeHandle,
10
10
  useState,
11
11
  type WheelEvent,
12
+ type MouseEvent,
13
+ useMemo,
12
14
  } from 'react';
13
15
 
14
16
  import { getValue } from '@dxos/echo-schema';
@@ -25,8 +27,9 @@ import { ColumnSettings } from './ColumnSettings';
25
27
  import { CreateRefPanel } from './CreateRefPanel';
26
28
  import { RefPanel } from './RefPanel';
27
29
  import { RowActionsMenu } from './RowActionsMenu';
28
- import { type TableModel } from '../../model';
30
+ import { ModalController, type TableModel, type TablePresentation } from '../../model';
29
31
  import { translationKey } from '../../translations';
32
+ import { tableButtons, tableControls } from '../../util';
30
33
  import { createOption, TableCellEditor, type TableCellEditorProps } from '../TableCellEditor';
31
34
 
32
35
  // NOTE(Zan): These fragments add border to inline-end and block-end of the grid using pseudo-elements.
@@ -70,174 +73,258 @@ export type TableController = {
70
73
 
71
74
  export type TableMainProps = {
72
75
  model?: TableModel;
76
+ presentation?: TablePresentation;
73
77
  ignoreAttention?: boolean;
74
78
  };
75
79
 
76
- const TableMain = forwardRef<TableController, TableMainProps>(({ model, ignoreAttention }, forwardedRef) => {
77
- const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
78
- const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : 'table');
79
- const { t } = useTranslation(translationKey);
80
-
81
- /**
82
- * Provides an external controller that can be called to repaint the table.
83
- */
84
- useImperativeHandle<TableController, TableController>(
85
- forwardedRef,
86
- () => {
87
- if (!model || !dxGrid) {
88
- return {};
89
- }
80
+ const TableMain = forwardRef<TableController, TableMainProps>(
81
+ ({ model, presentation, ignoreAttention }, forwardedRef) => {
82
+ const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
83
+ const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : 'table');
84
+ const { t } = useTranslation(translationKey);
85
+ const modals = useMemo(() => new ModalController(), []);
86
+
87
+ /**
88
+ * Provides an external controller that can be called to repaint the table.
89
+ */
90
+ useImperativeHandle<TableController, TableController>(
91
+ forwardedRef,
92
+ () => {
93
+ if (!presentation || !dxGrid) {
94
+ return {};
95
+ }
96
+
97
+ dxGrid.getCells = (range, plane) => presentation.getCells(range, plane);
98
+ return {
99
+ update: (cell) => {
100
+ if (cell) {
101
+ dxGrid.updateIfWithinBounds(cell);
102
+ } else {
103
+ dxGrid.updateCells(true);
104
+ dxGrid.requestUpdate();
105
+ }
106
+ },
107
+ };
108
+ },
109
+ [presentation, dxGrid],
110
+ );
111
+
112
+ const handleGridClick = useCallback(
113
+ (event: MouseEvent) => {
114
+ if (!modals) {
115
+ return;
116
+ }
90
117
 
91
- dxGrid.getCells = model.getCells.bind(model);
92
- return {
93
- update: (cell) => {
94
- if (cell) {
95
- dxGrid.updateIfWithinBounds(cell);
96
- } else {
97
- dxGrid.updateCells(true);
118
+ const buttonSelector = Object.values(tableButtons)
119
+ .map((button) => `button[${button.attr}]`)
120
+ .join(',');
121
+
122
+ const tableButtonElement = (event.target as HTMLElement).closest(buttonSelector) as HTMLElement;
123
+ if (tableButtonElement) {
124
+ const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
125
+ if (!button) {
126
+ return;
98
127
  }
99
- },
100
- };
101
- },
102
- [model, dxGrid],
103
- );
104
128
 
105
- const handleFocus = useCallback<NonNullable<TableCellEditorProps['onFocus']>>(
106
- (increment, delta) => {
107
- if (dxGrid) {
108
- dxGrid.refocus(increment, delta);
109
- }
110
- },
111
- [dxGrid],
112
- );
129
+ modals.setTrigger(tableButtonElement);
130
+ const data = button.getData(tableButtonElement);
131
+ switch (data.type) {
132
+ case 'rowMenu': {
133
+ modals.showRowMenu(data.rowIndex);
134
+ break;
135
+ }
136
+ case 'columnSettings': {
137
+ modals.showColumnMenu(data.fieldId);
138
+ break;
139
+ }
140
+ case 'newColumn': {
141
+ modals.showColumnCreator();
142
+ break;
143
+ }
144
+ case 'referencedCell': {
145
+ modals.showReferencePanel(data.targetId, data.schemaId);
146
+ break;
147
+ }
148
+ }
149
+ return;
150
+ }
113
151
 
114
- const handleEnter = useCallback<NonNullable<TableCellEditorProps['onEnter']>>(
115
- (cell) => {
116
- // TODO(burdon): Insert row only if bottom row isn't completely blank already.
117
- if (model && cell.row === model.getRowCount() - 1) {
118
- model.insertRow(cell.row);
152
+ const controlSelector = Object.values(tableControls)
153
+ .map((control) => `input[${control.attr}]`)
154
+ .join(',');
155
+
156
+ const controlElement = (event.target as HTMLElement).closest(controlSelector) as HTMLElement;
157
+ if (controlElement) {
158
+ const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
159
+ if (!control) {
160
+ return;
161
+ }
162
+
163
+ const data = control.getData(controlElement);
164
+ switch (data.type) {
165
+ case 'checkbox': {
166
+ if (data.header) {
167
+ model?.selection.setSelection(model.selection.allRowsSeleted.value ? 'none' : 'all');
168
+ } else {
169
+ model?.selection.toggleSelectionForRowIndex(data.rowIndex);
170
+ }
171
+ break;
172
+ }
173
+ case 'switch': {
174
+ if (model) {
175
+ model.updateCellData({ row: data.rowIndex, col: data.colIndex }, (value) => !value);
176
+ }
177
+ break;
178
+ }
179
+ }
180
+ }
181
+ },
182
+ [model, modals],
183
+ );
184
+
185
+ const handleFocus = useCallback<NonNullable<TableCellEditorProps['onFocus']>>(
186
+ (increment, delta) => {
119
187
  if (dxGrid) {
120
- requestAnimationFrame(() => {
121
- dxGrid?.scrollToRow(cell.row + 1);
122
- dxGrid?.refocus('row', 1);
123
- });
188
+ dxGrid.refocus(increment, delta);
124
189
  }
125
- }
126
- },
127
- [model, dxGrid],
128
- );
190
+ },
191
+ [dxGrid],
192
+ );
129
193
 
130
- const handleKeyDown = useCallback<NonNullable<GridContentProps['onKeyDown']>>(
131
- (event) => {
132
- const cell = closestCell(event.target);
133
- if (!model || !cell) {
134
- return;
135
- }
194
+ const handleEnter = useCallback<NonNullable<TableCellEditorProps['onEnter']>>(
195
+ (cell) => {
196
+ // TODO(burdon): Insert row only if bottom row isn't completely blank already.
197
+ if (model && cell.row === model.getRowCount() - 1) {
198
+ model.insertRow(cell.row);
199
+ if (dxGrid) {
200
+ requestAnimationFrame(() => {
201
+ dxGrid?.scrollToRow(cell.row + 1);
202
+ dxGrid?.refocus('row', 1);
203
+ });
204
+ }
205
+ }
206
+ },
207
+ [model, dxGrid],
208
+ );
136
209
 
137
- switch (event.key) {
138
- case 'Backspace':
139
- case 'Delete': {
140
- model.setCellData(cell, undefined);
141
- break;
210
+ const handleKeyDown = useCallback<NonNullable<GridContentProps['onKeyDown']>>(
211
+ (event) => {
212
+ const cell = closestCell(event.target);
213
+ if (!model || !cell) {
214
+ return;
142
215
  }
143
- }
144
- },
145
- [model],
146
- );
147
216
 
148
- const handleAxisResize = useCallback<NonNullable<GridContentProps['onAxisResize']>>(
149
- (event) => {
150
- if (event.axis === 'col') {
151
- const columnIndex = parseInt(event.index, 10);
152
- model?.setColumnWidth(columnIndex, event.size);
153
- }
154
- },
155
- [model],
156
- );
217
+ switch (event.key) {
218
+ case 'Backspace':
219
+ case 'Delete': {
220
+ model.setCellData(cell, undefined);
221
+ break;
222
+ }
223
+ }
224
+ },
225
+ [model],
226
+ );
227
+
228
+ const handleAxisResize = useCallback<NonNullable<GridContentProps['onAxisResize']>>(
229
+ (event) => {
230
+ if (event.axis === 'col') {
231
+ const columnIndex = parseInt(event.index, 10);
232
+ model?.setColumnWidth(columnIndex, event.size);
233
+ }
234
+ },
235
+ [model],
236
+ );
237
+
238
+ const handleWheel = useCallback(
239
+ (event: WheelEvent) => {
240
+ if (!ignoreAttention && !hasAttention) {
241
+ event.stopPropagation();
242
+ }
243
+ },
244
+ [hasAttention, ignoreAttention],
245
+ );
157
246
 
158
- const handleWheel = useCallback(
159
- (event: WheelEvent) => {
160
- if (!ignoreAttention && !hasAttention) {
161
- event.stopPropagation();
247
+ const handleNewColumn = useCallback(() => {
248
+ const columns = model?.getColumnCount();
249
+ if (dxGrid && columns) {
250
+ dxGrid.scrollToColumn(columns - 1);
162
251
  }
163
- },
164
- [hasAttention, ignoreAttention],
165
- );
252
+ }, [model, dxGrid]);
166
253
 
167
- const handleNewColumn = useCallback(() => {
168
- const columns = model?.getColumnCount();
169
- if (dxGrid && columns) {
170
- dxGrid.scrollToColumn(columns - 1);
171
- }
172
- }, [model, dxGrid]);
173
-
174
- // TODO(burdon): Factor out?
175
- // TODO(burdon): Generalize to handle other value types (e.g., enums).
176
- const handleQuery = useCallback<NonNullable<TableCellEditorProps['onQuery']>>(
177
- async ({ field, props }, text) => {
178
- if (model && props.referenceSchema && field.referencePath) {
179
- const space = getSpace(model.table);
180
- invariant(space);
181
- const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
182
- if (schema) {
183
- const { objects } = await space.db.query(Filter.schema(schema)).run();
184
- const options = objects
185
- .map((obj) => {
186
- const value = getValue(obj, field.referencePath!);
187
- if (!value || typeof value !== 'string') {
188
- return undefined;
189
- }
254
+ // TODO(burdon): Factor out?
255
+ // TODO(burdon): Generalize to handle other value types (e.g., enums).
256
+ const handleQuery = useCallback<NonNullable<TableCellEditorProps['onQuery']>>(
257
+ async ({ field, props }, text) => {
258
+ if (model && props.referenceSchema && field.referencePath) {
259
+ const space = getSpace(model.table);
260
+ invariant(space);
261
+ const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
262
+ if (schema) {
263
+ const { objects } = await space.db.query(Filter.schema(schema)).run();
264
+ const options = objects
265
+ .map((obj) => {
266
+ const value = getValue(obj, field.referencePath!);
267
+ if (!value || typeof value !== 'string') {
268
+ return undefined;
269
+ }
270
+
271
+ return {
272
+ label: value,
273
+ data: obj,
274
+ };
275
+ })
276
+ .filter(isNotFalsy);
190
277
 
191
- return {
192
- label: value,
193
- data: obj,
194
- };
195
- })
196
- .filter(isNotFalsy);
197
-
198
- return [
199
- ...options,
200
- {
201
- label: t('create new object label', { text }),
202
- data: createOption(text),
203
- },
204
- ];
278
+ return [
279
+ ...options,
280
+ {
281
+ label: t('create new object label', { text }),
282
+ data: createOption(text),
283
+ },
284
+ ];
285
+ }
205
286
  }
206
- }
207
287
 
208
- return [];
209
- },
210
- [model],
211
- );
288
+ return [];
289
+ },
290
+ [model],
291
+ );
212
292
 
213
- if (!model) {
214
- return <span role='none' className='attention-surface' />;
215
- }
293
+ if (!model || !modals) {
294
+ return <span role='none' className='attention-surface' />;
295
+ }
216
296
 
217
- return (
218
- <Grid.Root id={model.table.id ?? 'table-grid'}>
219
- <TableCellEditor model={model} onEnter={handleEnter} onFocus={handleFocus} onQuery={handleQuery} />
220
- <Grid.Content
221
- onWheelCapture={handleWheel}
222
- className={mx('[--dx-grid-base:var(--surface-bg)]', inlineEndLine, blockEndLine)}
223
- frozen={frozen}
224
- columns={model.columnMeta.value}
225
- limitRows={model.getRowCount() ?? 0}
226
- limitColumns={model.table.view?.fields?.length ?? 0}
227
- onAxisResize={handleAxisResize}
228
- onClick={model?.handleGridClick}
229
- onKeyDown={handleKeyDown}
230
- overscroll='trap'
231
- ref={setDxGrid}
232
- />
233
- <RowActionsMenu model={model} />
234
- <ColumnActionsMenu model={model} />
235
- <ColumnSettings model={model} onNewColumn={handleNewColumn} />
236
- <RefPanel model={model} />
237
- <CreateRefPanel model={model} />
238
- </Grid.Root>
239
- );
240
- });
297
+ return (
298
+ <Grid.Root id={model.table.id ?? 'table-grid'}>
299
+ <TableCellEditor
300
+ model={model}
301
+ modals={modals}
302
+ onEnter={handleEnter}
303
+ onFocus={handleFocus}
304
+ onQuery={handleQuery}
305
+ />
306
+ <Grid.Content
307
+ onWheelCapture={handleWheel}
308
+ className={mx('[--dx-grid-base:var(--surface-bg)]', inlineEndLine, blockEndLine)}
309
+ frozen={frozen}
310
+ columns={model.columnMeta.value}
311
+ limitRows={model.getRowCount() ?? 0}
312
+ limitColumns={model.table.view?.target?.fields?.length ?? 0}
313
+ onAxisResize={handleAxisResize}
314
+ onClick={handleGridClick}
315
+ onKeyDown={handleKeyDown}
316
+ overscroll='trap'
317
+ ref={setDxGrid}
318
+ />
319
+ <RowActionsMenu model={model} modals={modals} />
320
+ <ColumnActionsMenu model={model} modals={modals} />
321
+ <ColumnSettings model={model} modals={modals} onNewColumn={handleNewColumn} />
322
+ <RefPanel model={model} modals={modals} />
323
+ <CreateRefPanel model={model} modals={modals} />
324
+ </Grid.Root>
325
+ );
326
+ },
327
+ );
241
328
 
242
329
  //
243
330
  // CellEditor
@@ -7,11 +7,11 @@ import '@dxos-theme';
7
7
  import { type Meta, type StoryObj } from '@storybook/react';
8
8
  import React, { useEffect, useMemo, useState } from 'react';
9
9
 
10
- import { type MutableSchema } from '@dxos/echo-schema';
10
+ import { type EchoSchema } from '@dxos/echo-schema';
11
11
  import { invariant } from '@dxos/invariant';
12
12
  import { faker } from '@dxos/random';
13
- import { Filter, useSpaces, useQuery, create } from '@dxos/react-client/echo';
14
- import { withClientProvider } from '@dxos/react-client/testing';
13
+ import { Filter, useQuery, create } from '@dxos/react-client/echo';
14
+ import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
15
15
  import { defaultSizeRow, Grid, type GridEditing } from '@dxos/react-ui-grid';
16
16
  import { ViewProjection, ViewType } from '@dxos/schema';
17
17
  import { withLayout, withTheme } from '@dxos/storybook-utils';
@@ -27,23 +27,24 @@ type StoryProps = {
27
27
  };
28
28
 
29
29
  const DefaultStory = ({ editing }: StoryProps) => {
30
- const spaces = useSpaces();
31
- const space = spaces[spaces.length - 1];
30
+ const { space } = useClientProvider();
31
+ invariant(space);
32
+
32
33
  const tables = useQuery(space, Filter.schema(TableType));
33
34
  const [table, setTable] = useState<TableType>();
34
- const [schema, setSchema] = useState<MutableSchema>();
35
+ const [schema, setSchema] = useState<EchoSchema>();
35
36
  useEffect(() => {
36
- if (tables.length && !table) {
37
+ if (space && tables.length && !table) {
37
38
  const table = tables[0];
38
39
  invariant(table.view);
39
40
  setTable(table);
40
- setSchema(space.db.schemaRegistry.getSchema(table.view.query.type));
41
+ setSchema(space.db.schemaRegistry.getSchema(table.view.target!.query.type));
41
42
  }
42
- }, [tables]);
43
+ }, [space, tables]);
43
44
 
44
45
  const projection = useMemo(() => {
45
46
  if (schema && table?.view) {
46
- return new ViewProjection(schema, table.view);
47
+ return new ViewProjection(schema, table.view.target!);
47
48
  }
48
49
  }, [schema, table?.view]);
49
50
 
@@ -83,9 +84,9 @@ const meta: Meta<StoryProps> = {
83
84
  types: [TableType, ViewType],
84
85
  createIdentity: true,
85
86
  createSpace: true,
86
- onSpaceCreated: ({ space }) => {
87
+ onSpaceCreated: async ({ space }) => {
87
88
  const table = space.db.add(create(TableType, {}));
88
- const schema = initializeTable({ space, table });
89
+ const schema = await initializeTable({ space, table });
89
90
  Array.from({ length: 10 }).forEach(() => {
90
91
  space.db.add(
91
92
  create(schema, {
@@ -24,7 +24,7 @@ import {
24
24
  import { type FieldProjection } from '@dxos/schema';
25
25
 
26
26
  import { completion } from './extension';
27
- import { type TableModel } from '../../model';
27
+ import { type TableModel, type ModalController } from '../../model';
28
28
 
29
29
  const newValue = Symbol.for('newValue');
30
30
 
@@ -39,6 +39,7 @@ export type QueryResult = Pick<Completion, 'label'> & { data: any };
39
39
 
40
40
  export type TableCellEditorProps = {
41
41
  model?: TableModel;
42
+ modals?: ModalController;
42
43
  onEnter?: (cell: DxGridPlanePosition) => void;
43
44
  onFocus?: DxGrid['refocus'];
44
45
  onQuery?: (field: FieldProjection, text: string) => Promise<QueryResult[]>;
@@ -46,6 +47,7 @@ export type TableCellEditorProps = {
46
47
 
47
48
  export const TableCellEditor = ({
48
49
  model,
50
+ modals,
49
51
  onEnter,
50
52
  onFocus,
51
53
  onQuery,
@@ -133,12 +135,12 @@ export const TableCellEditor = ({
133
135
  completion({
134
136
  onQuery: (text) => onQuery(fieldProjection, text),
135
137
  onMatch: (data) => {
136
- if (model && editing) {
138
+ if (model && editing && modals) {
137
139
  if (isCreateOption(data)) {
138
140
  const { field, props } = fieldProjection;
139
141
  if (props.referenceSchema) {
140
142
  suppressNextBlur.current = true;
141
- model.modalController.openCreateRef(
143
+ modals.openCreateRef(
142
144
  props.referenceSchema,
143
145
  document.querySelector(cellQuery(editing.index, gridId)),
144
146
  {
@@ -162,7 +164,7 @@ export const TableCellEditor = ({
162
164
  }
163
165
 
164
166
  return extension;
165
- }, [model, editing, fieldProjection, handleClose]);
167
+ }, [model, modals, editing, fieldProjection, handleClose]);
166
168
 
167
169
  const getCellContent = useCallback<GridCellEditorProps['getCellContent']>(() => {
168
170
  if (model && editing) {
@@ -6,7 +6,7 @@ import { useEffect } from 'react';
6
6
 
7
7
  import { setValue, toJsonSchema, S, TypeEnum, TypedObject, FormatEnum } from '@dxos/echo-schema';
8
8
  import { faker } from '@dxos/random';
9
- import { create } from '@dxos/react-client/echo';
9
+ import { create, makeRef } from '@dxos/react-client/echo';
10
10
  import { createView, type ViewProjection } from '@dxos/schema';
11
11
  import {} from '@dxos/schema';
12
12
 
@@ -22,11 +22,13 @@ export const TestSchema = TypedObject({ typename: 'example.com/type/Test', versi
22
22
 
23
23
  export const createTable = (schema = TestSchema) => {
24
24
  return create(TableType, {
25
- view: createView({
26
- name: 'Test',
27
- typename: schema.typename,
28
- jsonSchema: toJsonSchema(schema),
29
- }),
25
+ view: makeRef(
26
+ createView({
27
+ name: 'Test',
28
+ typename: schema.typename,
29
+ jsonSchema: toJsonSchema(schema),
30
+ }),
31
+ ),
30
32
  });
31
33
  };
32
34
 
@@ -71,7 +73,7 @@ export const useSimulator = ({ items, table, insertInterval, updateInterval }: S
71
73
 
72
74
  const i = setInterval(() => {
73
75
  const rowIdx = Math.floor(Math.random() * items.length);
74
- const fields = table.view?.fields ?? [];
76
+ const fields = table.view?.target?.fields ?? [];
75
77
  const columnIdx = Math.floor(Math.random() * fields.length);
76
78
  const projection: ViewProjection = (table as any)._projection;
77
79
  const field = fields[columnIdx];
@@ -111,5 +113,5 @@ export const useSimulator = ({ items, table, insertInterval, updateInterval }: S
111
113
  }, updateInterval);
112
114
 
113
115
  return () => clearInterval(i);
114
- }, [items, table.view?.fields, updateInterval]);
116
+ }, [items, table.view?.target?.fields, updateInterval]);
115
117
  };
package/src/index.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  //
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
+
4
5
  import translations from './translations';
5
6
 
6
7
  export * from './components';
7
8
  export * from './hooks';
9
+ export * from './model';
8
10
  export * from './types';
9
11
  export * from './util';
10
12
 
@@ -4,3 +4,4 @@
4
4
 
5
5
  export * from './table-model';
6
6
  export * from './modal-controller';
7
+ export * from './table-presentation';