@dxos/react-ui-table 0.8.4-main.67995b8 → 0.8.4-main.70d3990

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