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