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

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