@dxos/react-ui-table 0.8.4-main.28f8d3d → 0.8.4-main.406dc2a

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