@dxos/react-ui-table 0.8.3 → 0.8.4-main.c1de068

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 (125) hide show
  1. package/dist/lib/browser/chunk-5XLSHLOG.mjs +1751 -0
  2. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-L2LSB6KV.mjs +18 -0
  4. package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +240 -1639
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +121 -0
  9. package/dist/lib/browser/testing/index.mjs.map +7 -0
  10. package/dist/lib/browser/types/index.mjs +3 -5
  11. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +20 -0
  12. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs +1752 -0
  14. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +240 -1639
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +122 -0
  19. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  20. package/dist/lib/node-esm/types/index.mjs +3 -5
  21. package/dist/types/src/components/Table/ColumnSettings.d.ts +3 -1
  22. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/DynamicTable.d.ts +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  26. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Table.stories.d.ts +1 -1
  30. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/relations.stories.d.ts +1 -1
  32. package/dist/types/src/components/Table/relations.stories.d.ts.map +1 -1
  33. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +2 -1
  34. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  35. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +2 -1
  36. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  37. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -2
  38. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  39. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +1 -1
  40. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  41. package/dist/types/src/components/testing.d.ts +3 -40
  42. package/dist/types/src/components/testing.d.ts.map +1 -1
  43. package/dist/types/src/hooks/index.d.ts +1 -0
  44. package/dist/types/src/hooks/index.d.ts.map +1 -1
  45. package/dist/types/src/hooks/useAddRow.d.ts +13 -0
  46. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -0
  47. package/dist/types/src/hooks/useTableModel.d.ts +7 -6
  48. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  49. package/dist/types/src/index.d.ts +1 -2
  50. package/dist/types/src/index.d.ts.map +1 -1
  51. package/dist/types/src/model/selection-model.d.ts +2 -1
  52. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  53. package/dist/types/src/model/table-model.d.ts +56 -20
  54. package/dist/types/src/model/table-model.d.ts.map +1 -1
  55. package/dist/types/src/model/table-presentation.d.ts +8 -0
  56. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  57. package/dist/types/src/model/table-sorting.d.ts +2 -2
  58. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  59. package/dist/types/src/playwright/playwright.config.d.ts +3 -0
  60. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -0
  61. package/dist/types/src/testing/index.d.ts +2 -0
  62. package/dist/types/src/testing/index.d.ts.map +1 -0
  63. package/dist/types/src/testing/useTestTableModel.d.ts +41 -0
  64. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -0
  65. package/dist/types/src/translations.d.ts +3 -4
  66. package/dist/types/src/translations.d.ts.map +1 -1
  67. package/dist/types/src/types/index.d.ts +1 -1
  68. package/dist/types/src/types/index.d.ts.map +1 -1
  69. package/dist/types/src/types/schema.d.ts +8 -0
  70. package/dist/types/src/types/schema.d.ts.map +1 -0
  71. package/dist/types/src/util/dynamic-table.d.ts +3 -4
  72. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  73. package/dist/types/src/util/table-buttons.d.ts +15 -1
  74. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  75. package/dist/types/src/util/table.d.ts +8 -11
  76. package/dist/types/src/util/table.d.ts.map +1 -1
  77. package/dist/types/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +48 -40
  79. package/src/components/Table/ColumnSettings.tsx +14 -10
  80. package/src/components/Table/CreateRefPanel.tsx +5 -3
  81. package/src/components/Table/DynamicTable.stories.tsx +2 -2
  82. package/src/components/Table/DynamicTable.tsx +13 -7
  83. package/src/components/Table/Table.stories.tsx +104 -148
  84. package/src/components/Table/Table.tsx +50 -32
  85. package/src/components/Table/relations.stories.tsx +27 -35
  86. package/src/components/TableCellEditor/CellValidationMessage.tsx +6 -1
  87. package/src/components/TableCellEditor/FormCellEditor.tsx +30 -21
  88. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +24 -28
  89. package/src/components/TableCellEditor/TableCellEditor.tsx +79 -21
  90. package/src/components/testing.ts +7 -24
  91. package/src/hooks/index.ts +1 -0
  92. package/src/hooks/useAddRow.ts +36 -0
  93. package/src/hooks/useTableModel.ts +20 -16
  94. package/src/index.ts +1 -2
  95. package/src/model/selection-model.ts +4 -2
  96. package/src/model/table-model.test.ts +7 -8
  97. package/src/model/table-model.ts +267 -78
  98. package/src/model/table-presentation.test.ts +6 -7
  99. package/src/model/table-presentation.ts +215 -132
  100. package/src/model/table-sorting.ts +9 -9
  101. package/src/playwright/playwright.config.ts +17 -0
  102. package/src/playwright/smoke.spec.ts +21 -20
  103. package/src/testing/index.ts +5 -0
  104. package/src/testing/useTestTableModel.ts +122 -0
  105. package/src/translations.ts +5 -3
  106. package/src/types/index.ts +2 -2
  107. package/src/types/schema.ts +16 -0
  108. package/src/util/dynamic-table.ts +19 -17
  109. package/src/util/table-buttons.ts +24 -1
  110. package/src/util/table.ts +33 -111
  111. package/dist/lib/browser/chunk-TL7CKQQV.mjs +0 -27
  112. package/dist/lib/browser/chunk-TL7CKQQV.mjs.map +0 -7
  113. package/dist/lib/node/chunk-O2VPBNS5.cjs +0 -50
  114. package/dist/lib/node/chunk-O2VPBNS5.cjs.map +0 -7
  115. package/dist/lib/node/index.cjs +0 -2739
  116. package/dist/lib/node/index.cjs.map +0 -7
  117. package/dist/lib/node/meta.json +0 -1
  118. package/dist/lib/node/types/index.cjs +0 -31
  119. package/dist/lib/node/types/index.cjs.map +0 -7
  120. package/dist/lib/node-esm/chunk-GBT6GD4G.mjs +0 -29
  121. package/dist/lib/node-esm/chunk-GBT6GD4G.mjs.map +0 -7
  122. package/dist/types/src/types/table.d.ts +0 -56
  123. package/dist/types/src/types/table.d.ts.map +0 -1
  124. package/src/playwright/playwright.config.cts +0 -18
  125. package/src/types/table.ts +0 -27
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-table",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-main.c1de068",
4
4
  "description": "A table component.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -19,6 +19,11 @@
19
19
  "browser": "./dist/lib/browser/index.mjs",
20
20
  "node": "./dist/lib/node-esm/index.mjs"
21
21
  },
22
+ "./testing": {
23
+ "types": "./dist/types/src/testing/index.d.ts",
24
+ "browser": "./dist/lib/browser/testing/index.mjs",
25
+ "node": "./dist/lib/node-esm/testing/index.mjs"
26
+ },
22
27
  "./types": {
23
28
  "types": "./dist/types/src/types/index.d.ts",
24
29
  "browser": "./dist/lib/browser/types/index.mjs",
@@ -31,6 +36,9 @@
31
36
  "deprecated": [
32
37
  "dist/types/src/deprecated/index.d.ts"
33
38
  ],
39
+ "testing": [
40
+ "dist/types/src/testing/index.d.ts"
41
+ ],
34
42
  "types": [
35
43
  "dist/types/src/types/index.d.ts"
36
44
  ]
@@ -53,60 +61,60 @@
53
61
  "@radix-ui/react-use-controllable-state": "1.1.0",
54
62
  "date-fns": "^3.3.1",
55
63
  "lodash.orderby": "^4.6.0",
56
- "@dxos/context": "0.8.3",
57
- "@dxos/debug": "0.8.3",
58
- "@dxos/echo": "0.8.3",
59
- "@dxos/invariant": "0.8.3",
60
- "@dxos/keys": "0.8.3",
61
- "@dxos/effect": "0.8.3",
62
- "@dxos/lit-grid": "0.8.3",
63
- "@dxos/live-object": "0.8.3",
64
- "@dxos/echo-schema": "0.8.3",
65
- "@dxos/log": "0.8.3",
66
- "@dxos/plugin-search": "0.8.3",
67
- "@dxos/react-client": "0.8.3",
68
- "@dxos/react-ui-attention": "0.8.3",
69
- "@dxos/plugin-space": "0.8.3",
70
- "@dxos/react-ui-editor": "0.8.3",
71
- "@dxos/react-ui-form": "0.8.3",
72
- "@dxos/react-ui-grid": "0.8.3",
73
- "@dxos/react-ui-menu": "0.8.3",
74
- "@dxos/react-ui-searchlist": "0.8.3",
75
- "@dxos/react-ui-syntax-highlighter": "0.8.3",
76
- "@dxos/react-ui-tag-picker": "0.8.3",
77
- "@dxos/react-ui-stack": "0.8.3",
78
- "@dxos/react-ui-types": "0.8.3",
79
- "@dxos/util": "0.8.3",
80
- "@dxos/schema": "0.8.3"
64
+ "@dxos/context": "0.8.4-main.c1de068",
65
+ "@dxos/debug": "0.8.4-main.c1de068",
66
+ "@dxos/echo": "0.8.4-main.c1de068",
67
+ "@dxos/effect": "0.8.4-main.c1de068",
68
+ "@dxos/echo-schema": "0.8.4-main.c1de068",
69
+ "@dxos/echo-db": "0.8.4-main.c1de068",
70
+ "@dxos/invariant": "0.8.4-main.c1de068",
71
+ "@dxos/lit-grid": "0.8.4-main.c1de068",
72
+ "@dxos/keys": "0.8.4-main.c1de068",
73
+ "@dxos/live-object": "0.8.4-main.c1de068",
74
+ "@dxos/plugin-search": "0.8.4-main.c1de068",
75
+ "@dxos/log": "0.8.4-main.c1de068",
76
+ "@dxos/react-client": "0.8.4-main.c1de068",
77
+ "@dxos/react-ui-attention": "0.8.4-main.c1de068",
78
+ "@dxos/random": "0.8.4-main.c1de068",
79
+ "@dxos/react-ui-form": "0.8.4-main.c1de068",
80
+ "@dxos/react-ui-grid": "0.8.4-main.c1de068",
81
+ "@dxos/react-ui-editor": "0.8.4-main.c1de068",
82
+ "@dxos/react-ui-menu": "0.8.4-main.c1de068",
83
+ "@dxos/react-ui-searchlist": "0.8.4-main.c1de068",
84
+ "@dxos/react-ui-stack": "0.8.4-main.c1de068",
85
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.c1de068",
86
+ "@dxos/react-ui-tag-picker": "0.8.4-main.c1de068",
87
+ "@dxos/react-ui-types": "0.8.4-main.c1de068",
88
+ "@dxos/schema": "0.8.4-main.c1de068",
89
+ "@dxos/util": "0.8.4-main.c1de068"
81
90
  },
82
91
  "devDependencies": {
83
- "@effect-rx/rx-react": "^0.34.1",
84
- "@effect/platform": "0.80.12",
85
- "@phosphor-icons/react": "^2.1.5",
92
+ "@effect-rx/rx-react": "0.38.0",
93
+ "@effect/platform": "0.89.0",
86
94
  "@types/lodash.orderby": "^4.6.9",
87
95
  "@types/react": "~18.2.0",
88
96
  "@types/react-dom": "~18.2.0",
89
- "effect": "3.14.21",
97
+ "effect": "3.17.0",
90
98
  "fast-check": "^3.19.0",
91
99
  "react": "~18.2.0",
92
100
  "react-dom": "~18.2.0",
93
101
  "vite": "5.4.7",
94
- "@dxos/random": "0.8.3",
95
- "@dxos/echo-signals": "0.8.3",
96
- "@dxos/storybook-utils": "0.8.3",
97
- "@dxos/react-ui": "0.8.3",
98
- "@dxos/react-ui-theme": "0.8.3",
99
- "@dxos/test-utils": "0.8.3"
102
+ "@dxos/echo-signals": "0.8.4-main.c1de068",
103
+ "@dxos/plugin-search": "0.8.4-main.c1de068",
104
+ "@dxos/random": "0.8.4-main.c1de068",
105
+ "@dxos/react-ui": "0.8.4-main.c1de068",
106
+ "@dxos/react-ui-theme": "0.8.4-main.c1de068",
107
+ "@dxos/storybook-utils": "0.8.4-main.c1de068",
108
+ "@dxos/test-utils": "0.8.4-main.c1de068"
100
109
  },
101
110
  "peerDependencies": {
102
111
  "@effect-rx/rx-react": "^0.34.1",
103
- "@effect/platform": "0.80.12",
104
- "@phosphor-icons/react": "^2.1.5",
112
+ "@effect/platform": "^0.80.12",
105
113
  "effect": "^3.13.3",
106
114
  "react": "~18.2.0",
107
115
  "react-dom": "~18.2.0",
108
- "@dxos/react-ui": "0.8.3",
109
- "@dxos/react-ui-theme": "0.8.3"
116
+ "@dxos/react-ui": "0.8.4-main.c1de068",
117
+ "@dxos/react-ui-theme": "0.8.4-main.c1de068"
110
118
  },
111
119
  "publishConfig": {
112
120
  "access": "public"
@@ -4,20 +4,25 @@
4
4
 
5
5
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
6
6
 
7
+ // TODO(burdon): Remove dependency on echo-db.
8
+ import { type SchemaRegistry } from '@dxos/echo-db';
7
9
  import { Popover } from '@dxos/react-ui';
8
10
  import { FieldEditor } from '@dxos/react-ui-form';
9
11
  import { type FieldType } from '@dxos/schema';
10
12
 
11
13
  import { type TableModel, type ModalController } from '../../model';
12
14
 
13
- type ColumnSettingsProps = { model?: TableModel; modals: ModalController; onNewColumn: () => void };
15
+ type ColumnSettingsProps = {
16
+ registry?: SchemaRegistry;
17
+ model?: TableModel;
18
+ modals: ModalController;
19
+ onNewColumn: () => void;
20
+ };
14
21
 
15
- export const ColumnSettings = ({ model, modals, onNewColumn }: ColumnSettingsProps) => {
22
+ export const ColumnSettings = ({ registry, model, modals, onNewColumn }: ColumnSettingsProps) => {
16
23
  const [newField, setNewField] = useState<FieldType>();
17
24
  const state = modals.state.value;
18
25
 
19
- const space = model?.space;
20
-
21
26
  useEffect(() => {
22
27
  if (state?.type === 'columnSettings' && state.mode.type === 'create' && model?.projection) {
23
28
  setNewField(model.projection.createFieldProjection());
@@ -33,11 +38,11 @@ export const ColumnSettings = ({ model, modals, onNewColumn }: ColumnSettingsPro
33
38
  if (state?.type === 'columnSettings') {
34
39
  const { mode } = state;
35
40
  if (mode.type === 'edit') {
36
- return model?.view?.fields.find((f) => f.id === mode.fieldId);
41
+ return model?.projection?.fields.find((f) => f.id === mode.fieldId);
37
42
  }
38
43
  }
39
44
  return undefined;
40
- }, [model?.view?.fields, state]);
45
+ }, [model?.projection?.fields, state]);
41
46
 
42
47
  const field = existingField ?? newField;
43
48
 
@@ -47,11 +52,11 @@ export const ColumnSettings = ({ model, modals, onNewColumn }: ColumnSettingsPro
47
52
 
48
53
  const handleCancel = useCallback(() => {
49
54
  if (state?.type === 'columnSettings' && state.mode.type === 'create' && newField) {
50
- model?.projection?.deleteFieldProjection(newField.id);
55
+ model?.projection.deleteFieldProjection(newField.id);
51
56
  }
52
57
  }, [model?.projection, state, newField]);
53
58
 
54
- if (!model?.view || !model.projection || !field) {
59
+ if (!model?.projection || !field) {
55
60
  return null;
56
61
  }
57
62
 
@@ -62,10 +67,9 @@ export const ColumnSettings = ({ model, modals, onNewColumn }: ColumnSettingsPro
62
67
  <Popover.Content classNames='md:is-64'>
63
68
  <Popover.Viewport>
64
69
  <FieldEditor
65
- view={model.view!}
66
70
  projection={model.projection}
67
71
  field={field}
68
- registry={space?.db.schemaRegistry}
72
+ registry={registry}
69
73
  onSave={handleSave}
70
74
  onCancel={handleCancel}
71
75
  />
@@ -5,7 +5,9 @@
5
5
  import { Schema } from 'effect';
6
6
  import React, { useCallback, useMemo } from 'react';
7
7
 
8
- import { live } from '@dxos/react-client/echo';
8
+ import { live } from '@dxos/live-object';
9
+ // TODO(wittjosiah): Remove dependency on react-client.
10
+ import { getSpace } from '@dxos/react-client/echo';
9
11
  import { Popover } from '@dxos/react-ui';
10
12
  import { Form } from '@dxos/react-ui-form';
11
13
  import { type GridScopedProps, useGridContext } from '@dxos/react-ui-grid';
@@ -17,7 +19,7 @@ export type CreateRefPanelProps = { model?: TableModel; modals: ModalController
17
19
  // TODO(burdon): Factor out Space dependency (to plugin?)
18
20
  export const CreateRefPanel = ({ model, modals, __gridScope }: GridScopedProps<CreateRefPanelProps>) => {
19
21
  const { id: gridId } = useGridContext('TableCellEditor', __gridScope);
20
- const space = model?.space;
22
+ const space = model && getSpace(model?.view);
21
23
  const state = modals.state.value;
22
24
 
23
25
  const schema = useMemo<Schema.Schema<any> | undefined>(() => {
@@ -54,7 +56,7 @@ export const CreateRefPanel = ({ model, modals, __gridScope }: GridScopedProps<C
54
56
  }
55
57
  }, [modals]);
56
58
 
57
- if (!model?.view || !model.projection) {
59
+ if (!model?.projection) {
58
60
  return null;
59
61
  }
60
62
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react';
7
+ import { type StoryObj, type Meta } from '@storybook/react-vite';
8
8
  import React, { useMemo, useState } from 'react';
9
9
 
10
10
  import { Obj } from '@dxos/echo';
@@ -19,7 +19,7 @@ import { withLayout, withTheme } from '@dxos/storybook-utils';
19
19
 
20
20
  import { DynamicTable } from './DynamicTable';
21
21
  import { type TableFeatures } from '../../model';
22
- import translations from '../../translations';
22
+ import { translations } from '../../translations';
23
23
 
24
24
  faker.seed(0);
25
25
 
@@ -36,18 +36,23 @@ export const DynamicTable = ({
36
36
  name = 'example.com/dynamic-table', // Rmove default or make random; this will lead to type collisions.
37
37
  rows,
38
38
  properties,
39
- jsonSchema,
39
+ jsonSchema: _jsonSchema,
40
40
  schema,
41
41
  rowActions,
42
42
  onRowClick,
43
43
  onRowAction,
44
44
  ...props
45
45
  }: DynamicTableProps) => {
46
- const { table, projection } = useMemo(() => {
47
- // TODO(burdon): Remove variance from the props (should be normalized externally; possibly via hooks).
48
- const props = getBaseSchema({ typename: name, properties, jsonSchema, schema });
49
- return makeDynamicTable({ ...props, properties });
50
- }, [name, properties, schema, jsonSchema]);
46
+ // TODO(burdon): Remove variance from the props (should be normalized externally; possibly via hooks).
47
+ const { typename, jsonSchema } = useMemo(
48
+ () => getBaseSchema({ typename: name, properties, jsonSchema: _jsonSchema, schema }),
49
+ [name, properties, _jsonSchema, schema],
50
+ );
51
+
52
+ const { projection, view } = useMemo(
53
+ () => makeDynamicTable({ typename, jsonSchema, properties }),
54
+ [typename, jsonSchema, properties],
55
+ );
51
56
 
52
57
  const tableRef = useRef<TableController>(null);
53
58
  const handleCellUpdate = useCallback((cell: any) => {
@@ -68,8 +73,9 @@ export const DynamicTable = ({
68
73
  );
69
74
 
70
75
  const model = useTableModel({
71
- table,
72
76
  rows,
77
+ view,
78
+ schema: jsonSchema,
73
79
  projection,
74
80
  features,
75
81
  rowActions,
@@ -4,150 +4,86 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj, type Meta } from '@storybook/react';
7
+ import { type StoryObj, type Meta } from '@storybook/react-vite';
8
8
  import { Schema } from 'effect';
9
- import React, { useCallback, useMemo, useRef } from 'react';
9
+ import React, { useCallback } from 'react';
10
10
 
11
11
  import { Obj, Type } from '@dxos/echo';
12
- import { FormatEnum, isMutable, toJsonSchema, EchoObject, GeneratorAnnotation } from '@dxos/echo-schema';
12
+ import {
13
+ FormatEnum,
14
+ EchoObject,
15
+ GeneratorAnnotation,
16
+ FormatAnnotation,
17
+ PropertyMetaAnnotationId,
18
+ } from '@dxos/echo-schema';
13
19
  import { invariant } from '@dxos/invariant';
14
- import { useGlobalFilteredObjects } from '@dxos/plugin-search';
15
20
  import { faker } from '@dxos/random';
16
- import { useClient } from '@dxos/react-client';
17
- import { Filter, useQuery, useSchema, live } from '@dxos/react-client/echo';
18
- import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
21
+ import { PublicKey } from '@dxos/react-client';
22
+ import { live, type Space } from '@dxos/react-client/echo';
23
+ import { withClientProvider } from '@dxos/react-client/testing';
19
24
  import { ViewEditor } from '@dxos/react-ui-form';
20
25
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
21
- import { getSchemaFromPropertyDefinitions, ViewProjection, ViewType } from '@dxos/schema';
26
+ import { getSchemaFromPropertyDefinitions, DataType } from '@dxos/schema';
22
27
  import { Testing, createObjectFactory } from '@dxos/schema/testing';
23
28
  import { withLayout, withTheme } from '@dxos/storybook-utils';
24
29
 
25
- import { Table, type TableController } from './Table';
26
- import { useTableModel } from '../../hooks';
27
- import { TablePresentation } from '../../model';
28
- import translations from '../../translations';
29
- import { TableType } from '../../types';
30
- import { initializeTable } from '../../util';
30
+ import { Table } from './Table';
31
+ import { useTestTableModel } from '../../testing';
32
+ import { translations } from '../../translations';
33
+ import { TableView } from '../../types';
34
+ import { createTable } from '../../util';
31
35
  import { TableToolbar } from '../TableToolbar';
32
36
 
33
- faker.seed(0); // NOTE(ZaymonFC): Required for smoke tests.
34
-
35
- /**
36
- * Custom hook to create and manage a test table model for storybook demonstrations.
37
- * Provides table data, schema, and handlers for table operations.
38
- */
39
- const useTestTableModel = () => {
40
- const client = useClient();
41
- const { space } = useClientProvider();
42
-
43
- const filter = useMemo(() => Filter.type(TableType), []);
44
- const tables = useQuery(space, filter);
45
- const table = useMemo(() => tables.at(0), [tables]);
46
- const schema = useSchema(client, space, table?.view?.target?.query.typename);
47
-
48
- const projection = useMemo(() => {
49
- if (schema && table?.view?.target) {
50
- return new ViewProjection(toJsonSchema(schema), table.view.target);
51
- }
52
- }, [schema, table?.view?.target]);
53
-
54
- const features = useMemo(
55
- () => ({
56
- selection: { enabled: true, mode: 'multiple' as const },
57
- dataEditable: true,
58
- schemaEditable: schema && isMutable(schema),
59
- }),
60
- [schema],
61
- );
62
-
63
- const objects = useQuery(space, schema ? Filter.type(schema) : Filter.nothing());
64
- const filteredObjects = useGlobalFilteredObjects(objects);
65
-
66
- const tableRef = useRef<TableController>(null);
67
- const handleCellUpdate = useCallback((cell: any) => {
68
- tableRef.current?.update?.(cell);
69
- }, []);
70
-
71
- const handleRowOrderChange = useCallback(() => {
72
- tableRef.current?.update?.();
73
- }, []);
74
-
75
- const handleInsertRow = useCallback(() => {
76
- if (space && schema) {
77
- space.db.add(live(schema, {}));
78
- }
79
- }, [space, schema]);
80
-
81
- const handleDeleteRows = useCallback(
82
- (_: number, objects: any[]) => {
83
- for (const object of objects) {
84
- space?.db.remove(object);
85
- }
86
- },
87
- [space],
88
- );
89
-
90
- const handleDeleteColumn = useCallback(
91
- (fieldId: string) => {
92
- if (projection) {
93
- projection.deleteFieldProjection(fieldId);
94
- }
95
- },
96
- [projection],
97
- );
98
-
99
- const model = useTableModel({
100
- table,
101
- projection,
102
- features,
103
- rows: filteredObjects,
104
- onInsertRow: handleInsertRow,
105
- onDeleteRows: handleDeleteRows,
106
- onDeleteColumn: handleDeleteColumn,
107
- onCellUpdate: handleCellUpdate,
108
- onRowOrderChange: handleRowOrderChange,
109
- });
110
-
111
- const handleSaveView = useCallback(() => {
112
- model?.saveView();
113
- }, [model]);
114
-
115
- const presentation = useMemo(() => {
116
- if (model) {
117
- return new TablePresentation(model);
118
- }
119
- }, [model]);
120
-
121
- return {
122
- schema,
123
- table,
124
- tableRef,
125
- model,
126
- presentation,
127
- space,
128
- client,
129
- handleInsertRow,
130
- handleSaveView,
131
- handleDeleteRows,
132
- handleDeleteColumn,
133
- };
134
- };
135
-
136
- const StoryViewEditor = () => {
137
- const { table, space, schema, handleDeleteColumn } = useTestTableModel();
138
-
37
+ const TestSchema = Schema.Struct({
38
+ // TODO(wittjosiah): Should be title. Currently name to work with default label.
39
+ name: Schema.optional(Schema.String).annotations({ title: 'Title' }),
40
+ urgent: Schema.optional(Schema.Boolean).annotations({ title: 'Urgent' }),
41
+ status: Schema.optional(
42
+ Schema.Literal('todo', 'in-progress', 'done')
43
+ .pipe(FormatAnnotation.set(FormatEnum.SingleSelect))
44
+ .annotations({
45
+ title: 'Status',
46
+ [PropertyMetaAnnotationId]: {
47
+ singleSelect: {
48
+ options: [
49
+ { id: 'todo', title: 'Todo', color: 'indigo' },
50
+ { id: 'in-progress', title: 'In Progress', color: 'purple' },
51
+ { id: 'done', title: 'Done', color: 'amber' },
52
+ ],
53
+ },
54
+ },
55
+ }),
56
+ ),
57
+ description: Schema.optional(Schema.String).annotations({ title: 'Description' }),
58
+ parent: Schema.optional(Schema.suspend((): Type.Ref<TestSchema> => Type.Ref(TestSchema))).annotations({
59
+ title: 'Parent',
60
+ }),
61
+ }).pipe(Type.Obj({ typename: `example.com/type/${PublicKey.random().truncate()}`, version: '0.1.0' }));
62
+ interface TestSchema extends Schema.Schema.Type<typeof TestSchema> {}
63
+
64
+ const StoryViewEditor = ({
65
+ view,
66
+ schema,
67
+ space,
68
+ handleDeleteColumn,
69
+ }: {
70
+ view?: DataType.View;
71
+ schema?: Schema.Schema.AnyNoContext;
72
+ space?: Space;
73
+ handleDeleteColumn: (fieldId: string) => void;
74
+ }) => {
139
75
  const handleTypenameChanged = useCallback(
140
76
  (typename: string) => {
141
77
  invariant(schema);
142
78
  invariant(Type.isMutable(schema));
143
79
  schema.updateTypename(typename);
144
- invariant(table?.view?.target);
145
- table.view.target.query.typename = typename;
80
+ invariant(view);
81
+ view.query.typename = typename;
146
82
  },
147
- [schema, table?.view?.target],
83
+ [schema, view],
148
84
  );
149
85
 
150
- if (!table || !schema || !table.view?.target) {
86
+ if (!view || !schema) {
151
87
  return null;
152
88
  }
153
89
 
@@ -155,7 +91,7 @@ const StoryViewEditor = () => {
155
91
  <ViewEditor
156
92
  registry={space?.db.schemaRegistry}
157
93
  schema={schema}
158
- view={table.view.target!}
94
+ view={view}
159
95
  onTypenameChanged={handleTypenameChanged}
160
96
  onDelete={handleDeleteColumn}
161
97
  />
@@ -167,9 +103,20 @@ const StoryViewEditor = () => {
167
103
  //
168
104
 
169
105
  const DefaultStory = () => {
170
- const { schema, table, tableRef, model, presentation, client, handleInsertRow, handleSaveView } = useTestTableModel();
106
+ const {
107
+ space,
108
+ schema,
109
+ view,
110
+ tableRef,
111
+ model,
112
+ presentation,
113
+ client,
114
+ handleInsertRow,
115
+ handleSaveView,
116
+ handleDeleteColumn,
117
+ } = useTestTableModel();
171
118
 
172
- if (!schema || !table) {
119
+ if (!schema || !view) {
173
120
  return <div />;
174
121
  }
175
122
 
@@ -189,9 +136,9 @@ const DefaultStory = () => {
189
136
  </Table.Root>
190
137
  </div>
191
138
  <div className='flex flex-col h-full border-l border-separator overflow-y-auto'>
192
- <StoryViewEditor />
139
+ <StoryViewEditor view={view} schema={schema} space={space} handleDeleteColumn={handleDeleteColumn} />
193
140
  <SyntaxHighlighter language='json' className='w-full text-xs'>
194
- {JSON.stringify({ view: table.view?.target, schema }, null, 2)}
141
+ {JSON.stringify({ view, schema }, null, 2)}
195
142
  </SyntaxHighlighter>
196
143
  </div>
197
144
  </div>
@@ -209,26 +156,36 @@ type StoryProps = { rows?: number };
209
156
  const meta: Meta<StoryProps> = {
210
157
  title: 'ui/react-ui-table/Table',
211
158
  render: DefaultStory,
212
- parameters: { translations, controls: { disable: true } },
159
+ parameters: {
160
+ translations,
161
+ layout: 'fullscreen',
162
+ controls: {
163
+ disable: true,
164
+ },
165
+ },
213
166
  decorators: [
167
+ withTheme,
168
+ withLayout({ fullscreen: true }),
214
169
  withClientProvider({
215
- types: [TableType, ViewType],
170
+ types: [DataType.View, TableView],
216
171
  createIdentity: true,
217
172
  createSpace: true,
218
173
  onSpaceCreated: async ({ client, space }) => {
219
- const table = space.db.add(Obj.make(TableType, {}));
220
- const schema = await initializeTable({ client, space, table, initialRow: false });
174
+ const [schema] = await space.db.schemaRegistry.register([TestSchema]);
175
+ const { view } = await createTable({ client, space, typename: schema.typename });
176
+ space.db.add(view);
177
+
221
178
  Array.from({ length: 10 }).map(() => {
222
179
  return space.db.add(
223
- live(schema, {
224
- name: faker.person.fullName(),
180
+ Obj.make(schema, {
181
+ name: faker.lorem.sentence(),
182
+ status: faker.helpers.arrayElement(['todo', 'in-progress', 'done'] as const),
183
+ description: faker.lorem.paragraph(),
225
184
  }),
226
185
  );
227
186
  });
228
187
  },
229
188
  }),
230
- withLayout({ fullscreen: true }),
231
- withTheme,
232
189
  ],
233
190
  };
234
191
 
@@ -241,18 +198,17 @@ export const StaticSchema: StoryObj = {
241
198
  parameters: { translations },
242
199
  decorators: [
243
200
  withClientProvider({
244
- types: [TableType, ViewType, Testing.Contact, Testing.Organization],
201
+ types: [DataType.View, TableView, Testing.Contact, Testing.Organization],
245
202
  createIdentity: true,
246
203
  createSpace: true,
247
204
  onSpaceCreated: async ({ client, space }) => {
248
- const table = space.db.add(Obj.make(TableType, {}));
249
- await initializeTable({ client, space, table, typename: Testing.Organization.typename });
205
+ const { view } = await createTable({ client, space, typename: Testing.Contact.typename });
206
+ space.db.add(view);
250
207
 
251
208
  const factory = createObjectFactory(space.db, faker as any);
252
209
  await factory([
253
- // { type: Testing.Contact, count: 10 },
210
+ { type: Testing.Contact, count: 10 },
254
211
  // { type: Testing.Organization, count: 1 },
255
- { type: ContactWithArrayOfEmails, count: 10 },
256
212
  ]);
257
213
  },
258
214
  }),
@@ -283,12 +239,12 @@ export const ArrayOfObjects: StoryObj = {
283
239
  parameters: { translations },
284
240
  decorators: [
285
241
  withClientProvider({
286
- types: [TableType, ViewType, Testing.Contact, Testing.Organization, ContactWithArrayOfEmails],
242
+ types: [DataType.View, TableView, Testing.Contact, Testing.Organization, ContactWithArrayOfEmails],
287
243
  createIdentity: true,
288
244
  createSpace: true,
289
245
  onSpaceCreated: async ({ client, space }) => {
290
- const table = space.db.add(Obj.make(TableType, {}));
291
- await initializeTable({ client, space, table, typename: ContactWithArrayOfEmails.typename });
246
+ const { view } = await createTable({ client, space, typename: ContactWithArrayOfEmails.typename });
247
+ space.db.add(view);
292
248
 
293
249
  const factory = createObjectFactory(space.db, faker as any);
294
250
  await factory([
@@ -309,7 +265,7 @@ export const Tags: Meta<StoryProps> = {
309
265
  parameters: { translations },
310
266
  decorators: [
311
267
  withClientProvider({
312
- types: [TableType, ViewType],
268
+ types: [DataType.View, TableView],
313
269
  createIdentity: true,
314
270
  createSpace: true,
315
271
  onSpaceCreated: async ({ client, space }) => {
@@ -340,8 +296,8 @@ export const Tags: Meta<StoryProps> = {
340
296
  const [storedSchema] = await space.db.schemaRegistry.register([schema]);
341
297
 
342
298
  // Initialize table.
343
- const table = space.db.add(Obj.make(TableType, {}));
344
- await initializeTable({ client, space, table, initialRow: false, typename });
299
+ const { view } = await createTable({ client, space, typename });
300
+ space.db.add(view);
345
301
 
346
302
  // Populate.
347
303
  Array.from({ length: 10 }).map(() => {