@dxos/react-ui-table 0.8.2-main.f11618f → 0.8.2-staging.42af850

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 (87) hide show
  1. package/dist/lib/browser/chunk-U6LL2AVU.mjs +26 -0
  2. package/dist/lib/browser/chunk-U6LL2AVU.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1074 -828
  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-TGG6OZ54.cjs → chunk-CXDGXPM6.cjs} +12 -12
  8. package/dist/lib/node/chunk-CXDGXPM6.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +1080 -837
  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-KKLP54L3.mjs → chunk-EFSM52KQ.mjs} +10 -10
  15. package/dist/lib/node-esm/chunk-EFSM52KQ.mjs.map +7 -0
  16. package/dist/lib/node-esm/index.mjs +1074 -828
  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/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/DynamicTable.d.ts +3 -4
  24. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  26. package/dist/types/src/components/Table/Table.d.ts +2 -0
  27. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/Table.stories.d.ts +1 -0
  29. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +13 -0
  32. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -0
  33. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -0
  34. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  35. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +1 -1
  37. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +6 -3
  38. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  39. package/dist/types/src/components/testing.d.ts +39 -39
  40. package/dist/types/src/components/testing.d.ts.map +1 -1
  41. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  42. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  43. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  44. package/dist/types/src/model/table-model.d.ts.map +1 -1
  45. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  46. package/dist/types/src/types/table.d.ts +46 -45
  47. package/dist/types/src/types/table.d.ts.map +1 -1
  48. package/dist/types/src/util/dynamic-table.d.ts +4 -3
  49. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  50. package/dist/types/src/util/index.d.ts +1 -0
  51. package/dist/types/src/util/index.d.ts.map +1 -1
  52. package/dist/types/src/util/schema.d.ts +12 -0
  53. package/dist/types/src/util/schema.d.ts.map +1 -0
  54. package/dist/types/src/util/signals.d.ts.map +1 -1
  55. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  56. package/dist/types/src/util/table.d.ts +2 -2
  57. package/dist/types/src/util/table.d.ts.map +1 -1
  58. package/dist/types/src/util/tag.d.ts.map +1 -1
  59. package/dist/types/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +41 -34
  61. package/src/components/Table/CreateRefPanel.tsx +3 -3
  62. package/src/components/Table/DynamicTable.stories.tsx +2 -2
  63. package/src/components/Table/DynamicTable.tsx +4 -5
  64. package/src/components/Table/Table.stories.tsx +76 -42
  65. package/src/components/Table/Table.tsx +8 -5
  66. package/src/components/Table/relations.stories.tsx +17 -20
  67. package/src/components/TableCellEditor/FormCellEditor.tsx +94 -0
  68. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +10 -8
  69. package/src/components/TableCellEditor/TableCellEditor.tsx +45 -4
  70. package/src/components/TableToolbar/TableToolbar.tsx +63 -33
  71. package/src/components/testing.ts +7 -6
  72. package/src/hooks/useTableModel.ts +4 -2
  73. package/src/model/selection-model.ts +1 -1
  74. package/src/model/table-model.test.ts +4 -3
  75. package/src/model/table-model.ts +1 -1
  76. package/src/model/table-presentation.test.ts +4 -3
  77. package/src/model/table-presentation.ts +53 -7
  78. package/src/types/table.ts +16 -11
  79. package/src/util/dynamic-table.ts +7 -4
  80. package/src/util/index.ts +1 -0
  81. package/src/util/schema.ts +36 -0
  82. package/src/util/table-buttons.ts +1 -1
  83. package/src/util/table.ts +11 -10
  84. package/dist/lib/browser/chunk-YWNRUF4J.mjs +0 -26
  85. package/dist/lib/browser/chunk-YWNRUF4J.mjs.map +0 -7
  86. package/dist/lib/node/chunk-TGG6OZ54.cjs.map +0 -7
  87. package/dist/lib/node-esm/chunk-KKLP54L3.mjs.map +0 -7
@@ -2,19 +2,23 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useMemo } from 'react';
5
+ import { Rx } from '@effect-rx/rx-react';
6
+ import React, { useMemo } from 'react';
6
7
 
7
8
  import { live } from '@dxos/live-object';
8
9
  import { type ThemedClassName } from '@dxos/react-ui';
9
10
  import {
11
+ type ActionGraphEdges,
12
+ type ActionGraphNodes,
13
+ type ActionGraphProps,
10
14
  createGapSeparator,
11
15
  createMenuAction,
12
16
  type MenuAction,
13
- type MenuActionHandler,
14
17
  MenuProvider,
15
18
  ToolbarMenu,
16
19
  useMenuActions,
17
20
  } from '@dxos/react-ui-menu';
21
+ import { rxFromSignal } from '@dxos/react-ui-menu';
18
22
 
19
23
  import { translationKey } from '../../translations';
20
24
 
@@ -27,45 +31,71 @@ export type TableToolbarActionType = 'add-row' | 'comment' | 'save-view';
27
31
  type TableToolbarState = Partial<{ viewDirty: boolean }>;
28
32
 
29
33
  export type TableToolbarProps = ThemedClassName<
30
- TableToolbarState & { onAction?: MenuActionHandler<TableToolbarAction>; attendableId?: string }
34
+ TableToolbarState & {
35
+ onAdd: () => void;
36
+ onSave: () => void;
37
+ attendableId?: string;
38
+ customActions?: Rx.Rx<ActionGraphProps>;
39
+ }
31
40
  >;
32
41
 
33
- const createTableToolbarActions = (state: TableToolbarState) => {
34
- const add = createMenuAction<TableToolbarActionProperties>('add-row', {
35
- type: 'add-row',
36
- icon: 'ph--plus--regular',
37
- label: ['add row', { ns: translationKey }],
38
- testId: 'table.toolbar.add-row',
42
+ const createTableToolbarActions = ({
43
+ state,
44
+ onAdd,
45
+ onSave,
46
+ customActions,
47
+ }: {
48
+ state: TableToolbarState;
49
+ onAdd: () => void;
50
+ onSave: () => void;
51
+ customActions?: Rx.Rx<ActionGraphProps>;
52
+ }) =>
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
+ });
68
+ const gap = createGapSeparator();
69
+ const nodes: ActionGraphNodes = [add, save, ...gap.nodes];
70
+ const edges: ActionGraphEdges = nodes.map(({ id: target }) => ({ source: 'root', target }));
71
+ if (customActions) {
72
+ const custom = get(customActions);
73
+ nodes.push(...custom.nodes);
74
+ edges.push(...custom.edges);
75
+ }
76
+ return {
77
+ nodes,
78
+ edges,
79
+ };
39
80
  });
40
- const save = createMenuAction<TableToolbarActionProperties>('save-view', {
41
- type: 'save-view',
42
- icon: 'ph--floppy-disk--regular',
43
- label: ['save view label', { ns: translationKey }],
44
- testId: 'table.toolbar.save-view',
45
- iconOnly: false,
46
- hidden: !state.viewDirty,
47
- });
48
- const gap = createGapSeparator();
49
- const comment = createMenuAction('comment', {
50
- type: 'comment',
51
- icon: 'ph--chat-text--regular',
52
- label: ['create comment', { ns: translationKey }],
53
- testId: 'table.toolbar.comment',
54
- });
55
- const nodes = [add, save, ...gap.nodes, comment];
56
- return {
57
- nodes,
58
- edges: nodes.map(({ id: target }) => ({ source: 'root', target })),
59
- };
60
- };
61
81
 
62
- export const TableToolbar = ({ classNames, viewDirty, attendableId, onAction }: TableToolbarProps) => {
82
+ export const TableToolbar = ({
83
+ classNames,
84
+ viewDirty,
85
+ attendableId,
86
+ onAdd,
87
+ onSave,
88
+ customActions,
89
+ }: TableToolbarProps) => {
63
90
  const state = useMemo(() => live<TableToolbarState>({ viewDirty }), []);
64
- const actionsCreator = useCallback(() => createTableToolbarActions(state), [state]);
91
+ const actionsCreator = useMemo(
92
+ () => createTableToolbarActions({ state, onAdd, onSave, customActions }),
93
+ [state, onAdd, onSave, customActions],
94
+ );
65
95
  const menu = useMenuActions(actionsCreator);
66
96
 
67
97
  return (
68
- <MenuProvider {...menu} attendableId={attendableId} onAction={onAction as MenuActionHandler}>
98
+ <MenuProvider {...menu} attendableId={attendableId}>
69
99
  <ToolbarMenu classNames={classNames} />
70
100
  </MenuProvider>
71
101
  );
@@ -2,9 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
5
6
  import { useEffect } from 'react';
6
7
 
7
- import { setValue, toJsonSchema, S, TypeEnum, TypedObject, FormatEnum } from '@dxos/echo-schema';
8
+ import { setValue, toJsonSchema, TypeEnum, TypedObject, FormatEnum, ObjectId } from '@dxos/echo-schema';
8
9
  import { faker } from '@dxos/random';
9
10
  import { live, makeRef } from '@dxos/react-client/echo';
10
11
  import { createView, type ViewProjection } from '@dxos/schema';
@@ -12,11 +13,11 @@ import { createView, type ViewProjection } from '@dxos/schema';
12
13
  import { TableType } from '../types';
13
14
 
14
15
  export const TestSchema = TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
15
- id: S.String,
16
- name: S.optional(S.String),
17
- age: S.optional(S.Number),
18
- active: S.optional(S.Boolean),
19
- netWorth: S.optional(S.Number),
16
+ id: ObjectId,
17
+ name: Schema.optional(Schema.String),
18
+ age: Schema.optional(Schema.Number),
19
+ active: Schema.optional(Schema.Boolean),
20
+ netWorth: Schema.optional(Schema.Number),
20
21
  });
21
22
 
22
23
  export const createTable = (schema = TestSchema) => {
@@ -70,7 +70,9 @@ export const useTableModel = <T extends TableRow = TableRow>({
70
70
  }
71
71
  }, [model, rows]);
72
72
 
73
- const { select, clear } = useSelectionActions([table?.id, table?.view?.target?.query.typename].filter(isNonNullable));
73
+ const { multiSelect, clear } = useSelectionActions(
74
+ [table?.id, table?.view?.target?.query.typename].filter(isNonNullable),
75
+ );
74
76
 
75
77
  useEffect(() => {
76
78
  if (!model) {
@@ -79,7 +81,7 @@ export const useTableModel = <T extends TableRow = TableRow>({
79
81
 
80
82
  const unsubscribe = effect(() => {
81
83
  const selectedItems = [...model.selection.selection.value];
82
- select(selectedItems);
84
+ multiSelect(selectedItems);
83
85
  onSelectionChanged?.(selectedItems);
84
86
  });
85
87
 
@@ -43,7 +43,7 @@ export class SelectionModel<T extends TableRow> extends Resource {
43
43
  super();
44
44
  }
45
45
 
46
- protected override async _open() {
46
+ protected override async _open(): Promise<void> {
47
47
  const selectionWatcher = effect(() => {
48
48
  touch(this._selection.value);
49
49
  this._onSelectionChanged?.();
@@ -3,9 +3,10 @@
3
3
  //
4
4
 
5
5
  import { computed } from '@preact/signals-core';
6
+ import { Schema } from 'effect';
6
7
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
7
8
 
8
- import { S, TypedObject } from '@dxos/echo-schema';
9
+ import { TypedObject } from '@dxos/echo-schema';
9
10
  import { updateCounter } from '@dxos/echo-schema/testing';
10
11
  import { registerSignalsRuntime } from '@dxos/echo-signals';
11
12
  import { createEchoSchema } from '@dxos/live-object/testing';
@@ -99,8 +100,8 @@ describe('TableModel', () => {
99
100
  });
100
101
 
101
102
  class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
102
- title: S.String,
103
- completed: S.Boolean,
103
+ title: Schema.String,
104
+ completed: Schema.Boolean,
104
105
  }) {}
105
106
 
106
107
  const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
@@ -202,7 +202,7 @@ export class TableModel<T extends TableRow = TableRow> extends Resource {
202
202
  // Initialisation
203
203
  //
204
204
 
205
- protected override async _open() {
205
+ protected override async _open(): Promise<void> {
206
206
  this.initializeColumnMeta();
207
207
  this.initializeEffects();
208
208
  this._selection = new SelectionModel(this._sorting.sortedRows, this._features.selection.mode ?? 'multiple', () =>
@@ -2,9 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
5
6
  import { describe, expect, it, beforeEach } from 'vitest';
6
7
 
7
- import { S, TypedObject } from '@dxos/echo-schema';
8
+ import { TypedObject } from '@dxos/echo-schema';
8
9
  import { live, makeRef } from '@dxos/live-object';
9
10
  import { createEchoSchema } from '@dxos/live-object/testing';
10
11
  import { createView, ViewProjection } from '@dxos/schema';
@@ -89,8 +90,8 @@ describe('TablePresentation', () => {
89
90
  });
90
91
 
91
92
  class Test extends TypedObject({ typename: 'example.com/type/Test', version: '0.1.0' })({
92
- title: S.String,
93
- completed: S.Boolean,
93
+ title: Schema.String,
94
+ completed: Schema.Boolean,
94
95
  }) {}
95
96
 
96
97
  const createTableModel = (props: Partial<TableModelProps> = {}): TableModel => {
@@ -3,8 +3,9 @@
3
3
  //
4
4
 
5
5
  import { signal } from '@preact/signals-core';
6
+ import { isNotNullable } from 'effect/Predicate';
6
7
 
7
- import { FormatEnum, getDXN, getValue } from '@dxos/echo-schema';
8
+ import { FormatEnum, getDXN, getValue, TypeEnum } from '@dxos/echo-schema';
8
9
  import { cellClassesForFieldType, formatForDisplay } from '@dxos/react-ui-form';
9
10
  import {
10
11
  type DxGridPlane,
@@ -84,6 +85,10 @@ export class TablePresentation<T extends TableRow = TableRow> {
84
85
  return '';
85
86
  }
86
87
 
88
+ if (props.type === 'array') {
89
+ return '';
90
+ }
91
+
87
92
  switch (props.format) {
88
93
  case FormatEnum.Boolean:
89
94
  case FormatEnum.SingleSelect:
@@ -121,11 +126,52 @@ export class TablePresentation<T extends TableRow = TableRow> {
121
126
  cell.className = mx(classes.flat());
122
127
  }
123
128
 
129
+ if (props.type === TypeEnum.Array) {
130
+ const targetArray = getValue(obj, field.path);
131
+ if (targetArray && Array.isArray(targetArray)) {
132
+ // TODO(ZaymonFC): For arrays of objects, objects should have a 'label' annotation on the field
133
+ // that can be used to render tags.
134
+ // TODO(ZaymonFC): Move to util.
135
+ const getLabel = (value: any) => {
136
+ // If the value is falsy, return undefined
137
+ // If the object is an array, check for 'name' property
138
+ // If the object is a primitive type (string, number, boolean) stringify
139
+ // If the object is an array return 'Array'
140
+ if (!value) {
141
+ return undefined;
142
+ }
143
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
144
+ return String(value);
145
+ }
146
+ if (Array.isArray(value)) {
147
+ return 'Array';
148
+ }
149
+ if (typeof value === 'object' && value.name) {
150
+ return value.name;
151
+ }
152
+ if (typeof value === 'object' && value.value) {
153
+ return `${value.value}`;
154
+ }
155
+ return 'Object';
156
+ };
157
+
158
+ const tags = targetArray
159
+ .map(getLabel)
160
+ .filter(isNotNullable)
161
+ .map((title) => {
162
+ return `<span class="dx-tag rounded-xl" data-hue="neutral">${title}</span>`;
163
+ })
164
+ .join('');
165
+
166
+ cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
167
+ }
168
+ }
169
+
124
170
  if (props.format === FormatEnum.Ref && props.referenceSchema) {
125
171
  const targetObj = getValue(obj, field.path)?.target;
126
172
  if (targetObj) {
127
173
  const dxn = getDXN(targetObj)?.toString();
128
- cell.accessoryHtml = `<dx-ref-tag ref=${dxn} class="dx-button block is-6 pli-[3px] plb-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
174
+ cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button block is-6 pli-[3px] plb-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
129
175
  }
130
176
  }
131
177
 
@@ -166,7 +212,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
166
212
  .join(' ');
167
213
 
168
214
  if (tags) {
169
- cell.accessoryHtml = tags;
215
+ cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1">${tags}</div>`;
170
216
  }
171
217
  }
172
218
  }
@@ -206,7 +252,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
206
252
  ${direction !== undefined ? tableButtons.sort.render({ fieldId: field.id, direction }) : ''}
207
253
  ${tableButtons.columnSettings.render({ fieldId: field.id })}
208
254
  `,
209
- className: '!bg-gridHeader',
255
+ className: '!bg-toolbarSurface',
210
256
  };
211
257
  }
212
258
 
@@ -249,7 +295,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
249
295
  if (!this.model.features.selection.enabled || this.model.selection.selectionMode === 'single') {
250
296
  return {
251
297
  [toPlaneCellIndex({ col: 0, row: 0 })]: {
252
- className: '!bg-gridHeader',
298
+ className: '!bg-toolbarSurface',
253
299
  readonly: true,
254
300
  value: '',
255
301
  },
@@ -263,7 +309,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
263
309
  header: true,
264
310
  checked: this.model.selection.allRowsSeleted.value,
265
311
  }),
266
- className: '!bg-gridHeader',
312
+ className: '!bg-toolbarSurface',
267
313
  readonly: true,
268
314
  value: '',
269
315
  },
@@ -278,7 +324,7 @@ export class TablePresentation<T extends TableRow = TableRow> {
278
324
  disabled: (this.model.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT,
279
325
  })
280
326
  : undefined,
281
- className: '!bg-gridHeader',
327
+ className: '!bg-toolbarSurface',
282
328
  readonly: true,
283
329
  value: '',
284
330
  },
@@ -2,20 +2,25 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';
5
+ import { Schema } from 'effect';
6
+
6
7
  // import { ThreadType } from '@dxos/plugin-space/types';
8
+ import { ObjectId, Ref, Expando, EchoObject, LabelAnnotation } from '@dxos/echo-schema';
7
9
  import { ViewType } from '@dxos/schema';
8
10
 
9
- export const TableSchema = S.Struct({
11
+ export const TableSchema = Schema.Struct({
10
12
  id: ObjectId,
11
- name: S.optional(S.String),
12
- view: S.optional(Ref(ViewType)),
13
+ name: Schema.optional(Schema.String),
14
+ view: Schema.optional(Ref(ViewType)),
13
15
  // TODO(burdon): Document why threads is included here?
14
- threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),
15
- }).annotations({
16
- // TODO(burdon): Move annotation to property.
17
- [LabelAnnotationId]: 'name',
18
- });
16
+ threads: Schema.optional(Schema.Array(Ref(Expando /* ThreadType */))),
17
+ }).pipe(LabelAnnotation.set(['name']));
19
18
 
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> {}
19
+ // TODO(burdon): Move out of react-ui-xxx.
20
+ export const TableType = TableSchema.pipe(
21
+ EchoObject({
22
+ typename: 'dxos.org/type/Table',
23
+ version: '0.1.0',
24
+ }),
25
+ );
26
+ export interface TableType extends Schema.Schema.Type<typeof TableType> {}
@@ -2,7 +2,10 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import type { BaseSchema, JsonSchemaType, SortDirectionType } from '@dxos/echo-schema';
5
+ import { type Schema } from 'effect';
6
+
7
+ import { getTypename, toJsonSchema } from '@dxos/echo-schema';
8
+ import type { JsonSchemaType, SortDirectionType } from '@dxos/echo-schema';
6
9
  import { live, makeRef } from '@dxos/live-object';
7
10
  import {
8
11
  createView,
@@ -27,7 +30,7 @@ export type TablePropertyDefinition = SchemaPropertyDefinition & Partial<Propert
27
30
  * @deprecated
28
31
  */
29
32
  // TODO(burdon): Remove variance.
30
- export const getBaseSchems = ({
33
+ export const getBaseSchema = ({
31
34
  typename,
32
35
  properties,
33
36
  jsonSchema,
@@ -36,13 +39,13 @@ export const getBaseSchems = ({
36
39
  typename?: string;
37
40
  properties?: TablePropertyDefinition[];
38
41
  jsonSchema?: JsonSchemaType;
39
- schema?: BaseSchema;
42
+ schema?: Schema.Schema.AnyNoContext;
40
43
  }): { typename: string; jsonSchema: JsonSchemaType } => {
41
44
  if (typename && properties) {
42
45
  const schema = getSchemaFromPropertyDefinitions(typename, properties);
43
46
  return { typename: schema.typename, jsonSchema: schema.jsonSchema };
44
47
  } else if (schema) {
45
- return { typename: schema.typename, jsonSchema: schema.jsonSchema };
48
+ return { typename: getTypename(schema)!, jsonSchema: toJsonSchema(schema) };
46
49
  } else if (typename && jsonSchema) {
47
50
  return { typename, jsonSchema };
48
51
  } else {
package/src/util/index.ts CHANGED
@@ -7,3 +7,4 @@ export * from './signals';
7
7
  export * from './table';
8
8
  export * from './table-buttons';
9
9
  export * from './table-controls';
10
+ export * from './schema';
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Schema } from 'effect';
6
+ import { isTypeLiteral, TypeLiteral } from 'effect/SchemaAST';
7
+
8
+ /**
9
+ * Creates a narrowed schema from an original schema that only includes
10
+ * the specified paths. This allows form components to only display
11
+ * and edit/validate specific fields rather than the entire object.
12
+ *
13
+ * @param schema The original schema to narrow
14
+ * @param paths Array of field paths to extract
15
+ * @returns A narrowed Schema instance containing only the properties at the specified paths
16
+ */
17
+ export const narrowSchema = <S extends Schema.Schema.AnyNoContext>(
18
+ schema: S,
19
+ paths: string[],
20
+ ): Schema.Schema<unknown, unknown> | undefined => {
21
+ const ast = (schema as any)?.ast;
22
+
23
+ if (isTypeLiteral(ast)) {
24
+ // Filter property signatures that match any of the provided paths
25
+ const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
26
+
27
+ // If we found at least one matching property
28
+ if (propertySignatures.length > 0) {
29
+ // Create a new TypeLiteral with only the matching properties
30
+ const narrowType = new TypeLiteral(propertySignatures, []);
31
+ return Schema.make(narrowType);
32
+ }
33
+ }
34
+
35
+ return undefined;
36
+ };
@@ -38,7 +38,7 @@ const createButton = ({
38
38
  .join(' ');
39
39
 
40
40
  const positionClass = type === 'primary' ? 'inline-end-2' : 'inline-end-9';
41
- return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? 'disabled' : ''}><svg><use href="/icons.svg#${icon}"/></svg></button>`;
41
+ return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? 'disabled' : ''}><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
42
42
  };
43
43
 
44
44
  const addColumnButton = {
package/src/util/table.ts CHANGED
@@ -2,19 +2,20 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
6
+
5
7
  import {
6
- AST,
7
8
  type EchoSchema,
8
9
  Format,
9
10
  FormatEnum,
10
11
  type JsonPath,
11
12
  type JsonProp,
12
- S,
13
+ Ref,
13
14
  TypedObject,
14
15
  TypeEnum,
15
16
  } from '@dxos/echo-schema';
16
17
  import { type Client, PublicKey } from '@dxos/react-client';
17
- import { live, makeRef, type Space } from '@dxos/react-client/echo';
18
+ import { live, type Space } from '@dxos/react-client/echo';
18
19
  import { createFieldId, createView, getSchemaProperties, ViewProjection, type ViewType } from '@dxos/schema';
19
20
 
20
21
  import { type TableType } from '../types';
@@ -34,7 +35,7 @@ export const initializeTable = async ({
34
35
  table,
35
36
  typename,
36
37
  initialRow = true,
37
- }: InitialiseTableProps): Promise<S.Schema.AnyNoContext> => {
38
+ }: InitialiseTableProps): Promise<Schema.Schema.AnyNoContext> => {
38
39
  if (typename) {
39
40
  const schema = await space.db.graph.getSchemaByTypename(typename, space.db);
40
41
  if (!schema) {
@@ -43,7 +44,7 @@ export const initializeTable = async ({
43
44
 
44
45
  const fields = getSchemaProperties(schema.ast).map((prop) => prop.name);
45
46
 
46
- table.view = makeRef(
47
+ table.view = Ref.make(
47
48
  createView({
48
49
  // TODO(ZaymonFC): Don't hardcode name?
49
50
  name: 'View',
@@ -58,7 +59,7 @@ export const initializeTable = async ({
58
59
  const [schema] = await space.db.schemaRegistry.register([ContactSchema]);
59
60
  const fields = ContactFields;
60
61
 
61
- table.view = makeRef(
62
+ table.view = Ref.make(
62
63
  createView({
63
64
  name: 'View',
64
65
  typename: schema.typename,
@@ -82,10 +83,10 @@ const ContactSchema = TypedObject({
82
83
  typename: `example.com/type/${PublicKey.random().truncate()}`,
83
84
  version: '0.1.0',
84
85
  })({
85
- name: S.optional(S.String).annotations({ [AST.TitleAnnotationId]: 'Name' }),
86
- active: S.optional(S.Boolean),
87
- email: S.optional(Format.Email),
88
- salary: S.optional(Format.Currency()).annotations({ [AST.TitleAnnotationId]: 'Salary' }),
86
+ name: Schema.optional(Schema.String).annotations({ title: 'Name' }),
87
+ active: Schema.optional(Schema.Boolean),
88
+ email: Schema.optional(Format.Email),
89
+ salary: Schema.optional(Format.Currency()).annotations({ title: 'Salary' }),
89
90
  });
90
91
 
91
92
  const ContactFields = ['name', 'email', 'salary', 'active'];
@@ -1,26 +0,0 @@
1
- // packages/ui/react-ui-table/src/types/table.ts
2
- import { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from "@dxos/echo-schema";
3
- import { ViewType } from "@dxos/schema";
4
- var TableSchema = S.Struct({
5
- id: ObjectId,
6
- name: S.optional(S.String),
7
- view: S.optional(Ref(ViewType)),
8
- // TODO(burdon): Document why threads is included here?
9
- threads: S.optional(S.Array(Ref(
10
- Expando
11
- /* ThreadType */
12
- )))
13
- }).annotations({
14
- // TODO(burdon): Move annotation to property.
15
- [LabelAnnotationId]: "name"
16
- });
17
- var TableType = TableSchema.pipe(EchoObject({
18
- typename: "dxos.org/type/Table",
19
- version: "0.1.0"
20
- }));
21
-
22
- export {
23
- TableSchema,
24
- TableType
25
- };
26
- //# sourceMappingURL=chunk-YWNRUF4J.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = S.Struct({\n id: ObjectId,\n name: S.optional(S.String),\n view: S.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\nexport const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));\nexport interface TableType extends S.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";AAIA,SAASA,YAAYC,SAASC,mBAAmBC,UAAUC,KAAKC,SAAS;AAEzE,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,EAAEC,OAAO;EAClCC,IAAIC;EACJC,MAAMJ,EAAEK,SAASL,EAAEM,MAAM;EACzBC,MAAMP,EAAEK,SAASG,IAAIC,QAAAA,CAAAA;;EAErBC,SAASV,EAAEK,SAASL,EAAEW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AACxD,CAAA,EAAGC,YAAY;;EAEb,CAACC,iBAAAA,GAAoB;AACvB,CAAA;AAEO,IAAMC,YAAYhB,YAAYiB,KAAKC,WAAW;EAAEC,UAAU;EAAuBC,SAAS;AAAQ,CAAA,CAAA;",
6
- "names": ["EchoObject", "Expando", "LabelAnnotationId", "ObjectId", "Ref", "S", "ViewType", "TableSchema", "S", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "annotations", "LabelAnnotationId", "TableType", "pipe", "EchoObject", "typename", "version"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = S.Struct({\n id: ObjectId,\n name: S.optional(S.String),\n view: S.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\nexport const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));\nexport interface TableType extends S.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAIA,yBAAyE;AAEzE,oBAAyB;AAElB,IAAMA,cAAcC,qBAAEC,OAAO;EAClCC,IAAIC;EACJC,MAAMJ,qBAAEK,SAASL,qBAAEM,MAAM;EACzBC,MAAMP,qBAAEK,aAASG,wBAAIC,sBAAAA,CAAAA;;EAErBC,SAASV,qBAAEK,SAASL,qBAAEW,UAAMH;IAAII;;EAAsB,CAAA,CAAA;AACxD,CAAA,EAAGC,YAAY;;EAEb,CAACC,oCAAAA,GAAoB;AACvB,CAAA;AAEO,IAAMC,YAAYhB,YAAYiB,SAAKC,+BAAW;EAAEC,UAAU;EAAuBC,SAAS;AAAQ,CAAA,CAAA;",
6
- "names": ["TableSchema", "S", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "annotations", "LabelAnnotationId", "TableType", "pipe", "EchoObject", "typename", "version"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/table.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { EchoObject, Expando, LabelAnnotationId, ObjectId, Ref, S } from '@dxos/echo-schema';\n// import { ThreadType } from '@dxos/plugin-space/types';\nimport { ViewType } from '@dxos/schema';\n\nexport const TableSchema = S.Struct({\n id: ObjectId,\n name: S.optional(S.String),\n view: S.optional(Ref(ViewType)),\n // TODO(burdon): Document why threads is included here?\n threads: S.optional(S.Array(Ref(Expando /* ThreadType */))),\n}).annotations({\n // TODO(burdon): Move annotation to property.\n [LabelAnnotationId]: 'name',\n});\n\nexport const TableType = TableSchema.pipe(EchoObject({ typename: 'dxos.org/type/Table', version: '0.1.0' }));\nexport interface TableType extends S.Schema.Type<typeof TableType> {}\n"],
5
- "mappings": ";;;AAIA,SAASA,YAAYC,SAASC,mBAAmBC,UAAUC,KAAKC,SAAS;AAEzE,SAASC,gBAAgB;AAElB,IAAMC,cAAcC,EAAEC,OAAO;EAClCC,IAAIC;EACJC,MAAMJ,EAAEK,SAASL,EAAEM,MAAM;EACzBC,MAAMP,EAAEK,SAASG,IAAIC,QAAAA,CAAAA;;EAErBC,SAASV,EAAEK,SAASL,EAAEW,MAAMH;IAAII;;EAAsB,CAAA,CAAA;AACxD,CAAA,EAAGC,YAAY;;EAEb,CAACC,iBAAAA,GAAoB;AACvB,CAAA;AAEO,IAAMC,YAAYhB,YAAYiB,KAAKC,WAAW;EAAEC,UAAU;EAAuBC,SAAS;AAAQ,CAAA,CAAA;",
6
- "names": ["EchoObject", "Expando", "LabelAnnotationId", "ObjectId", "Ref", "S", "ViewType", "TableSchema", "S", "Struct", "id", "ObjectId", "name", "optional", "String", "view", "Ref", "ViewType", "threads", "Array", "Expando", "annotations", "LabelAnnotationId", "TableType", "pipe", "EchoObject", "typename", "version"]
7
- }