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

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 (158) hide show
  1. package/dist/lib/browser/chunk-BF54SSNL.mjs +70 -0
  2. package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-PTHMYAAM.mjs +1751 -0
  4. package/dist/lib/browser/chunk-PTHMYAAM.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1188 -1139
  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 +31 -38
  9. package/dist/lib/browser/testing/index.mjs.map +3 -3
  10. package/dist/lib/browser/types/index.mjs +3 -3
  11. package/dist/lib/node-esm/chunk-GI72MQSG.mjs +1753 -0
  12. package/dist/lib/node-esm/chunk-GI72MQSG.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs +71 -0
  14. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +1188 -1139
  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 +31 -38
  19. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/types/index.mjs +3 -3
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +2 -3
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +3 -3
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
  26. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +37 -3
  28. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Relations.stories.d.ts +111 -0
  30. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  31. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  32. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/Table.d.ts +16 -12
  34. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  35. package/dist/types/src/components/Table/Table.stories.d.ts +108 -4
  36. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
  38. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  39. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +13 -9
  40. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  41. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +11 -18
  42. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  43. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +39 -4
  44. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
  46. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -1
  47. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +5 -5
  48. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  49. package/dist/types/src/components/testing.d.ts +23 -16
  50. package/dist/types/src/components/testing.d.ts.map +1 -1
  51. package/dist/types/src/hooks/index.d.ts +2 -1
  52. package/dist/types/src/hooks/index.d.ts.map +1 -1
  53. package/dist/types/src/hooks/useAddRow.d.ts +6 -6
  54. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  55. package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
  56. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
  57. package/dist/types/src/hooks/useTableModel.d.ts +10 -10
  58. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  59. package/dist/types/src/model/modal-controller.d.ts +5 -8
  60. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  61. package/dist/types/src/model/selection-model.d.ts +17 -8
  62. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  63. package/dist/types/src/model/table-model.d.ts +112 -30
  64. package/dist/types/src/model/table-model.d.ts.map +1 -1
  65. package/dist/types/src/model/table-presentation.d.ts +5 -2
  66. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  67. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  68. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  69. package/dist/types/src/testing/useTestTableModel.d.ts +18 -34
  70. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  71. package/dist/types/src/translations.d.ts +4 -4
  72. package/dist/types/src/translations.d.ts.map +1 -1
  73. package/dist/types/src/types/Table.d.ts +26 -0
  74. package/dist/types/src/types/Table.d.ts.map +1 -0
  75. package/dist/types/src/types/index.d.ts +1 -1
  76. package/dist/types/src/types/index.d.ts.map +1 -1
  77. package/dist/types/src/util/dynamic-table.d.ts +14 -12
  78. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  79. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  80. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  81. package/dist/types/src/util/index.d.ts +2 -1
  82. package/dist/types/src/util/index.d.ts.map +1 -1
  83. package/dist/types/src/util/query-ast.d.ts +7 -0
  84. package/dist/types/src/util/query-ast.d.ts.map +1 -0
  85. package/dist/types/src/util/schema.d.ts +1 -1
  86. package/dist/types/src/util/schema.d.ts.map +1 -1
  87. package/dist/types/src/util/sort.d.ts +12 -0
  88. package/dist/types/src/util/sort.d.ts.map +1 -0
  89. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  90. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  91. package/dist/types/tsconfig.tsbuildinfo +1 -1
  92. package/package.json +61 -56
  93. package/src/components/Table/ColumnActionsMenu.tsx +11 -7
  94. package/src/components/Table/ColumnSettings.tsx +9 -10
  95. package/src/components/Table/DynamicTable.stories.tsx +28 -24
  96. package/src/components/Table/DynamicTable.tsx +34 -28
  97. package/src/components/Table/Relations.stories.tsx +240 -0
  98. package/src/components/Table/RowActionsMenu.tsx +26 -17
  99. package/src/components/Table/Table.stories.tsx +148 -118
  100. package/src/components/Table/Table.tsx +351 -296
  101. package/src/components/TableCellEditor/CellValidationMessage.tsx +6 -6
  102. package/src/components/TableCellEditor/FormCellEditor.tsx +134 -40
  103. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +31 -66
  104. package/src/components/TableCellEditor/TableCellEditor.tsx +88 -238
  105. package/src/components/TableCellEditor/index.ts +1 -0
  106. package/src/components/TableToolbar/TableToolbar.tsx +54 -38
  107. package/src/components/testing.ts +39 -13
  108. package/src/hooks/index.ts +2 -1
  109. package/src/hooks/useAddRow.ts +14 -14
  110. package/src/hooks/useProjectionModel.ts +39 -0
  111. package/src/hooks/useTableModel.ts +36 -34
  112. package/src/model/modal-controller.ts +24 -41
  113. package/src/model/selection-model.ts +75 -43
  114. package/src/model/table-model.test.ts +92 -55
  115. package/src/model/table-model.ts +453 -175
  116. package/src/model/table-presentation.test.ts +70 -58
  117. package/src/model/table-presentation.ts +111 -64
  118. package/src/playwright/TableManager.ts +13 -6
  119. package/src/playwright/playwright.config.ts +1 -1
  120. package/src/playwright/smoke.spec.ts +171 -33
  121. package/src/testing/useTestTableModel.ts +46 -35
  122. package/src/translations.ts +3 -3
  123. package/src/types/Table.ts +79 -0
  124. package/src/types/index.ts +1 -1
  125. package/src/util/dynamic-table.test.ts +70 -0
  126. package/src/util/dynamic-table.ts +46 -33
  127. package/src/util/index.ts +2 -1
  128. package/src/util/query-ast.ts +22 -0
  129. package/src/util/schema.ts +4 -4
  130. package/src/util/sort.ts +90 -0
  131. package/src/util/table-buttons.ts +4 -3
  132. package/src/util/table-controls.ts +6 -3
  133. package/dist/lib/browser/chunk-5XLSHLOG.mjs +0 -1751
  134. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  135. package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
  136. package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +0 -7
  137. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +0 -20
  138. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +0 -7
  139. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs +0 -1752
  140. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  141. package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
  142. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
  143. package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
  144. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
  145. package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
  146. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
  147. package/dist/types/src/model/table-sorting.d.ts +0 -53
  148. package/dist/types/src/model/table-sorting.d.ts.map +0 -1
  149. package/dist/types/src/types/schema.d.ts +0 -8
  150. package/dist/types/src/types/schema.d.ts.map +0 -1
  151. package/dist/types/src/util/table.d.ts +0 -11
  152. package/dist/types/src/util/table.d.ts.map +0 -1
  153. package/src/components/Table/CreateRefPanel.tsx +0 -86
  154. package/src/components/Table/relations.stories.tsx +0 -116
  155. package/src/components/TableCellEditor/extension.ts +0 -61
  156. package/src/model/table-sorting.ts +0 -216
  157. package/src/types/schema.ts +0 -16
  158. package/src/util/table.ts +0 -49
@@ -4,7 +4,7 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { useGridContext, type GridScopedProps } from '@dxos/react-ui-grid';
7
+ import { type GridScopedProps, useGridContext } from '@dxos/react-ui-grid';
8
8
 
9
9
  export type CellValidationMessageProps = {
10
10
  validationError: string | null;
@@ -12,9 +12,9 @@ export type CellValidationMessageProps = {
12
12
  };
13
13
 
14
14
  export const CellValidationMessage = ({
15
+ __gridScope,
15
16
  validationError,
16
17
  variant = 'error',
17
- __gridScope,
18
18
  }: GridScopedProps<CellValidationMessageProps>) => {
19
19
  const { editing, editBox: box } = useGridContext('GridSheetCellEditor', __gridScope);
20
20
 
@@ -22,15 +22,15 @@ export const CellValidationMessage = ({
22
22
  return null;
23
23
  }
24
24
 
25
- const bgClass = variant === 'error' ? 'bg-errorSurface' : 'bg-warningSurface';
26
- const textClass = variant === 'error' ? 'text-errorSurfaceText' : 'text-warningSurfaceText';
25
+ const bgClass = variant === 'error' ? 'bg-error-surface' : 'bg-warning-surface';
26
+ const textClass = variant === 'error' ? 'text-error-surface-text' : 'text-warning-surface-text';
27
27
 
28
28
  return (
29
29
  <div
30
30
  role='none'
31
- className={`absolute ${bgClass} ${textClass} rounded-bs-sm text-xs p-1`}
31
+ className={`absolute ${bgClass} ${textClass} rounded-h-sm text-xs p-1`}
32
32
  style={{
33
- ...{ '--dx-gridCellWidth': `${box?.inlineSize ?? 200}px` },
33
+ ...{ '--dx-grid-cell-width': `${box?.inlineSize ?? 200}px` },
34
34
  zIndex: 10,
35
35
  insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
36
36
  insetInlineStart: box.insetInlineStart,
@@ -2,32 +2,48 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Schema } from 'effect';
5
+ import type * as Schema from 'effect/Schema';
6
6
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
 
8
- import { getSnapshot } from '@dxos/echo-schema';
8
+ import { Entity, type Type } from '@dxos/echo';
9
+ import { Ref, getValue } from '@dxos/echo/internal';
9
10
  import { invariant } from '@dxos/invariant';
10
- import { Popover } from '@dxos/react-ui';
11
- import { Form } from '@dxos/react-ui-form';
11
+ import { type Label, Popover } from '@dxos/react-ui';
12
+ import { Form, type FormRootProps, type RefFieldProps } from '@dxos/react-ui-form';
12
13
  import { parseCellIndex, useGridContext } from '@dxos/react-ui-grid';
13
14
  import { type FieldProjection } from '@dxos/schema';
14
- import { getDeep, setDeep } from '@dxos/util';
15
+ import { getDeep, isTruthy, setDeep } from '@dxos/util';
15
16
 
16
- import { type TableModel } from '../../model';
17
+ import { type ModalController, type TableModel, type TableRow } from '../../model';
18
+ import { translationKey } from '../../translations';
17
19
  import { narrowSchema } from '../../util';
18
20
 
19
- type FormCellEditorProps = {
20
- fieldProjection: FieldProjection;
21
+ const createOptionLabel: Label = ['create new object label', { ns: translationKey }];
22
+
23
+ export type OnCreateHandler = (schema: Type.AnyEntity, values: any) => Parameters<typeof Ref.make>[0];
24
+
25
+ export type FormCellEditorProps<T extends Type.AnyEntity = Type.AnyEntity> = {
26
+ __gridScope: any;
27
+ schema?: T;
21
28
  model?: TableModel;
22
- schema?: Schema.Schema.AnyNoContext;
29
+ fieldProjection: FieldProjection;
30
+ modals?: ModalController; // TODO(burdon): Not used. Remove?
23
31
  onSave?: () => void;
24
- __gridScope: any;
25
- };
32
+ onCreate?: OnCreateHandler;
33
+ } & Omit<FormRootProps<any>, 'values' | 'schema' | 'onCreate'>;
26
34
 
27
- export const FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }: FormCellEditorProps) => {
28
- const { editing: contextEditing, setEditing } = useGridContext('ArrayEditor', __gridScope);
29
- const [editing, setLocalEditing] = useState(false);
35
+ export const FormCellEditor = <T extends Type.AnyEntity = Type.AnyEntity>({
36
+ __gridScope,
37
+ schema,
38
+ model,
39
+ fieldProjection,
40
+ onSave,
41
+ onCreate,
42
+ ...formProps
43
+ }: FormCellEditorProps<T>) => {
30
44
  const anchorRef = useRef<HTMLButtonElement | null>(null);
45
+ const { id: _gridId, editing: contextEditing, setEditing } = useGridContext('ArrayEditor', __gridScope);
46
+ const [editing, setLocalEditing] = useState(false);
31
47
 
32
48
  useEffect(() => {
33
49
  if (contextEditing && contextEditing.cellElement) {
@@ -41,51 +57,106 @@ export const FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridS
41
57
  }
42
58
  }, [contextEditing]);
43
59
 
44
- const narrowedSchema = useMemo(() => {
60
+ const narrowedSchema = useMemo<Schema.Schema.AnyNoContext | undefined>(() => {
45
61
  if (!schema) {
46
62
  return undefined;
47
63
  }
64
+
48
65
  return narrowSchema(schema, [fieldProjection.field.path]);
49
66
  }, [JSON.stringify(schema), fieldProjection.field.path]); // TODO(burdon): Avoid stringify.
50
67
 
51
- const originalRow = useMemo(() => {
68
+ const originalRow = useMemo<TableRow | undefined>(() => {
52
69
  if (model && contextEditing) {
70
+ // Check if this is a draft cell and get the appropriate row data
53
71
  const cell = parseCellIndex(contextEditing.index);
54
- const row = model.getRowAt(cell.row);
55
- invariant(row);
56
-
57
- return row;
72
+ if (model.isDraftCell(cell)) {
73
+ const draftRow = model.getDraftRows()[cell.row];
74
+ invariant(draftRow);
75
+ return draftRow.data;
76
+ } else {
77
+ const row = model.getRowAt(cell.row);
78
+ invariant(row);
79
+ return row;
80
+ }
58
81
  }
59
82
 
60
83
  return undefined;
61
84
  }, [model, contextEditing]);
62
85
 
63
- const formValues = useMemo(() => {
64
- if (originalRow) {
65
- // NOTE(ZaymonFC): Important to get a snapshot to eject from the live object.
66
- return getSnapshot(originalRow);
86
+ // NOTE: Important to get a mutable deep clone to eject from the echo object.
87
+ // TODO(wittjosiah): Consider using something like Obj.clone for this use case.
88
+ const initialFormValues = useMemo(() => (originalRow ? JSON.parse(JSON.stringify(originalRow)) : {}), [originalRow]);
89
+ const [formValues, setFormValues] = useState<any>(initialFormValues);
90
+
91
+ const handleValuesChanged = useCallback<NonNullable<FormRootProps<any>['onValuesChanged']>>((values) => {
92
+ setFormValues(values);
93
+ }, []);
94
+ const handleOpenChange = useCallback((nextOpen: boolean) => {
95
+ if (nextOpen === false) {
96
+ setEditing(null);
97
+ onSave?.();
67
98
  }
68
- }, [originalRow]);
99
+ setLocalEditing(nextOpen);
100
+ }, []);
69
101
 
70
- const handleSave = useCallback(
71
- (values: any) => {
102
+ const handleSave = useCallback<NonNullable<FormRootProps<any>['onSave']>>(
103
+ (values) => {
104
+ if (!originalRow) {
105
+ return;
106
+ }
72
107
  const path = fieldProjection.field.path;
73
108
  const value = getDeep(values, [path]);
74
- setDeep(originalRow, [path], value);
109
+ // Use model's changeRow for consistent mutation handling.
110
+ if (model) {
111
+ model.changeRow(originalRow, (mutableRow) => {
112
+ setDeep(mutableRow, [path], value);
113
+ });
114
+ } else {
115
+ setDeep(originalRow, [path], value);
116
+ }
117
+ contextEditing?.cellElement?.focus();
75
118
  setEditing(null);
76
119
  setLocalEditing(false);
77
120
  onSave?.();
78
121
  },
79
- [fieldProjection.field.path, originalRow],
122
+ [fieldProjection.field.path, onSave, contextEditing, originalRow, model],
80
123
  );
81
124
 
82
- const handleOpenChange = useCallback((nextOpen: boolean) => {
83
- if (nextOpen === false) {
125
+ const handleCreate = useCallback<NonNullable<FormRootProps<any>['onCreate']>>(
126
+ (schema, values) => {
127
+ const objectWithId = onCreate?.(schema, values);
128
+ if (objectWithId && originalRow) {
129
+ const ref = Ref.make(objectWithId);
130
+ const path = fieldProjection.field.path;
131
+ // Use model's changeRow for consistent mutation handling.
132
+ if (model) {
133
+ model.changeRow(originalRow, (mutableRow) => {
134
+ setDeep(mutableRow, [path], ref);
135
+ });
136
+ } else {
137
+ setDeep(originalRow, [path], ref);
138
+ }
139
+ }
140
+ contextEditing?.cellElement?.focus();
84
141
  setEditing(null);
142
+ setLocalEditing(false);
85
143
  onSave?.();
86
- }
87
- setLocalEditing(nextOpen);
88
- }, []);
144
+ },
145
+ [fieldProjection.field.path, onSave, contextEditing, originalRow, onCreate, model],
146
+ );
147
+
148
+ const getOptions = useCallback<NonNullable<RefFieldProps['getOptions']>>(
149
+ (results) =>
150
+ results
151
+ .map((obj) => {
152
+ return {
153
+ id: Entity.getDXN(obj).toString(),
154
+ label: getValue(obj, fieldProjection.field.referencePath!) || obj.id.toString(),
155
+ };
156
+ })
157
+ .filter(isTruthy),
158
+ [fieldProjection],
159
+ );
89
160
 
90
161
  if (!editing) {
91
162
  return null;
@@ -94,12 +165,35 @@ export const FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridS
94
165
  return (
95
166
  <Popover.Root open={editing} onOpenChange={handleOpenChange}>
96
167
  <Popover.VirtualTrigger virtualRef={anchorRef} />
97
- <Popover.Content tabIndex={-1} classNames='popover-card-width density-fine'>
98
- <Popover.Arrow />
99
- <Popover.Viewport>
100
- <Form values={formValues} schema={narrowedSchema as any} onSave={handleSave} />
101
- </Popover.Viewport>
102
- </Popover.Content>
168
+ <Popover.Portal>
169
+ <Popover.Content tabIndex={-1} classNames='dx-card-popover-width dx-density-fine'>
170
+ <Popover.Arrow />
171
+ <Popover.Viewport>
172
+ <Form.Root
173
+ {...formProps}
174
+ autoFocus
175
+ schema={narrowedSchema}
176
+ values={formValues}
177
+ onValuesChanged={handleValuesChanged}
178
+ projection={model?.projection}
179
+ createInitialValuePath={fieldProjection.field.referencePath}
180
+ createOptionIcon='ph--plus--regular'
181
+ createOptionLabel={createOptionLabel}
182
+ db={model?.db}
183
+ getOptions={getOptions}
184
+ onCreate={handleCreate}
185
+ onSave={handleSave}
186
+ >
187
+ <Form.Viewport>
188
+ <Form.Content>
189
+ <Form.FieldSet />
190
+ <Form.Actions />
191
+ </Form.Content>
192
+ </Form.Viewport>
193
+ </Form.Root>
194
+ </Popover.Viewport>
195
+ </Popover.Content>
196
+ </Popover.Portal>
103
197
  </Popover.Root>
104
198
  );
105
199
  };
@@ -2,100 +2,63 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
- import React, { useEffect, useMemo, useState } from 'react';
6
+ import React from 'react';
9
7
 
10
8
  import { Obj } from '@dxos/echo';
11
- import { type EchoSchema, isMutable } from '@dxos/echo-schema';
12
- import { invariant } from '@dxos/invariant';
9
+ import { View } from '@dxos/echo';
13
10
  import { faker } from '@dxos/random';
14
- import { Filter, useQuery } from '@dxos/react-client/echo';
15
- import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
16
- import { defaultRowSize, Grid, type GridEditing } from '@dxos/react-ui-grid';
17
- import { createDefaultSchema, DataType } from '@dxos/schema';
18
- import { withLayout, withTheme } from '@dxos/storybook-utils';
11
+ import { withClientProvider } from '@dxos/react-client/testing';
12
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
13
+ import { Grid, type GridEditing, defaultRowSize } from '@dxos/react-ui-grid';
14
+ import { ViewModel } from '@dxos/schema';
15
+ import { Task } from '@dxos/types';
19
16
 
20
- import { TableCellEditor, type TableCellEditorProps } from './TableCellEditor';
21
- import { useTableModel } from '../../hooks';
22
- import { type TableFeatures } from '../../model';
17
+ import { useTestTableModel } from '../../testing';
23
18
  import { translations } from '../../translations';
24
- import { TableView } from '../../types';
25
- import { createTable } from '../../util';
19
+ import { Table } from '../../types';
20
+
21
+ import { TableCellEditor } from './TableCellEditor';
26
22
 
27
23
  type StoryProps = {
28
24
  editing: GridEditing;
29
25
  };
30
26
 
27
+ // TODO(burdon): Broken layout.
31
28
  const DefaultStory = ({ editing }: StoryProps) => {
32
- const { space } = useClientProvider();
33
- invariant(space);
34
-
35
- const views = useQuery(space, Filter.type(DataType.View));
36
- const [view, setView] = useState<DataType.View>();
37
- const [schema, setSchema] = useState<EchoSchema>();
38
- useEffect(() => {
39
- if (space && views.length && !view) {
40
- const view = views[0];
41
- setView(view);
42
- setSchema(space.db.schemaRegistry.getSchema(view.query.typename!));
43
- }
44
- }, [space, views, view]);
45
-
46
- const features: Partial<TableFeatures> = useMemo(
47
- () => ({
48
- selection: { enabled: true, mode: 'multiple' },
49
- dataEditable: true,
50
- schemaEditable: schema && isMutable(schema),
51
- }),
52
- [schema],
53
- );
54
-
55
- const model = useTableModel({ view, schema: schema?.jsonSchema, features });
56
-
57
- const handleQuery: TableCellEditorProps['onQuery'] = async ({ field }) => {
58
- // TODO(dmaretskyi): If no schema query nothing
59
- const { objects } = await space.db.query(schema ? Filter.type(schema) : Filter.everything()).run();
60
- return objects.map((obj) => {
61
- const label = obj[field.referencePath ?? 'id'];
62
- return {
63
- label,
64
- data: obj,
65
- };
66
- });
67
- };
29
+ const { model, table } = useTestTableModel();
68
30
 
69
- if (!model || !schema || !view) {
31
+ if (!model || !table) {
70
32
  return <div />;
71
33
  }
72
34
 
73
35
  return (
74
- <div className='flex w-[300px] border border-separator' style={{ height: defaultRowSize }}>
36
+ <div className='border border-separator' style={{ height: defaultRowSize }}>
75
37
  <Grid.Root id='test' editing={editing}>
76
- <TableCellEditor model={model} onQuery={handleQuery} />
38
+ <TableCellEditor model={model} schema={Task.Task} />
77
39
  </Grid.Root>
78
40
  </div>
79
41
  );
80
42
  };
81
43
 
82
- const meta: Meta<StoryProps> = {
44
+ const meta = {
83
45
  title: 'ui/react-ui-table/TableCellEditor',
84
46
  component: DefaultStory,
85
47
  render: DefaultStory,
86
- parameters: { translations, layout: 'centered' },
87
48
  decorators: [
49
+ withTheme(),
50
+ withLayout({ layout: 'column' }),
88
51
  withClientProvider({
89
- types: [DataType.View, TableView],
52
+ types: [View.View, Task.Task, Table.Table],
90
53
  createIdentity: true,
91
54
  createSpace: true,
92
- onSpaceCreated: async ({ client, space }) => {
93
- const schema = createDefaultSchema();
94
- const { view } = await createTable({ client, space, typename: schema.typename });
95
- space.db.add(view);
55
+ onCreateSpace: async ({ space }) => {
56
+ const { view, jsonSchema } = await ViewModel.makeFromDatabase({ db: space.db, typename: Task.Task.typename });
57
+ const table = Table.make({ view, jsonSchema });
58
+ space.db.add(table);
96
59
  Array.from({ length: 10 }).forEach(() => {
97
60
  space.db.add(
98
- Obj.make(schema, {
61
+ Obj.make(Task.Task, {
99
62
  title: faker.person.fullName(),
100
63
  status: faker.helpers.arrayElement(['todo', 'in-progress', 'done'] as const),
101
64
  description: faker.lorem.sentence(),
@@ -104,14 +67,16 @@ const meta: Meta<StoryProps> = {
104
67
  });
105
68
  },
106
69
  }),
107
- withTheme,
108
- withLayout(),
109
70
  ],
110
- };
71
+ parameters: {
72
+ layout: 'fullscreen',
73
+ translations,
74
+ },
75
+ } satisfies Meta<typeof DefaultStory>;
111
76
 
112
77
  export default meta;
113
78
 
114
- type Story = StoryObj<StoryProps>;
79
+ type Story = StoryObj<typeof meta>;
115
80
 
116
81
  export const Default: Story = {
117
82
  args: {