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