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

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 (90) hide show
  1. package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-ZAOSIG3L.mjs} +382 -319
  2. package/dist/lib/browser/chunk-ZAOSIG3L.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +404 -381
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +4 -2
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/{chunk-Y66YLSTC.mjs → chunk-ZOFFI3JJ.mjs} +382 -319
  9. package/dist/lib/node-esm/chunk-ZOFFI3JJ.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +404 -381
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +4 -2
  14. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  15. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -1
  16. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  17. package/dist/types/src/components/Table/ColumnSettings.d.ts +1 -1
  18. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  19. package/dist/types/src/components/Table/CreateRefPanel.d.ts +1 -1
  20. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  21. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  22. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +1 -1
  23. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Table/{relations.stories.d.ts → Relations.stories.d.ts} +2 -2
  25. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  27. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/Table.d.ts +1 -0
  29. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/Table.stories.d.ts +1 -1
  31. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  33. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -5
  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.map +1 -1
  38. package/dist/types/src/hooks/useTableModel.d.ts +1 -1
  39. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  40. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  41. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  42. package/dist/types/src/model/table-model.d.ts +3 -2
  43. package/dist/types/src/model/table-model.d.ts.map +1 -1
  44. package/dist/types/src/model/table-presentation.d.ts +2 -1
  45. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  46. package/dist/types/src/model/table-sorting.d.ts +2 -2
  47. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  48. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  49. package/dist/types/src/translations.d.ts +2 -2
  50. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  51. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  52. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  53. package/dist/types/src/util/table.d.ts +2 -1
  54. package/dist/types/src/util/table.d.ts.map +1 -1
  55. package/dist/types/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +42 -38
  57. package/src/components/Table/ColumnActionsMenu.tsx +1 -1
  58. package/src/components/Table/ColumnSettings.tsx +1 -1
  59. package/src/components/Table/CreateRefPanel.tsx +1 -1
  60. package/src/components/Table/DynamicTable.stories.tsx +3 -2
  61. package/src/components/Table/DynamicTable.tsx +4 -3
  62. package/src/components/Table/{relations.stories.tsx → Relations.stories.tsx} +12 -4
  63. package/src/components/Table/RowActionsMenu.tsx +3 -3
  64. package/src/components/Table/Table.stories.tsx +12 -7
  65. package/src/components/Table/Table.tsx +56 -45
  66. package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
  67. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +4 -3
  68. package/src/components/TableCellEditor/TableCellEditor.tsx +16 -20
  69. package/src/components/TableCellEditor/extension.ts +2 -2
  70. package/src/components/TableToolbar/TableToolbar.tsx +2 -2
  71. package/src/components/testing.ts +1 -1
  72. package/src/hooks/useTableModel.ts +1 -1
  73. package/src/model/modal-controller.ts +1 -1
  74. package/src/model/selection-model.ts +3 -2
  75. package/src/model/table-model.test.ts +2 -1
  76. package/src/model/table-model.ts +13 -10
  77. package/src/model/table-presentation.test.ts +3 -2
  78. package/src/model/table-presentation.ts +28 -6
  79. package/src/model/table-sorting.ts +3 -3
  80. package/src/playwright/smoke.spec.ts +92 -0
  81. package/src/testing/useTestTableModel.ts +3 -2
  82. package/src/translations.ts +2 -2
  83. package/src/util/dynamic-table.ts +2 -2
  84. package/src/util/schema.ts +1 -1
  85. package/src/util/table-buttons.ts +2 -1
  86. package/src/util/table-controls.ts +4 -1
  87. package/src/util/table.ts +7 -3
  88. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  89. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  90. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
@@ -16,7 +16,7 @@ import {
16
16
  touch,
17
17
  useAddRow,
18
18
  useTableModel
19
- } from "./chunk-5XLSHLOG.mjs";
19
+ } from "./chunk-ZAOSIG3L.mjs";
20
20
  import "./chunk-L2LSB6KV.mjs";
21
21
 
22
22
  // src/translations.ts
@@ -29,8 +29,8 @@ var translations = [
29
29
  "create object label": "Create table",
30
30
  "table name placeholder": "Table name",
31
31
  "settings title": "Table settings",
32
- "table schema label": "Schema",
33
- "new schema": "New schema",
32
+ "table schema label": "Record type",
33
+ "new schema": "New record type",
34
34
  "continue label": "Continue",
35
35
  "create stack section label": "Create table",
36
36
  "add row label": "Add row",
@@ -53,270 +53,41 @@ var translations = [
53
53
 
54
54
  // src/components/Table/Table.tsx
55
55
  import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
56
- import React8, { forwardRef, useCallback as useCallback5, useImperativeHandle, useState as useState4, useMemo as useMemo5, useEffect as useEffect4 } from "react";
56
+ import React8, { forwardRef, useCallback as useCallback5, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo5, useState as useState4 } from "react";
57
57
  import { Filter } from "@dxos/echo";
58
58
  import { getValue } from "@dxos/echo-schema";
59
59
  import { invariant as invariant3 } from "@dxos/invariant";
60
60
  import { getSpace as getSpace2 } from "@dxos/react-client/echo";
61
61
  import { useTranslation as useTranslation3 } from "@dxos/react-ui";
62
62
  import { useAttention } from "@dxos/react-ui-attention";
63
- import { closestCell, Grid, gridSeparatorInlineEnd, gridSeparatorBlockEnd } from "@dxos/react-ui-grid";
63
+ import { Grid, closestCell, gridSeparatorBlockEnd, gridSeparatorInlineEnd } from "@dxos/react-ui-grid";
64
64
  import { mx } from "@dxos/react-ui-theme";
65
65
  import { isNotFalsy, safeParseInt } from "@dxos/util";
66
66
 
67
- // src/components/Table/ColumnActionsMenu.tsx
68
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
69
- import React from "react";
70
- import { DropdownMenu, useTranslation } from "@dxos/react-ui";
71
- var ColumnActionsMenu = ({ model, modals }) => {
72
- var _effect = _useSignals();
73
- try {
74
- const { t } = useTranslation(translationKey);
75
- const state = modals.state.value;
76
- if (state?.type !== "column") {
77
- return null;
78
- }
79
- const currentSort = model.sorting?.sorting;
80
- const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
81
- return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
82
- modal: false,
83
- open: true,
84
- onOpenChange: modals.close
85
- }, /* @__PURE__ */ React.createElement(DropdownMenu.VirtualTrigger, {
86
- virtualRef: modals.trigger
87
- }), /* @__PURE__ */ React.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
88
- "data-testid": "column-sort-descending",
89
- onClick: () => model.sorting?.setSort(state.fieldId, "desc")
90
- }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
91
- "data-testid": "column-sort-ascending",
92
- onClick: () => model.sorting?.setSort(state.fieldId, "asc")
93
- }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
94
- "data-testid": "column-clear-sort",
95
- onClick: () => model.sorting?.clearSort()
96
- }, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
97
- "data-testid": "column-delete",
98
- onClick: () => model.deleteColumn(state.fieldId)
99
- }, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
100
- "data-testid": "column-settings",
101
- onClick: () => modals.openColumnSettings()
102
- }, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
103
- } finally {
104
- _effect.f();
105
- }
106
- };
107
-
108
- // src/components/Table/ColumnSettings.tsx
109
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
110
- import React2, { useCallback, useEffect, useMemo, useState } from "react";
111
- import { Popover } from "@dxos/react-ui";
112
- import { FieldEditor } from "@dxos/react-ui-form";
113
- var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
114
- var _effect = _useSignals2();
115
- try {
116
- const [newField, setNewField] = useState();
117
- const state = modals.state.value;
118
- useEffect(() => {
119
- if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
120
- setNewField(model.projection.createFieldProjection());
121
- requestAnimationFrame(() => {
122
- onNewColumn();
123
- });
124
- } else {
125
- setNewField(void 0);
126
- }
127
- }, [
128
- model?.projection,
129
- state
130
- ]);
131
- const existingField = useMemo(() => {
132
- if (state?.type === "columnSettings") {
133
- const { mode } = state;
134
- if (mode.type === "edit") {
135
- return model?.projection?.fields.find((f) => f.id === mode.fieldId);
136
- }
137
- }
138
- return void 0;
139
- }, [
140
- model?.projection?.fields,
141
- state
142
- ]);
143
- const field = existingField ?? newField;
144
- const handleSave = useCallback(() => {
145
- modals.close();
146
- }, [
147
- modals
148
- ]);
149
- const handleCancel = useCallback(() => {
150
- if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
151
- model?.projection.deleteFieldProjection(newField.id);
152
- }
153
- }, [
154
- model?.projection,
155
- state,
156
- newField
157
- ]);
158
- if (!model?.projection || !field) {
159
- return null;
160
- }
161
- return /* @__PURE__ */ React2.createElement(Popover.Root, {
162
- modal: false,
163
- open: state?.type === "columnSettings"
164
- }, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
165
- virtualRef: modals.trigger
166
- }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
167
- classNames: "md:is-64"
168
- }, /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
169
- projection: model.projection,
170
- field,
171
- registry,
172
- onSave: handleSave,
173
- onCancel: handleCancel
174
- })), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))));
175
- } finally {
176
- _effect.f();
177
- }
178
- };
179
-
180
- // src/components/Table/CreateRefPanel.tsx
181
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
182
- import { Schema } from "effect";
183
- import React3, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
184
- import { live } from "@dxos/live-object";
185
- import { getSpace } from "@dxos/react-client/echo";
186
- import { Popover as Popover2 } from "@dxos/react-ui";
187
- import { Form } from "@dxos/react-ui-form";
188
- import { useGridContext } from "@dxos/react-ui-grid";
189
- var CreateRefPanel = ({ model, modals, __gridScope }) => {
190
- var _effect = _useSignals3();
191
- try {
192
- const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
193
- const space = model && getSpace(model?.view);
194
- const state = modals.state.value;
195
- const schema = useMemo2(() => {
196
- if (!space || state?.type !== "createRefPanel") {
197
- return;
198
- }
199
- const [schema2] = space.db.schemaRegistry.query({
200
- typename: state.typename
201
- }).runSync();
202
- if (schema2) {
203
- const omit = Schema.omit("id");
204
- return omit(schema2);
205
- }
206
- }, [
207
- space,
208
- state
209
- ]);
210
- const handleSave = useCallback2((values) => {
211
- if (!model || !space || state?.type !== "createRefPanel") {
212
- return;
213
- }
214
- const [schema2] = space.db.schemaRegistry.query({
215
- typename: state.typename
216
- }).runSync();
217
- if (schema2) {
218
- const obj = space.db.add(live(schema2, values));
219
- state.onCreate?.(obj);
220
- }
221
- void modals.close();
222
- }, [
223
- modals,
224
- space,
225
- state
226
- ]);
227
- const handleCancel = useCallback2(() => {
228
- if (model) {
229
- modals.close();
230
- }
231
- }, [
232
- modals
233
- ]);
234
- if (!model?.projection) {
235
- return null;
236
- }
237
- return /* @__PURE__ */ React3.createElement(Popover2.Root, {
238
- modal: false,
239
- open: state?.type === "createRefPanel" && !!schema,
240
- onOpenChange: (nextOpen) => {
241
- if (model && !nextOpen) {
242
- return modals.close();
243
- }
244
- }
245
- }, /* @__PURE__ */ React3.createElement(Popover2.VirtualTrigger, {
246
- virtualRef: modals.trigger
247
- }), /* @__PURE__ */ React3.createElement(Popover2.Portal, null, /* @__PURE__ */ React3.createElement(Popover2.Content, {
248
- classNames: "md:is-64",
249
- "data-grid": gridId
250
- }, /* @__PURE__ */ React3.createElement(Popover2.Viewport, null, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React3.createElement(Form, {
251
- schema,
252
- values: state.initialValues ?? {},
253
- onSave: handleSave,
254
- onCancel: handleCancel
255
- })), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null))));
256
- } finally {
257
- _effect.f();
258
- }
259
- };
260
-
261
- // src/components/Table/RowActionsMenu.tsx
262
- import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
263
- import React4 from "react";
264
- import { DropdownMenu as DropdownMenu2, useTranslation as useTranslation2 } from "@dxos/react-ui";
265
- var RowActionsMenu = ({ model, modals }) => {
266
- var _effect = _useSignals4();
267
- try {
268
- const { t } = useTranslation2(translationKey);
269
- const hasSelection = model.selection.hasSelection.value;
270
- const state = modals.state.value;
271
- if (state?.type !== "row") {
272
- return null;
273
- }
274
- return /* @__PURE__ */ React4.createElement(DropdownMenu2.Root, {
275
- modal: false,
276
- open: true,
277
- onOpenChange: modals.close
278
- }, /* @__PURE__ */ React4.createElement(DropdownMenu2.VirtualTrigger, {
279
- virtualRef: modals.trigger
280
- }), /* @__PURE__ */ React4.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu2.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
281
- "data-testid": "row-menu-delete",
282
- onClick: () => model.deleteRow(state.rowIndex)
283
- }, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
284
- key: action.id,
285
- "data-testid": `row-action-${action.id}`,
286
- onClick: () => {
287
- modals.close();
288
- model.handleRowAction(action.id, state.rowIndex);
289
- }
290
- }, t(action.translationKey)))), /* @__PURE__ */ React4.createElement(DropdownMenu2.Arrow, null)));
291
- } finally {
292
- _effect.f();
293
- }
294
- };
295
-
296
67
  // src/components/TableCellEditor/TableCellEditor.tsx
297
- import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
298
- import React7, { useCallback as useCallback4, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef2, useState as useState3 } from "react";
68
+ import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
69
+ import React3, { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
299
70
  import { FormatEnum, TypeEnum } from "@dxos/echo-schema";
300
71
  import { invariant as invariant2 } from "@dxos/invariant";
301
72
  import { useThemeContext } from "@dxos/react-ui";
302
73
  import { createMarkdownExtensions } from "@dxos/react-ui-editor";
303
- import { cellQuery, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext4, GridCellEditor } from "@dxos/react-ui-grid";
304
- import { tagPicker, createLinks } from "@dxos/react-ui-tag-picker";
74
+ import { GridCellEditor, cellQuery, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
75
+ import { createLinks, tagPicker } from "@dxos/react-ui-tag-picker";
305
76
 
306
77
  // src/components/TableCellEditor/CellValidationMessage.tsx
307
- import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
308
- import React5 from "react";
309
- import { useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
78
+ import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
79
+ import React from "react";
80
+ import { useGridContext } from "@dxos/react-ui-grid";
310
81
  var CellValidationMessage = ({ validationError, variant = "error", __gridScope }) => {
311
- var _effect = _useSignals5();
82
+ var _effect = _useSignals();
312
83
  try {
313
- const { editing, editBox: box } = useGridContext2("GridSheetCellEditor", __gridScope);
84
+ const { editing, editBox: box } = useGridContext("GridSheetCellEditor", __gridScope);
314
85
  if (!editing || !validationError) {
315
86
  return null;
316
87
  }
317
88
  const bgClass = variant === "error" ? "bg-errorSurface" : "bg-warningSurface";
318
89
  const textClass = variant === "error" ? "text-errorSurfaceText" : "text-warningSurfaceText";
319
- return /* @__PURE__ */ React5.createElement("div", {
90
+ return /* @__PURE__ */ React.createElement("div", {
320
91
  role: "none",
321
92
  className: `absolute ${bgClass} ${textClass} rounded-bs-sm text-xs p-1`,
322
93
  style: {
@@ -334,23 +105,62 @@ var CellValidationMessage = ({ validationError, variant = "error", __gridScope }
334
105
  }
335
106
  };
336
107
 
108
+ // src/components/TableCellEditor/extension.ts
109
+ import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
110
+ import { EditorView } from "@codemirror/view";
111
+ var completion = ({ debug, onQuery, onMatch }) => {
112
+ return [
113
+ EditorView.theme({
114
+ ".cm-completionDialog": {
115
+ width: "var(--dx-gridCellWidth)"
116
+ }
117
+ }),
118
+ autocompletion({
119
+ icons: false,
120
+ activateOnTyping: true,
121
+ closeOnBlur: !debug,
122
+ override: [
123
+ async (context) => {
124
+ const text = context.state.doc.toString();
125
+ return {
126
+ from: 0,
127
+ options: await onQuery(text)
128
+ };
129
+ }
130
+ ],
131
+ // TODO(burdon): Consts from grid (to line-up with grid).
132
+ tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
133
+ optionClass: () => "flex h-[33px] items-center"
134
+ }),
135
+ // Check for accepted completion metadata in the transaction.
136
+ EditorView.updateListener.of((update) => {
137
+ update.transactions.forEach((tr) => {
138
+ const completion2 = tr.annotation(pickedCompletion);
139
+ if (completion2) {
140
+ onMatch(completion2.data);
141
+ }
142
+ });
143
+ })
144
+ ];
145
+ };
146
+
337
147
  // src/components/TableCellEditor/FormCellEditor.tsx
338
- import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
339
- import React6, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useRef, useState as useState2 } from "react";
148
+ import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
149
+ import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
340
150
  import { getSnapshot } from "@dxos/echo-schema";
341
151
  import { invariant } from "@dxos/invariant";
342
- import { Popover as Popover3 } from "@dxos/react-ui";
343
- import { Form as Form2 } from "@dxos/react-ui-form";
344
- import { parseCellIndex, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
152
+ import { Popover } from "@dxos/react-ui";
153
+ import { Form } from "@dxos/react-ui-form";
154
+ import { parseCellIndex, useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
345
155
  import { getDeep, setDeep } from "@dxos/util";
346
156
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
347
157
  var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) => {
348
- var _effect = _useSignals6();
158
+ var _effect = _useSignals2();
349
159
  try {
350
- const { editing: contextEditing, setEditing } = useGridContext3("ArrayEditor", __gridScope);
351
- const [editing, setLocalEditing] = useState2(false);
160
+ const { editing: contextEditing, setEditing } = useGridContext2("ArrayEditor", __gridScope);
161
+ const [editing, setLocalEditing] = useState(false);
352
162
  const anchorRef = useRef(null);
353
- useEffect2(() => {
163
+ useEffect(() => {
354
164
  if (contextEditing && contextEditing.cellElement) {
355
165
  anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
356
166
  setLocalEditing(true);
@@ -361,7 +171,7 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
361
171
  }, [
362
172
  contextEditing
363
173
  ]);
364
- const narrowedSchema = useMemo3(() => {
174
+ const narrowedSchema = useMemo(() => {
365
175
  if (!schema) {
366
176
  return void 0;
367
177
  }
@@ -372,7 +182,7 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
372
182
  JSON.stringify(schema),
373
183
  fieldProjection.field.path
374
184
  ]);
375
- const originalRow = useMemo3(() => {
185
+ const originalRow = useMemo(() => {
376
186
  if (model && contextEditing) {
377
187
  const cell = parseCellIndex(contextEditing.index);
378
188
  const row = model.getRowAt(cell.row);
@@ -392,14 +202,14 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
392
202
  model,
393
203
  contextEditing
394
204
  ]);
395
- const formValues = useMemo3(() => {
205
+ const formValues = useMemo(() => {
396
206
  if (originalRow) {
397
207
  return getSnapshot(originalRow);
398
208
  }
399
209
  }, [
400
210
  originalRow
401
211
  ]);
402
- const handleSave = useCallback3((values) => {
212
+ const handleSave = useCallback((values) => {
403
213
  const path = fieldProjection.field.path;
404
214
  const value = getDeep(values, [
405
215
  path
@@ -412,73 +222,34 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
412
222
  onSave?.();
413
223
  }, [
414
224
  fieldProjection.field.path,
415
- originalRow
416
- ]);
417
- const handleOpenChange = useCallback3((nextOpen) => {
418
- if (nextOpen === false) {
419
- setEditing(null);
420
- onSave?.();
421
- }
422
- setLocalEditing(nextOpen);
423
- }, []);
424
- if (!editing) {
425
- return null;
426
- }
427
- return /* @__PURE__ */ React6.createElement(Popover3.Root, {
428
- open: editing,
429
- onOpenChange: handleOpenChange
430
- }, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
431
- virtualRef: anchorRef
432
- }), /* @__PURE__ */ React6.createElement(Popover3.Content, {
433
- tabIndex: -1,
434
- classNames: "popover-card-width density-fine"
435
- }, /* @__PURE__ */ React6.createElement(Popover3.Arrow, null), /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, /* @__PURE__ */ React6.createElement(Form2, {
436
- values: formValues,
437
- schema: narrowedSchema,
438
- onSave: handleSave
439
- }))));
440
- } finally {
441
- _effect.f();
442
- }
443
- };
444
-
445
- // src/components/TableCellEditor/extension.ts
446
- import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
447
- import { EditorView } from "@codemirror/view";
448
- var completion = ({ debug, onQuery, onMatch }) => {
449
- return [
450
- EditorView.theme({
451
- ".cm-completionDialog": {
452
- width: "var(--dx-gridCellWidth)"
453
- }
454
- }),
455
- autocompletion({
456
- icons: false,
457
- activateOnTyping: true,
458
- closeOnBlur: !debug,
459
- override: [
460
- async (context) => {
461
- const text = context.state.doc.toString();
462
- return {
463
- from: 0,
464
- options: await onQuery(text)
465
- };
466
- }
467
- ],
468
- // TODO(burdon): Consts from grid (to line-up with grid).
469
- tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
470
- optionClass: () => "flex h-[33px] items-center"
471
- }),
472
- // Check for accepted completion metadata in the transaction.
473
- EditorView.updateListener.of((update) => {
474
- update.transactions.forEach((tr) => {
475
- const completion2 = tr.annotation(pickedCompletion);
476
- if (completion2) {
477
- onMatch(completion2.data);
478
- }
479
- });
480
- })
481
- ];
225
+ originalRow
226
+ ]);
227
+ const handleOpenChange = useCallback((nextOpen) => {
228
+ if (nextOpen === false) {
229
+ setEditing(null);
230
+ onSave?.();
231
+ }
232
+ setLocalEditing(nextOpen);
233
+ }, []);
234
+ if (!editing) {
235
+ return null;
236
+ }
237
+ return /* @__PURE__ */ React2.createElement(Popover.Root, {
238
+ open: editing,
239
+ onOpenChange: handleOpenChange
240
+ }, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
241
+ virtualRef: anchorRef
242
+ }), /* @__PURE__ */ React2.createElement(Popover.Content, {
243
+ tabIndex: -1,
244
+ classNames: "popover-card-width density-fine"
245
+ }, /* @__PURE__ */ React2.createElement(Popover.Arrow, null), /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(Form, {
246
+ values: formValues,
247
+ schema: narrowedSchema,
248
+ onSave: handleSave
249
+ }))));
250
+ } finally {
251
+ _effect.f();
252
+ }
482
253
  };
483
254
 
484
255
  // src/components/TableCellEditor/TableCellEditor.tsx
@@ -490,10 +261,10 @@ var createOption = (text) => ({
490
261
  });
491
262
  var isCreateOption = (data) => typeof data === "object" && data[newValue];
492
263
  var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQuery, __gridScope }) => {
493
- var _effect = _useSignals7();
264
+ var _effect = _useSignals3();
494
265
  try {
495
- const { editing } = useGridContext4("TableValueEditor", __gridScope);
496
- const fieldProjection = useMemo4(() => {
266
+ const { editing } = useGridContext3("TableValueEditor", __gridScope);
267
+ const fieldProjection = useMemo2(() => {
497
268
  if (!model || !editing) {
498
269
  return;
499
270
  }
@@ -515,7 +286,7 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQue
515
286
  editing
516
287
  ]);
517
288
  if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum.SingleSelect) {
518
- return /* @__PURE__ */ React7.createElement(FormCellEditor, {
289
+ return /* @__PURE__ */ React3.createElement(FormCellEditor, {
519
290
  fieldProjection,
520
291
  model,
521
292
  schema,
@@ -523,7 +294,7 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQue
523
294
  onSave
524
295
  });
525
296
  }
526
- return /* @__PURE__ */ React7.createElement(TableCellEditor, {
297
+ return /* @__PURE__ */ React3.createElement(TableCellEditor, {
527
298
  model,
528
299
  modals,
529
300
  onEnter,
@@ -542,14 +313,14 @@ var editorSlots = {
542
313
  }
543
314
  };
544
315
  var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gridScope }) => {
545
- var _effect = _useSignals7();
316
+ var _effect = _useSignals3();
546
317
  try {
547
- const { id: gridId, editing, setEditing } = useGridContext4("TableCellEditor", __gridScope);
318
+ const { id: gridId, editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
548
319
  const suppressNextBlur = useRef2(false);
549
320
  const { themeMode } = useThemeContext();
550
- const [_validationError, setValidationError] = useState3(null);
551
- const [_validationVariant, setValidationVariant] = useState3("error");
552
- const fieldProjection = useMemo4(() => {
321
+ const [validationError, setValidationError] = useState2(null);
322
+ const [validationVariant, setValidationVariant] = useState2("error");
323
+ const fieldProjection = useMemo2(() => {
553
324
  if (!model || !editing) {
554
325
  return;
555
326
  }
@@ -570,7 +341,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
570
341
  model,
571
342
  editing
572
343
  ]);
573
- useEffect3(() => {
344
+ useEffect2(() => {
574
345
  if (!model || !editing || !fieldProjection) {
575
346
  setValidationError(null);
576
347
  return;
@@ -584,9 +355,9 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
584
355
  const draftRows = model.draftRows.value;
585
356
  if (row >= 0 && row < draftRows.length) {
586
357
  const draftRow = draftRows[row];
587
- const validationError = draftRow.validationErrors?.find((error) => error.path === field.path);
588
- if (validationError) {
589
- setValidationError(validationError.message);
358
+ const validationError2 = draftRow.validationErrors?.find((error) => error.path === field.path);
359
+ if (validationError2) {
360
+ setValidationError(validationError2.message);
590
361
  setValidationVariant("warning");
591
362
  }
592
363
  }
@@ -601,7 +372,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
601
372
  editing,
602
373
  fieldProjection
603
374
  ]);
604
- const handleEnter = useCallback4(async (value) => {
375
+ const handleEnter = useCallback2(async (value) => {
605
376
  if (!model || !editing) {
606
377
  return;
607
378
  }
@@ -625,7 +396,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
625
396
  onFocus,
626
397
  setEditing
627
398
  ]);
628
- const handleBlur = useCallback4(async (value) => {
399
+ const handleBlur = useCallback2(async (value) => {
629
400
  if (!model || !editing) {
630
401
  return;
631
402
  }
@@ -636,7 +407,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
636
407
  model,
637
408
  editing
638
409
  ]);
639
- const handleClose = useCallback4(async (value, event) => {
410
+ const handleClose = useCallback2(async (value, event) => {
640
411
  if (!model || !editing || !fieldProjection) {
641
412
  return;
642
413
  }
@@ -650,7 +421,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
650
421
  onSave?.();
651
422
  onEnter?.(cell);
652
423
  if (event && onFocus) {
653
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
424
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
654
425
  }
655
426
  } else {
656
427
  setValidationError(result.error);
@@ -673,7 +444,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
673
444
  setEditing,
674
445
  onSave
675
446
  ]);
676
- const extension = useMemo4(() => {
447
+ const extension = useMemo2(() => {
677
448
  if (!fieldProjection) {
678
449
  return [];
679
450
  }
@@ -754,7 +525,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
754
525
  handleClose,
755
526
  themeMode
756
527
  ]);
757
- const getCellContent = useCallback4(() => {
528
+ const getCellContent = useCallback2(() => {
758
529
  if (model && editing) {
759
530
  const cell = parseCellIndex2(editing.index);
760
531
  const { col } = cell;
@@ -800,11 +571,11 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
800
571
  model,
801
572
  editing
802
573
  ]);
803
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(CellValidationMessage, {
804
- validationError: _validationError,
805
- variant: _validationVariant,
574
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(CellValidationMessage, {
575
+ validationError,
576
+ variant: validationVariant,
806
577
  __gridScope
807
- }), /* @__PURE__ */ React7.createElement(GridCellEditor, {
578
+ }), /* @__PURE__ */ React3.createElement(GridCellEditor, {
808
579
  extension,
809
580
  getCellContent,
810
581
  onBlur: handleBlur,
@@ -839,6 +610,235 @@ var determineNavigationDelta = ({ key, shift }) => {
839
610
  return shift ? -1 : 1;
840
611
  };
841
612
 
613
+ // src/components/Table/ColumnActionsMenu.tsx
614
+ import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
615
+ import React4 from "react";
616
+ import { DropdownMenu, useTranslation } from "@dxos/react-ui";
617
+ var ColumnActionsMenu = ({ model, modals }) => {
618
+ var _effect = _useSignals4();
619
+ try {
620
+ const { t } = useTranslation(translationKey);
621
+ const state = modals.state.value;
622
+ if (state?.type !== "column") {
623
+ return null;
624
+ }
625
+ const currentSort = model.sorting?.sorting;
626
+ const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
627
+ return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
628
+ modal: false,
629
+ open: true,
630
+ onOpenChange: modals.close
631
+ }, /* @__PURE__ */ React4.createElement(DropdownMenu.VirtualTrigger, {
632
+ virtualRef: modals.trigger
633
+ }), /* @__PURE__ */ React4.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
634
+ "data-testid": "column-sort-descending",
635
+ onClick: () => model.sorting?.setSort(state.fieldId, "desc")
636
+ }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
637
+ "data-testid": "column-sort-ascending",
638
+ onClick: () => model.sorting?.setSort(state.fieldId, "asc")
639
+ }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
640
+ "data-testid": "column-clear-sort",
641
+ onClick: () => model.sorting?.clearSort()
642
+ }, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
643
+ "data-testid": "column-delete",
644
+ onClick: () => model.deleteColumn(state.fieldId)
645
+ }, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
646
+ "data-testid": "column-settings",
647
+ onClick: () => modals.openColumnSettings()
648
+ }, t("column action settings"))), /* @__PURE__ */ React4.createElement(DropdownMenu.Arrow, null))));
649
+ } finally {
650
+ _effect.f();
651
+ }
652
+ };
653
+
654
+ // src/components/Table/ColumnSettings.tsx
655
+ import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
656
+ import React5, { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
657
+ import { Popover as Popover2 } from "@dxos/react-ui";
658
+ import { FieldEditor } from "@dxos/react-ui-form";
659
+ var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
660
+ var _effect = _useSignals5();
661
+ try {
662
+ const [newField, setNewField] = useState3();
663
+ const state = modals.state.value;
664
+ useEffect3(() => {
665
+ if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
666
+ setNewField(model.projection.createFieldProjection());
667
+ requestAnimationFrame(() => {
668
+ onNewColumn();
669
+ });
670
+ } else {
671
+ setNewField(void 0);
672
+ }
673
+ }, [
674
+ model?.projection,
675
+ state
676
+ ]);
677
+ const existingField = useMemo3(() => {
678
+ if (state?.type === "columnSettings") {
679
+ const { mode } = state;
680
+ if (mode.type === "edit") {
681
+ return model?.projection?.fields.find((f) => f.id === mode.fieldId);
682
+ }
683
+ }
684
+ return void 0;
685
+ }, [
686
+ model?.projection?.fields,
687
+ state
688
+ ]);
689
+ const field = existingField ?? newField;
690
+ const handleSave = useCallback3(() => {
691
+ modals.close();
692
+ }, [
693
+ modals
694
+ ]);
695
+ const handleCancel = useCallback3(() => {
696
+ if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
697
+ model?.projection.deleteFieldProjection(newField.id);
698
+ }
699
+ }, [
700
+ model?.projection,
701
+ state,
702
+ newField
703
+ ]);
704
+ if (!model?.projection || !field) {
705
+ return null;
706
+ }
707
+ return /* @__PURE__ */ React5.createElement(Popover2.Root, {
708
+ modal: false,
709
+ open: state?.type === "columnSettings"
710
+ }, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
711
+ virtualRef: modals.trigger
712
+ }), /* @__PURE__ */ React5.createElement(Popover2.Portal, null, /* @__PURE__ */ React5.createElement(Popover2.Content, {
713
+ classNames: "md:is-64"
714
+ }, /* @__PURE__ */ React5.createElement(Popover2.Viewport, null, /* @__PURE__ */ React5.createElement(FieldEditor, {
715
+ projection: model.projection,
716
+ field,
717
+ registry,
718
+ onSave: handleSave,
719
+ onCancel: handleCancel
720
+ })), /* @__PURE__ */ React5.createElement(Popover2.Arrow, null))));
721
+ } finally {
722
+ _effect.f();
723
+ }
724
+ };
725
+
726
+ // src/components/Table/CreateRefPanel.tsx
727
+ import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
728
+ import { Schema } from "effect";
729
+ import React6, { useCallback as useCallback4, useMemo as useMemo4 } from "react";
730
+ import { live } from "@dxos/live-object";
731
+ import { getSpace } from "@dxos/react-client/echo";
732
+ import { Popover as Popover3 } from "@dxos/react-ui";
733
+ import { Form as Form2 } from "@dxos/react-ui-form";
734
+ import { useGridContext as useGridContext4 } from "@dxos/react-ui-grid";
735
+ var CreateRefPanel = ({ model, modals, __gridScope }) => {
736
+ var _effect = _useSignals6();
737
+ try {
738
+ const { id: gridId } = useGridContext4("TableCellEditor", __gridScope);
739
+ const space = model && getSpace(model?.view);
740
+ const state = modals.state.value;
741
+ const schema = useMemo4(() => {
742
+ if (!space || state?.type !== "createRefPanel") {
743
+ return;
744
+ }
745
+ const [schema2] = space.db.schemaRegistry.query({
746
+ typename: state.typename
747
+ }).runSync();
748
+ if (schema2) {
749
+ const omit = Schema.omit("id");
750
+ return omit(schema2);
751
+ }
752
+ }, [
753
+ space,
754
+ state
755
+ ]);
756
+ const handleSave = useCallback4((values) => {
757
+ if (!model || !space || state?.type !== "createRefPanel") {
758
+ return;
759
+ }
760
+ const [schema2] = space.db.schemaRegistry.query({
761
+ typename: state.typename
762
+ }).runSync();
763
+ if (schema2) {
764
+ const obj = space.db.add(live(schema2, values));
765
+ state.onCreate?.(obj);
766
+ }
767
+ void modals.close();
768
+ }, [
769
+ modals,
770
+ space,
771
+ state
772
+ ]);
773
+ const handleCancel = useCallback4(() => {
774
+ if (model) {
775
+ modals.close();
776
+ }
777
+ }, [
778
+ modals
779
+ ]);
780
+ if (!model?.projection) {
781
+ return null;
782
+ }
783
+ return /* @__PURE__ */ React6.createElement(Popover3.Root, {
784
+ modal: false,
785
+ open: state?.type === "createRefPanel" && !!schema,
786
+ onOpenChange: (nextOpen) => {
787
+ if (model && !nextOpen) {
788
+ return modals.close();
789
+ }
790
+ }
791
+ }, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
792
+ virtualRef: modals.trigger
793
+ }), /* @__PURE__ */ React6.createElement(Popover3.Portal, null, /* @__PURE__ */ React6.createElement(Popover3.Content, {
794
+ classNames: "md:is-64",
795
+ "data-grid": gridId
796
+ }, /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React6.createElement(Form2, {
797
+ schema,
798
+ values: state.initialValues ?? {},
799
+ onSave: handleSave,
800
+ onCancel: handleCancel
801
+ })), /* @__PURE__ */ React6.createElement(Popover3.Arrow, null))));
802
+ } finally {
803
+ _effect.f();
804
+ }
805
+ };
806
+
807
+ // src/components/Table/RowActionsMenu.tsx
808
+ import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
809
+ import React7 from "react";
810
+ import { DropdownMenu as DropdownMenu2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
811
+ var RowActionsMenu = ({ model, modals }) => {
812
+ var _effect = _useSignals7();
813
+ try {
814
+ const { t } = useTranslation2(translationKey);
815
+ const hasSelection = model.selection.hasSelection.value;
816
+ const state = modals.state.value;
817
+ if (state?.type !== "row") {
818
+ return null;
819
+ }
820
+ return /* @__PURE__ */ React7.createElement(DropdownMenu2.Root, {
821
+ modal: false,
822
+ open: true,
823
+ onOpenChange: modals.close
824
+ }, /* @__PURE__ */ React7.createElement(DropdownMenu2.VirtualTrigger, {
825
+ virtualRef: modals.trigger
826
+ }), /* @__PURE__ */ React7.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React7.createElement(DropdownMenu2.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
827
+ "data-testid": "row-menu-delete",
828
+ onClick: () => model.deleteRow(state.rowIndex)
829
+ }, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
830
+ key: action.id,
831
+ "data-testid": `row-action-${action.id}`,
832
+ onClick: () => {
833
+ modals.close();
834
+ model.handleRowAction(action.id, state.rowIndex);
835
+ }
836
+ }, toLocalizedString(action.label, t)))), /* @__PURE__ */ React7.createElement(DropdownMenu2.Arrow, null)));
837
+ } finally {
838
+ _effect.f();
839
+ }
840
+ };
841
+
842
842
  // src/components/Table/Table.tsx
843
843
  var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
844
844
  var TableRoot = ({ children, role = "article" }) => {
@@ -904,12 +904,35 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
904
904
  dxGrid.updateCells(true);
905
905
  dxGrid.requestUpdate();
906
906
  }
907
+ },
908
+ focusDraft: () => {
909
+ requestAnimationFrame(() => {
910
+ dxGrid.setFocus({
911
+ plane: "frozenRowsEnd",
912
+ col: 0,
913
+ row: 0
914
+ });
915
+ dxGrid.refocus();
916
+ });
907
917
  }
908
918
  };
909
919
  }, [
910
920
  presentation,
911
921
  dxGrid
912
922
  ]);
923
+ const handleSaveDraftRow = useCallback5((rowIndex = 0) => {
924
+ if (model && dxGrid) {
925
+ const didCommitSuccessfully = model.commitDraftRow(rowIndex);
926
+ if (didCommitSuccessfully) {
927
+ requestAnimationFrame(() => {
928
+ dxGrid.scrollToEndRow();
929
+ });
930
+ }
931
+ }
932
+ }, [
933
+ model,
934
+ dxGrid
935
+ ]);
913
936
  const handleGridClick = useCallback5((event) => {
914
937
  const rowIndex = safeParseInt(event.target.closest("[aria-rowindex]")?.ariaRowIndex ?? "");
915
938
  if (rowIndex != null) {
@@ -951,14 +974,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
951
974
  break;
952
975
  }
953
976
  case "saveDraftRow": {
954
- if (model) {
955
- const didCommitSuccessfully = model.commitDraftRow(data.rowIndex);
956
- if (dxGrid && didCommitSuccessfully) {
957
- requestAnimationFrame(() => {
958
- dxGrid.scrollToEndRow();
959
- });
960
- }
961
- }
977
+ handleSaveDraftRow();
962
978
  break;
963
979
  }
964
980
  }
@@ -997,29 +1013,32 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
997
1013
  modals,
998
1014
  dxGrid
999
1015
  ]);
1000
- const handleFocus = useCallback5((increment, delta) => {
1001
- if (dxGrid) {
1002
- dxGrid.refocus(increment, delta);
1003
- }
1004
- }, [
1005
- dxGrid
1006
- ]);
1007
- const handleEnter = useCallback5((cell) => {
1008
- if (!model?.features.dataEditable) {
1009
- return;
1010
- }
1011
- if (model && cell.row === model.getRowCount() - 1) {
1012
- model.insertRow();
1013
- if (dxGrid) {
1014
- requestAnimationFrame(() => {
1015
- dxGrid?.scrollToRow(cell.row + 1);
1016
- dxGrid?.refocus("row", 1);
1016
+ const handleFocus = useCallback5((increment, delta, cell) => {
1017
+ if (dxGrid && model) {
1018
+ if (cell?.plane === "grid" && cell?.row >= model.getRowCount() - 1) {
1019
+ if (draftRowCount < 1) {
1020
+ model.insertRow();
1021
+ }
1022
+ dxGrid.setFocus({
1023
+ plane: "frozenRowsEnd",
1024
+ col: 0,
1025
+ row: 0
1026
+ });
1027
+ } else if (cell?.plane === "frozenRowsEnd" && increment === "row") {
1028
+ handleSaveDraftRow(cell.row);
1029
+ model.insertRow();
1030
+ dxGrid.setFocus({
1031
+ plane: "frozenRowsEnd",
1032
+ col: 0,
1033
+ row: 0
1017
1034
  });
1035
+ } else {
1036
+ dxGrid.refocus(increment, delta);
1018
1037
  }
1019
1038
  }
1020
1039
  }, [
1021
- model,
1022
- dxGrid
1040
+ dxGrid,
1041
+ model
1023
1042
  ]);
1024
1043
  const handleKeyDown = useCallback5((event) => {
1025
1044
  if (!model?.features.dataEditable) {
@@ -1032,7 +1051,11 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1032
1051
  switch (event.key) {
1033
1052
  case "Backspace":
1034
1053
  case "Delete": {
1035
- model.setCellData(cell, void 0);
1054
+ try {
1055
+ model.setCellData(cell, void 0);
1056
+ event.preventDefault();
1057
+ } catch {
1058
+ }
1036
1059
  break;
1037
1060
  }
1038
1061
  }
@@ -1069,7 +1092,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1069
1092
  const space = getSpace2(model.view);
1070
1093
  invariant3(space, void 0, {
1071
1094
  F: __dxlog_file3,
1072
- L: 325,
1095
+ L: 336,
1073
1096
  S: void 0,
1074
1097
  A: [
1075
1098
  "space",
@@ -1114,6 +1137,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1114
1137
  ]);
1115
1138
  const handleSave = useCallback5(() => {
1116
1139
  dxGrid?.updateCells(true);
1140
+ dxGrid?.requestUpdate();
1117
1141
  }, [
1118
1142
  dxGrid
1119
1143
  ]);
@@ -1129,7 +1153,6 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1129
1153
  model,
1130
1154
  modals,
1131
1155
  schema,
1132
- onEnter: handleEnter,
1133
1156
  onFocus: handleFocus,
1134
1157
  onQuery: handleQuery,
1135
1158
  onSave: handleSave
@@ -1142,7 +1165,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1142
1165
  overscroll: "trap",
1143
1166
  onAxisResize: handleAxisResize,
1144
1167
  onClick: handleGridClick,
1145
- onKeyDown: handleKeyDown,
1168
+ onKeyDownCapture: handleKeyDown,
1146
1169
  onWheelCapture: handleWheel,
1147
1170
  ref: setDxGrid
1148
1171
  }), /* @__PURE__ */ React8.createElement(RowActionsMenu, {
@@ -1170,7 +1193,7 @@ var Table = {
1170
1193
 
1171
1194
  // src/components/Table/DynamicTable.tsx
1172
1195
  import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
1173
- import React9, { useRef as useRef3, useMemo as useMemo6, useCallback as useCallback6 } from "react";
1196
+ import React9, { useCallback as useCallback6, useMemo as useMemo6, useRef as useRef3 } from "react";
1174
1197
  import { useDefaultValue } from "@dxos/react-ui";
1175
1198
  import { mx as mx2 } from "@dxos/react-ui-theme";
1176
1199
  var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema: _jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
@@ -1250,7 +1273,7 @@ import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking
1250
1273
  import { Rx } from "@effect-rx/rx-react";
1251
1274
  import React10, { useMemo as useMemo7 } from "react";
1252
1275
  import { live as live2 } from "@dxos/live-object";
1253
- import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
1276
+ import { MenuProvider, ToolbarMenu, createGapSeparator, createMenuAction, useMenuActions } from "@dxos/react-ui-menu";
1254
1277
  import { rxFromSignal } from "@dxos/react-ui-menu";
1255
1278
  var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.make((get) => {
1256
1279
  const add = createMenuAction("add-row", onAdd, {