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

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 (120) hide show
  1. package/dist/lib/browser/chunk-63UUF4IG.mjs +66 -0
  2. package/dist/lib/browser/chunk-63UUF4IG.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-5XLSHLOG.mjs → chunk-BBXDTWCX.mjs} +537 -466
  4. package/dist/lib/browser/chunk-BBXDTWCX.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +730 -669
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +9 -6
  9. package/dist/lib/browser/testing/index.mjs.map +3 -3
  10. package/dist/lib/browser/types/index.mjs +3 -3
  11. package/dist/lib/node-esm/chunk-K734DJB7.mjs +67 -0
  12. package/dist/lib/node-esm/chunk-K734DJB7.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-Y66YLSTC.mjs → chunk-RNQDU7IQ.mjs} +537 -466
  14. package/dist/lib/node-esm/chunk-RNQDU7IQ.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +730 -669
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +9 -6
  19. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/types/index.mjs +3 -3
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +1 -1
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +1 -1
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/CreateRefPanel.d.ts +1 -1
  26. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  28. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +50 -2
  29. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  30. package/dist/types/src/components/Table/Relations.stories.d.ts +44 -0
  31. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  32. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  33. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  34. package/dist/types/src/components/Table/Table.d.ts +3 -2
  35. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  36. package/dist/types/src/components/Table/Table.stories.d.ts +42 -3
  37. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  39. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +7 -3
  40. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  41. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +8 -15
  42. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  43. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +39 -3
  44. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  46. package/dist/types/src/hooks/useAddRow.d.ts +2 -1
  47. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  48. package/dist/types/src/hooks/useTableModel.d.ts +1 -1
  49. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  50. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  51. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  52. package/dist/types/src/model/table-model.d.ts +9 -7
  53. package/dist/types/src/model/table-model.d.ts.map +1 -1
  54. package/dist/types/src/model/table-presentation.d.ts +2 -1
  55. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  56. package/dist/types/src/model/table-sorting.d.ts +2 -3
  57. package/dist/types/src/model/table-sorting.d.ts.map +1 -1
  58. package/dist/types/src/testing/useTestTableModel.d.ts +2 -21
  59. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  60. package/dist/types/src/translations.d.ts +2 -2
  61. package/dist/types/src/types/index.d.ts +1 -1
  62. package/dist/types/src/types/index.d.ts.map +1 -1
  63. package/dist/types/src/types/schema.d.ts +24 -4
  64. package/dist/types/src/types/schema.d.ts.map +1 -1
  65. package/dist/types/src/util/dynamic-table.d.ts +2 -2
  66. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  67. package/dist/types/src/util/index.d.ts +0 -1
  68. package/dist/types/src/util/index.d.ts.map +1 -1
  69. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  70. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  71. package/dist/types/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +47 -42
  73. package/src/components/Table/ColumnActionsMenu.tsx +1 -1
  74. package/src/components/Table/ColumnSettings.tsx +1 -1
  75. package/src/components/Table/CreateRefPanel.tsx +25 -8
  76. package/src/components/Table/DynamicTable.stories.tsx +7 -4
  77. package/src/components/Table/DynamicTable.tsx +4 -3
  78. package/src/components/Table/{relations.stories.tsx → Relations.stories.tsx} +40 -23
  79. package/src/components/Table/RowActionsMenu.tsx +3 -3
  80. package/src/components/Table/Table.stories.tsx +39 -28
  81. package/src/components/Table/Table.tsx +138 -112
  82. package/src/components/TableCellEditor/CellValidationMessage.tsx +1 -1
  83. package/src/components/TableCellEditor/FormCellEditor.tsx +143 -42
  84. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +12 -24
  85. package/src/components/TableCellEditor/TableCellEditor.tsx +74 -137
  86. package/src/components/TableToolbar/TableToolbar.tsx +2 -2
  87. package/src/components/testing.ts +1 -1
  88. package/src/hooks/useAddRow.ts +6 -4
  89. package/src/hooks/useTableModel.ts +1 -1
  90. package/src/model/modal-controller.ts +1 -1
  91. package/src/model/selection-model.ts +3 -2
  92. package/src/model/table-model.test.ts +9 -5
  93. package/src/model/table-model.ts +35 -24
  94. package/src/model/table-presentation.test.ts +10 -5
  95. package/src/model/table-presentation.ts +72 -30
  96. package/src/model/table-sorting.ts +16 -7
  97. package/src/playwright/smoke.spec.ts +129 -37
  98. package/src/testing/useTestTableModel.ts +7 -5
  99. package/src/translations.ts +2 -2
  100. package/src/types/index.ts +1 -1
  101. package/src/types/schema.ts +62 -5
  102. package/src/util/dynamic-table.ts +10 -9
  103. package/src/util/index.ts +0 -1
  104. package/src/util/schema.ts +1 -1
  105. package/src/util/table-buttons.ts +4 -3
  106. package/src/util/table-controls.ts +4 -1
  107. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  108. package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
  109. package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +0 -7
  110. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +0 -20
  111. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +0 -7
  112. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  113. package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
  114. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
  115. package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
  116. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
  117. package/dist/types/src/util/table.d.ts +0 -11
  118. package/dist/types/src/util/table.d.ts.map +0 -1
  119. package/src/components/TableCellEditor/extension.ts +0 -61
  120. package/src/util/table.ts +0 -49
@@ -8,7 +8,6 @@ import {
8
8
  TableModel,
9
9
  TablePresentation,
10
10
  cellClassesForRowSelection,
11
- createTable,
12
11
  getBaseSchema,
13
12
  makeDynamicTable,
14
13
  narrowSchema,
@@ -17,8 +16,8 @@ import {
17
16
  touch,
18
17
  useAddRow,
19
18
  useTableModel
20
- } from "./chunk-Y66YLSTC.mjs";
21
- import "./chunk-NXZ4CJYX.mjs";
19
+ } from "./chunk-RNQDU7IQ.mjs";
20
+ import "./chunk-K734DJB7.mjs";
22
21
 
23
22
  // src/translations.ts
24
23
  var translationKey = "react-ui-table";
@@ -30,8 +29,8 @@ var translations = [
30
29
  "create object label": "Create table",
31
30
  "table name placeholder": "Table name",
32
31
  "settings title": "Table settings",
33
- "table schema label": "Schema",
34
- "new schema": "New schema",
32
+ "table schema label": "Record type",
33
+ "new schema": "New record type",
35
34
  "continue label": "Continue",
36
35
  "create stack section label": "Create table",
37
36
  "add row label": "Add row",
@@ -54,270 +53,37 @@ var translations = [
54
53
 
55
54
  // src/components/Table/Table.tsx
56
55
  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";
58
- import { Filter } from "@dxos/echo";
59
- import { getValue } from "@dxos/echo-schema";
60
- import { invariant as invariant3 } from "@dxos/invariant";
61
- import { getSpace as getSpace2 } from "@dxos/react-client/echo";
62
- import { useTranslation as useTranslation3 } from "@dxos/react-ui";
56
+ import React8, { forwardRef, useCallback as useCallback5, useEffect as useEffect3, useImperativeHandle, useMemo as useMemo5, useState as useState4 } from "react";
63
57
  import { useAttention } from "@dxos/react-ui-attention";
64
- import { closestCell, Grid, gridSeparatorInlineEnd, gridSeparatorBlockEnd } from "@dxos/react-ui-grid";
58
+ import { Grid, closestCell, gridSeparatorBlockEnd, gridSeparatorInlineEnd } from "@dxos/react-ui-grid";
59
+ import { DxEditRequest } from "@dxos/react-ui-grid";
65
60
  import { mx } from "@dxos/react-ui-theme";
66
- import { isNotFalsy, safeParseInt } from "@dxos/util";
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
61
 
297
62
  // 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";
63
+ import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
64
+ import { EditorView } from "@codemirror/view";
65
+ import React3, { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
66
+ import { debounce } from "@dxos/async";
300
67
  import { FormatEnum, TypeEnum } from "@dxos/echo-schema";
301
68
  import { invariant as invariant2 } from "@dxos/invariant";
302
- import { useThemeContext } from "@dxos/react-ui";
303
69
  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";
70
+ import { GridCellEditor, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
71
+ import { createLinks, tagPicker } from "@dxos/react-ui-tag-picker";
306
72
 
307
73
  // 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";
74
+ import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
75
+ import React from "react";
76
+ import { useGridContext } from "@dxos/react-ui-grid";
311
77
  var CellValidationMessage = ({ validationError, variant = "error", __gridScope }) => {
312
- var _effect = _useSignals5();
78
+ var _effect = _useSignals();
313
79
  try {
314
- const { editing, editBox: box } = useGridContext2("GridSheetCellEditor", __gridScope);
80
+ const { editing, editBox: box } = useGridContext("GridSheetCellEditor", __gridScope);
315
81
  if (!editing || !validationError) {
316
82
  return null;
317
83
  }
318
84
  const bgClass = variant === "error" ? "bg-errorSurface" : "bg-warningSurface";
319
85
  const textClass = variant === "error" ? "text-errorSurfaceText" : "text-warningSurfaceText";
320
- return /* @__PURE__ */ React5.createElement("div", {
86
+ return /* @__PURE__ */ React.createElement("div", {
321
87
  role: "none",
322
88
  className: `absolute ${bgClass} ${textClass} rounded-bs-sm text-xs p-1`,
323
89
  style: {
@@ -336,71 +102,107 @@ var CellValidationMessage = ({ validationError, variant = "error", __gridScope }
336
102
  };
337
103
 
338
104
  // 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";
341
- import { getSnapshot } from "@dxos/echo-schema";
105
+ import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
106
+ import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
107
+ import { Filter, Obj } from "@dxos/echo";
108
+ import { Ref, getValue } from "@dxos/echo-schema";
342
109
  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";
346
- import { getDeep, setDeep } from "@dxos/util";
110
+ import { getSnapshot } from "@dxos/live-object";
111
+ import { getSpace } from "@dxos/react-client/echo";
112
+ import { Popover } from "@dxos/react-ui";
113
+ import { Form } from "@dxos/react-ui-form";
114
+ import { cellQuery, parseCellIndex, useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
115
+ import { getDeep, isNotFalsy, setDeep } from "@dxos/util";
347
116
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
348
- var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) => {
349
- var _effect = _useSignals6();
117
+ var createOptionLabel = [
118
+ "create new object label",
119
+ {
120
+ ns: translationKey
121
+ }
122
+ ];
123
+ var FormCellEditor = ({ fieldProjection, model, schema, onSave, client, modals, __gridScope, ...formProps }) => {
124
+ var _effect = _useSignals2();
350
125
  try {
351
- const { editing: contextEditing, setEditing } = useGridContext3("ArrayEditor", __gridScope);
352
- const [editing, setLocalEditing] = useState2(false);
126
+ const { editing: contextEditing, setEditing, id: gridId } = useGridContext2("ArrayEditor", __gridScope);
127
+ const [editing, setLocalEditing] = useState(false);
353
128
  const anchorRef = useRef(null);
354
- useEffect2(() => {
355
- if (contextEditing && contextEditing.cellElement) {
356
- anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
357
- setLocalEditing(true);
358
- } else {
359
- anchorRef.current = null;
360
- setLocalEditing(false);
129
+ const getSchema = useCallback((typeAnnotation) => {
130
+ const space = getSpace(model.view);
131
+ invariant(space, void 0, {
132
+ F: __dxlog_file,
133
+ L: 53,
134
+ S: void 0,
135
+ A: [
136
+ "space",
137
+ ""
138
+ ]
139
+ });
140
+ let schema2;
141
+ if (client) {
142
+ schema2 = client.graph.schemaRegistry.getSchema(typeAnnotation.typename);
143
+ }
144
+ if (!schema2) {
145
+ schema2 = space.db.schemaRegistry.getSchema(typeAnnotation.typename);
361
146
  }
147
+ return {
148
+ space,
149
+ schema: schema2
150
+ };
362
151
  }, [
363
- contextEditing
152
+ client,
153
+ model
364
154
  ]);
365
- const narrowedSchema = useMemo3(() => {
366
- if (!schema) {
367
- return void 0;
155
+ const handleQueryRefOptions = useCallback(async (typeAnnotation) => {
156
+ const { schema: schema2, space } = getSchema(typeAnnotation);
157
+ if (model && schema2 && space) {
158
+ const { objects } = await space.db.query(Filter.type(schema2)).run();
159
+ return objects.map((obj) => {
160
+ return {
161
+ dxn: Obj.getDXN(obj),
162
+ label: getValue(obj, fieldProjection.field.referencePath) || obj.id.toString()
163
+ };
164
+ }).filter(isNotFalsy);
368
165
  }
369
- return narrowSchema(schema, [
370
- fieldProjection.field.path
371
- ]);
166
+ return [];
372
167
  }, [
373
- JSON.stringify(schema),
374
- fieldProjection.field.path
168
+ client,
169
+ model
375
170
  ]);
376
- const originalRow = useMemo3(() => {
171
+ const originalRow = useMemo(() => {
377
172
  if (model && contextEditing) {
378
173
  const cell = parseCellIndex(contextEditing.index);
379
- const row = model.getRowAt(cell.row);
380
- invariant(row, void 0, {
381
- F: __dxlog_file,
382
- L: 55,
383
- S: void 0,
384
- A: [
385
- "row",
386
- ""
387
- ]
388
- });
389
- return row;
174
+ if (model.isDraftCell(cell)) {
175
+ const draftRow = model.draftRows.value[cell.row];
176
+ invariant(draftRow, void 0, {
177
+ F: __dxlog_file,
178
+ L: 94,
179
+ S: void 0,
180
+ A: [
181
+ "draftRow",
182
+ ""
183
+ ]
184
+ });
185
+ return draftRow.data;
186
+ } else {
187
+ const row = model.getRowAt(cell.row);
188
+ invariant(row, void 0, {
189
+ F: __dxlog_file,
190
+ L: 98,
191
+ S: void 0,
192
+ A: [
193
+ "row",
194
+ ""
195
+ ]
196
+ });
197
+ return row;
198
+ }
390
199
  }
391
200
  return void 0;
392
201
  }, [
393
202
  model,
394
203
  contextEditing
395
204
  ]);
396
- const formValues = useMemo3(() => {
397
- if (originalRow) {
398
- return getSnapshot(originalRow);
399
- }
400
- }, [
401
- originalRow
402
- ]);
403
- const handleSave = useCallback3((values) => {
205
+ const handleSave = useCallback((values) => {
404
206
  const path = fieldProjection.field.path;
405
207
  const value = getDeep(values, [
406
208
  path
@@ -408,14 +210,74 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
408
210
  setDeep(originalRow, [
409
211
  path
410
212
  ], value);
213
+ contextEditing?.cellElement?.focus();
411
214
  setEditing(null);
412
215
  setLocalEditing(false);
413
216
  onSave?.();
414
217
  }, [
415
218
  fieldProjection.field.path,
219
+ onSave,
220
+ contextEditing,
221
+ originalRow
222
+ ]);
223
+ const handleCreate = useCallback((object) => {
224
+ const ref = Ref.make(object);
225
+ const path = fieldProjection.field.path;
226
+ setDeep(originalRow, [
227
+ path
228
+ ], ref);
229
+ contextEditing?.cellElement?.focus();
230
+ setEditing(null);
231
+ setLocalEditing(false);
232
+ onSave?.();
233
+ }, [
234
+ fieldProjection.field.path,
235
+ onSave,
236
+ contextEditing,
237
+ originalRow
238
+ ]);
239
+ const handleCreateFromQuery = useCallback(async (typeAnnotation, query) => {
240
+ if (model && modals && contextEditing?.index) {
241
+ setLocalEditing(false);
242
+ modals.openCreateRef(typeAnnotation.typename, document.querySelector(cellQuery(contextEditing.index, gridId)), {
243
+ [fieldProjection.field.referencePath]: query
244
+ }, handleCreate);
245
+ }
246
+ }, [
247
+ model,
248
+ modals,
249
+ client,
250
+ contextEditing?.index,
251
+ gridId,
252
+ fieldProjection,
253
+ handleSave
254
+ ]);
255
+ useEffect(() => {
256
+ if (contextEditing && contextEditing.cellElement) {
257
+ anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
258
+ setLocalEditing(true);
259
+ } else {
260
+ anchorRef.current = null;
261
+ setLocalEditing(false);
262
+ }
263
+ }, [
264
+ contextEditing
265
+ ]);
266
+ const narrowedSchema = useMemo(() => {
267
+ if (!schema) {
268
+ return void 0;
269
+ }
270
+ return narrowSchema(schema, [
271
+ fieldProjection.field.path
272
+ ]);
273
+ }, [
274
+ JSON.stringify(schema),
275
+ fieldProjection.field.path
276
+ ]);
277
+ const formValues = useMemo(() => originalRow ? getSnapshot(originalRow) : {}, [
416
278
  originalRow
417
279
  ]);
418
- const handleOpenChange = useCallback3((nextOpen) => {
280
+ const handleOpenChange = useCallback((nextOpen) => {
419
281
  if (nextOpen === false) {
420
282
  setEditing(null);
421
283
  onSave?.();
@@ -425,76 +287,38 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
425
287
  if (!editing) {
426
288
  return null;
427
289
  }
428
- return /* @__PURE__ */ React6.createElement(Popover3.Root, {
290
+ return /* @__PURE__ */ React2.createElement(Popover.Root, {
429
291
  open: editing,
430
292
  onOpenChange: handleOpenChange
431
- }, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
293
+ }, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
432
294
  virtualRef: anchorRef
433
- }), /* @__PURE__ */ React6.createElement(Popover3.Content, {
295
+ }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
434
296
  tabIndex: -1,
435
297
  classNames: "popover-card-width density-fine"
436
- }, /* @__PURE__ */ React6.createElement(Popover3.Arrow, null), /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, /* @__PURE__ */ React6.createElement(Form2, {
298
+ }, /* @__PURE__ */ React2.createElement(Popover.Arrow, null), /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(Form, {
299
+ autoFocus: true,
437
300
  values: formValues,
438
301
  schema: narrowedSchema,
439
- onSave: handleSave
440
- }))));
302
+ onSave: handleSave,
303
+ ...formProps,
304
+ onQueryRefOptions: handleQueryRefOptions,
305
+ onCreateFromQuery: handleCreateFromQuery,
306
+ createOptionIcon: "ph--plus--regular",
307
+ createOptionLabel
308
+ })))));
441
309
  } finally {
442
310
  _effect.f();
443
311
  }
444
312
  };
445
313
 
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
- ];
483
- };
484
-
485
314
  // src/components/TableCellEditor/TableCellEditor.tsx
486
315
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
487
- var newValue = Symbol.for("newValue");
488
- var createOption = (text) => ({
489
- [newValue]: true,
490
- text
491
- });
492
- var isCreateOption = (data) => typeof data === "object" && data[newValue];
493
- var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQuery, __gridScope }) => {
494
- var _effect = _useSignals7();
316
+ var adaptValidationMessage = (message) => message ? message.endsWith("is missing") ? "Can\u2019t be blank" : message : null;
317
+ var TableValueEditor = ({ model, modals, schema, onFocus, onSave, client, __gridScope }) => {
318
+ var _effect = _useSignals3();
495
319
  try {
496
- const { editing } = useGridContext4("TableValueEditor", __gridScope);
497
- const fieldProjection = useMemo4(() => {
320
+ const { editing } = useGridContext3("TableValueEditor", __gridScope);
321
+ const fieldProjection = useMemo2(() => {
498
322
  if (!model || !editing) {
499
323
  return;
500
324
  }
@@ -503,7 +327,7 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQue
503
327
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
504
328
  invariant2(fieldProjection2, void 0, {
505
329
  F: __dxlog_file2,
506
- L: 76,
330
+ L: 71,
507
331
  S: void 0,
508
332
  A: [
509
333
  "fieldProjection",
@@ -515,21 +339,21 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQue
515
339
  model,
516
340
  editing
517
341
  ]);
518
- if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum.SingleSelect) {
519
- return /* @__PURE__ */ React7.createElement(FormCellEditor, {
342
+ if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum.SingleSelect || fieldProjection?.props.format === FormatEnum.Ref) {
343
+ return /* @__PURE__ */ React3.createElement(FormCellEditor, {
520
344
  fieldProjection,
521
345
  model,
522
346
  schema,
523
347
  __gridScope,
524
- onSave
348
+ onSave,
349
+ client,
350
+ modals
525
351
  });
526
352
  }
527
- return /* @__PURE__ */ React7.createElement(TableCellEditor, {
353
+ return /* @__PURE__ */ React3.createElement(TableCellEditor, {
528
354
  model,
529
355
  modals,
530
- onEnter,
531
356
  onFocus,
532
- onQuery,
533
357
  onSave,
534
358
  __gridScope
535
359
  });
@@ -538,19 +362,18 @@ var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQue
538
362
  }
539
363
  };
540
364
  var editorSlots = {
541
- scroller: {
365
+ scroll: {
542
366
  className: "!plb-[--dx-grid-cell-editor-padding-block]"
543
367
  }
544
368
  };
545
- var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gridScope }) => {
546
- var _effect = _useSignals7();
369
+ var TableCellEditor = ({ model, modals, onFocus, onSave, __gridScope }) => {
370
+ var _effect = _useSignals3();
547
371
  try {
548
- const { id: gridId, editing, setEditing } = useGridContext4("TableCellEditor", __gridScope);
372
+ const { editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
549
373
  const suppressNextBlur = useRef2(false);
550
- const { themeMode } = useThemeContext();
551
- const [_validationError, setValidationError] = useState3(null);
552
- const [_validationVariant, setValidationVariant] = useState3("error");
553
- const fieldProjection = useMemo4(() => {
374
+ const [validationError, setValidationError] = useState2(null);
375
+ const [validationVariant, setValidationVariant] = useState2("error");
376
+ const fieldProjection = useMemo2(() => {
554
377
  if (!model || !editing) {
555
378
  return;
556
379
  }
@@ -559,7 +382,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
559
382
  const fieldProjection2 = model.projection.getFieldProjection(field.id);
560
383
  invariant2(fieldProjection2, void 0, {
561
384
  F: __dxlog_file2,
562
- L: 135,
385
+ L: 120,
563
386
  S: void 0,
564
387
  A: [
565
388
  "fieldProjection",
@@ -571,38 +394,7 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
571
394
  model,
572
395
  editing
573
396
  ]);
574
- useEffect3(() => {
575
- if (!model || !editing || !fieldProjection) {
576
- setValidationError(null);
577
- return;
578
- }
579
- const cell = parseCellIndex2(editing.index);
580
- const { row, col } = cell;
581
- if (model.isDraftCell(cell)) {
582
- const field = model.projection.fields[col];
583
- const hasValidationError = model.hasDraftRowValidationError(row, field.path);
584
- if (hasValidationError) {
585
- const draftRows = model.draftRows.value;
586
- if (row >= 0 && row < draftRows.length) {
587
- const draftRow = draftRows[row];
588
- const validationError = draftRow.validationErrors?.find((error) => error.path === field.path);
589
- if (validationError) {
590
- setValidationError(validationError.message);
591
- setValidationVariant("warning");
592
- }
593
- }
594
- } else {
595
- setValidationError(null);
596
- }
597
- } else {
598
- setValidationError(null);
599
- }
600
- }, [
601
- model,
602
- editing,
603
- fieldProjection
604
- ]);
605
- const handleEnter = useCallback4(async (value) => {
397
+ const handleEnter = useCallback2(async (value) => {
606
398
  if (!model || !editing) {
607
399
  return;
608
400
  }
@@ -611,33 +403,39 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
611
403
  if (validationResult.valid) {
612
404
  setValidationError(null);
613
405
  model.setCellData(cell, value);
614
- onEnter?.(cell);
615
406
  onFocus?.();
616
407
  setEditing(null);
617
408
  onSave?.();
618
409
  } else {
619
- setValidationError(validationResult.error);
410
+ setValidationError(adaptValidationMessage(validationResult.error));
620
411
  setValidationVariant("error");
621
412
  }
622
413
  }, [
623
414
  model,
624
415
  editing,
625
- onEnter,
626
416
  onFocus,
627
417
  setEditing
628
418
  ]);
629
- const handleBlur = useCallback4(async (value) => {
630
- if (!model || !editing) {
631
- return;
632
- }
419
+ const handleBlur = useCallback2(async (value) => {
633
420
  if (suppressNextBlur.current) {
634
421
  suppressNextBlur.current = false;
422
+ } else if (model && editing) {
423
+ const cell = parseCellIndex2(editing.index);
424
+ if (value !== void 0) {
425
+ const result = await model.validateCellData(cell, value);
426
+ if (result.valid) {
427
+ setValidationError(null);
428
+ model.setCellData(cell, value);
429
+ setEditing(null);
430
+ onSave?.();
431
+ }
432
+ }
635
433
  }
636
434
  }, [
637
435
  model,
638
436
  editing
639
437
  ]);
640
- const handleClose = useCallback4(async (value, event) => {
438
+ const handleClose = useCallback2(async (value, event) => {
641
439
  if (!model || !editing || !fieldProjection) {
642
440
  return;
643
441
  }
@@ -645,19 +443,20 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
645
443
  if (value !== void 0) {
646
444
  const result = await model.validateCellData(cell, value);
647
445
  if (result.valid) {
446
+ suppressNextBlur.current = true;
648
447
  setValidationError(null);
649
448
  model.setCellData(cell, value);
650
449
  setEditing(null);
651
450
  onSave?.();
652
- onEnter?.(cell);
653
451
  if (event && onFocus) {
654
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
452
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
655
453
  }
656
454
  } else {
657
455
  setValidationError(result.error);
658
456
  setValidationVariant("error");
659
457
  }
660
458
  } else {
459
+ suppressNextBlur.current = true;
661
460
  setValidationError(null);
662
461
  setEditing(null);
663
462
  onSave?.();
@@ -666,182 +465,416 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
666
465
  }
667
466
  }
668
467
  }, [
669
- model,
670
- editing,
671
- onFocus,
672
- onEnter,
673
- fieldProjection,
674
- setEditing,
675
- onSave
468
+ model,
469
+ editing,
470
+ onFocus,
471
+ fieldProjection,
472
+ setEditing,
473
+ onSave
474
+ ]);
475
+ const extensions = useMemo2(() => {
476
+ if (!fieldProjection) {
477
+ return [];
478
+ }
479
+ const extensions2 = [
480
+ editorKeys({
481
+ onClose: handleClose,
482
+ ...editing?.initialContent && {
483
+ onNav: handleClose
484
+ }
485
+ })
486
+ ];
487
+ const format = fieldProjection.props.format;
488
+ if (format === FormatEnum.SingleSelect || format === FormatEnum.MultiSelect) {
489
+ const options = fieldProjection.props.options || [];
490
+ const mode = format === FormatEnum.SingleSelect ? "single-select" : "multi-select";
491
+ extensions2.push(createMarkdownExtensions());
492
+ extensions2.push(tagPicker({
493
+ mode,
494
+ keymap: false,
495
+ onSearch: (text, selectedIds) => {
496
+ return options.filter((option) => selectedIds.indexOf(option.id) === -1 && (text.length === 0 || option.title.toLowerCase().includes(text.toLowerCase()))).map((option) => ({
497
+ id: option.id,
498
+ label: option.title,
499
+ hue: option.color
500
+ }));
501
+ },
502
+ onUpdate: (ids) => {
503
+ if (model && editing) {
504
+ if (ids.length === 0) {
505
+ return;
506
+ }
507
+ if (mode === "single-select") {
508
+ void handleEnter(ids[0]);
509
+ } else {
510
+ void handleEnter(ids);
511
+ }
512
+ }
513
+ }
514
+ }));
515
+ }
516
+ if (model && editing) {
517
+ extensions2.push(EditorView.updateListener.of(debounce((update) => {
518
+ const content = update.state.doc.toString();
519
+ const cell = parseCellIndex2(editing.index);
520
+ void model.validateCellData(cell, content).then((result) => {
521
+ if (result.valid) {
522
+ setValidationError(null);
523
+ } else {
524
+ setValidationError(result.error);
525
+ setValidationVariant("error");
526
+ }
527
+ });
528
+ }, 10)));
529
+ }
530
+ return extensions2;
531
+ }, [
532
+ model,
533
+ modals,
534
+ editing,
535
+ fieldProjection,
536
+ handleClose
537
+ ]);
538
+ const getCellContent = useCallback2(() => {
539
+ if (model && editing) {
540
+ const cell = parseCellIndex2(editing.index);
541
+ const { col } = cell;
542
+ const field = model.projection.fields[col];
543
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
544
+ if (fieldProjection2?.props.format === FormatEnum.SingleSelect || fieldProjection2?.props.format === FormatEnum.MultiSelect) {
545
+ const value2 = model.getCellData(cell);
546
+ if (value2 !== void 0) {
547
+ const options = fieldProjection2.props.options || [];
548
+ if (fieldProjection2.props.format === FormatEnum.MultiSelect) {
549
+ const tagItems = value2.split(",").map((id) => {
550
+ const option = options.find((o) => o.id === id);
551
+ if (option) {
552
+ return {
553
+ id,
554
+ label: option.title,
555
+ hue: option.color
556
+ };
557
+ }
558
+ return void 0;
559
+ }).filter((item) => item !== void 0);
560
+ return createLinks(tagItems);
561
+ } else {
562
+ const option = options.find((o) => o.id === value2);
563
+ if (option) {
564
+ const tagItem = {
565
+ id: value2,
566
+ label: option.title,
567
+ hue: option.color
568
+ };
569
+ return createLinks([
570
+ tagItem
571
+ ]);
572
+ }
573
+ }
574
+ }
575
+ return "";
576
+ }
577
+ const value = model.getCellData(cell);
578
+ return value !== void 0 ? String(value) : "";
579
+ }
580
+ }, [
581
+ model,
582
+ editing
583
+ ]);
584
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(CellValidationMessage, {
585
+ validationError,
586
+ variant: validationVariant,
587
+ __gridScope
588
+ }), /* @__PURE__ */ React3.createElement(GridCellEditor, {
589
+ extensions,
590
+ getCellContent,
591
+ onBlur: handleBlur,
592
+ slots: editorSlots
593
+ }));
594
+ } finally {
595
+ _effect.f();
596
+ }
597
+ };
598
+ var determineNavigationAxis = ({ key }) => {
599
+ switch (key) {
600
+ case "ArrowUp":
601
+ case "ArrowDown":
602
+ case "Enter": {
603
+ return "row";
604
+ }
605
+ case "ArrowLeft":
606
+ case "ArrowRight":
607
+ case "Tab":
608
+ return "col";
609
+ }
610
+ };
611
+ var determineNavigationDelta = ({ key, shift }) => {
612
+ switch (key) {
613
+ case "ArrowUp":
614
+ case "ArrowLeft":
615
+ return -1;
616
+ case "ArrowDown":
617
+ case "ArrowRight":
618
+ return 1;
619
+ }
620
+ return shift ? -1 : 1;
621
+ };
622
+
623
+ // src/components/Table/ColumnActionsMenu.tsx
624
+ import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
625
+ import React4 from "react";
626
+ import { DropdownMenu, useTranslation } from "@dxos/react-ui";
627
+ var ColumnActionsMenu = ({ model, modals }) => {
628
+ var _effect = _useSignals4();
629
+ try {
630
+ const { t } = useTranslation(translationKey);
631
+ const state = modals.state.value;
632
+ if (state?.type !== "column") {
633
+ return null;
634
+ }
635
+ const currentSort = model.sorting?.sorting;
636
+ const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
637
+ return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
638
+ modal: false,
639
+ open: true,
640
+ onOpenChange: modals.close
641
+ }, /* @__PURE__ */ React4.createElement(DropdownMenu.VirtualTrigger, {
642
+ virtualRef: modals.trigger
643
+ }), /* @__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, {
644
+ "data-testid": "column-sort-descending",
645
+ onClick: () => model.sorting?.setSort(state.fieldId, "desc")
646
+ }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
647
+ "data-testid": "column-sort-ascending",
648
+ onClick: () => model.sorting?.setSort(state.fieldId, "asc")
649
+ }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
650
+ "data-testid": "column-clear-sort",
651
+ onClick: () => model.sorting?.clearSort()
652
+ }, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
653
+ "data-testid": "column-delete",
654
+ onClick: () => model.deleteColumn(state.fieldId)
655
+ }, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
656
+ "data-testid": "column-settings",
657
+ onClick: () => modals.openColumnSettings()
658
+ }, t("column action settings"))), /* @__PURE__ */ React4.createElement(DropdownMenu.Arrow, null))));
659
+ } finally {
660
+ _effect.f();
661
+ }
662
+ };
663
+
664
+ // src/components/Table/ColumnSettings.tsx
665
+ import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
666
+ import React5, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useState as useState3 } from "react";
667
+ import { Popover as Popover2 } from "@dxos/react-ui";
668
+ import { FieldEditor } from "@dxos/react-ui-form";
669
+ var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
670
+ var _effect = _useSignals5();
671
+ try {
672
+ const [newField, setNewField] = useState3();
673
+ const state = modals.state.value;
674
+ useEffect2(() => {
675
+ if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
676
+ setNewField(model.projection.createFieldProjection());
677
+ requestAnimationFrame(() => {
678
+ onNewColumn();
679
+ });
680
+ } else {
681
+ setNewField(void 0);
682
+ }
683
+ }, [
684
+ model?.projection,
685
+ state
686
+ ]);
687
+ const existingField = useMemo3(() => {
688
+ if (state?.type === "columnSettings") {
689
+ const { mode } = state;
690
+ if (mode.type === "edit") {
691
+ return model?.projection?.fields.find((f) => f.id === mode.fieldId);
692
+ }
693
+ }
694
+ return void 0;
695
+ }, [
696
+ model?.projection?.fields,
697
+ state
698
+ ]);
699
+ const field = existingField ?? newField;
700
+ const handleSave = useCallback3(() => {
701
+ modals.close();
702
+ }, [
703
+ modals
704
+ ]);
705
+ const handleCancel = useCallback3(() => {
706
+ if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
707
+ model?.projection.deleteFieldProjection(newField.id);
708
+ }
709
+ }, [
710
+ model?.projection,
711
+ state,
712
+ newField
713
+ ]);
714
+ if (!model?.projection || !field) {
715
+ return null;
716
+ }
717
+ return /* @__PURE__ */ React5.createElement(Popover2.Root, {
718
+ modal: false,
719
+ open: state?.type === "columnSettings"
720
+ }, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
721
+ virtualRef: modals.trigger
722
+ }), /* @__PURE__ */ React5.createElement(Popover2.Portal, null, /* @__PURE__ */ React5.createElement(Popover2.Content, {
723
+ classNames: "md:is-64"
724
+ }, /* @__PURE__ */ React5.createElement(Popover2.Viewport, null, /* @__PURE__ */ React5.createElement(FieldEditor, {
725
+ projection: model.projection,
726
+ field,
727
+ registry,
728
+ onSave: handleSave,
729
+ onCancel: handleCancel
730
+ })), /* @__PURE__ */ React5.createElement(Popover2.Arrow, null))));
731
+ } finally {
732
+ _effect.f();
733
+ }
734
+ };
735
+
736
+ // src/components/Table/CreateRefPanel.tsx
737
+ import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
738
+ import { Schema } from "effect";
739
+ import React6, { useCallback as useCallback4, useMemo as useMemo4 } from "react";
740
+ import { Type } from "@dxos/echo";
741
+ import { live } from "@dxos/live-object";
742
+ import { useClient } from "@dxos/react-client";
743
+ import { getSpace as getSpace2 } from "@dxos/react-client/echo";
744
+ import { Popover as Popover3 } from "@dxos/react-ui";
745
+ import { Form as Form2 } from "@dxos/react-ui-form";
746
+ import { useGridContext as useGridContext4 } from "@dxos/react-ui-grid";
747
+ var CreateRefPanel = ({ model, modals, __gridScope }) => {
748
+ var _effect = _useSignals6();
749
+ try {
750
+ const { id: gridId } = useGridContext4("TableCellEditor", __gridScope);
751
+ const client = useClient();
752
+ const space = model && getSpace2(model?.view);
753
+ const state = modals.state.value;
754
+ const getSchema = useCallback4(() => {
755
+ if (!space || state?.type !== "createRefPanel") {
756
+ return;
757
+ }
758
+ const staticSchema = client.graph.schemaRegistry.schemas.find((schema3) => Type.getTypename(schema3) === state.typename);
759
+ if (staticSchema) {
760
+ return staticSchema;
761
+ }
762
+ const [schema2] = space.db.schemaRegistry.query({
763
+ typename: state.typename
764
+ }).runSync();
765
+ return schema2;
766
+ }, [
767
+ space,
768
+ state
769
+ ]);
770
+ const schema = useMemo4(() => {
771
+ const schema2 = getSchema();
772
+ if (!schema2) {
773
+ return;
774
+ }
775
+ const omit = Schema.omit("id");
776
+ return omit(schema2);
777
+ }, [
778
+ getSchema
676
779
  ]);
677
- const extension = useMemo4(() => {
678
- if (!fieldProjection) {
679
- return [];
680
- }
681
- const extension2 = [
682
- editorKeys({
683
- onClose: handleClose,
684
- ...editing?.initialContent && {
685
- onNav: handleClose
686
- }
687
- })
688
- ];
689
- const format = fieldProjection.props.format;
690
- if (format === FormatEnum.SingleSelect || format === FormatEnum.MultiSelect) {
691
- extension2.push(createMarkdownExtensions({
692
- themeMode
693
- }));
694
- const options = fieldProjection.props.options || [];
695
- const mode = format === FormatEnum.SingleSelect ? "single-select" : "multi-select";
696
- extension2.push(tagPicker({
697
- mode,
698
- keymap: false,
699
- onSearch: (text, selectedIds) => {
700
- return options.filter((option) => selectedIds.indexOf(option.id) === -1 && (text.length === 0 || option.title.toLowerCase().includes(text.toLowerCase()))).map((option) => ({
701
- id: option.id,
702
- label: option.title,
703
- hue: option.color
704
- }));
705
- },
706
- onUpdate: (ids) => {
707
- if (model && editing) {
708
- if (ids.length === 0) {
709
- return;
710
- }
711
- if (mode === "single-select") {
712
- void handleEnter(ids[0]);
713
- } else {
714
- void handleEnter(ids);
715
- }
716
- }
717
- }
718
- }));
780
+ const handleSave = useCallback4((values) => {
781
+ if (!model || !space || state?.type !== "createRefPanel") {
782
+ return;
719
783
  }
720
- if (onQuery) {
721
- switch (fieldProjection.props.format) {
722
- case FormatEnum.Ref: {
723
- extension2.push([
724
- completion({
725
- onQuery: (text) => onQuery(fieldProjection, text),
726
- onMatch: (data) => {
727
- if (model && editing && modals) {
728
- if (isCreateOption(data)) {
729
- const { field, props } = fieldProjection;
730
- if (props.referenceSchema) {
731
- suppressNextBlur.current = true;
732
- modals.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
733
- [field.referencePath]: data.text
734
- }, (data2) => {
735
- void handleEnter(data2);
736
- });
737
- }
738
- } else {
739
- void handleEnter(data);
740
- }
741
- }
742
- }
743
- })
744
- ]);
745
- break;
746
- }
747
- }
784
+ const schema2 = getSchema();
785
+ if (schema2) {
786
+ const obj = space.db.add(live(schema2, values));
787
+ state.onCreate?.(obj);
748
788
  }
749
- return extension2;
789
+ void modals.close();
750
790
  }, [
751
791
  model,
752
792
  modals,
753
- editing,
754
- fieldProjection,
755
- handleClose,
756
- themeMode
793
+ space,
794
+ state
757
795
  ]);
758
- const getCellContent = useCallback4(() => {
759
- if (model && editing) {
760
- const cell = parseCellIndex2(editing.index);
761
- const { col } = cell;
762
- const field = model.projection.fields[col];
763
- const fieldProjection2 = model.projection.getFieldProjection(field.id);
764
- if (fieldProjection2?.props.format === FormatEnum.SingleSelect || fieldProjection2?.props.format === FormatEnum.MultiSelect) {
765
- const value2 = model.getCellData(cell);
766
- if (value2 !== void 0) {
767
- const options = fieldProjection2.props.options || [];
768
- if (fieldProjection2.props.format === FormatEnum.MultiSelect) {
769
- const tagItems = value2.split(",").map((id) => {
770
- const option = options.find((o) => o.id === id);
771
- if (option) {
772
- return {
773
- id,
774
- label: option.title,
775
- hue: option.color
776
- };
777
- }
778
- return void 0;
779
- }).filter((item) => item !== void 0);
780
- return createLinks(tagItems);
781
- } else {
782
- const option = options.find((o) => o.id === value2);
783
- if (option) {
784
- const tagItem = {
785
- id: value2,
786
- label: option.title,
787
- hue: option.color
788
- };
789
- return createLinks([
790
- tagItem
791
- ]);
792
- }
793
- }
794
- }
795
- return "";
796
- }
797
- const value = model.getCellData(cell);
798
- return value !== void 0 ? String(value) : "";
796
+ const handleCancel = useCallback4(() => {
797
+ if (model) {
798
+ modals.close();
799
799
  }
800
800
  }, [
801
- model,
802
- editing
801
+ modals
803
802
  ]);
804
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(CellValidationMessage, {
805
- validationError: _validationError,
806
- variant: _validationVariant,
807
- __gridScope
808
- }), /* @__PURE__ */ React7.createElement(GridCellEditor, {
809
- extension,
810
- getCellContent,
811
- onBlur: handleBlur,
812
- slots: editorSlots
813
- }));
803
+ if (!model?.projection) {
804
+ return null;
805
+ }
806
+ return /* @__PURE__ */ React6.createElement(Popover3.Root, {
807
+ modal: false,
808
+ open: state?.type === "createRefPanel" && !!schema,
809
+ onOpenChange: (nextOpen) => {
810
+ if (model && !nextOpen) {
811
+ return modals.close();
812
+ }
813
+ }
814
+ }, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
815
+ virtualRef: modals.trigger
816
+ }), /* @__PURE__ */ React6.createElement(Popover3.Portal, null, /* @__PURE__ */ React6.createElement(Popover3.Content, {
817
+ classNames: "md:is-64",
818
+ "data-grid": gridId
819
+ }, /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React6.createElement(Form2, {
820
+ schema,
821
+ values: state.initialValues ?? {},
822
+ onSave: handleSave,
823
+ onCancel: handleCancel
824
+ })), /* @__PURE__ */ React6.createElement(Popover3.Arrow, null))));
814
825
  } finally {
815
826
  _effect.f();
816
827
  }
817
828
  };
818
- var determineNavigationAxis = ({ key }) => {
819
- switch (key) {
820
- case "ArrowUp":
821
- case "ArrowDown":
822
- case "Enter": {
823
- return "row";
829
+
830
+ // src/components/Table/RowActionsMenu.tsx
831
+ import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
832
+ import React7 from "react";
833
+ import { DropdownMenu as DropdownMenu2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
834
+ var RowActionsMenu = ({ model, modals }) => {
835
+ var _effect = _useSignals7();
836
+ try {
837
+ const { t } = useTranslation2(translationKey);
838
+ const hasSelection = model.selection.hasSelection.value;
839
+ const state = modals.state.value;
840
+ if (state?.type !== "row") {
841
+ return null;
824
842
  }
825
- case "ArrowLeft":
826
- case "ArrowRight":
827
- case "Tab":
828
- return "col";
829
- }
830
- };
831
- var determineNavigationDelta = ({ key, shift }) => {
832
- switch (key) {
833
- case "ArrowUp":
834
- case "ArrowLeft":
835
- return -1;
836
- case "ArrowDown":
837
- case "ArrowRight":
838
- return 1;
843
+ return /* @__PURE__ */ React7.createElement(DropdownMenu2.Root, {
844
+ modal: false,
845
+ open: true,
846
+ onOpenChange: modals.close
847
+ }, /* @__PURE__ */ React7.createElement(DropdownMenu2.VirtualTrigger, {
848
+ virtualRef: modals.trigger
849
+ }), /* @__PURE__ */ React7.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React7.createElement(DropdownMenu2.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
850
+ "data-testid": "row-menu-delete",
851
+ onClick: () => model.deleteRow(state.rowIndex)
852
+ }, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
853
+ key: action.id,
854
+ "data-testid": `row-action-${action.id}`,
855
+ onClick: () => {
856
+ modals.close();
857
+ model.handleRowAction(action.id, state.rowIndex);
858
+ }
859
+ }, toLocalizedString(action.label, t)))), /* @__PURE__ */ React7.createElement(DropdownMenu2.Arrow, null)));
860
+ } finally {
861
+ _effect.f();
839
862
  }
840
- return shift ? -1 : 1;
841
863
  };
842
864
 
843
865
  // src/components/Table/Table.tsx
844
- var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
866
+ var columnDefault = {
867
+ grid: {
868
+ minSize: 80,
869
+ maxSize: 640
870
+ }
871
+ };
872
+ var rowDefault = {
873
+ frozenRowsStart: {
874
+ readonly: true,
875
+ focusUnfurl: false
876
+ }
877
+ };
845
878
  var TableRoot = ({ children, role = "article" }) => {
846
879
  var _effect = _useSignals8();
847
880
  try {
@@ -865,14 +898,19 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
865
898
  try {
866
899
  const [dxGrid, setDxGrid] = useState4(null);
867
900
  const { hasAttention } = useAttention(model?.id ?? "table");
868
- const { t } = useTranslation3(translationKey);
869
901
  const modals = useMemo5(() => new ModalController(), []);
870
902
  const draftRowCount = model?.getDraftRowCount() ?? 0;
903
+ const handleSave = useCallback5(() => {
904
+ dxGrid?.updateCells(true);
905
+ dxGrid?.requestUpdate();
906
+ }, [
907
+ dxGrid
908
+ ]);
871
909
  const frozen = useMemo5(() => {
872
910
  const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
873
911
  return {
874
912
  frozenRowsStart: 1,
875
- frozenRowsEnd: draftRowCount,
913
+ frozenRowsEnd: Math.max(1, draftRowCount),
876
914
  frozenColsStart: model?.features.selection.enabled ? 1 : 0,
877
915
  frozenColsEnd: noActionColumn ? 0 : 1
878
916
  };
@@ -883,7 +921,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
883
921
  const getCells = useCallback5((range, plane) => presentation?.getCells(range, plane) ?? {}, [
884
922
  presentation
885
923
  ]);
886
- useEffect4(() => {
924
+ useEffect3(() => {
887
925
  if (!presentation || !dxGrid) {
888
926
  return;
889
927
  }
@@ -893,6 +931,30 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
893
931
  dxGrid,
894
932
  getCells
895
933
  ]);
934
+ const handleInsertRowResult = useCallback5((insertResult) => {
935
+ if (insertResult === "draft") {
936
+ requestAnimationFrame(() => {
937
+ dxGrid?.setFocus({
938
+ plane: "frozenRowsEnd",
939
+ col: 0,
940
+ row: 0
941
+ });
942
+ dxGrid?.refocus();
943
+ });
944
+ } else {
945
+ requestAnimationFrame(() => {
946
+ dxGrid?.setFocus({
947
+ plane: "grid",
948
+ col: 0,
949
+ row: model ? model.getRowCount() - 1 : 0
950
+ });
951
+ dxGrid?.refocus();
952
+ });
953
+ }
954
+ }, [
955
+ model,
956
+ dxGrid
957
+ ]);
896
958
  useImperativeHandle(forwardedRef, () => {
897
959
  if (!presentation || !dxGrid) {
898
960
  return {};
@@ -905,18 +967,38 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
905
967
  dxGrid.updateCells(true);
906
968
  dxGrid.requestUpdate();
907
969
  }
908
- }
970
+ },
971
+ handleInsertRowResult
909
972
  };
910
973
  }, [
911
974
  presentation,
975
+ dxGrid,
976
+ model
977
+ ]);
978
+ const handleSaveDraftRow = useCallback5((rowIndex = 0) => {
979
+ if (model && dxGrid) {
980
+ const didCommitSuccessfully = model.commitDraftRow(rowIndex);
981
+ if (didCommitSuccessfully) {
982
+ requestAnimationFrame(() => {
983
+ dxGrid.scrollToEndRow();
984
+ });
985
+ }
986
+ }
987
+ }, [
988
+ model,
912
989
  dxGrid
913
990
  ]);
914
991
  const handleGridClick = useCallback5((event) => {
915
- const rowIndex = safeParseInt(event.target.closest("[aria-rowindex]")?.ariaRowIndex ?? "");
916
- if (rowIndex != null) {
992
+ const cell = closestCell(event.target);
993
+ if (cell) {
994
+ const { row: rowIndex, plane } = cell;
917
995
  if (onRowClick) {
918
- const row = model?.getRowAt(rowIndex);
919
- row && onRowClick(row);
996
+ if (plane === "grid") {
997
+ const row = model?.getRowAt(rowIndex);
998
+ row && onRowClick(row);
999
+ } else {
1000
+ onRowClick(cell);
1001
+ }
920
1002
  }
921
1003
  if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
922
1004
  model.selection.toggleSelectionForRowIndex(rowIndex);
@@ -952,14 +1034,7 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
952
1034
  break;
953
1035
  }
954
1036
  case "saveDraftRow": {
955
- if (model) {
956
- const didCommitSuccessfully = model.commitDraftRow(data.rowIndex);
957
- if (dxGrid && didCommitSuccessfully) {
958
- requestAnimationFrame(() => {
959
- dxGrid.scrollToEndRow();
960
- });
961
- }
962
- }
1037
+ handleSaveDraftRow();
963
1038
  break;
964
1039
  }
965
1040
  }
@@ -998,29 +1073,20 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
998
1073
  modals,
999
1074
  dxGrid
1000
1075
  ]);
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);
1018
- });
1076
+ const handleFocus = useCallback5((increment, delta, cell) => {
1077
+ if (dxGrid && model) {
1078
+ if (cell?.plane === "grid" && cell?.row >= model.getRowCount() - 1) {
1079
+ handleInsertRowResult(draftRowCount < 1 ? model.insertRow() : "final");
1080
+ } else if (cell?.plane === "frozenRowsEnd" && increment === "row") {
1081
+ handleSaveDraftRow(cell.row);
1082
+ handleInsertRowResult(model.insertRow());
1083
+ } else {
1084
+ dxGrid.refocus(increment, delta);
1019
1085
  }
1020
1086
  }
1021
1087
  }, [
1022
- model,
1023
- dxGrid
1088
+ dxGrid,
1089
+ model
1024
1090
  ]);
1025
1091
  const handleKeyDown = useCallback5((event) => {
1026
1092
  if (!model?.features.dataEditable) {
@@ -1030,15 +1096,63 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1030
1096
  if (!model || !cell) {
1031
1097
  return;
1032
1098
  }
1099
+ if (event.metaKey || event.ctrlKey) {
1100
+ switch (event.key) {
1101
+ case "c": {
1102
+ try {
1103
+ const cellData = model.getCellData(cell);
1104
+ const textContent = cellData?.toString() ?? "";
1105
+ void navigator.clipboard.writeText(textContent);
1106
+ event.preventDefault();
1107
+ } catch (error) {
1108
+ console.warn("Failed to copy cell content:", error);
1109
+ }
1110
+ break;
1111
+ }
1112
+ case "v": {
1113
+ event.preventDefault();
1114
+ void navigator.clipboard.readText().then((clipboardText) => {
1115
+ try {
1116
+ model.setCellData(cell, clipboardText);
1117
+ handleSave();
1118
+ } catch {
1119
+ const cellElement = event.target.closest('[data-dx-grid-action="cell"]');
1120
+ if (cellElement) {
1121
+ const rect = cellElement.getBoundingClientRect();
1122
+ const editRequest = new DxEditRequest({
1123
+ cellIndex: `${cell.plane},${cell.col},${cell.row}`,
1124
+ cellBox: {
1125
+ insetInlineStart: rect.left,
1126
+ insetBlockStart: rect.top,
1127
+ inlineSize: rect.width,
1128
+ blockSize: rect.height
1129
+ },
1130
+ cellElement,
1131
+ initialContent: clipboardText
1132
+ });
1133
+ cellElement.dispatchEvent(editRequest);
1134
+ }
1135
+ }
1136
+ });
1137
+ break;
1138
+ }
1139
+ }
1140
+ }
1033
1141
  switch (event.key) {
1034
1142
  case "Backspace":
1035
1143
  case "Delete": {
1036
- model.setCellData(cell, void 0);
1144
+ try {
1145
+ model.setCellData(cell, void 0);
1146
+ event.preventDefault();
1147
+ } catch {
1148
+ }
1037
1149
  break;
1038
1150
  }
1039
1151
  }
1040
1152
  }, [
1041
- model
1153
+ model,
1154
+ dxGrid,
1155
+ handleSave
1042
1156
  ]);
1043
1157
  const handleAxisResize = useCallback5((event) => {
1044
1158
  if (event.axis === "col") {
@@ -1065,59 +1179,6 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1065
1179
  model,
1066
1180
  dxGrid
1067
1181
  ]);
1068
- const handleQuery = useCallback5(async ({ field, props }, text) => {
1069
- if (model && props.referenceSchema && field.referencePath) {
1070
- const space = getSpace2(model.view);
1071
- invariant3(space, void 0, {
1072
- F: __dxlog_file3,
1073
- L: 325,
1074
- S: void 0,
1075
- A: [
1076
- "space",
1077
- ""
1078
- ]
1079
- });
1080
- let schema2;
1081
- if (client) {
1082
- schema2 = client.graph.schemaRegistry.getSchema(props.referenceSchema);
1083
- }
1084
- if (!schema2) {
1085
- schema2 = space.db.schemaRegistry.getSchema(props.referenceSchema);
1086
- }
1087
- if (schema2) {
1088
- const { objects } = await space.db.query(Filter.type(schema2)).run();
1089
- const options = objects.map((obj) => {
1090
- const value = getValue(obj, field.referencePath);
1091
- if (!value || typeof value !== "string") {
1092
- return void 0;
1093
- }
1094
- return {
1095
- label: value,
1096
- data: obj
1097
- };
1098
- }).filter(isNotFalsy);
1099
- return [
1100
- ...options,
1101
- {
1102
- label: t("create new object label", {
1103
- text
1104
- }),
1105
- data: createOption(text)
1106
- }
1107
- ];
1108
- }
1109
- }
1110
- return [];
1111
- }, [
1112
- model,
1113
- client,
1114
- t
1115
- ]);
1116
- const handleSave = useCallback5(() => {
1117
- dxGrid?.updateCells(true);
1118
- }, [
1119
- dxGrid
1120
- ]);
1121
1182
  if (!model || !modals) {
1122
1183
  return /* @__PURE__ */ React8.createElement("span", {
1123
1184
  role: "none",
@@ -1130,20 +1191,21 @@ var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttenti
1130
1191
  model,
1131
1192
  modals,
1132
1193
  schema,
1133
- onEnter: handleEnter,
1134
1194
  onFocus: handleFocus,
1135
- onQuery: handleQuery,
1136
- onSave: handleSave
1195
+ onSave: handleSave,
1196
+ client
1137
1197
  }), /* @__PURE__ */ React8.createElement(Grid.Content, {
1138
1198
  className: mx("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
1139
1199
  frozen,
1140
1200
  columns: model.columnMeta.value,
1201
+ columnDefault,
1202
+ rowDefault,
1141
1203
  limitRows: model.getRowCount() ?? 0,
1142
1204
  limitColumns: model.projection.fields.length,
1143
1205
  overscroll: "trap",
1144
1206
  onAxisResize: handleAxisResize,
1145
1207
  onClick: handleGridClick,
1146
- onKeyDown: handleKeyDown,
1208
+ onKeyDownCapture: handleKeyDown,
1147
1209
  onWheelCapture: handleWheel,
1148
1210
  ref: setDxGrid
1149
1211
  }), /* @__PURE__ */ React8.createElement(RowActionsMenu, {
@@ -1171,7 +1233,7 @@ var Table = {
1171
1233
 
1172
1234
  // src/components/Table/DynamicTable.tsx
1173
1235
  import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
1174
- import React9, { useRef as useRef3, useMemo as useMemo6, useCallback as useCallback6 } from "react";
1236
+ import React9, { useCallback as useCallback6, useMemo as useMemo6, useRef as useRef3 } from "react";
1175
1237
  import { useDefaultValue } from "@dxos/react-ui";
1176
1238
  import { mx as mx2 } from "@dxos/react-ui-theme";
1177
1239
  var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema: _jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
@@ -1251,7 +1313,7 @@ import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking
1251
1313
  import { Rx } from "@effect-rx/rx-react";
1252
1314
  import React10, { useMemo as useMemo7 } from "react";
1253
1315
  import { live as live2 } from "@dxos/live-object";
1254
- import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
1316
+ import { MenuProvider, ToolbarMenu, createGapSeparator, createMenuAction, useMenuActions } from "@dxos/react-ui-menu";
1255
1317
  import { rxFromSignal } from "@dxos/react-ui-menu";
1256
1318
  var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.make((get) => {
1257
1319
  const add = createMenuAction("add-row", onAdd, {
@@ -1338,7 +1400,6 @@ export {
1338
1400
  TablePresentation,
1339
1401
  TableToolbar,
1340
1402
  cellClassesForRowSelection,
1341
- createTable,
1342
1403
  getBaseSchema,
1343
1404
  makeDynamicTable,
1344
1405
  narrowSchema,