@dxos/react-ui-table 0.8.4-main.67995b8 → 0.8.4-main.72ec0f3

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