@dxos/react-ui-table 0.8.1-staging.5be625a → 0.8.1-staging.9eaf14f
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.
- package/dist/lib/browser/{chunk-5MKYB7NF.mjs → chunk-YWNRUF4J.mjs} +7 -3
- package/dist/lib/browser/{chunk-5MKYB7NF.mjs.map → chunk-YWNRUF4J.mjs.map} +3 -3
- package/dist/lib/browser/index.mjs +295 -97
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node/{chunk-NRFKBRPV.cjs → chunk-TGG6OZ54.cjs} +10 -6
- package/dist/lib/node/{chunk-NRFKBRPV.cjs.map → chunk-TGG6OZ54.cjs.map} +3 -3
- package/dist/lib/node/index.cjs +293 -93
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +3 -3
- package/dist/lib/node/types/index.cjs.map +1 -1
- package/dist/lib/node-esm/{chunk-SU4D55KI.mjs → chunk-KKLP54L3.mjs} +7 -3
- package/dist/lib/node-esm/{chunk-SU4D55KI.mjs.map → chunk-KKLP54L3.mjs.map} +3 -3
- package/dist/lib/node-esm/index.mjs +295 -97
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/types/index.mjs +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts +15 -10
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +10 -0
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -0
- package/dist/types/src/components/Table/Table.d.ts +1 -1
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +2 -3
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/relations.stories.d.ts +9 -0
- package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -0
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/useTableModel.d.ts +6 -10
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/model/index.d.ts +1 -0
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts +6 -3
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +13 -14
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +4 -4
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- package/dist/types/src/model/table-sorting.d.ts +2 -2
- package/dist/types/src/model/table-sorting.d.ts.map +1 -1
- package/dist/types/src/types/table.d.ts +2 -1
- package/dist/types/src/types/table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +21 -30
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
- package/dist/types/src/util/table-controls.d.ts +2 -2
- package/dist/types/src/util/table-controls.d.ts.map +1 -1
- package/dist/types/src/util/table.d.ts.map +1 -1
- package/package.json +33 -32
- package/src/components/Table/DynamicTable.stories.tsx +155 -0
- package/src/components/Table/DynamicTable.tsx +46 -28
- package/src/components/Table/Table.stories.tsx +129 -125
- package/src/components/Table/Table.tsx +51 -26
- package/src/components/Table/relations.stories.tsx +113 -0
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +8 -3
- package/src/components/TableCellEditor/TableCellEditor.tsx +102 -4
- package/src/components/testing.ts +0 -1
- package/src/hooks/useTableModel.ts +11 -11
- package/src/model/index.ts +1 -0
- package/src/model/selection-model.ts +12 -2
- package/src/model/table-model.test.ts +1 -1
- package/src/model/table-model.ts +27 -18
- package/src/model/table-presentation.test.ts +1 -1
- package/src/model/table-presentation.ts +65 -11
- package/src/model/table-sorting.ts +2 -2
- package/src/playwright/smoke.spec.ts +2 -3
- package/src/types/table.ts +6 -5
- package/src/util/dynamic-table.ts +57 -25
- package/src/util/table-controls.ts +4 -4
- package/src/util/table.ts +2 -1
- package/dist/lib/browser/deprecated/index.mjs +0 -1483
- package/dist/lib/browser/deprecated/index.mjs.map +0 -7
- package/dist/lib/node/deprecated/index.cjs +0 -1511
- package/dist/lib/node/deprecated/index.cjs.map +0 -7
- package/dist/lib/node-esm/deprecated/index.mjs +0 -1485
- package/dist/lib/node-esm/deprecated/index.mjs.map +0 -7
- package/dist/types/src/deprecated/components/Cell/Cell.d.ts +0 -12
- package/dist/types/src/deprecated/components/Cell/Cell.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Cell/CellCombobox.d.ts +0 -13
- package/dist/types/src/deprecated/components/Cell/CellCombobox.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Cell/index.d.ts +0 -2
- package/dist/types/src/deprecated/components/Cell/index.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.d.ts +0 -23
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts +0 -36
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.d.ts +0 -15
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts +0 -84
- package/dist/types/src/deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/ColumnMenu/index.d.ts +0 -3
- package/dist/types/src/deprecated/components/ColumnMenu/index.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/Table.d.ts +0 -20
- package/dist/types/src/deprecated/components/Table/Table.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/Table.stories.d.ts +0 -116
- package/dist/types/src/deprecated/components/Table/Table.stories.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/TableBody.d.ts +0 -12
- package/dist/types/src/deprecated/components/Table/TableBody.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/TableContext.d.ts +0 -13
- package/dist/types/src/deprecated/components/Table/TableContext.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/TableHead.d.ts +0 -9
- package/dist/types/src/deprecated/components/Table/TableHead.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/TableRootContext.d.ts +0 -17
- package/dist/types/src/deprecated/components/Table/TableRootContext.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/index.d.ts +0 -5
- package/dist/types/src/deprecated/components/Table/index.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/Table/props.d.ts +0 -42
- package/dist/types/src/deprecated/components/Table/props.d.ts.map +0 -1
- package/dist/types/src/deprecated/components/index.d.ts +0 -4
- package/dist/types/src/deprecated/components/index.d.ts.map +0 -1
- package/dist/types/src/deprecated/helpers.d.ts +0 -91
- package/dist/types/src/deprecated/helpers.d.ts.map +0 -1
- package/dist/types/src/deprecated/hooks/index.d.ts +0 -5
- package/dist/types/src/deprecated/hooks/index.d.ts.map +0 -1
- package/dist/types/src/deprecated/hooks/useColumnSizing.d.ts +0 -12
- package/dist/types/src/deprecated/hooks/useColumnSizing.d.ts.map +0 -1
- package/dist/types/src/deprecated/hooks/useColumnSorting.d.ts +0 -15
- package/dist/types/src/deprecated/hooks/useColumnSorting.d.ts.map +0 -1
- package/dist/types/src/deprecated/hooks/usePinLastRow.d.ts +0 -3
- package/dist/types/src/deprecated/hooks/usePinLastRow.d.ts.map +0 -1
- package/dist/types/src/deprecated/hooks/useRowSelection.d.ts +0 -7
- package/dist/types/src/deprecated/hooks/useRowSelection.d.ts.map +0 -1
- package/dist/types/src/deprecated/index.d.ts +0 -8
- package/dist/types/src/deprecated/index.d.ts.map +0 -1
- package/dist/types/src/deprecated/schema/Schema.stories.d.ts +0 -11
- package/dist/types/src/deprecated/schema/Schema.stories.d.ts.map +0 -1
- package/dist/types/src/deprecated/schema/column-utils.d.ts +0 -7
- package/dist/types/src/deprecated/schema/column-utils.d.ts.map +0 -1
- package/dist/types/src/deprecated/schema/index.d.ts +0 -3
- package/dist/types/src/deprecated/schema/index.d.ts.map +0 -1
- package/dist/types/src/deprecated/schema/types.d.ts +0 -27
- package/dist/types/src/deprecated/schema/types.d.ts.map +0 -1
- package/dist/types/src/deprecated/theme.d.ts +0 -29
- package/dist/types/src/deprecated/theme.d.ts.map +0 -1
- package/dist/types/src/deprecated/translations.d.ts +0 -21
- package/dist/types/src/deprecated/translations.d.ts.map +0 -1
- package/dist/types/src/deprecated/types.d.ts +0 -26
- package/dist/types/src/deprecated/types.d.ts.map +0 -1
- package/src/deprecated/components/Cell/Cell.tsx +0 -88
- package/src/deprecated/components/Cell/CellCombobox.tsx +0 -103
- package/src/deprecated/components/Cell/index.ts +0 -5
- package/src/deprecated/components/ColumnMenu/ColumnMenu.stories.tsx +0 -129
- package/src/deprecated/components/ColumnMenu/ColumnMenu.tsx +0 -182
- package/src/deprecated/components/ColumnMenu/ColumnSettings.stories.tsx +0 -108
- package/src/deprecated/components/ColumnMenu/ColumnSettings.tsx +0 -207
- package/src/deprecated/components/ColumnMenu/index.ts +0 -6
- package/src/deprecated/components/Table/Table.stories.tsx +0 -508
- package/src/deprecated/components/Table/Table.tsx +0 -301
- package/src/deprecated/components/Table/TableBody.tsx +0 -82
- package/src/deprecated/components/Table/TableContext.tsx +0 -34
- package/src/deprecated/components/Table/TableHead.tsx +0 -78
- package/src/deprecated/components/Table/TableRootContext.ts +0 -39
- package/src/deprecated/components/Table/index.ts +0 -8
- package/src/deprecated/components/Table/props.ts +0 -60
- package/src/deprecated/components/index.ts +0 -7
- package/src/deprecated/helpers.tsx +0 -526
- package/src/deprecated/hooks/index.ts +0 -8
- package/src/deprecated/hooks/useColumnSizing.ts +0 -46
- package/src/deprecated/hooks/useColumnSorting.ts +0 -64
- package/src/deprecated/hooks/usePinLastRow.ts +0 -47
- package/src/deprecated/hooks/useRowSelection.ts +0 -40
- package/src/deprecated/index.ts +0 -12
- package/src/deprecated/schema/Schema.stories.tsx +0 -59
- package/src/deprecated/schema/column-utils.ts +0 -54
- package/src/deprecated/schema/index.ts +0 -6
- package/src/deprecated/schema/types.ts +0 -40
- package/src/deprecated/theme.ts +0 -82
- package/src/deprecated/translations.ts +0 -26
- package/src/deprecated/types.ts +0 -38
|
@@ -8,6 +8,8 @@ import React, { useCallback, useMemo, useRef } from 'react';
|
|
|
8
8
|
import { FormatEnum } from '@dxos/echo-schema';
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
10
|
import { type DxGrid } from '@dxos/lit-grid';
|
|
11
|
+
import { useThemeContext } from '@dxos/react-ui';
|
|
12
|
+
import { createMarkdownExtensions } from '@dxos/react-ui-editor';
|
|
11
13
|
import {
|
|
12
14
|
cellQuery,
|
|
13
15
|
editorKeys,
|
|
@@ -21,6 +23,7 @@ import {
|
|
|
21
23
|
type GridCellEditorProps,
|
|
22
24
|
type GridScopedProps,
|
|
23
25
|
} from '@dxos/react-ui-grid';
|
|
26
|
+
import { tagPickerExtension, createLinks } from '@dxos/react-ui-tag-picker';
|
|
24
27
|
import { type FieldProjection } from '@dxos/schema';
|
|
25
28
|
|
|
26
29
|
import { completion } from './extension';
|
|
@@ -55,6 +58,7 @@ export const TableCellEditor = ({
|
|
|
55
58
|
}: GridScopedProps<TableCellEditorProps>) => {
|
|
56
59
|
const { id: gridId, editing, setEditing } = useGridContext('TableCellEditor', __gridScope);
|
|
57
60
|
const suppressNextBlur = useRef(false);
|
|
61
|
+
const { themeMode } = useThemeContext();
|
|
58
62
|
|
|
59
63
|
const fieldProjection = useMemo<FieldProjection | undefined>(() => {
|
|
60
64
|
if (!model || !editing) {
|
|
@@ -80,7 +84,7 @@ export const TableCellEditor = ({
|
|
|
80
84
|
onFocus?.();
|
|
81
85
|
setEditing(null);
|
|
82
86
|
},
|
|
83
|
-
[model, editing],
|
|
87
|
+
[model, editing, onEnter, onFocus, setEditing],
|
|
84
88
|
);
|
|
85
89
|
|
|
86
90
|
const handleBlur = useCallback<EditorBlurHandler>(
|
|
@@ -113,7 +117,7 @@ export const TableCellEditor = ({
|
|
|
113
117
|
onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
|
|
114
118
|
}
|
|
115
119
|
},
|
|
116
|
-
[model, editing, onFocus, onEnter, fieldProjection
|
|
120
|
+
[model, editing, onFocus, onEnter, fieldProjection],
|
|
117
121
|
);
|
|
118
122
|
|
|
119
123
|
const extension = useMemo(() => {
|
|
@@ -128,6 +132,50 @@ export const TableCellEditor = ({
|
|
|
128
132
|
}),
|
|
129
133
|
];
|
|
130
134
|
|
|
135
|
+
const format = fieldProjection.props.format;
|
|
136
|
+
|
|
137
|
+
if (format === FormatEnum.SingleSelect || format === FormatEnum.MultiSelect) {
|
|
138
|
+
// TODO(ZaymonFC): Reconcile this with the TagPicker component?
|
|
139
|
+
// Add markdown extensions needed by tag picker.
|
|
140
|
+
extension.push(createMarkdownExtensions({ themeMode }));
|
|
141
|
+
|
|
142
|
+
const options = fieldProjection.props.options || [];
|
|
143
|
+
|
|
144
|
+
const mode = format === FormatEnum.SingleSelect ? ('single-select' as const) : ('multi-select' as const);
|
|
145
|
+
|
|
146
|
+
extension.push(
|
|
147
|
+
tagPickerExtension({
|
|
148
|
+
mode,
|
|
149
|
+
inGrid: true,
|
|
150
|
+
onSearch: (text, selectedIds) => {
|
|
151
|
+
return options
|
|
152
|
+
.filter(
|
|
153
|
+
(option) =>
|
|
154
|
+
selectedIds.indexOf(option.id) === -1 &&
|
|
155
|
+
(text.length === 0 || option.title.toLowerCase().includes(text.toLowerCase())),
|
|
156
|
+
)
|
|
157
|
+
.map((option) => ({
|
|
158
|
+
id: option.id,
|
|
159
|
+
label: option.title,
|
|
160
|
+
hue: option.color as any,
|
|
161
|
+
}));
|
|
162
|
+
},
|
|
163
|
+
onUpdate: (ids) => {
|
|
164
|
+
if (model && editing) {
|
|
165
|
+
if (ids.length === 0) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (mode === 'single-select') {
|
|
169
|
+
handleEnter(ids[0]);
|
|
170
|
+
} else {
|
|
171
|
+
handleEnter(ids);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
}),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
131
179
|
if (onQuery) {
|
|
132
180
|
switch (fieldProjection.props.format) {
|
|
133
181
|
case FormatEnum.Ref: {
|
|
@@ -164,11 +212,61 @@ export const TableCellEditor = ({
|
|
|
164
212
|
}
|
|
165
213
|
|
|
166
214
|
return extension;
|
|
167
|
-
}, [model, modals, editing, fieldProjection, handleClose]);
|
|
215
|
+
}, [model, modals, editing, fieldProjection, handleClose, themeMode]);
|
|
168
216
|
|
|
169
217
|
const getCellContent = useCallback<GridCellEditorProps['getCellContent']>(() => {
|
|
170
218
|
if (model && editing) {
|
|
171
|
-
const
|
|
219
|
+
const cell = parseCellIndex(editing.index);
|
|
220
|
+
const { col } = cell;
|
|
221
|
+
const field = model.projection.view.fields[col];
|
|
222
|
+
const fieldProjection = model.projection.getFieldProjection(field.id);
|
|
223
|
+
|
|
224
|
+
if (
|
|
225
|
+
fieldProjection?.props.format === FormatEnum.SingleSelect ||
|
|
226
|
+
fieldProjection?.props.format === FormatEnum.MultiSelect
|
|
227
|
+
) {
|
|
228
|
+
const value = model.getCellData(cell);
|
|
229
|
+
|
|
230
|
+
if (value !== undefined) {
|
|
231
|
+
const options = fieldProjection.props.options || [];
|
|
232
|
+
|
|
233
|
+
if (fieldProjection.props.format === FormatEnum.MultiSelect && Array.isArray(value)) {
|
|
234
|
+
const tagItems = value
|
|
235
|
+
.map((id) => {
|
|
236
|
+
const option = options.find((o) => o.id === id);
|
|
237
|
+
if (option) {
|
|
238
|
+
return {
|
|
239
|
+
id,
|
|
240
|
+
label: option.title,
|
|
241
|
+
hue: option.color as any,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return undefined;
|
|
245
|
+
})
|
|
246
|
+
.filter((item): item is { id: any; label: string; hue: any } => item !== undefined);
|
|
247
|
+
|
|
248
|
+
return createLinks(tagItems);
|
|
249
|
+
} else {
|
|
250
|
+
const option = options.find((o) => o.id === value);
|
|
251
|
+
|
|
252
|
+
if (option) {
|
|
253
|
+
const tagItem = {
|
|
254
|
+
id: value,
|
|
255
|
+
label: option.title,
|
|
256
|
+
hue: option.color as any,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
return createLinks([tagItem]);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Return empty string if no value
|
|
265
|
+
return '';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Default behavior for other formats
|
|
269
|
+
const value = model.getCellData(cell);
|
|
172
270
|
return value !== undefined ? String(value) : '';
|
|
173
271
|
}
|
|
174
272
|
}, [model, editing]);
|
|
@@ -8,7 +8,6 @@ import { setValue, toJsonSchema, S, TypeEnum, TypedObject, FormatEnum } from '@d
|
|
|
8
8
|
import { faker } from '@dxos/random';
|
|
9
9
|
import { create, makeRef } from '@dxos/react-client/echo';
|
|
10
10
|
import { createView, type ViewProjection } from '@dxos/schema';
|
|
11
|
-
import {} from '@dxos/schema';
|
|
12
11
|
|
|
13
12
|
import { TableType } from '../types';
|
|
14
13
|
|
|
@@ -10,28 +10,28 @@ import { useSelectionActions } from '@dxos/react-ui-attention';
|
|
|
10
10
|
import { type ViewProjection } from '@dxos/schema';
|
|
11
11
|
import { isNonNullable } from '@dxos/util';
|
|
12
12
|
|
|
13
|
-
import { type
|
|
13
|
+
import { type TableRow, TableModel, type TableModelProps, type TableRowAction } from '../model';
|
|
14
14
|
import { type TableType } from '../types';
|
|
15
15
|
|
|
16
|
-
export type UseTableModelParams<T extends
|
|
16
|
+
export type UseTableModelParams<T extends TableRow = TableRow> = {
|
|
17
17
|
table?: TableType;
|
|
18
18
|
projection?: ViewProjection;
|
|
19
|
-
|
|
20
|
-
onSelectionChanged?: (selection: string[]) => void;
|
|
19
|
+
rows?: ReactiveObject<T>[];
|
|
21
20
|
rowActions?: TableRowAction[];
|
|
21
|
+
onSelectionChanged?: (selection: string[]) => void;
|
|
22
22
|
onRowAction?: (actionId: string, data: T) => void;
|
|
23
23
|
} & Pick<
|
|
24
24
|
TableModelProps<T>,
|
|
25
|
-
'features' | 'onInsertRow' | 'onDeleteRows' | 'onDeleteColumn' | 'onCellUpdate' | '
|
|
25
|
+
'features' | 'onInsertRow' | 'onDeleteRows' | 'onDeleteColumn' | 'onCellUpdate' | 'onRowOrderChange'
|
|
26
26
|
>;
|
|
27
27
|
|
|
28
|
-
export const useTableModel = <T extends
|
|
29
|
-
objects,
|
|
28
|
+
export const useTableModel = <T extends TableRow = TableRow>({
|
|
30
29
|
table,
|
|
31
30
|
projection,
|
|
31
|
+
rows,
|
|
32
|
+
rowActions,
|
|
32
33
|
features,
|
|
33
34
|
onSelectionChanged,
|
|
34
|
-
rowActions,
|
|
35
35
|
onRowAction,
|
|
36
36
|
...props
|
|
37
37
|
}: UseTableModelParams<T>): TableModel<T> | undefined => {
|
|
@@ -65,10 +65,10 @@ export const useTableModel = <T extends BaseTableRow = { id: string }>({
|
|
|
65
65
|
|
|
66
66
|
// Update data.
|
|
67
67
|
useEffect(() => {
|
|
68
|
-
if (
|
|
69
|
-
model?.setRows(
|
|
68
|
+
if (rows) {
|
|
69
|
+
model?.setRows(rows);
|
|
70
70
|
}
|
|
71
|
-
}, [model,
|
|
71
|
+
}, [model, rows]);
|
|
72
72
|
|
|
73
73
|
const { select, clear } = useSelectionActions([table?.id, table?.view?.target?.query.typename].filter(isNonNullable));
|
|
74
74
|
|
package/src/model/index.ts
CHANGED
|
@@ -6,10 +6,12 @@ import { computed, effect, signal, type ReadonlySignal } from '@preact/signals-c
|
|
|
6
6
|
|
|
7
7
|
import { Resource } from '@dxos/context';
|
|
8
8
|
|
|
9
|
-
import { type
|
|
9
|
+
import { type TableRow } from './table-model';
|
|
10
10
|
import { touch } from '../util';
|
|
11
11
|
|
|
12
|
-
export
|
|
12
|
+
export type SelectionMode = 'single' | 'multiple';
|
|
13
|
+
|
|
14
|
+
export class SelectionModel<T extends TableRow> extends Resource {
|
|
13
15
|
private readonly _selection = signal<Set<string>>(new Set());
|
|
14
16
|
|
|
15
17
|
private readonly _validSelectedIds = computed<Set<string>>(() => {
|
|
@@ -35,6 +37,7 @@ export class SelectionModel<T extends BaseTableRow> extends Resource {
|
|
|
35
37
|
|
|
36
38
|
constructor(
|
|
37
39
|
private readonly _rows: ReadonlySignal<T[]>,
|
|
40
|
+
private readonly _selectionMode: SelectionMode,
|
|
38
41
|
private readonly _onSelectionChanged?: () => void,
|
|
39
42
|
) {
|
|
40
43
|
super();
|
|
@@ -64,6 +67,10 @@ export class SelectionModel<T extends BaseTableRow> extends Resource {
|
|
|
64
67
|
return this._allSelected;
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
public get selectionMode(): SelectionMode {
|
|
71
|
+
return this._selectionMode;
|
|
72
|
+
}
|
|
73
|
+
|
|
67
74
|
public getSelectedRows = (): T[] => {
|
|
68
75
|
const selectedIds = this._validSelectedIds.value;
|
|
69
76
|
return this._rows.value.filter((row) => selectedIds.has(row.id));
|
|
@@ -89,6 +96,9 @@ export class SelectionModel<T extends BaseTableRow> extends Resource {
|
|
|
89
96
|
if (newSelection.has(row.id)) {
|
|
90
97
|
newSelection.delete(row.id);
|
|
91
98
|
} else {
|
|
99
|
+
if (this._selectionMode === 'single') {
|
|
100
|
+
newSelection.clear();
|
|
101
|
+
}
|
|
92
102
|
newSelection.add(row.id);
|
|
93
103
|
}
|
|
94
104
|
|
|
@@ -106,7 +106,7 @@ class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.
|
|
|
106
106
|
const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
|
|
107
107
|
const schema = createEchoSchema(Test);
|
|
108
108
|
const view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
|
|
109
|
-
const projection = new ViewProjection(schema, view);
|
|
109
|
+
const projection = new ViewProjection(schema.jsonSchema, view);
|
|
110
110
|
const table = create(TableType, { view: makeRef(view) });
|
|
111
111
|
return new TableModel({ id: table.id, space: undefined, view, projection, ...props });
|
|
112
112
|
};
|
package/src/model/table-model.ts
CHANGED
|
@@ -18,31 +18,31 @@ import {
|
|
|
18
18
|
} from '@dxos/react-ui-grid';
|
|
19
19
|
import { type ViewType, type ViewProjection } from '@dxos/schema';
|
|
20
20
|
|
|
21
|
-
import { SelectionModel } from './selection-model';
|
|
21
|
+
import { type SelectionMode, SelectionModel } from './selection-model';
|
|
22
22
|
import { TableSorting } from './table-sorting';
|
|
23
23
|
import { touch } from '../util';
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// TODO(burdon): Use schema types.
|
|
26
|
+
export type TableRow = Record<JsonProp, any> & { id: string };
|
|
26
27
|
|
|
27
28
|
export type TableRowAction = {
|
|
28
29
|
id: string;
|
|
29
30
|
translationKey: string;
|
|
30
31
|
};
|
|
31
32
|
|
|
32
|
-
// TODO(ZaymonFC): There should be a separate concept for immutable schemata.
|
|
33
33
|
export type TableFeatures = {
|
|
34
|
-
selection: boolean;
|
|
34
|
+
selection: { enabled: boolean; mode?: SelectionMode };
|
|
35
35
|
dataEditable: boolean;
|
|
36
36
|
schemaEditable: boolean;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
const defaultFeatures: TableFeatures = {
|
|
40
|
-
selection: true,
|
|
40
|
+
selection: { enabled: true, mode: 'multiple' },
|
|
41
41
|
dataEditable: false,
|
|
42
42
|
schemaEditable: false,
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
export type TableModelProps<T extends
|
|
45
|
+
export type TableModelProps<T extends TableRow = TableRow> = {
|
|
46
46
|
id?: string;
|
|
47
47
|
space?: Space;
|
|
48
48
|
view?: ViewType;
|
|
@@ -50,16 +50,16 @@ export type TableModelProps<T extends BaseTableRow = { id: string }> = {
|
|
|
50
50
|
features?: Partial<TableFeatures>;
|
|
51
51
|
sorting?: FieldSortType[];
|
|
52
52
|
pinnedRows?: { top: number[]; bottom: number[] };
|
|
53
|
+
rowActions?: TableRowAction[];
|
|
53
54
|
onInsertRow?: (index?: number) => void;
|
|
54
55
|
onDeleteRows?: (index: number, obj: T[]) => void;
|
|
55
56
|
onDeleteColumn?: (fieldId: string) => void;
|
|
56
57
|
onCellUpdate?: (cell: DxGridPosition) => void;
|
|
57
|
-
|
|
58
|
-
rowActions?: TableRowAction[];
|
|
58
|
+
onRowOrderChange?: () => void;
|
|
59
59
|
onRowAction?: (actionId: string, data: T) => void;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
export class TableModel<T extends
|
|
62
|
+
export class TableModel<T extends TableRow = TableRow> extends Resource {
|
|
63
63
|
private readonly _id: string | undefined;
|
|
64
64
|
private readonly _space: Space | undefined;
|
|
65
65
|
private readonly _view: ViewType | undefined;
|
|
@@ -74,9 +74,9 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
|
|
|
74
74
|
private readonly _onDeleteRows?: TableModelProps<T>['onDeleteRows'];
|
|
75
75
|
private readonly _onDeleteColumn?: TableModelProps<T>['onDeleteColumn'];
|
|
76
76
|
private readonly _onCellUpdate?: TableModelProps<T>['onCellUpdate'];
|
|
77
|
-
private readonly
|
|
78
|
-
private readonly _rowActions: TableRowAction[];
|
|
77
|
+
private readonly _onRowOrderChange?: TableModelProps<T>['onRowOrderChange'];
|
|
79
78
|
private readonly _onRowAction?: TableModelProps<T>['onRowAction'];
|
|
79
|
+
private readonly _rowActions: TableRowAction[];
|
|
80
80
|
private readonly _features: TableFeatures;
|
|
81
81
|
|
|
82
82
|
private readonly _rows = signal<T[]>([]);
|
|
@@ -94,12 +94,12 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
|
|
|
94
94
|
features = {},
|
|
95
95
|
sorting = [],
|
|
96
96
|
pinnedRows = { top: [], bottom: [] },
|
|
97
|
+
rowActions = [],
|
|
97
98
|
onCellUpdate,
|
|
98
99
|
onDeleteColumn,
|
|
99
100
|
onDeleteRows,
|
|
100
101
|
onInsertRow,
|
|
101
|
-
|
|
102
|
-
rowActions = [],
|
|
102
|
+
onRowOrderChange,
|
|
103
103
|
onRowAction,
|
|
104
104
|
}: TableModelProps<T>) {
|
|
105
105
|
super();
|
|
@@ -107,8 +107,15 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
|
|
|
107
107
|
this._space = space;
|
|
108
108
|
this._view = view;
|
|
109
109
|
this._projection = projection;
|
|
110
|
+
|
|
111
|
+
// TODO(ZaymonFC): Use our more robust config merging module?
|
|
110
112
|
this._features = { ...defaultFeatures, ...features };
|
|
111
113
|
|
|
114
|
+
invariant(
|
|
115
|
+
!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single'),
|
|
116
|
+
'Single selection is not compatible with editable tables.',
|
|
117
|
+
);
|
|
118
|
+
|
|
112
119
|
this._sorting = new TableSorting(this._rows, this._view, projection);
|
|
113
120
|
|
|
114
121
|
if (sorting.length > 0) {
|
|
@@ -117,12 +124,12 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
|
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
this._pinnedRows = pinnedRows;
|
|
127
|
+
this._rowActions = rowActions;
|
|
120
128
|
this._onInsertRow = onInsertRow;
|
|
121
129
|
this._onDeleteRows = onDeleteRows;
|
|
122
130
|
this._onDeleteColumn = onDeleteColumn;
|
|
123
131
|
this._onCellUpdate = onCellUpdate;
|
|
124
|
-
this.
|
|
125
|
-
this._rowActions = rowActions;
|
|
132
|
+
this._onRowOrderChange = onRowOrderChange;
|
|
126
133
|
this._onRowAction = onRowAction;
|
|
127
134
|
}
|
|
128
135
|
|
|
@@ -197,7 +204,9 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
|
|
|
197
204
|
protected override async _open() {
|
|
198
205
|
this.initializeColumnMeta();
|
|
199
206
|
this.initializeEffects();
|
|
200
|
-
this._selection = new SelectionModel(this._sorting.sortedRows, () =>
|
|
207
|
+
this._selection = new SelectionModel(this._sorting.sortedRows, this._features.selection.mode ?? 'multiple', () =>
|
|
208
|
+
this._onRowOrderChange?.(),
|
|
209
|
+
);
|
|
201
210
|
await this._selection.open(this._ctx);
|
|
202
211
|
}
|
|
203
212
|
|
|
@@ -219,7 +228,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
|
|
|
219
228
|
private initializeEffects(): void {
|
|
220
229
|
const rowOrderWatcher = effect(() => {
|
|
221
230
|
touch(this._sorting.sortedRows.value);
|
|
222
|
-
this.
|
|
231
|
+
this._onRowOrderChange?.();
|
|
223
232
|
});
|
|
224
233
|
this._ctx.onDispose(rowOrderWatcher);
|
|
225
234
|
|
|
@@ -268,7 +277,7 @@ export class TableModel<T extends BaseTableRow = { id: string }> extends Resourc
|
|
|
268
277
|
const obj = this._rows.value[row];
|
|
269
278
|
const objectsToDelete = [];
|
|
270
279
|
|
|
271
|
-
if (this._selection.hasSelection.value) {
|
|
280
|
+
if (this.features.selection.enabled && this._selection.hasSelection.value) {
|
|
272
281
|
const selectedRows = this._selection.getSelectedRows();
|
|
273
282
|
objectsToDelete.push(...selectedRows);
|
|
274
283
|
} else {
|
|
@@ -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 view = createView({ name: 'Test', typename: schema.typename, jsonSchema: schema.jsonSchema });
|
|
99
|
-
const projection = new ViewProjection(schema, view);
|
|
99
|
+
const projection = new ViewProjection(schema.jsonSchema, view);
|
|
100
100
|
const table = create(TableType, { view: makeRef(view) });
|
|
101
101
|
return new TableModel({ id: table.id, view, projection, ...props });
|
|
102
102
|
};
|
|
@@ -5,18 +5,19 @@
|
|
|
5
5
|
import { signal } from '@preact/signals-core';
|
|
6
6
|
|
|
7
7
|
import { FormatEnum, getValue } from '@dxos/echo-schema';
|
|
8
|
-
import { cellClassesForFieldType,
|
|
8
|
+
import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
|
|
9
9
|
import {
|
|
10
10
|
type DxGridPlane,
|
|
11
11
|
type DxGridPlaneCells,
|
|
12
|
-
toPlaneCellIndex,
|
|
13
12
|
type DxGridPlaneRange,
|
|
14
13
|
type DxGridCellValue,
|
|
14
|
+
toPlaneCellIndex,
|
|
15
15
|
} from '@dxos/react-ui-grid';
|
|
16
16
|
import { mx } from '@dxos/react-ui-theme';
|
|
17
17
|
import { VIEW_FIELD_LIMIT, type FieldType } from '@dxos/schema';
|
|
18
18
|
|
|
19
|
-
import { type
|
|
19
|
+
import { type SelectionMode } from './selection-model';
|
|
20
|
+
import { type TableRow, type TableModel } from './table-model';
|
|
20
21
|
import { tableButtons, tableControls } from '../util';
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -24,7 +25,7 @@ import { tableButtons, tableControls } from '../util';
|
|
|
24
25
|
* Manages rendering of table cells, headers, selection columns, and action columns across
|
|
25
26
|
* different grid planes.
|
|
26
27
|
*/
|
|
27
|
-
export class TablePresentation<T extends
|
|
28
|
+
export class TablePresentation<T extends TableRow = TableRow> {
|
|
28
29
|
constructor(
|
|
29
30
|
private readonly model: TableModel<T>,
|
|
30
31
|
private readonly _visibleRange = signal<DxGridPlaneRange>({
|
|
@@ -62,7 +63,7 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
62
63
|
|
|
63
64
|
if (plane === 'grid' && this.model.features.dataEditable === false) {
|
|
64
65
|
Object.values(cells).forEach((cell) => {
|
|
65
|
-
cell.readonly =
|
|
66
|
+
cell.readonly = 'text-select';
|
|
66
67
|
});
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -85,7 +86,8 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
85
86
|
|
|
86
87
|
switch (props.format) {
|
|
87
88
|
case FormatEnum.Boolean:
|
|
88
|
-
case FormatEnum.SingleSelect:
|
|
89
|
+
case FormatEnum.SingleSelect:
|
|
90
|
+
case FormatEnum.MultiSelect: {
|
|
89
91
|
return '';
|
|
90
92
|
}
|
|
91
93
|
case FormatEnum.Ref: {
|
|
@@ -108,7 +110,10 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
108
110
|
if (formatClasses) {
|
|
109
111
|
classes.push(formatClasses);
|
|
110
112
|
}
|
|
111
|
-
const rowSelectionClasses = cellClassesForRowSelection(
|
|
113
|
+
const rowSelectionClasses = cellClassesForRowSelection(
|
|
114
|
+
this.model.selection.isObjectSelected(obj),
|
|
115
|
+
this.model.selection.selectionMode,
|
|
116
|
+
);
|
|
112
117
|
if (rowSelectionClasses) {
|
|
113
118
|
classes.push(rowSelectionClasses);
|
|
114
119
|
}
|
|
@@ -133,7 +138,7 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
133
138
|
rowIndex: displayIndex,
|
|
134
139
|
checked: value ?? false,
|
|
135
140
|
});
|
|
136
|
-
cell.readonly =
|
|
141
|
+
cell.readonly = 'no-text-select';
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
if (props.format === FormatEnum.SingleSelect) {
|
|
@@ -147,6 +152,27 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
147
152
|
}
|
|
148
153
|
}
|
|
149
154
|
|
|
155
|
+
if (props.format === FormatEnum.MultiSelect) {
|
|
156
|
+
const values = getValue(obj, field.path) as string[] | undefined;
|
|
157
|
+
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
158
|
+
if (options && values && values.length > 0) {
|
|
159
|
+
const tags = values
|
|
160
|
+
.map((value) => {
|
|
161
|
+
const option = options.find((o) => o.id === value);
|
|
162
|
+
if (option) {
|
|
163
|
+
return `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
})
|
|
167
|
+
.filter(Boolean)
|
|
168
|
+
.join(' ');
|
|
169
|
+
|
|
170
|
+
if (tags) {
|
|
171
|
+
cell.accessoryHtml = tags;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
150
176
|
const idx = toPlaneCellIndex({ col: colIndex, row: displayIndex });
|
|
151
177
|
cells[idx] = cell;
|
|
152
178
|
};
|
|
@@ -193,10 +219,10 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
193
219
|
const cells: DxGridPlaneCells = {};
|
|
194
220
|
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
195
221
|
const isSelected = this.model.selection.isRowIndexSelected(row);
|
|
196
|
-
const classes = cellClassesForRowSelection(isSelected);
|
|
222
|
+
const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
|
|
197
223
|
cells[toPlaneCellIndex({ col: 0, row })] = {
|
|
198
224
|
value: '',
|
|
199
|
-
readonly:
|
|
225
|
+
readonly: 'no-text-select',
|
|
200
226
|
className: classes ? mx(classes) : undefined,
|
|
201
227
|
accessoryHtml: tableControls.checkbox.render({ rowIndex: row, checked: isSelected }),
|
|
202
228
|
};
|
|
@@ -209,7 +235,7 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
209
235
|
const cells: DxGridPlaneCells = {};
|
|
210
236
|
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
211
237
|
const isSelected = this.model.selection.isRowIndexSelected(row);
|
|
212
|
-
const classes = cellClassesForRowSelection(isSelected);
|
|
238
|
+
const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
|
|
213
239
|
cells[toPlaneCellIndex({ col: 0, row })] = {
|
|
214
240
|
value: '',
|
|
215
241
|
readonly: true,
|
|
@@ -222,6 +248,16 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
222
248
|
}
|
|
223
249
|
|
|
224
250
|
private getSelectAllCell(): DxGridPlaneCells {
|
|
251
|
+
if (!this.model.features.selection.enabled || this.model.selection.selectionMode === 'single') {
|
|
252
|
+
return {
|
|
253
|
+
[toPlaneCellIndex({ col: 0, row: 0 })]: {
|
|
254
|
+
className: '!bg-gridHeader',
|
|
255
|
+
readonly: true,
|
|
256
|
+
value: '',
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
225
261
|
return {
|
|
226
262
|
[toPlaneCellIndex({ col: 0, row: 0 })]: {
|
|
227
263
|
accessoryHtml: tableControls.checkbox.render({
|
|
@@ -251,3 +287,21 @@ export class TablePresentation<T extends BaseTableRow = { id: string }> {
|
|
|
251
287
|
};
|
|
252
288
|
}
|
|
253
289
|
}
|
|
290
|
+
|
|
291
|
+
export const cellClassesForRowSelection = (selected: boolean, selectionMode: SelectionMode) => {
|
|
292
|
+
if (!selected) {
|
|
293
|
+
if (selectionMode === 'single') {
|
|
294
|
+
return ['!cursor-pointer'];
|
|
295
|
+
} else {
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
switch (selectionMode) {
|
|
301
|
+
case 'single':
|
|
302
|
+
// TODO(ZaymonFC): @thure, do we need a grid version of 'currentRelated'?
|
|
303
|
+
return ['!bg-currentRelated hover:bg-hoverSurface', '!cursor-pointer'];
|
|
304
|
+
case 'multiple':
|
|
305
|
+
return ['!bg-gridCellSelected'];
|
|
306
|
+
}
|
|
307
|
+
};
|
|
@@ -9,7 +9,7 @@ import { getValue, FormatEnum, TypeEnum, type SortDirectionType, type FieldSortT
|
|
|
9
9
|
import { formatForDisplay } from '@dxos/react-ui-form';
|
|
10
10
|
import type { PropertyType, FieldType, ViewProjection, ViewType } from '@dxos/schema';
|
|
11
11
|
|
|
12
|
-
import { type
|
|
12
|
+
import { type TableRow } from './table-model';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Represents the local sort state.
|
|
@@ -40,7 +40,7 @@ type LocalSort = { type: 'cleared' } | { type: 'active'; sort: FieldSortType } |
|
|
|
40
40
|
* │ 2: "Cherry" │ => │ 2: "Cherry" │ => │ 2 => 2 │
|
|
41
41
|
* └──────────────┘ └──────────────┘ └────────┘
|
|
42
42
|
*/
|
|
43
|
-
export class TableSorting<T extends
|
|
43
|
+
export class TableSorting<T extends TableRow> {
|
|
44
44
|
private readonly _displayToDataIndex = new Map<number, number>();
|
|
45
45
|
private readonly _rows: Signal<T[]>;
|
|
46
46
|
private readonly _localSort = signal<LocalSort>(undefined);
|
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
import { expect, test } from '@playwright/test';
|
|
6
6
|
|
|
7
|
-
import { setupPage } from '@dxos/test-utils/playwright';
|
|
7
|
+
import { setupPage, storybookUrl } from '@dxos/test-utils/playwright';
|
|
8
8
|
|
|
9
9
|
import { TableManager } from './TableManager';
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
const storyUrl = `http://localhost:9009/iframe.html?id=${storyId}&viewMode=story`;
|
|
11
|
+
const storyUrl = storybookUrl('ui-react-ui-table-table--default');
|
|
13
12
|
|
|
14
13
|
// NOTE(ZaymonFC): This test suite relies on the faker seed being set to 0 in the story.
|
|
15
14
|
test.describe('Table', () => {
|
package/src/types/table.ts
CHANGED
|
@@ -7,14 +7,15 @@ import { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/
|
|
|
7
7
|
import { ViewType } from '@dxos/schema';
|
|
8
8
|
|
|
9
9
|
export const TableSchema = S.Struct({
|
|
10
|
-
id: ObjectId,
|
|
10
|
+
id: ObjectId,
|
|
11
11
|
name: S.optional(S.String),
|
|
12
12
|
view: S.optional(Ref(ViewType)),
|
|
13
|
-
// TODO(burdon):
|
|
14
|
-
threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),
|
|
13
|
+
// TODO(burdon): Document why threads is included here?
|
|
14
|
+
threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),
|
|
15
15
|
}).annotations({
|
|
16
|
+
// TODO(burdon): Move annotation to property.
|
|
16
17
|
[LabelAnnotationId]: 'name',
|
|
17
18
|
});
|
|
18
19
|
|
|
19
|
-
export const TableType = TableSchema.pipe(EchoObject('dxos.org/type/Table', '0.1.0'));
|
|
20
|
-
export
|
|
20
|
+
export const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));
|
|
21
|
+
export interface TableType extends S.Schema.Type<typeof TableType> {}
|