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