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