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

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 (194) hide show
  1. package/dist/lib/browser/chunk-FBURZBPH.mjs +70 -0
  2. package/dist/lib/browser/chunk-FBURZBPH.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  4. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-YGC7LZJN.mjs +1695 -0
  6. package/dist/lib/browser/chunk-YGC7LZJN.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +1162 -2554
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/testing/index.mjs +115 -0
  11. package/dist/lib/browser/testing/index.mjs.map +7 -0
  12. package/dist/lib/browser/translations.mjs +36 -0
  13. package/dist/lib/browser/translations.mjs.map +7 -0
  14. package/dist/lib/browser/types/index.mjs +4 -5
  15. package/dist/lib/node-esm/chunk-DKKMSVKP.mjs +71 -0
  16. package/dist/lib/node-esm/chunk-DKKMSVKP.mjs.map +7 -0
  17. package/dist/lib/node-esm/chunk-GKIWDEZ7.mjs +1697 -0
  18. package/dist/lib/node-esm/chunk-GKIWDEZ7.mjs.map +7 -0
  19. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  20. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  21. package/dist/lib/node-esm/index.mjs +1162 -2554
  22. package/dist/lib/node-esm/index.mjs.map +4 -4
  23. package/dist/lib/node-esm/meta.json +1 -1
  24. package/dist/lib/node-esm/testing/index.mjs +116 -0
  25. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  26. package/dist/lib/node-esm/translations.mjs +37 -0
  27. package/dist/lib/node-esm/translations.mjs.map +7 -0
  28. package/dist/lib/node-esm/types/index.mjs +4 -5
  29. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +2 -3
  30. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/ColumnSettings.d.ts +4 -2
  32. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
  34. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  35. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +35 -3
  36. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/Table/Relations.stories.d.ts +111 -0
  38. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  39. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  40. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  41. package/dist/types/src/components/Table/Table.d.ts +21 -18
  42. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  43. package/dist/types/src/components/Table/Table.stories.d.ts +110 -6
  44. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/Table/TableContent.d.ts +17 -0
  46. package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
  47. package/dist/types/src/components/Table/TableToolbar.d.ts +21 -0
  48. package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
  49. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +2 -1
  50. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  51. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +14 -9
  52. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  53. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +12 -18
  54. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  55. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +38 -5
  56. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  57. package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
  58. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -1
  59. package/dist/types/src/components/index.d.ts +0 -1
  60. package/dist/types/src/components/index.d.ts.map +1 -1
  61. package/dist/types/src/components/testing.d.ts +26 -56
  62. package/dist/types/src/components/testing.d.ts.map +1 -1
  63. package/dist/types/src/hooks/index.d.ts +2 -0
  64. package/dist/types/src/hooks/index.d.ts.map +1 -1
  65. package/dist/types/src/hooks/useAddRow.d.ts +13 -0
  66. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -0
  67. package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
  68. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
  69. package/dist/types/src/hooks/useTableModel.d.ts +11 -10
  70. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  71. package/dist/types/src/index.d.ts +0 -3
  72. package/dist/types/src/index.d.ts.map +1 -1
  73. package/dist/types/src/model/modal-controller.d.ts +5 -8
  74. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  75. package/dist/types/src/model/selection-model.d.ts +18 -8
  76. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  77. package/dist/types/src/model/table-model.d.ts +150 -32
  78. package/dist/types/src/model/table-model.d.ts.map +1 -1
  79. package/dist/types/src/model/table-presentation.d.ts +13 -2
  80. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  81. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  82. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  83. package/dist/types/src/playwright/playwright.config.d.ts +3 -0
  84. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -0
  85. package/dist/types/src/testing/index.d.ts +2 -0
  86. package/dist/types/src/testing/index.d.ts.map +1 -0
  87. package/dist/types/src/testing/useTestTableModel.d.ts +25 -0
  88. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -0
  89. package/dist/types/src/translations.d.ts +22 -25
  90. package/dist/types/src/translations.d.ts.map +1 -1
  91. package/dist/types/src/types/Table.d.ts +26 -0
  92. package/dist/types/src/types/Table.d.ts.map +1 -0
  93. package/dist/types/src/types/index.d.ts +1 -1
  94. package/dist/types/src/types/index.d.ts.map +1 -1
  95. package/dist/types/src/util/dynamic-table.d.ts +15 -14
  96. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  97. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  98. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  99. package/dist/types/src/util/index.d.ts +2 -1
  100. package/dist/types/src/util/index.d.ts.map +1 -1
  101. package/dist/types/src/util/query-ast.d.ts +7 -0
  102. package/dist/types/src/util/query-ast.d.ts.map +1 -0
  103. package/dist/types/src/util/schema.d.ts +1 -1
  104. package/dist/types/src/util/schema.d.ts.map +1 -1
  105. package/dist/types/src/util/signals.d.ts.map +1 -1
  106. package/dist/types/src/util/sort.d.ts +12 -0
  107. package/dist/types/src/util/sort.d.ts.map +1 -0
  108. package/dist/types/src/util/table-buttons.d.ts +31 -17
  109. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  110. package/dist/types/src/util/table-controls.d.ts +4 -4
  111. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  112. package/dist/types/src/util/tag.d.ts.map +1 -1
  113. package/dist/types/tsconfig.tsbuildinfo +1 -1
  114. package/package.json +76 -72
  115. package/src/components/Table/ColumnActionsMenu.tsx +18 -13
  116. package/src/components/Table/ColumnSettings.tsx +18 -15
  117. package/src/components/Table/DynamicTable.stories.tsx +40 -36
  118. package/src/components/Table/DynamicTable.tsx +38 -34
  119. package/src/components/Table/Relations.stories.tsx +281 -0
  120. package/src/components/Table/RowActionsMenu.tsx +29 -19
  121. package/src/components/Table/Table.stories.tsx +198 -214
  122. package/src/components/Table/Table.tsx +47 -363
  123. package/src/components/Table/TableContent.tsx +421 -0
  124. package/src/components/Table/TableToolbar.tsx +111 -0
  125. package/src/components/TableCellEditor/CellValidationMessage.tsx +9 -5
  126. package/src/components/TableCellEditor/FormCellEditor.tsx +153 -49
  127. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +40 -79
  128. package/src/components/TableCellEditor/TableCellEditor.tsx +109 -199
  129. package/src/components/TableCellEditor/index.ts +1 -0
  130. package/src/components/index.ts +0 -1
  131. package/src/components/testing.ts +46 -37
  132. package/src/hooks/index.ts +2 -0
  133. package/src/hooks/useAddRow.ts +36 -0
  134. package/src/hooks/useProjectionModel.ts +39 -0
  135. package/src/hooks/useTableModel.ts +41 -35
  136. package/src/index.ts +0 -5
  137. package/src/model/modal-controller.ts +24 -41
  138. package/src/model/selection-model.ts +75 -41
  139. package/src/model/table-model.test.ts +91 -56
  140. package/src/model/table-model.ts +629 -162
  141. package/src/model/table-presentation.test.ts +69 -59
  142. package/src/model/table-presentation.ts +283 -154
  143. package/src/playwright/TableManager.ts +13 -6
  144. package/src/playwright/playwright.config.ts +17 -0
  145. package/src/playwright/smoke.spec.ts +181 -42
  146. package/src/testing/index.ts +5 -0
  147. package/src/testing/useTestTableModel.ts +133 -0
  148. package/src/translations.ts +24 -24
  149. package/src/types/Table.ts +79 -0
  150. package/src/types/index.ts +2 -2
  151. package/src/util/dynamic-table.test.ts +70 -0
  152. package/src/util/dynamic-table.ts +51 -36
  153. package/src/util/index.ts +2 -1
  154. package/src/util/query-ast.ts +22 -0
  155. package/src/util/schema.ts +4 -4
  156. package/src/util/sort.ts +90 -0
  157. package/src/util/table-buttons.ts +28 -4
  158. package/src/util/table-controls.ts +6 -3
  159. package/dist/lib/browser/chunk-TL7CKQQV.mjs +0 -27
  160. package/dist/lib/browser/chunk-TL7CKQQV.mjs.map +0 -7
  161. package/dist/lib/node/chunk-O2VPBNS5.cjs +0 -50
  162. package/dist/lib/node/chunk-O2VPBNS5.cjs.map +0 -7
  163. package/dist/lib/node/index.cjs +0 -2739
  164. package/dist/lib/node/index.cjs.map +0 -7
  165. package/dist/lib/node/meta.json +0 -1
  166. package/dist/lib/node/types/index.cjs +0 -31
  167. package/dist/lib/node/types/index.cjs.map +0 -7
  168. package/dist/lib/node-esm/chunk-GBT6GD4G.mjs +0 -29
  169. package/dist/lib/node-esm/chunk-GBT6GD4G.mjs.map +0 -7
  170. package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
  171. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
  172. package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
  173. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
  174. package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
  175. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
  176. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +0 -21
  177. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +0 -1
  178. package/dist/types/src/components/TableToolbar/index.d.ts +0 -2
  179. package/dist/types/src/components/TableToolbar/index.d.ts.map +0 -1
  180. package/dist/types/src/model/table-sorting.d.ts +0 -53
  181. package/dist/types/src/model/table-sorting.d.ts.map +0 -1
  182. package/dist/types/src/types/table.d.ts +0 -56
  183. package/dist/types/src/types/table.d.ts.map +0 -1
  184. package/dist/types/src/util/table.d.ts +0 -14
  185. package/dist/types/src/util/table.d.ts.map +0 -1
  186. package/src/components/Table/CreateRefPanel.tsx +0 -84
  187. package/src/components/Table/relations.stories.tsx +0 -124
  188. package/src/components/TableCellEditor/extension.ts +0 -61
  189. package/src/components/TableToolbar/TableToolbar.tsx +0 -102
  190. package/src/components/TableToolbar/index.ts +0 -5
  191. package/src/model/table-sorting.ts +0 -216
  192. package/src/playwright/playwright.config.cts +0 -18
  193. package/src/types/table.ts +0 -27
  194. package/src/util/table.ts +0 -127
@@ -2,391 +2,75 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { type Schema } from 'effect/Schema';
6
- import React, {
7
- type MouseEvent,
8
- type PropsWithChildren,
9
- type WheelEvent,
10
- forwardRef,
11
- useCallback,
12
- useImperativeHandle,
13
- useState,
14
- useMemo,
15
- useEffect,
16
- } from 'react';
5
+ import { Atom } from '@effect-atom/atom-react';
6
+ import { createContext } from '@radix-ui/react-context';
7
+ import React, { type PropsWithChildren, type RefObject, forwardRef, useImperativeHandle, useRef } from 'react';
17
8
 
18
- import { type Client } from '@dxos/client';
19
- import { getValue } from '@dxos/echo-schema';
20
- import { invariant } from '@dxos/invariant';
21
- import { Filter } from '@dxos/react-client/echo';
22
- import { useTranslation } from '@dxos/react-ui';
23
- import { useAttention } from '@dxos/react-ui-attention';
24
- import {
25
- closestCell,
26
- type DxGridElement,
27
- type DxGridPosition,
28
- type GridContentProps,
29
- Grid,
30
- type DxGridPlane,
31
- type DxGridPlaneRange,
32
- gridSeparatorInlineEnd,
33
- gridSeparatorBlockEnd,
34
- } from '@dxos/react-ui-grid';
35
- import { mx } from '@dxos/react-ui-theme';
36
- import { isNotFalsy, safeParseInt } from '@dxos/util';
9
+ import { type DxGridAxisMeta, type DxGridPosition } from '@dxos/react-ui-grid';
37
10
 
38
- import { ColumnActionsMenu } from './ColumnActionsMenu';
39
- import { ColumnSettings } from './ColumnSettings';
40
- import { CreateRefPanel } from './CreateRefPanel';
41
- import { RowActionsMenu } from './RowActionsMenu';
42
- import { ModalController, type TableModel, type TablePresentation } from '../../model';
43
- import { translationKey } from '../../translations';
44
- import { tableButtons, tableControls } from '../../util';
45
- import { createOption, TableValueEditor, type TableCellEditorProps } from '../TableCellEditor';
11
+ import { type InsertRowResult } from '../../model';
12
+ import { TableContent } from './TableContent';
13
+ import { TableToolbar } from './TableToolbar';
14
+
15
+ const columnDefault = { grid: { minSize: 80, maxSize: 640 } };
16
+ const rowDefault = { frozenRowsStart: { readonly: true, focusUnfurl: false } };
17
+ const emptyColumnMeta = Atom.make<DxGridAxisMeta>({ grid: {} });
46
18
 
47
19
  //
48
- // Table.Root
20
+ // Context
49
21
  //
50
22
 
51
- export type TableRootProps = PropsWithChildren<{ role?: string }>;
52
-
53
- const TableRoot = ({ children, role }: TableRootProps) => {
54
- return (
55
- <div
56
- role='none'
57
- className={mx(
58
- 'relative !border-separator',
59
- role === 'section' // TODO(burdon): This leaks composer plugin concepts? Standardize for react-ui?
60
- ? 'attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]'
61
- : 'flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]',
62
- )}
63
- >
64
- {children}
65
- </div>
66
- );
23
+ type TableContextValue = {
24
+ /** Mutable ref populated by Content so Root can expose the controller. */
25
+ controllerRef: RefObject<TableController>;
67
26
  };
68
27
 
28
+ const [TableContextProvider, useTableContext] = createContext<TableContextValue>('Table');
29
+
69
30
  //
70
- // Table.Main
31
+ // Controller
71
32
  //
72
33
 
73
- export type TableController = {
34
+ type TableController = {
74
35
  update?: (cell?: DxGridPosition) => void;
36
+ handleInsertRowResult?: (insertRowResult?: InsertRowResult) => void;
75
37
  };
76
38
 
77
- export type TableMainProps = {
78
- model?: TableModel;
79
- presentation?: TablePresentation;
80
- schema?: Schema.AnyNoContext;
81
- client?: Client;
82
- // TODO(burdon): Rename since attention isn't a useful concept here? Standardize across other components. Pass property into useAttention.
83
- ignoreAttention?: boolean;
84
- onRowClick?: (row: any) => void;
85
- };
86
-
87
- const TableMain = forwardRef<TableController, TableMainProps>(
88
- ({ model, presentation, ignoreAttention, schema, client, onRowClick }, forwardedRef) => {
89
- const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
90
- const { hasAttention } = useAttention(model?.id ?? 'table');
91
- const { t } = useTranslation(translationKey);
92
- const modals = useMemo(() => new ModalController(), []);
93
-
94
- const frozen = useMemo(() => {
95
- const noActionColumn =
96
- model?.features.dataEditable === false &&
97
- model?.features.schemaEditable === false &&
98
- model.rowActions.length === 0;
99
-
100
- return {
101
- frozenRowsStart: 1,
102
- frozenColsStart: model?.features.selection.enabled ? 1 : 0,
103
- frozenColsEnd: noActionColumn ? 0 : 1,
104
- };
105
- }, [model]);
106
-
107
- const getCells = useCallback<NonNullable<GridContentProps['getCells']>>(
108
- (range: DxGridPlaneRange, plane: DxGridPlane) => presentation?.getCells(range, plane) ?? {},
109
- [presentation],
110
- );
111
-
112
- useEffect(() => {
113
- if (!presentation || !dxGrid) {
114
- return;
115
- }
116
- dxGrid.getCells = getCells;
117
- }, [presentation, dxGrid, getCells]);
118
-
119
- /**
120
- * Provides an external controller that can be called to repaint the table.
121
- */
122
- useImperativeHandle<TableController, TableController>(
123
- forwardedRef,
124
- () => {
125
- if (!presentation || !dxGrid) {
126
- return {};
127
- }
128
-
129
- return {
130
- update: (cell) => {
131
- if (cell) {
132
- dxGrid.updateIfWithinBounds(cell);
133
- } else {
134
- dxGrid.updateCells(true);
135
- dxGrid.requestUpdate();
136
- }
137
- },
138
- };
139
- },
140
- [presentation, dxGrid],
141
- );
142
-
143
- const handleGridClick = useCallback(
144
- (event: MouseEvent) => {
145
- const rowIndex = safeParseInt((event.target as HTMLElement).ariaRowIndex ?? '');
146
- if (rowIndex != null) {
147
- if (onRowClick) {
148
- const row = model?.getRowAt(rowIndex);
149
- row && onRowClick(row);
150
- }
151
-
152
- if (model?.features.selection.enabled && model?.selection.selectionMode === 'single') {
153
- model.selection.toggleSelectionForRowIndex(rowIndex);
154
- }
155
- }
156
-
157
- if (!modals) {
158
- return;
159
- }
160
-
161
- const buttonSelector = Object.values(tableButtons)
162
- .map((button) => `button[${button.attr}]`)
163
- .join(',');
164
-
165
- const tableButtonElement = (event.target as HTMLElement).closest(buttonSelector) as HTMLElement;
166
- if (tableButtonElement) {
167
- const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
168
- if (!button) {
169
- return;
170
- }
171
-
172
- modals.setTrigger(tableButtonElement);
173
- const data = button.getData(tableButtonElement);
174
- switch (data.type) {
175
- case 'rowMenu': {
176
- modals.showRowMenu(data.rowIndex);
177
- break;
178
- }
179
- case 'columnSettings': {
180
- modals.showColumnMenu(data.fieldId);
181
- break;
182
- }
183
- case 'newColumn': {
184
- modals.showColumnCreator();
185
- break;
186
- }
187
- case 'sort': {
188
- model?.sorting?.toggleSort(data.fieldId);
189
- break;
190
- }
191
- }
192
- return;
193
- }
194
-
195
- const controlSelector = Object.values(tableControls)
196
- .map((control) => `input[${control.attr}]`)
197
- .join(',');
198
-
199
- const controlElement = (event.target as HTMLElement).closest(controlSelector) as HTMLElement;
200
- if (controlElement) {
201
- const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
202
- if (!control) {
203
- return;
204
- }
205
-
206
- const data = control.getData(controlElement);
207
- switch (data.type) {
208
- case 'checkbox': {
209
- if (data.header) {
210
- model?.selection.setSelection(model.selection.allRowsSeleted.value ? 'none' : 'all');
211
- } else {
212
- model?.selection.toggleSelectionForRowIndex(data.rowIndex);
213
- }
214
- break;
215
- }
216
- case 'switch': {
217
- if (model) {
218
- model.updateCellData({ row: data.rowIndex, col: data.colIndex }, (value) => !value);
219
- }
220
- break;
221
- }
222
- }
223
- }
224
- },
225
- [model, modals],
226
- );
227
-
228
- const handleFocus = useCallback<NonNullable<TableCellEditorProps['onFocus']>>(
229
- (increment, delta) => {
230
- if (dxGrid) {
231
- dxGrid.refocus(increment, delta);
232
- }
233
- },
234
- [dxGrid],
235
- );
236
-
237
- const handleEnter = useCallback<NonNullable<TableCellEditorProps['onEnter']>>(
238
- (cell) => {
239
- if (!model?.features.dataEditable) {
240
- return;
241
- }
242
-
243
- // TODO(burdon): Insert row only if bottom row isn't completely blank already.
244
- if (model && cell.row === model.getRowCount() - 1) {
245
- model.insertRow(cell.row);
246
- if (dxGrid) {
247
- requestAnimationFrame(() => {
248
- dxGrid?.scrollToRow(cell.row + 1);
249
- dxGrid?.refocus('row', 1);
250
- });
251
- }
252
- }
253
- },
254
- [model, dxGrid],
255
- );
256
-
257
- const handleKeyDown = useCallback<NonNullable<GridContentProps['onKeyDown']>>(
258
- (event) => {
259
- if (!model?.features.dataEditable) {
260
- return;
261
- }
262
-
263
- const cell = closestCell(event.target);
264
- if (!model || !cell) {
265
- return;
266
- }
267
-
268
- switch (event.key) {
269
- case 'Backspace':
270
- case 'Delete': {
271
- model.setCellData(cell, undefined);
272
- break;
273
- }
274
- }
275
- },
276
- [model],
277
- );
278
-
279
- const handleAxisResize = useCallback<NonNullable<GridContentProps['onAxisResize']>>(
280
- (event) => {
281
- if (event.axis === 'col') {
282
- const columnIndex = parseInt(event.index, 10);
283
- model?.setColumnWidth(columnIndex, event.size);
284
- }
285
- },
286
- [model],
287
- );
288
-
289
- const handleWheel = useCallback(
290
- (event: WheelEvent) => {
291
- if (!ignoreAttention && !hasAttention) {
292
- event.stopPropagation();
293
- }
294
- },
295
- [hasAttention, ignoreAttention],
296
- );
297
-
298
- const handleNewColumn = useCallback(() => {
299
- const columns = model?.getColumnCount();
300
- if (dxGrid && columns) {
301
- dxGrid.scrollToColumn(columns - 1);
302
- }
303
- }, [model, dxGrid]);
304
-
305
- // TODO(burdon): Factor out?
306
- // TODO(burdon): Generalize to handle other value types (e.g., enums).
307
- const handleQuery = useCallback<NonNullable<TableCellEditorProps['onQuery']>>(
308
- async ({ field, props }, text) => {
309
- if (model && props.referenceSchema && field.referencePath) {
310
- const space = model.space;
311
- invariant(space);
39
+ //
40
+ // Root
41
+ //
312
42
 
313
- let schema;
314
- if (client) {
315
- schema = client.graph.schemaRegistry.getSchema(props.referenceSchema);
316
- }
317
- if (!schema) {
318
- schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
319
- }
43
+ const TABLE_ROOT_NAME = 'Table.Root';
320
44
 
321
- if (schema) {
322
- const { objects } = await space.db.query(Filter.type(schema)).run();
323
- const options = objects
324
- .map((obj) => {
325
- const value = getValue(obj, field.referencePath!);
326
- if (!value || typeof value !== 'string') {
327
- return undefined;
328
- }
45
+ type TableRootProps = PropsWithChildren;
329
46
 
330
- return {
331
- label: value,
332
- data: obj,
333
- };
334
- })
335
- .filter(isNotFalsy);
47
+ const TableRoot = forwardRef<TableController, TableRootProps>(({ children }, forwardedRef) => {
48
+ const controllerRef = useRef<TableController>({});
336
49
 
337
- return [
338
- ...options,
339
- {
340
- label: t('create new object label', { text }),
341
- data: createOption(text),
342
- },
343
- ];
344
- }
345
- }
50
+ useImperativeHandle(
51
+ forwardedRef,
52
+ () => ({
53
+ update: (cell) => controllerRef.current?.update?.(cell),
54
+ handleInsertRowResult: (result) => controllerRef.current?.handleInsertRowResult?.(result),
55
+ }),
56
+ [],
57
+ );
346
58
 
347
- return [];
348
- },
349
- [model, client, t],
350
- );
59
+ return <TableContextProvider controllerRef={controllerRef}>{children}</TableContextProvider>;
60
+ });
351
61
 
352
- if (!model || !modals) {
353
- return <span role='none' className='attention-surface' />;
354
- }
62
+ TableRoot.displayName = TABLE_ROOT_NAME;
355
63
 
356
- return (
357
- <Grid.Root id={model.id ?? 'table-grid'}>
358
- <TableValueEditor
359
- model={model}
360
- modals={modals}
361
- schema={schema}
362
- onEnter={handleEnter}
363
- onFocus={handleFocus}
364
- onQuery={handleQuery}
365
- />
366
- <Grid.Content
367
- className={mx('[--dx-grid-base:var(--baseSurface)]', gridSeparatorInlineEnd, gridSeparatorBlockEnd)}
368
- frozen={frozen}
369
- // getCells={getCells}
370
- columns={model.columnMeta.value}
371
- limitRows={model.getRowCount() ?? 0}
372
- limitColumns={model.view?.fields?.length ?? 0}
373
- overscroll='trap'
374
- onAxisResize={handleAxisResize}
375
- onClick={handleGridClick}
376
- onKeyDown={handleKeyDown}
377
- onWheelCapture={handleWheel}
378
- ref={setDxGrid}
379
- />
380
- <RowActionsMenu model={model} modals={modals} />
381
- <ColumnActionsMenu model={model} modals={modals} />
382
- <ColumnSettings model={model} modals={modals} onNewColumn={handleNewColumn} />
383
- <CreateRefPanel model={model} modals={modals} />
384
- </Grid.Root>
385
- );
386
- },
387
- );
64
+ //
65
+ // Table
66
+ //
388
67
 
389
68
  export const Table = {
390
69
  Root: TableRoot,
391
- Main: TableMain,
70
+ Toolbar: TableToolbar,
71
+ Content: TableContent,
392
72
  };
73
+
74
+ export type { TableController, TableRootProps };
75
+
76
+ export { useTableContext };