@dxos/react-ui-table 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0

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 (145) hide show
  1. package/dist/lib/browser/chunk-BF54SSNL.mjs +70 -0
  2. package/dist/lib/browser/chunk-BF54SSNL.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-GS2UNGJK.mjs → chunk-NTWHM2PX.mjs} +656 -680
  4. package/dist/lib/browser/chunk-NTWHM2PX.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1166 -1011
  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 +32 -44
  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-SIRDIPHZ.mjs +71 -0
  12. package/dist/lib/node-esm/chunk-SIRDIPHZ.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-TRR3C5NX.mjs → chunk-Z3TLFG6Z.mjs} +656 -679
  14. package/dist/lib/node-esm/chunk-Z3TLFG6Z.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +1166 -1011
  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 +32 -44
  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 -2
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +2 -2
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
  26. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +21 -37
  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 +82 -80
  30. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  32. package/dist/types/src/components/Table/Table.d.ts +28 -21
  33. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  34. package/dist/types/src/components/Table/Table.stories.d.ts +90 -26
  35. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/Table/TableContent.d.ts +21 -0
  37. package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
  38. package/dist/types/src/components/Table/TableToolbar.d.ts +25 -0
  39. package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
  40. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
  41. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +10 -12
  42. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  43. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +5 -7
  44. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  45. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +24 -26
  46. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/index.d.ts +0 -1
  48. package/dist/types/src/components/index.d.ts.map +1 -1
  49. package/dist/types/src/components/testing.d.ts +22 -15
  50. package/dist/types/src/components/testing.d.ts.map +1 -1
  51. package/dist/types/src/hooks/index.d.ts +2 -1
  52. package/dist/types/src/hooks/index.d.ts.map +1 -1
  53. package/dist/types/src/hooks/useAddRow.d.ts +5 -6
  54. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  55. package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
  56. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
  57. package/dist/types/src/hooks/useTableModel.d.ts +9 -9
  58. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  59. package/dist/types/src/model/modal-controller.d.ts +5 -1
  60. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  61. package/dist/types/src/model/selection-model.d.ts +17 -8
  62. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  63. package/dist/types/src/model/table-model.d.ts +104 -24
  64. package/dist/types/src/model/table-model.d.ts.map +1 -1
  65. package/dist/types/src/model/table-presentation.d.ts +3 -1
  66. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  67. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  68. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  69. package/dist/types/src/testing/useTestTableModel.d.ts +18 -15
  70. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  71. package/dist/types/src/translations.d.ts +21 -23
  72. package/dist/types/src/translations.d.ts.map +1 -1
  73. package/dist/types/src/types/Table.d.ts +26 -0
  74. package/dist/types/src/types/Table.d.ts.map +1 -0
  75. package/dist/types/src/types/index.d.ts +1 -1
  76. package/dist/types/src/types/index.d.ts.map +1 -1
  77. package/dist/types/src/util/dynamic-table.d.ts +14 -11
  78. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  79. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  80. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  81. package/dist/types/src/util/index.d.ts +2 -0
  82. package/dist/types/src/util/index.d.ts.map +1 -1
  83. package/dist/types/src/util/query-ast.d.ts +7 -0
  84. package/dist/types/src/util/query-ast.d.ts.map +1 -0
  85. package/dist/types/src/util/sort.d.ts +12 -0
  86. package/dist/types/src/util/sort.d.ts.map +1 -0
  87. package/dist/types/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +55 -56
  89. package/src/components/Table/ColumnActionsMenu.tsx +15 -11
  90. package/src/components/Table/ColumnSettings.tsx +8 -9
  91. package/src/components/Table/DynamicTable.stories.tsx +27 -28
  92. package/src/components/Table/DynamicTable.tsx +32 -32
  93. package/src/components/Table/Relations.stories.tsx +61 -58
  94. package/src/components/Table/RowActionsMenu.tsx +3 -2
  95. package/src/components/Table/Table.stories.tsx +118 -102
  96. package/src/components/Table/Table.tsx +43 -407
  97. package/src/components/Table/TableContent.tsx +421 -0
  98. package/src/components/{TableToolbar → Table}/TableToolbar.tsx +43 -44
  99. package/src/components/TableCellEditor/CellValidationMessage.tsx +5 -5
  100. package/src/components/TableCellEditor/FormCellEditor.tsx +118 -135
  101. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +20 -17
  102. package/src/components/TableCellEditor/TableCellEditor.tsx +37 -33
  103. package/src/components/index.ts +0 -1
  104. package/src/components/testing.ts +43 -17
  105. package/src/hooks/index.ts +2 -1
  106. package/src/hooks/useAddRow.ts +8 -10
  107. package/src/hooks/useProjectionModel.ts +39 -0
  108. package/src/hooks/useTableModel.ts +36 -34
  109. package/src/model/modal-controller.ts +23 -12
  110. package/src/model/selection-model.ts +75 -44
  111. package/src/model/table-model.test.ts +82 -55
  112. package/src/model/table-model.ts +430 -167
  113. package/src/model/table-presentation.test.ts +59 -50
  114. package/src/model/table-presentation.ts +43 -38
  115. package/src/playwright/TableManager.ts +13 -6
  116. package/src/playwright/playwright.config.ts +1 -1
  117. package/src/playwright/smoke.spec.ts +52 -8
  118. package/src/testing/useTestTableModel.ts +48 -41
  119. package/src/translations.ts +20 -22
  120. package/src/types/Table.ts +79 -0
  121. package/src/types/index.ts +1 -1
  122. package/src/util/dynamic-table.test.ts +70 -0
  123. package/src/util/dynamic-table.ts +40 -26
  124. package/src/util/index.ts +2 -0
  125. package/src/util/query-ast.ts +22 -0
  126. package/src/util/sort.ts +90 -0
  127. package/src/util/table-buttons.ts +1 -1
  128. package/src/util/table-controls.ts +2 -2
  129. package/dist/lib/browser/chunk-2PFAPQL4.mjs +0 -66
  130. package/dist/lib/browser/chunk-2PFAPQL4.mjs.map +0 -7
  131. package/dist/lib/browser/chunk-GS2UNGJK.mjs.map +0 -7
  132. package/dist/lib/node-esm/chunk-6POOFFYF.mjs +0 -67
  133. package/dist/lib/node-esm/chunk-6POOFFYF.mjs.map +0 -7
  134. package/dist/lib/node-esm/chunk-TRR3C5NX.mjs.map +0 -7
  135. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +0 -21
  136. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +0 -1
  137. package/dist/types/src/components/TableToolbar/index.d.ts +0 -2
  138. package/dist/types/src/components/TableToolbar/index.d.ts.map +0 -1
  139. package/dist/types/src/model/table-sorting.d.ts +0 -52
  140. package/dist/types/src/model/table-sorting.d.ts.map +0 -1
  141. package/dist/types/src/types/schema.d.ts +0 -28
  142. package/dist/types/src/types/schema.d.ts.map +0 -1
  143. package/src/components/TableToolbar/index.ts +0 -5
  144. package/src/model/table-sorting.ts +0 -225
  145. package/src/types/schema.ts +0 -73
@@ -3,546 +3,669 @@ import {
3
3
  BUTTON_IDENTIFIERS,
4
4
  CONTROL_IDENTIFIERS,
5
5
  CheckboxStory,
6
- ModalController,
7
6
  SwitchStory,
8
7
  TableModel,
9
8
  TablePresentation,
10
9
  cellClassesForRowSelection,
11
- getBaseSchema,
12
- makeDynamicTable,
13
- narrowSchema,
10
+ compareValues,
11
+ createDirectChangeCallback,
12
+ createEchoChangeCallback,
13
+ extractOrder,
14
+ getSortValue,
14
15
  tableButtons,
15
16
  tableControls,
16
- touch,
17
17
  useAddRow,
18
+ useProjectionModel,
18
19
  useTableModel
19
- } from "./chunk-TRR3C5NX.mjs";
20
- import "./chunk-6POOFFYF.mjs";
20
+ } from "./chunk-Z3TLFG6Z.mjs";
21
+ import {
22
+ Table_exports
23
+ } from "./chunk-SIRDIPHZ.mjs";
21
24
 
22
25
  // src/translations.ts
23
- var translationKey = "react-ui-table";
26
+ var translationKey = "@dxos/react-ui-table";
24
27
  var translations = [
25
28
  {
26
29
  "en-US": {
27
30
  [translationKey]: {
28
- "object placeholder": "New table",
29
- "create object label": "Create table",
30
- "table name placeholder": "Table name",
31
- "settings title": "Table settings",
32
- "table schema label": "Record type",
33
- "new schema": "New record type",
34
- "continue label": "Continue",
35
- "create stack section label": "Create table",
36
- "add row label": "Add row",
37
- "create comment": "Create thread",
38
- "column action sort descending": "Sort Descending",
39
- "column action sort ascending": "Sort Ascending",
40
- "column action clear sorting": "Clear Sorting",
41
- "column action settings": "Column Settings",
42
- "column action delete": "Delete Column",
43
- "delete row label": "Delete row",
44
- "bulk delete row label": "Delete selected rows",
45
- "column deleted label": "Column deleted",
46
- "new column button label": "Create column",
47
- "create new object label": "Create new object \u201C{{text}}\u201D",
48
- "save view label": "Save changes to view"
31
+ "object.placeholder": "New table",
32
+ "create-object.label": "Create table",
33
+ "table-name.placeholder": "Table name",
34
+ "settings.title": "Table settings",
35
+ "table-schema.label": "Type",
36
+ "continue.label": "Continue",
37
+ "create-stack-section.label": "Create table",
38
+ "add-row.label": "Add row",
39
+ "column-action-sort-descending.menu": "Sort Descending",
40
+ "column-action-sort-ascending.menu": "Sort Ascending",
41
+ "column-action-clear-sorting.menu": "Clear Sorting",
42
+ "column-action-settings.menu": "Column Settings",
43
+ "column-action-delete.menu": "Delete Column",
44
+ "delete-row.label": "Delete row",
45
+ "bulk-delete-row.label": "Delete selected rows",
46
+ "column-deleted.label": "Column deleted",
47
+ "new-column-button.label": "Create column",
48
+ "create-new-object.label": "Create new object \u201C{{text}}\u201D",
49
+ "save-view.label": "Save changes to view"
49
50
  }
50
51
  }
51
52
  }
52
53
  ];
53
54
 
54
55
  // src/components/Table/Table.tsx
55
- import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
56
+ import { Atom as Atom4 } from "@effect-atom/atom-react";
57
+ import { createContext } from "@radix-ui/react-context";
58
+ import React9, { forwardRef, useImperativeHandle, useRef as useRef3 } from "react";
59
+
60
+ // src/components/Table/TableContent.tsx
61
+ import { Atom as Atom2, RegistryContext, useAtomValue as useAtomValue4 } from "@effect-atom/atom-react";
56
62
  import * as String2 from "effect/String";
57
- import React7, { forwardRef, useCallback as useCallback4, useEffect as useEffect3, useImperativeHandle, useMemo as useMemo4, useState as useState4 } from "react";
63
+ import React7, { useCallback as useCallback4, useContext, useEffect as useEffect3, useMemo as useMemo4, useState as useState4 } from "react";
64
+ import { log } from "@dxos/log";
58
65
  import { useAttention } from "@dxos/react-ui-attention";
59
66
  import { Grid, closestCell, gridSeparatorBlockEnd, gridSeparatorInlineEnd } from "@dxos/react-ui-grid";
60
67
  import { DxEditRequest } from "@dxos/react-ui-grid";
61
- import { mx } from "@dxos/react-ui-theme";
68
+ import { composable, composableProps, mx } from "@dxos/ui-theme";
69
+
70
+ // src/util/dynamic-table.ts
71
+ import { Filter, JsonSchema, Obj, Order, Query, Ref, Type } from "@dxos/echo";
72
+ import { ProjectionModel, ViewModel, createEchoChangeCallback as createEchoChangeCallback2, getSchemaFromPropertyDefinitions } from "@dxos/schema";
73
+ var getBaseSchema = ({ schema, typename, properties, jsonSchema }) => {
74
+ if (typename && properties) {
75
+ const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
76
+ return {
77
+ typename: schema2.typename,
78
+ jsonSchema: JsonSchema.toJsonSchema(schema2)
79
+ };
80
+ } else if (schema) {
81
+ return {
82
+ typename: Type.getTypename(schema),
83
+ jsonSchema: JsonSchema.toJsonSchema(schema)
84
+ };
85
+ } else if (typename && jsonSchema) {
86
+ return {
87
+ typename,
88
+ jsonSchema
89
+ };
90
+ } else {
91
+ throw new Error("invalid properties");
92
+ }
93
+ };
94
+ var makeDynamicTable = ({ registry, jsonSchema, properties }) => {
95
+ const view = ViewModel.make({
96
+ query: Query.select(Filter.everything()),
97
+ jsonSchema,
98
+ ...properties && {
99
+ fields: properties.map((property) => property.name)
100
+ }
101
+ });
102
+ const object = Obj.make(Table_exports.Table, {
103
+ view: Ref.make(view),
104
+ sizes: {}
105
+ });
106
+ const projection = new ProjectionModel({
107
+ registry,
108
+ view,
109
+ baseSchema: jsonSchema,
110
+ change: createEchoChangeCallback2(view, jsonSchema)
111
+ });
112
+ projection.normalizeView();
113
+ if (properties && projection.getFields()) {
114
+ setProperties(view, projection, object, properties);
115
+ }
116
+ return {
117
+ projection,
118
+ object
119
+ };
120
+ };
121
+ var setProperties = (view, projection, table, properties) => {
122
+ for (const property of properties) {
123
+ const field = projection.getFields().find((field2) => field2.path === property.name);
124
+ if (field) {
125
+ if (property.size !== void 0) {
126
+ Obj.change(table, (obj) => {
127
+ obj.sizes[field.path] = property.size;
128
+ });
129
+ }
130
+ if (property.title !== void 0) {
131
+ const fieldProjection = projection.getFieldProjection(field.id);
132
+ projection.setFieldProjection({
133
+ ...fieldProjection,
134
+ props: {
135
+ ...fieldProjection.props,
136
+ title: property.title
137
+ }
138
+ });
139
+ }
140
+ if (property.sort) {
141
+ const currentQuery = Query.fromAst(Obj.getSnapshot(view).query.ast);
142
+ const newQuery = currentQuery.orderBy(Order.property(field.path, property.sort));
143
+ Obj.change(view, (obj) => {
144
+ obj.query.ast = newQuery.ast;
145
+ });
146
+ }
147
+ }
148
+ }
149
+ };
150
+
151
+ // src/util/signals.ts
152
+ var touch = (value) => value;
153
+
154
+ // src/util/schema.ts
155
+ import * as Schema from "effect/Schema";
156
+ import * as SchemaAST from "effect/SchemaAST";
157
+ var narrowSchema = (schema, paths) => {
158
+ const ast = schema?.ast;
159
+ if (SchemaAST.isTypeLiteral(ast)) {
160
+ const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
161
+ if (propertySignatures.length > 0) {
162
+ const narrowType = new SchemaAST.TypeLiteral(propertySignatures, []);
163
+ return Schema.make(narrowType);
164
+ }
165
+ }
166
+ return void 0;
167
+ };
168
+
169
+ // src/model/modal-controller.ts
170
+ import { Atom } from "@effect-atom/atom-react";
171
+ var ModalController = class {
172
+ _registry;
173
+ _state;
174
+ _triggerRef = {
175
+ current: null
176
+ };
177
+ constructor(registry) {
178
+ this._registry = registry;
179
+ this._state = Atom.make({
180
+ type: "closed"
181
+ });
182
+ }
183
+ get state() {
184
+ return this._state;
185
+ }
186
+ get stateValue() {
187
+ return this._registry.get(this._state);
188
+ }
189
+ get trigger() {
190
+ return this._triggerRef;
191
+ }
192
+ setTrigger = (trigger) => {
193
+ this._triggerRef.current = trigger;
194
+ };
195
+ showRowMenu = (rowIndex) => {
196
+ this._registry.set(this._state, {
197
+ type: "row",
198
+ rowIndex
199
+ });
200
+ };
201
+ showColumnMenu = (fieldId) => {
202
+ this._registry.set(this._state, {
203
+ type: "column",
204
+ fieldId
205
+ });
206
+ };
207
+ showColumnCreator = () => {
208
+ this._registry.set(this._state, {
209
+ type: "columnSettings",
210
+ mode: {
211
+ type: "create"
212
+ }
213
+ });
214
+ };
215
+ showReferencePanel = (targetId, schemaId) => {
216
+ this._registry.set(this._state, {
217
+ type: "refPanel",
218
+ targetId,
219
+ typename: schemaId
220
+ });
221
+ };
222
+ openColumnSettings = () => {
223
+ const currentState = this._registry.get(this._state);
224
+ if (currentState.type === "column") {
225
+ const fieldId = currentState.fieldId;
226
+ requestAnimationFrame(() => {
227
+ this._registry.set(this._state, {
228
+ type: "columnSettings",
229
+ mode: {
230
+ type: "edit",
231
+ fieldId
232
+ }
233
+ });
234
+ });
235
+ }
236
+ };
237
+ close = () => {
238
+ this._registry.set(this._state, {
239
+ type: "closed"
240
+ });
241
+ };
242
+ };
62
243
 
63
244
  // src/components/TableCellEditor/TableCellEditor.tsx
64
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
65
245
  import { EditorView } from "@codemirror/view";
66
246
  import React3, { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
67
247
  import { debounce } from "@dxos/async";
68
- import { FormatEnum as FormatEnum2, TypeEnum } from "@dxos/echo/internal";
248
+ import { Format, TypeEnum } from "@dxos/echo/internal";
69
249
  import { invariant as invariant2 } from "@dxos/invariant";
70
250
  import { GridCellEditor, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
71
251
 
72
252
  // src/components/TableCellEditor/CellValidationMessage.tsx
73
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
74
253
  import React from "react";
75
254
  import { useGridContext } from "@dxos/react-ui-grid";
76
- var CellValidationMessage = ({ validationError, variant = "error", __gridScope }) => {
77
- var _effect = _useSignals();
78
- try {
79
- const { editing, editBox: box } = useGridContext("GridSheetCellEditor", __gridScope);
80
- if (!editing || !validationError) {
81
- return null;
82
- }
83
- const bgClass = variant === "error" ? "bg-errorSurface" : "bg-warningSurface";
84
- const textClass = variant === "error" ? "text-errorSurfaceText" : "text-warningSurfaceText";
85
- return /* @__PURE__ */ React.createElement("div", {
86
- role: "none",
87
- className: `absolute ${bgClass} ${textClass} rounded-bs-sm text-xs p-1`,
88
- style: {
89
- ...{
90
- "--dx-gridCellWidth": `${box?.inlineSize ?? 200}px`
91
- },
92
- zIndex: 10,
93
- insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
94
- insetInlineStart: box.insetInlineStart,
95
- inlineSize: box.inlineSize
96
- }
97
- }, validationError);
98
- } finally {
99
- _effect.f();
255
+ var CellValidationMessage = ({ __gridScope, validationError, variant = "error" }) => {
256
+ const { editing, editBox: box } = useGridContext("GridSheetCellEditor", __gridScope);
257
+ if (!editing || !validationError) {
258
+ return null;
100
259
  }
260
+ const bgClass = variant === "error" ? "bg-error-surface" : "bg-warning-surface";
261
+ const textClass = variant === "error" ? "text-error-surface-text" : "text-warning-surface-text";
262
+ return /* @__PURE__ */ React.createElement("div", {
263
+ role: "none",
264
+ className: `absolute ${bgClass} ${textClass} rounded-h-sm text-xs p-1`,
265
+ style: {
266
+ ...{
267
+ "--dx-grid-cell-width": `${box?.inlineSize ?? 200}px`
268
+ },
269
+ zIndex: 10,
270
+ insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
271
+ insetInlineStart: box.insetInlineStart,
272
+ inlineSize: box.inlineSize
273
+ }
274
+ }, validationError);
101
275
  };
102
276
 
103
277
  // src/components/TableCellEditor/FormCellEditor.tsx
104
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
105
- import * as Schema from "effect/Schema";
106
278
  import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
107
- import { Filter, Obj } from "@dxos/echo";
108
- import { FormatEnum, Ref, getValue } from "@dxos/echo/internal";
279
+ import { Entity } from "@dxos/echo";
280
+ import { Ref as Ref2, getValue } from "@dxos/echo/internal";
109
281
  import { invariant } from "@dxos/invariant";
110
- import { getSnapshot } from "@dxos/live-object";
111
- import { getSpace } from "@dxos/react-client/echo";
112
282
  import { Popover } from "@dxos/react-ui";
113
283
  import { Form } from "@dxos/react-ui-form";
114
284
  import { parseCellIndex, useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
115
285
  import { getDeep, isTruthy, setDeep } from "@dxos/util";
116
286
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
117
287
  var createOptionLabel = [
118
- "create new object label",
288
+ "create-new-object.label",
119
289
  {
120
290
  ns: translationKey
121
291
  }
122
292
  ];
123
- var FormCellEditor = ({ fieldProjection, model, schema, onSave, client, modals, onCreate, __gridScope, ...formProps }) => {
124
- var _effect = _useSignals2();
125
- try {
126
- const { editing: contextEditing, setEditing, id: gridId } = useGridContext2("ArrayEditor", __gridScope);
127
- const [editing, setLocalEditing] = useState(false);
128
- const anchorRef = useRef(null);
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);
146
- }
147
- return {
148
- space,
149
- schema: schema2
150
- };
151
- }, [
152
- client,
153
- model
154
- ]);
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);
165
- }
166
- return [];
167
- }, [
168
- client,
169
- model
170
- ]);
171
- const originalRow = useMemo(() => {
172
- if (model && contextEditing) {
173
- const cell = parseCellIndex(contextEditing.index);
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
- }
199
- }
200
- return void 0;
201
- }, [
202
- model,
203
- contextEditing
204
- ]);
205
- const handleSave = useCallback((values) => {
206
- const path = fieldProjection.field.path;
207
- const value = getDeep(values, [
208
- path
209
- ]);
210
- setDeep(originalRow, [
211
- path
212
- ], value);
213
- contextEditing?.cellElement?.focus();
214
- setEditing(null);
293
+ var FormCellEditor = ({ __gridScope, schema, model, fieldProjection, onSave, onCreate, ...formProps }) => {
294
+ const anchorRef = useRef(null);
295
+ const { id: _gridId, editing: contextEditing, setEditing } = useGridContext2("ArrayEditor", __gridScope);
296
+ const [editing, setLocalEditing] = useState(false);
297
+ useEffect(() => {
298
+ if (contextEditing && contextEditing.cellElement) {
299
+ anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
300
+ setLocalEditing(true);
301
+ } else {
302
+ anchorRef.current = null;
215
303
  setLocalEditing(false);
216
- onSave?.();
217
- }, [
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),
304
+ }
305
+ }, [
306
+ contextEditing
307
+ ]);
308
+ const narrowedSchema = useMemo(() => {
309
+ if (!schema) {
310
+ return void 0;
311
+ }
312
+ return narrowSchema(schema, [
243
313
  fieldProjection.field.path
244
314
  ]);
245
- const formValues = useMemo(() => originalRow ? getSnapshot(originalRow) : {}, [
246
- originalRow
247
- ]);
248
- const handleOpenChange = useCallback((nextOpen) => {
249
- if (nextOpen === false) {
250
- setEditing(null);
251
- onSave?.();
252
- }
253
- setLocalEditing(nextOpen);
254
- }, []);
255
- const refSchema = useMemo(() => {
256
- if (fieldProjection.props.format === FormatEnum.Ref && fieldProjection.props.referenceSchema) {
257
- const { schema: refSchema2 } = getSchema({
258
- typename: fieldProjection.props.referenceSchema
315
+ }, [
316
+ JSON.stringify(schema),
317
+ fieldProjection.field.path
318
+ ]);
319
+ const originalRow = useMemo(() => {
320
+ if (model && contextEditing) {
321
+ const cell = parseCellIndex(contextEditing.index);
322
+ if (model.isDraftCell(cell)) {
323
+ const draftRow = model.getDraftRows()[cell.row];
324
+ invariant(draftRow, void 0, {
325
+ F: __dxlog_file,
326
+ L: 74,
327
+ S: void 0,
328
+ A: [
329
+ "draftRow",
330
+ ""
331
+ ]
259
332
  });
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
- }
333
+ return draftRow.data;
334
+ } else {
335
+ const row = model.getRowAt(cell.row);
336
+ invariant(row, void 0, {
337
+ F: __dxlog_file,
338
+ L: 78,
339
+ S: void 0,
340
+ A: [
341
+ "row",
342
+ ""
343
+ ]
344
+ });
345
+ return row;
283
346
  }
284
- contextEditing?.cellElement?.focus();
347
+ }
348
+ return void 0;
349
+ }, [
350
+ model,
351
+ contextEditing
352
+ ]);
353
+ const initialFormValues = useMemo(() => originalRow ? JSON.parse(JSON.stringify(originalRow)) : {}, [
354
+ originalRow
355
+ ]);
356
+ const [formValues, setFormValues] = useState(initialFormValues);
357
+ const handleValuesChanged = useCallback((values) => {
358
+ setFormValues(values);
359
+ }, []);
360
+ const handleOpenChange = useCallback((nextOpen) => {
361
+ if (nextOpen === false) {
285
362
  setEditing(null);
286
- setLocalEditing(false);
287
363
  onSave?.();
288
- }, [
289
- fieldProjection.field.path,
290
- onSave,
291
- contextEditing,
292
- originalRow,
293
- refSchema,
294
- onCreate
364
+ }
365
+ setLocalEditing(nextOpen);
366
+ }, []);
367
+ const handleSave = useCallback((values) => {
368
+ if (!originalRow) {
369
+ return;
370
+ }
371
+ const path = fieldProjection.field.path;
372
+ const value = getDeep(values, [
373
+ path
295
374
  ]);
296
- if (!editing) {
297
- return null;
375
+ if (model) {
376
+ model.changeRow(originalRow, (mutableRow) => {
377
+ setDeep(mutableRow, [
378
+ path
379
+ ], value);
380
+ });
381
+ } else {
382
+ setDeep(originalRow, [
383
+ path
384
+ ], value);
298
385
  }
299
- return /* @__PURE__ */ React2.createElement(Popover.Root, {
300
- open: editing,
301
- onOpenChange: handleOpenChange
302
- }, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
303
- virtualRef: anchorRef
304
- }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
305
- tabIndex: -1,
306
- classNames: "popover-card-width density-fine"
307
- }, /* @__PURE__ */ React2.createElement(Popover.Arrow, null), /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(Form, {
308
- autoFocus: true,
309
- values: formValues,
310
- schema: narrowedSchema,
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
386
+ contextEditing?.cellElement?.focus();
387
+ setEditing(null);
388
+ setLocalEditing(false);
389
+ onSave?.();
390
+ }, [
391
+ fieldProjection.field.path,
392
+ onSave,
393
+ contextEditing,
394
+ originalRow,
395
+ model
396
+ ]);
397
+ const handleCreate = useCallback((schema2, values) => {
398
+ const objectWithId = onCreate?.(schema2, values);
399
+ if (objectWithId && originalRow) {
400
+ const ref = Ref2.make(objectWithId);
401
+ const path = fieldProjection.field.path;
402
+ if (model) {
403
+ model.changeRow(originalRow, (mutableRow) => {
404
+ setDeep(mutableRow, [
405
+ path
406
+ ], ref);
407
+ });
408
+ } else {
409
+ setDeep(originalRow, [
410
+ path
411
+ ], ref);
320
412
  }
321
- })))));
322
- } finally {
323
- _effect.f();
413
+ }
414
+ contextEditing?.cellElement?.focus();
415
+ setEditing(null);
416
+ setLocalEditing(false);
417
+ onSave?.();
418
+ }, [
419
+ fieldProjection.field.path,
420
+ onSave,
421
+ contextEditing,
422
+ originalRow,
423
+ onCreate,
424
+ model
425
+ ]);
426
+ const getOptions = useCallback((results) => results.map((obj) => {
427
+ return {
428
+ id: Entity.getDXN(obj).toString(),
429
+ label: getValue(obj, fieldProjection.field.referencePath) || obj.id.toString()
430
+ };
431
+ }).filter(isTruthy), [
432
+ fieldProjection
433
+ ]);
434
+ if (!editing) {
435
+ return null;
324
436
  }
437
+ return /* @__PURE__ */ React2.createElement(Popover.Root, {
438
+ open: editing,
439
+ onOpenChange: handleOpenChange
440
+ }, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
441
+ virtualRef: anchorRef
442
+ }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
443
+ tabIndex: -1,
444
+ classNames: "dx-card-popover-width dx-density-fine"
445
+ }, /* @__PURE__ */ React2.createElement(Popover.Arrow, null), /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(Form.Root, {
446
+ ...formProps,
447
+ autoFocus: true,
448
+ schema: narrowedSchema,
449
+ values: formValues,
450
+ onValuesChanged: handleValuesChanged,
451
+ projection: model?.projection,
452
+ createInitialValuePath: fieldProjection.field.referencePath,
453
+ createOptionIcon: "ph--plus--regular",
454
+ createOptionLabel,
455
+ db: model?.db,
456
+ getOptions,
457
+ onCreate: handleCreate,
458
+ onSave: handleSave
459
+ }, /* @__PURE__ */ React2.createElement(Form.Viewport, null, /* @__PURE__ */ React2.createElement(Form.Content, null, /* @__PURE__ */ React2.createElement(Form.FieldSet, null), /* @__PURE__ */ React2.createElement(Form.Actions, null))))))));
325
460
  };
326
461
 
327
462
  // src/components/TableCellEditor/TableCellEditor.tsx
328
463
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
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();
332
- try {
333
- const { editing } = useGridContext3("TableValueEditor", __gridScope);
334
- const fieldProjection = useMemo2(() => {
335
- if (!model || !editing) {
336
- return;
337
- }
338
- const { col } = parseCellIndex2(editing.index);
339
- const field = model.projection.fields[col];
340
- const fieldProjection2 = model.projection.getFieldProjection(field.id);
341
- invariant2(fieldProjection2, void 0, {
342
- F: __dxlog_file2,
343
- L: 71,
344
- S: void 0,
345
- A: [
346
- "fieldProjection",
347
- ""
348
- ]
349
- });
350
- return fieldProjection2;
351
- }, [
352
- model,
353
- editing
354
- ]);
355
- if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum2.SingleSelect || fieldProjection?.props.format === FormatEnum2.Ref) {
356
- return /* @__PURE__ */ React3.createElement(FormCellEditor, {
357
- fieldProjection,
358
- model,
359
- schema,
360
- __gridScope,
361
- onSave,
362
- onCreate,
363
- client,
364
- modals
365
- });
464
+ var documentSlots = {
465
+ scroll: {
466
+ className: "!py-(--dx-grid-cell-editor-padding-block)"
467
+ }
468
+ };
469
+ var TableValueEditor = ({ __gridScope, schema, model, modals, onFocus, onSave, onCreate }) => {
470
+ const { editing } = useGridContext3("TableValueEditor", __gridScope);
471
+ const fieldProjection = useMemo2(() => {
472
+ if (!model || !editing) {
473
+ return;
366
474
  }
367
- return /* @__PURE__ */ React3.createElement(TableCellEditor, {
475
+ const { col } = parseCellIndex2(editing.index);
476
+ const field = model.projection.getFields()[col];
477
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
478
+ invariant2(fieldProjection2, void 0, {
479
+ F: __dxlog_file2,
480
+ L: 72,
481
+ S: void 0,
482
+ A: [
483
+ "fieldProjection",
484
+ ""
485
+ ]
486
+ });
487
+ return fieldProjection2;
488
+ }, [
489
+ model,
490
+ editing
491
+ ]);
492
+ if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === Format.TypeFormat.SingleSelect || fieldProjection?.props.format === Format.TypeFormat.Ref) {
493
+ return /* @__PURE__ */ React3.createElement(FormCellEditor, {
494
+ __gridScope,
495
+ schema,
368
496
  model,
497
+ fieldProjection,
369
498
  modals,
370
- onFocus,
371
499
  onSave,
372
- __gridScope
500
+ onCreate
373
501
  });
374
- } finally {
375
- _effect.f();
376
- }
377
- };
378
- var editorSlots = {
379
- scroll: {
380
- className: "!plb-[--dx-grid-cell-editor-padding-block]"
381
502
  }
503
+ return /* @__PURE__ */ React3.createElement(TableCellEditor, {
504
+ model,
505
+ modals,
506
+ onFocus,
507
+ onSave,
508
+ __gridScope
509
+ });
382
510
  };
383
- var TableCellEditor = ({ model, modals, onFocus, onSave, __gridScope }) => {
384
- var _effect = _useSignals3();
385
- try {
386
- const { editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
387
- const suppressNextBlur = useRef2(false);
388
- const [validationError, setValidationError] = useState2(null);
389
- const [validationVariant, setValidationVariant] = useState2("error");
390
- const fieldProjection = useMemo2(() => {
391
- if (!model || !editing) {
392
- return;
393
- }
394
- const { col } = parseCellIndex2(editing.index);
395
- const field = model.projection.fields[col];
396
- const fieldProjection2 = model.projection.getFieldProjection(field.id);
397
- invariant2(fieldProjection2, void 0, {
398
- F: __dxlog_file2,
399
- L: 121,
400
- S: void 0,
401
- A: [
402
- "fieldProjection",
403
- ""
404
- ]
405
- });
406
- return fieldProjection2;
407
- }, [
408
- model,
409
- editing
410
- ]);
411
- const handleEnter = useCallback2(async (value) => {
412
- if (!model || !editing) {
413
- return;
414
- }
415
- const cell = parseCellIndex2(editing.index);
416
- const validationResult = await model.validateCellData(cell, value);
417
- if (validationResult.valid) {
418
- setValidationError(null);
419
- model.setCellData(cell, value);
420
- onFocus?.();
421
- setEditing(null);
422
- onSave?.();
423
- } else {
424
- setValidationError(adaptValidationMessage(validationResult.error));
425
- setValidationVariant("error");
426
- }
427
- }, [
428
- model,
429
- editing,
430
- onFocus,
431
- setEditing
432
- ]);
433
- const handleBlur = useCallback2(async (value) => {
434
- if (suppressNextBlur.current) {
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
- }
447
- }
448
- }, [
449
- model,
450
- editing
451
- ]);
452
- const handleClose = useCallback2(async (value, event) => {
453
- if (!model || !editing || !fieldProjection) {
454
- return;
455
- }
511
+ var TableCellEditor = ({ __gridScope, model, modals, onFocus, onSave }) => {
512
+ const { editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
513
+ const suppressNextBlur = useRef2(false);
514
+ const [validationError, setValidationError] = useState2(null);
515
+ const [validationVariant, setValidationVariant] = useState2("error");
516
+ const fieldProjection = useMemo2(() => {
517
+ if (!model || !editing) {
518
+ return;
519
+ }
520
+ const { col } = parseCellIndex2(editing.index);
521
+ const field = model.projection.getFields()[col];
522
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
523
+ invariant2(fieldProjection2, void 0, {
524
+ F: __dxlog_file2,
525
+ L: 119,
526
+ S: void 0,
527
+ A: [
528
+ "fieldProjection",
529
+ ""
530
+ ]
531
+ });
532
+ return fieldProjection2;
533
+ }, [
534
+ model,
535
+ editing
536
+ ]);
537
+ const handleEnter = useCallback2(async (value) => {
538
+ if (!model || !editing) {
539
+ return;
540
+ }
541
+ const cell = parseCellIndex2(editing.index);
542
+ const validationResult = await model.validateCellData(cell, value);
543
+ if (validationResult.valid) {
544
+ setValidationError(null);
545
+ model.setCellData(cell, value);
546
+ onFocus?.();
547
+ setEditing(null);
548
+ onSave?.();
549
+ } else {
550
+ setValidationError(validationResult.error);
551
+ setValidationVariant("error");
552
+ }
553
+ }, [
554
+ model,
555
+ editing,
556
+ onFocus,
557
+ setEditing
558
+ ]);
559
+ const handleBlur = useCallback2(async (value) => {
560
+ if (suppressNextBlur.current) {
561
+ suppressNextBlur.current = false;
562
+ } else if (model && editing) {
456
563
  const cell = parseCellIndex2(editing.index);
457
564
  if (value !== void 0) {
458
565
  const result = await model.validateCellData(cell, value);
459
566
  if (result.valid) {
460
- suppressNextBlur.current = true;
461
567
  setValidationError(null);
462
568
  model.setCellData(cell, value);
463
569
  setEditing(null);
464
570
  onSave?.();
465
- if (event && onFocus) {
466
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
467
- }
468
- } else {
469
- setValidationError(result.error);
470
- setValidationVariant("error");
471
571
  }
472
- } else {
572
+ }
573
+ }
574
+ }, [
575
+ model,
576
+ editing
577
+ ]);
578
+ const handleClose = useCallback2(async (value, event) => {
579
+ if (!model || !editing || !fieldProjection) {
580
+ return;
581
+ }
582
+ const cell = parseCellIndex2(editing.index);
583
+ if (value !== void 0) {
584
+ const result = await model.validateCellData(cell, value);
585
+ if (result.valid) {
473
586
  suppressNextBlur.current = true;
474
587
  setValidationError(null);
588
+ model.setCellData(cell, value);
475
589
  setEditing(null);
476
590
  onSave?.();
477
591
  if (event && onFocus) {
478
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
592
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
479
593
  }
594
+ } else {
595
+ setValidationError(result.error);
596
+ setValidationVariant("error");
480
597
  }
481
- }, [
482
- model,
483
- editing,
484
- onFocus,
485
- fieldProjection,
486
- setEditing,
487
- onSave
488
- ]);
489
- const extensions = useMemo2(() => {
490
- if (!fieldProjection) {
491
- return [];
492
- }
493
- const extensions2 = [
494
- editorKeys({
495
- onClose: handleClose,
496
- ...editing?.initialContent && {
497
- onNav: handleClose
498
- }
499
- })
500
- ];
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");
511
- }
512
- });
513
- }, 10)));
598
+ } else {
599
+ suppressNextBlur.current = true;
600
+ setValidationError(null);
601
+ setEditing(null);
602
+ onSave?.();
603
+ if (event && onFocus) {
604
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
514
605
  }
515
- return extensions2;
516
- }, [
517
- model,
518
- modals,
519
- editing,
520
- fieldProjection,
521
- handleClose
522
- ]);
523
- const getCellContent = useCallback2(() => {
524
- if (model && editing) {
606
+ }
607
+ }, [
608
+ model,
609
+ editing,
610
+ onFocus,
611
+ fieldProjection,
612
+ setEditing,
613
+ onSave
614
+ ]);
615
+ const extensions = useMemo2(() => {
616
+ if (!fieldProjection) {
617
+ return [];
618
+ }
619
+ const extensions2 = [
620
+ editorKeys({
621
+ onClose: handleClose,
622
+ ...editing?.initialContent && {
623
+ onNav: handleClose
624
+ }
625
+ })
626
+ ];
627
+ if (model && editing) {
628
+ extensions2.push(EditorView.updateListener.of(debounce((update) => {
629
+ const content = update.state.doc.toString();
525
630
  const cell = parseCellIndex2(editing.index);
526
- const value = model.getCellData(cell);
527
- return value !== void 0 ? String(value) : "";
528
- }
529
- }, [
530
- model,
531
- editing
532
- ]);
533
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(CellValidationMessage, {
534
- validationError,
535
- variant: validationVariant,
536
- __gridScope
537
- }), /* @__PURE__ */ React3.createElement(GridCellEditor, {
538
- extensions,
539
- getCellContent,
540
- onBlur: handleBlur,
541
- slots: editorSlots
542
- }));
543
- } finally {
544
- _effect.f();
545
- }
631
+ void model.validateCellData(cell, content).then((result) => {
632
+ if (result.valid) {
633
+ setValidationError(null);
634
+ } else {
635
+ setValidationError(result.error);
636
+ setValidationVariant("error");
637
+ }
638
+ });
639
+ }, 10)));
640
+ }
641
+ return extensions2;
642
+ }, [
643
+ model,
644
+ modals,
645
+ editing,
646
+ fieldProjection,
647
+ handleClose
648
+ ]);
649
+ const getCellContent = useCallback2(() => {
650
+ if (model && editing) {
651
+ const cell = parseCellIndex2(editing.index);
652
+ const value = model.getCellData(cell);
653
+ return value !== void 0 ? String(value) : "";
654
+ }
655
+ }, [
656
+ model,
657
+ editing
658
+ ]);
659
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(CellValidationMessage, {
660
+ validationError,
661
+ variant: validationVariant,
662
+ __gridScope
663
+ }), /* @__PURE__ */ React3.createElement(GridCellEditor, {
664
+ extensions,
665
+ getCellContent,
666
+ onBlur: handleBlur,
667
+ slots: documentSlots
668
+ }));
546
669
  };
547
670
  var determineNavigationAxis = ({ key }) => {
548
671
  switch (key) {
@@ -570,154 +693,140 @@ var determineNavigationDelta = ({ key, shift }) => {
570
693
  };
571
694
 
572
695
  // src/components/Table/ColumnActionsMenu.tsx
573
- import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
696
+ import { useAtomValue } from "@effect-atom/atom-react";
574
697
  import React4 from "react";
575
698
  import { DropdownMenu, useTranslation } from "@dxos/react-ui";
576
699
  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();
700
+ const { t } = useTranslation(translationKey);
701
+ const state = useAtomValue(modals.state);
702
+ if (state?.type !== "column") {
703
+ return null;
610
704
  }
705
+ const currentSort = model.getSorting();
706
+ const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
707
+ return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
708
+ modal: false,
709
+ open: true,
710
+ onOpenChange: modals.close
711
+ }, /* @__PURE__ */ React4.createElement(DropdownMenu.VirtualTrigger, {
712
+ virtualRef: modals.trigger
713
+ }), /* @__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, {
714
+ "data-testid": "column-sort-descending",
715
+ onClick: () => model.setSort(state.fieldId, "desc")
716
+ }, t("column-action-sort-descending.menu")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
717
+ "data-testid": "column-sort-ascending",
718
+ onClick: () => model.setSort(state.fieldId, "asc")
719
+ }, t("column-action-sort-ascending.menu")), isCurrentColumnSorted && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
720
+ "data-testid": "column-clear-sort",
721
+ onClick: () => model.clearSort()
722
+ }, t("column-action-clear-sorting.menu")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
723
+ "data-testid": "column-delete",
724
+ onClick: () => model.deleteColumn(state.fieldId)
725
+ }, t("column-action-delete.menu")), model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
726
+ "data-testid": "column-settings",
727
+ onClick: () => modals.openColumnSettings()
728
+ }, t("column-action-settings.menu"))), /* @__PURE__ */ React4.createElement(DropdownMenu.Arrow, null))));
611
729
  };
612
730
 
613
731
  // src/components/Table/ColumnSettings.tsx
614
- import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
732
+ import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
615
733
  import React5, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useState as useState3 } from "react";
616
734
  import { Popover as Popover2 } from "@dxos/react-ui";
617
735
  import { FieldEditor } from "@dxos/react-ui-form";
618
736
  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);
737
+ const [newField, setNewField] = useState3();
738
+ const state = useAtomValue2(modals.state);
739
+ useEffect2(() => {
740
+ if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
741
+ setNewField(model.projection.createFieldProjection());
742
+ requestAnimationFrame(() => {
743
+ onNewColumn();
744
+ });
745
+ } else {
746
+ setNewField(void 0);
747
+ }
748
+ }, [
749
+ model?.projection,
750
+ state
751
+ ]);
752
+ const existingField = useMemo3(() => {
753
+ if (state?.type === "columnSettings") {
754
+ const { mode } = state;
755
+ if (mode.type === "edit") {
756
+ return model?.projection?.getFields().find((f) => f.id === mode.fieldId);
657
757
  }
658
- }, [
659
- model?.projection,
660
- state,
661
- newField
662
- ]);
663
- if (!model?.projection || !field) {
664
- return null;
665
758
  }
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();
759
+ return void 0;
760
+ }, [
761
+ model?.projection,
762
+ state
763
+ ]);
764
+ const field = existingField ?? newField;
765
+ const handleSave = useCallback3(() => {
766
+ modals.close();
767
+ }, [
768
+ modals
769
+ ]);
770
+ const handleCancel = useCallback3(() => {
771
+ if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
772
+ model?.projection.deleteFieldProjection(newField.id);
773
+ }
774
+ }, [
775
+ model?.projection,
776
+ state,
777
+ newField
778
+ ]);
779
+ if (!model?.projection || !field) {
780
+ return null;
682
781
  }
782
+ return /* @__PURE__ */ React5.createElement(Popover2.Root, {
783
+ modal: false,
784
+ open: state?.type === "columnSettings"
785
+ }, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
786
+ virtualRef: modals.trigger
787
+ }), /* @__PURE__ */ React5.createElement(Popover2.Portal, null, /* @__PURE__ */ React5.createElement(Popover2.Content, {
788
+ classNames: "md:w-64"
789
+ }, /* @__PURE__ */ React5.createElement(Popover2.Viewport, null, /* @__PURE__ */ React5.createElement(FieldEditor, {
790
+ projection: model.projection,
791
+ field,
792
+ registry,
793
+ onSave: handleSave,
794
+ onCancel: handleCancel
795
+ })), /* @__PURE__ */ React5.createElement(Popover2.Arrow, null))));
683
796
  };
684
797
 
685
798
  // src/components/Table/RowActionsMenu.tsx
686
- import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
799
+ import { useAtomValue as useAtomValue3 } from "@effect-atom/atom-react";
687
800
  import React6 from "react";
688
801
  import { DropdownMenu as DropdownMenu2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
689
802
  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();
803
+ const { t } = useTranslation2(translationKey);
804
+ const hasSelection = model.selection.hasSelection;
805
+ const state = useAtomValue3(modals.state);
806
+ if (state?.type !== "row") {
807
+ return null;
717
808
  }
809
+ return /* @__PURE__ */ React6.createElement(DropdownMenu2.Root, {
810
+ modal: false,
811
+ open: true,
812
+ onOpenChange: modals.close
813
+ }, /* @__PURE__ */ React6.createElement(DropdownMenu2.VirtualTrigger, {
814
+ virtualRef: modals.trigger
815
+ }), /* @__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, {
816
+ key: action.id,
817
+ "data-testid": `row-action-${action.id}`,
818
+ onClick: () => {
819
+ modals.close();
820
+ model.handleRowAction(action.id, state.rowIndex);
821
+ }
822
+ }, toLocalizedString(action.label, t)))), /* @__PURE__ */ React6.createElement(DropdownMenu2.Separator, null)), model.features.dataEditable !== false && /* @__PURE__ */ React6.createElement(DropdownMenu2.Item, {
823
+ "data-testid": "row-menu-delete",
824
+ onClick: () => model.deleteRow(state.rowIndex)
825
+ }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React6.createElement(DropdownMenu2.Arrow, null)));
718
826
  };
719
827
 
720
- // src/components/Table/Table.tsx
828
+ // src/components/Table/TableContent.tsx
829
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/Table/TableContent.tsx";
721
830
  var columnDefault = {
722
831
  grid: {
723
832
  minSize: 80,
@@ -730,454 +839,385 @@ var rowDefault = {
730
839
  focusUnfurl: false
731
840
  }
732
841
  };
733
- var TableRoot = ({ children, role = "article" }) => {
734
- var _effect = _useSignals7();
735
- try {
736
- return /* @__PURE__ */ React7.createElement("div", {
737
- role: "none",
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]", [
739
- "card--popover",
740
- "section",
741
- "card--extrinsic"
742
- ].includes(role) && "overflow-hidden", [
743
- "article",
744
- "slide"
745
- ].includes(role) && "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:bs-0")
746
- }, children);
747
- } finally {
748
- _effect.f();
749
- }
750
- };
751
- var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention, schema, client, onCreate, onRowClick, testId }, forwardedRef) => {
752
- var _effect = _useSignals7();
753
- try {
754
- const [dxGrid, setDxGrid] = useState4(null);
755
- const { hasAttention } = useAttention(model?.id ?? "table");
756
- const modals = useMemo4(() => new ModalController(), []);
757
- const draftRowCount = model?.getDraftRowCount() ?? 0;
758
- const handleSave = useCallback4(() => {
759
- dxGrid?.updateCells(true);
760
- dxGrid?.requestUpdate();
761
- }, [
762
- dxGrid
763
- ]);
764
- const frozen = useMemo4(() => {
765
- const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
766
- return {
767
- frozenRowsStart: 1,
768
- frozenRowsEnd: Math.max(1, draftRowCount),
769
- frozenColsStart: model?.features.selection.enabled ? 1 : 0,
770
- frozenColsEnd: noActionColumn ? 0 : 1
771
- };
772
- }, [
773
- model,
774
- draftRowCount
775
- ]);
776
- const getCells = useCallback4((range, plane) => presentation?.getCells(range, plane) ?? {}, [
777
- presentation
778
- ]);
779
- useEffect3(() => {
780
- if (!presentation || !dxGrid) {
781
- return;
782
- }
783
- dxGrid.getCells = getCells;
784
- }, [
785
- presentation,
786
- dxGrid,
787
- getCells
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();
842
+ var emptyColumnMeta = Atom2.make({
843
+ grid: {}
844
+ });
845
+ var emptyRowsAtom = Atom2.make([]);
846
+ var emptyCellUpdateAtom = Atom2.make(0);
847
+ var TABLE_CONTENT_NAME = "Table.Content";
848
+ var TableContent = composable(({ schema, model, presentation, ignoreAttention, onCreate, onRowClick, testId, ...props }, forwardedRef) => {
849
+ const registry = useContext(RegistryContext);
850
+ const [dxGrid, setDxGrid] = useState4(null);
851
+ const { hasAttention } = useAttention(model?.id ?? "table");
852
+ const modals = useMemo4(() => new ModalController(registry), [
853
+ registry
854
+ ]);
855
+ const columnMeta = useAtomValue4(model?.columnMeta ?? emptyColumnMeta);
856
+ const rows = useAtomValue4(model?.rows ?? emptyRowsAtom);
857
+ const cellUpdateCounter = useAtomValue4(model?.cellUpdate ?? emptyCellUpdateAtom);
858
+ const columnCount = Object.keys(columnMeta.grid).length || model?.projection.getFields().length || 0;
859
+ const draftRowCount = model?.getDraftRowCount() ?? 0;
860
+ const frozen = useMemo4(() => {
861
+ const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
862
+ return {
863
+ frozenRowsStart: 1,
864
+ frozenRowsEnd: Math.max(1, draftRowCount),
865
+ frozenColsStart: model?.features.selection.enabled ? 1 : 0,
866
+ frozenColsEnd: noActionColumn ? 0 : 1
867
+ };
868
+ }, [
869
+ model,
870
+ draftRowCount
871
+ ]);
872
+ const getCells = useCallback4((range, plane) => presentation?.getCells(range, plane) ?? {}, [
873
+ presentation
874
+ ]);
875
+ useEffect3(() => {
876
+ if (!dxGrid || !presentation) {
877
+ return;
878
+ }
879
+ dxGrid.getCells = getCells;
880
+ }, [
881
+ dxGrid,
882
+ presentation,
883
+ getCells
884
+ ]);
885
+ useEffect3(() => {
886
+ if (!dxGrid) {
887
+ return;
888
+ }
889
+ dxGrid.updateCells(true);
890
+ dxGrid.requestUpdate();
891
+ }, [
892
+ dxGrid,
893
+ rows,
894
+ cellUpdateCounter
895
+ ]);
896
+ const handleInsertRowResult = useCallback4((insertResult) => {
897
+ if (insertResult === "draft") {
898
+ requestAnimationFrame(() => {
899
+ dxGrid?.setFocus({
900
+ plane: "frozenRowsEnd",
901
+ col: 0,
902
+ row: 0
798
903
  });
799
- } else {
904
+ dxGrid?.refocus();
905
+ });
906
+ } else {
907
+ requestAnimationFrame(() => {
908
+ dxGrid?.setFocus({
909
+ plane: "grid",
910
+ col: 0,
911
+ row: model ? model.getRowCount() - 1 : 0
912
+ });
913
+ dxGrid?.refocus();
914
+ });
915
+ }
916
+ }, [
917
+ model,
918
+ dxGrid
919
+ ]);
920
+ const handleSave = useCallback4(() => {
921
+ dxGrid?.updateCells(true);
922
+ dxGrid?.requestUpdate();
923
+ }, [
924
+ dxGrid
925
+ ]);
926
+ const handleSaveDraftRow = useCallback4((rowIndex = 0) => {
927
+ if (model && dxGrid) {
928
+ const didCommitSuccessfully = model.commitDraftRow(rowIndex);
929
+ if (didCommitSuccessfully) {
800
930
  requestAnimationFrame(() => {
801
- dxGrid?.setFocus({
802
- plane: "grid",
803
- col: 0,
804
- row: model ? model.getRowCount() - 1 : 0
805
- });
806
- dxGrid?.refocus();
931
+ dxGrid.scrollToEndRow();
807
932
  });
808
933
  }
809
- }, [
810
- model,
811
- dxGrid
812
- ]);
813
- useImperativeHandle(forwardedRef, () => {
814
- if (!presentation || !dxGrid) {
815
- return {};
816
- }
817
- return {
818
- update: (cell) => {
819
- if (cell) {
820
- dxGrid.updateIfWithinBounds(cell, true);
821
- } else {
822
- dxGrid.updateCells(true);
823
- dxGrid.requestUpdate();
824
- }
825
- },
826
- handleInsertRowResult
827
- };
828
- }, [
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
- });
934
+ }
935
+ }, [
936
+ model,
937
+ dxGrid
938
+ ]);
939
+ const handleGridClick = useCallback4((event) => {
940
+ const cell = closestCell(event.target);
941
+ if (cell) {
942
+ const { row: rowIndex, plane } = cell;
943
+ if (onRowClick) {
944
+ if (plane === "grid") {
945
+ const row = model?.getRowAt(rowIndex);
946
+ row && onRowClick(row);
947
+ } else {
948
+ onRowClick(cell);
840
949
  }
841
950
  }
842
- }, [
843
- model,
844
- dxGrid
845
- ]);
846
- const handleGridClick = useCallback4((event) => {
847
- const cell = closestCell(event.target);
848
- if (cell) {
849
- const { row: rowIndex, plane } = cell;
850
- if (onRowClick) {
851
- if (plane === "grid") {
852
- const row = model?.getRowAt(rowIndex);
853
- row && onRowClick(row);
854
- } else {
855
- onRowClick(cell);
856
- }
857
- }
858
- if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
859
- model.selection.toggleSelectionForRowIndex(rowIndex);
860
- }
951
+ if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
952
+ model.selection.toggleSelectionForRowIndex(rowIndex);
861
953
  }
862
- if (!modals) {
954
+ }
955
+ if (!modals) {
956
+ return;
957
+ }
958
+ const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
959
+ const tableButtonElement = event.target.closest(buttonSelector);
960
+ if (tableButtonElement) {
961
+ const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
962
+ if (!button) {
863
963
  return;
864
964
  }
865
- const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
866
- const tableButtonElement = event.target.closest(buttonSelector);
867
- if (tableButtonElement) {
868
- const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
869
- if (!button) {
870
- return;
965
+ modals.setTrigger(tableButtonElement);
966
+ const data = button.getData(tableButtonElement);
967
+ switch (data.type) {
968
+ case "rowMenu": {
969
+ modals.showRowMenu(data.rowIndex);
970
+ break;
871
971
  }
872
- modals.setTrigger(tableButtonElement);
873
- const data = button.getData(tableButtonElement);
874
- switch (data.type) {
875
- case "rowMenu": {
876
- modals.showRowMenu(data.rowIndex);
877
- break;
878
- }
879
- case "columnSettings": {
880
- modals.showColumnMenu(data.fieldId);
881
- break;
882
- }
883
- case "newColumn": {
884
- modals.showColumnCreator();
885
- break;
886
- }
887
- case "sort": {
888
- model?.sorting?.toggleSort(data.fieldId);
889
- break;
890
- }
891
- case "saveDraftRow": {
892
- handleSaveDraftRow();
893
- break;
894
- }
972
+ case "columnSettings": {
973
+ modals.showColumnMenu(data.fieldId);
974
+ break;
895
975
  }
896
- return;
897
- }
898
- const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
899
- const controlElement = event.target.closest(controlSelector);
900
- if (controlElement) {
901
- const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
902
- if (!control) {
903
- return;
976
+ case "newColumn": {
977
+ modals.showColumnCreator();
978
+ break;
904
979
  }
905
- const data = control.getData(controlElement);
906
- switch (data.type) {
907
- case "checkbox": {
908
- if (data.header) {
909
- model?.selection.setSelection(model.selection.allRowsSeleted.value ? "none" : "all");
910
- } else {
911
- model?.selection.toggleSelectionForRowIndex(data.rowIndex);
912
- }
913
- break;
914
- }
915
- case "switch": {
916
- if (model) {
917
- model.updateCellData({
918
- row: data.rowIndex,
919
- col: data.colIndex
920
- }, (value) => !value);
921
- }
922
- break;
923
- }
980
+ case "sort": {
981
+ model?.toggleSort(data.fieldId);
982
+ break;
924
983
  }
925
- }
926
- }, [
927
- model,
928
- modals,
929
- dxGrid
930
- ]);
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);
984
+ case "saveDraftRow": {
985
+ handleSaveDraftRow();
986
+ break;
940
987
  }
941
988
  }
942
- }, [
943
- dxGrid,
944
- model
945
- ]);
946
- const handleKeyDown = useCallback4((event) => {
947
- if (!model?.features.dataEditable) {
948
- return;
949
- }
950
- const cell = closestCell(event.target);
951
- if (!model || !cell) {
989
+ return;
990
+ }
991
+ const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
992
+ const controlElement = event.target.closest(controlSelector);
993
+ if (controlElement) {
994
+ const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
995
+ if (!control) {
952
996
  return;
953
997
  }
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;
998
+ const data = control.getData(controlElement);
999
+ switch (data.type) {
1000
+ case "checkbox": {
1001
+ if (data.header) {
1002
+ model?.selection.setSelection(model.selection.allRowsSelected ? "none" : "all");
1003
+ } else {
1004
+ model?.selection.toggleSelectionForRowIndex(data.rowIndex);
966
1005
  }
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;
1006
+ break;
1007
+ }
1008
+ case "switch": {
1009
+ if (model) {
1010
+ model.updateCellData({
1011
+ row: data.rowIndex,
1012
+ col: data.colIndex
1013
+ }, (value) => !value);
993
1014
  }
1015
+ break;
994
1016
  }
995
1017
  }
1018
+ }
1019
+ }, [
1020
+ model,
1021
+ modals,
1022
+ dxGrid
1023
+ ]);
1024
+ const handleFocus = useCallback4((increment, delta, cell) => {
1025
+ if (dxGrid && model) {
1026
+ if (cell?.plane === "grid" && cell?.row >= model.getRowCount() - 1 && increment !== "col") {
1027
+ handleInsertRowResult(draftRowCount < 1 ? model.insertRow() : "final");
1028
+ } else if (cell?.plane === "frozenRowsEnd" && increment === "row") {
1029
+ handleSaveDraftRow(cell.row);
1030
+ handleInsertRowResult(model.insertRow());
1031
+ } else {
1032
+ dxGrid.refocus(increment, delta);
1033
+ }
1034
+ }
1035
+ }, [
1036
+ dxGrid,
1037
+ model
1038
+ ]);
1039
+ const handleKeyDown = useCallback4((event) => {
1040
+ if (!model?.features.dataEditable) {
1041
+ return;
1042
+ }
1043
+ const cell = closestCell(event.target);
1044
+ if (!model || !cell) {
1045
+ return;
1046
+ }
1047
+ if (event.metaKey || event.ctrlKey) {
996
1048
  switch (event.key) {
997
- case "Backspace":
998
- case "Delete": {
1049
+ case "c": {
999
1050
  try {
1000
- model.setCellData(cell, void 0);
1051
+ const cellData = model.getCellData(cell);
1052
+ const textContent = cellData?.toString() ?? "";
1053
+ void navigator.clipboard.writeText(textContent);
1001
1054
  event.preventDefault();
1002
- handleSave();
1003
- } catch {
1055
+ } catch (error) {
1056
+ log.catch(error, void 0, {
1057
+ F: __dxlog_file3,
1058
+ L: 278,
1059
+ S: void 0,
1060
+ C: (f, a) => f(...a)
1061
+ });
1004
1062
  }
1005
1063
  break;
1006
1064
  }
1065
+ case "v": {
1066
+ event.preventDefault();
1067
+ void navigator.clipboard.readText().then((clipboardText) => {
1068
+ try {
1069
+ model.setCellData(cell, String2.trim(clipboardText).replace(/[\n\r]+/, " "));
1070
+ handleSave();
1071
+ } catch {
1072
+ const cellElement = event.target.closest('[data-dx-grid-action="cell"]');
1073
+ if (cellElement) {
1074
+ const rect = cellElement.getBoundingClientRect();
1075
+ const editRequest = new DxEditRequest({
1076
+ cellIndex: `${cell.plane},${cell.col},${cell.row}`,
1077
+ cellBox: {
1078
+ insetInlineStart: rect.left,
1079
+ insetBlockStart: rect.top,
1080
+ inlineSize: rect.width,
1081
+ blockSize: rect.height
1082
+ },
1083
+ cellElement,
1084
+ initialContent: clipboardText
1085
+ });
1086
+ cellElement.dispatchEvent(editRequest);
1087
+ }
1088
+ }
1089
+ });
1090
+ break;
1091
+ }
1007
1092
  }
1008
- }, [
1009
- model,
1010
- dxGrid,
1011
- handleSave
1012
- ]);
1013
- const handleAxisResize = useCallback4((event) => {
1014
- if (event.axis === "col") {
1015
- const columnIndex = parseInt(event.index, 10);
1016
- model?.setColumnWidth(columnIndex, event.size);
1017
- }
1018
- }, [
1019
- model
1020
- ]);
1021
- const handleWheel = useCallback4((event) => {
1022
- if (!ignoreAttention && !hasAttention) {
1023
- event.stopPropagation();
1024
- }
1025
- }, [
1026
- hasAttention,
1027
- ignoreAttention
1028
- ]);
1029
- const handleNewColumn = useCallback4(() => {
1030
- const columns = model?.getColumnCount();
1031
- if (dxGrid && columns) {
1032
- dxGrid.scrollToColumn(columns - 1);
1093
+ }
1094
+ switch (event.key) {
1095
+ case "Backspace":
1096
+ case "Delete": {
1097
+ try {
1098
+ model.setCellData(cell, void 0);
1099
+ event.preventDefault();
1100
+ handleSave();
1101
+ } catch {
1102
+ }
1103
+ break;
1033
1104
  }
1034
- }, [
1035
- model,
1036
- dxGrid
1037
- ]);
1038
- if (!model || !modals) {
1039
- return /* @__PURE__ */ React7.createElement("span", {
1040
- role: "none",
1041
- className: "attention-surface"
1042
- });
1043
1105
  }
1044
- return /* @__PURE__ */ React7.createElement(Grid.Root, {
1045
- id: model.id ?? "table-grid"
1046
- }, /* @__PURE__ */ React7.createElement(TableValueEditor, {
1047
- model,
1048
- modals,
1049
- schema,
1050
- onFocus: handleFocus,
1051
- onSave: handleSave,
1052
- onCreate,
1053
- client
1054
- }), /* @__PURE__ */ React7.createElement(Grid.Content, {
1055
- className: mx("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
1056
- frozen,
1057
- columns: model.columnMeta.value,
1058
- columnDefault,
1059
- rowDefault,
1060
- limitRows: model.getRowCount() ?? 0,
1061
- limitColumns: model.projection.fields.length,
1062
- overscroll: "trap",
1063
- onAxisResize: handleAxisResize,
1064
- onClick: handleGridClick,
1065
- onKeyDownCapture: handleKeyDown,
1066
- onWheelCapture: handleWheel,
1067
- ...testId && {
1068
- "data-testid": testId
1069
- },
1070
- ref: setDxGrid
1071
- }), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
1072
- model,
1073
- modals
1074
- }), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
1075
- model,
1076
- modals
1077
- }), /* @__PURE__ */ React7.createElement(ColumnSettings, {
1078
- model,
1079
- modals,
1080
- onNewColumn: handleNewColumn
1081
- }));
1082
- } finally {
1083
- _effect.f();
1084
- }
1085
- });
1086
- var Table = {
1087
- Root: TableRoot,
1088
- Main: TableMain
1089
- };
1090
-
1091
- // src/components/Table/DynamicTable.tsx
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";
1094
- import { useDefaultValue } from "@dxos/react-ui";
1095
- import { mx as mx2 } from "@dxos/react-ui-theme";
1096
- var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema: _jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
1097
- var _effect = _useSignals8();
1098
- try {
1099
- const { jsonSchema } = useMemo5(() => getBaseSchema({
1100
- typename: name,
1101
- properties,
1102
- jsonSchema: _jsonSchema,
1103
- schema
1104
- }), [
1105
- name,
1106
- properties,
1107
- _jsonSchema,
1108
- schema
1109
- ]);
1110
- const { projection, view } = useMemo5(() => makeDynamicTable({
1111
- jsonSchema,
1112
- properties
1113
- }), [
1114
- jsonSchema,
1115
- properties
1116
- ]);
1117
- const tableRef = useRef3(null);
1118
- const handleCellUpdate = useCallback5((cell) => {
1119
- tableRef.current?.update?.(cell);
1120
- }, []);
1121
- const handleRowOrderChange = useCallback5(() => {
1122
- tableRef.current?.update?.();
1123
- }, []);
1124
- const features = useDefaultValue(props.features, () => ({
1125
- selection: {
1126
- enabled: false
1106
+ }, [
1107
+ model,
1108
+ dxGrid,
1109
+ handleSave
1110
+ ]);
1111
+ const handleAxisResize = useCallback4((event) => {
1112
+ if (event.axis === "col") {
1113
+ const columnIndex = parseInt(event.index, 10);
1114
+ model?.setColumnWidth(columnIndex, event.size);
1115
+ }
1116
+ }, [
1117
+ model
1118
+ ]);
1119
+ const handleWheel = useCallback4((event) => {
1120
+ if (!ignoreAttention && !hasAttention) {
1121
+ event.stopPropagation();
1122
+ }
1123
+ }, [
1124
+ hasAttention,
1125
+ ignoreAttention
1126
+ ]);
1127
+ const handleNewColumn = useCallback4(() => {
1128
+ const columns = model?.getColumnCount();
1129
+ if (dxGrid && columns) {
1130
+ dxGrid.scrollToColumn(columns - 1);
1131
+ }
1132
+ }, [
1133
+ model,
1134
+ dxGrid
1135
+ ]);
1136
+ const { controllerRef } = useTableContext(TABLE_CONTENT_NAME);
1137
+ controllerRef.current = useMemo4(() => {
1138
+ if (!dxGrid || !presentation) {
1139
+ return {};
1140
+ }
1141
+ return {
1142
+ update: (cell) => {
1143
+ if (cell) {
1144
+ dxGrid.updateIfWithinBounds(cell, true);
1145
+ } else {
1146
+ dxGrid.updateCells(true);
1147
+ dxGrid.requestUpdate();
1148
+ }
1127
1149
  },
1128
- dataEditable: false
1129
- }));
1130
- const model = useTableModel({
1131
- rows,
1132
- view,
1133
- schema: jsonSchema,
1134
- projection,
1135
- features,
1136
- rowActions,
1137
- onCellUpdate: handleCellUpdate,
1138
- onRowOrderChange: handleRowOrderChange,
1139
- onRowAction
1140
- });
1141
- const presentation = useMemo5(() => {
1142
- if (model) {
1143
- return new TablePresentation(model);
1144
- }
1145
- }, [
1146
- model
1147
- ]);
1148
- return /* @__PURE__ */ React8.createElement("div", {
1149
- role: "none",
1150
- className: mx2("is-full bs-full grow grid", classNames)
1151
- }, /* @__PURE__ */ React8.createElement("div", {
1150
+ handleInsertRowResult
1151
+ };
1152
+ }, [
1153
+ dxGrid,
1154
+ model,
1155
+ presentation
1156
+ ]);
1157
+ if (!model || !modals) {
1158
+ return /* @__PURE__ */ React7.createElement("span", {
1152
1159
  role: "none",
1153
- className: "grid min-bs-0 overflow-hidden"
1154
- }, /* @__PURE__ */ React8.createElement(Table.Root, null, /* @__PURE__ */ React8.createElement(Table.Main, {
1155
- ref: tableRef,
1156
- model,
1157
- presentation,
1158
- ignoreAttention: true,
1159
- onRowClick
1160
- }))));
1161
- } finally {
1162
- _effect.f();
1160
+ className: "dx-attention-surface"
1161
+ });
1163
1162
  }
1164
- };
1163
+ return /* @__PURE__ */ React7.createElement("div", {
1164
+ ...composableProps(props, {
1165
+ classNames: "dx-container relative"
1166
+ }),
1167
+ ref: forwardedRef
1168
+ }, /* @__PURE__ */ React7.createElement(Grid.Root, {
1169
+ id: model.id ?? "table-grid"
1170
+ }, /* @__PURE__ */ React7.createElement(TableValueEditor, {
1171
+ model,
1172
+ modals,
1173
+ schema,
1174
+ onFocus: handleFocus,
1175
+ onSave: handleSave,
1176
+ onCreate
1177
+ }), /* @__PURE__ */ React7.createElement(Grid.Content, {
1178
+ className: mx("[--dx-grid-base:var(--base-surface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
1179
+ frozen,
1180
+ columns: columnMeta,
1181
+ columnDefault,
1182
+ rowDefault,
1183
+ limitRows: rows.length,
1184
+ limitColumns: columnCount,
1185
+ overscroll: "trap",
1186
+ onAxisResize: handleAxisResize,
1187
+ onClick: handleGridClick,
1188
+ onKeyDownCapture: handleKeyDown,
1189
+ onWheelCapture: handleWheel,
1190
+ ...testId && {
1191
+ "data-testid": testId
1192
+ },
1193
+ ref: setDxGrid
1194
+ }), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
1195
+ model,
1196
+ modals
1197
+ }), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
1198
+ model,
1199
+ modals
1200
+ }), /* @__PURE__ */ React7.createElement(ColumnSettings, {
1201
+ model,
1202
+ modals,
1203
+ onNewColumn: handleNewColumn
1204
+ })));
1205
+ });
1206
+ TableContent.displayName = TABLE_CONTENT_NAME;
1165
1207
 
1166
- // src/components/TableToolbar/TableToolbar.tsx
1167
- import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
1168
- import { Atom } from "@effect-atom/atom-react";
1169
- import React9, { useMemo as useMemo6 } from "react";
1170
- import { live } from "@dxos/live-object";
1171
- import { MenuProvider, ToolbarMenu, createGapSeparator, createMenuAction, useMenuActions } from "@dxos/react-ui-menu";
1172
- import { atomFromSignal } from "@dxos/react-ui-menu";
1173
- var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Atom.make((get) => {
1208
+ // src/components/Table/TableToolbar.tsx
1209
+ import { Atom as Atom3, RegistryContext as RegistryContext2 } from "@effect-atom/atom-react";
1210
+ import React8, { useContext as useContext2, useEffect as useEffect4, useMemo as useMemo5 } from "react";
1211
+ import { Menu, createGapSeparator, createMenuAction, useMenuActions } from "@dxos/react-ui-menu";
1212
+ import { composable as composable2, composableProps as composableProps2 } from "@dxos/ui-theme";
1213
+ var createTableToolbarActions = ({ stateAtom, onAdd, onSave, customActions }) => Atom3.make((get) => {
1174
1214
  const nodes = [];
1175
1215
  if (onAdd) {
1176
1216
  const add = createMenuAction("add-row", onAdd, {
1177
1217
  type: "add-row",
1178
1218
  icon: "ph--plus--regular",
1179
1219
  label: [
1180
- "add row",
1220
+ "add-row.label",
1181
1221
  {
1182
1222
  ns: translationKey
1183
1223
  }
@@ -1187,18 +1227,19 @@ var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Ato
1187
1227
  nodes.push(add);
1188
1228
  }
1189
1229
  if (onSave) {
1230
+ const state = get(stateAtom);
1190
1231
  const save = createMenuAction("save-view", onSave, {
1191
1232
  type: "save-view",
1192
1233
  icon: "ph--floppy-disk--regular",
1193
1234
  label: [
1194
- "save view label",
1235
+ "save-view.label",
1195
1236
  {
1196
1237
  ns: translationKey
1197
1238
  }
1198
1239
  ],
1199
1240
  testId: "table.toolbar.save-view",
1200
1241
  iconOnly: false,
1201
- hidden: get(atomFromSignal(() => !state.viewDirty))
1242
+ hidden: !state.viewDirty
1202
1243
  });
1203
1244
  nodes.push(save);
1204
1245
  }
@@ -1206,7 +1247,8 @@ var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Ato
1206
1247
  nodes.push(...gap.nodes);
1207
1248
  const edges = nodes.map(({ id: target }) => ({
1208
1249
  source: "root",
1209
- target
1250
+ target,
1251
+ relation: "child"
1210
1252
  }));
1211
1253
  if (customActions) {
1212
1254
  const custom = get(customActions);
@@ -1218,33 +1260,140 @@ var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Ato
1218
1260
  edges
1219
1261
  };
1220
1262
  });
1221
- var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, customActions }) => {
1222
- var _effect = _useSignals9();
1223
- try {
1224
- const state = useMemo6(() => live({
1263
+ var TableToolbar = composable2(({ attendableId, viewDirty, onAdd, onSave, customActions, ...props }, forwardedRef) => {
1264
+ const registry = useContext2(RegistryContext2);
1265
+ const stateAtom = useMemo5(() => Atom3.make({
1266
+ viewDirty
1267
+ }), []);
1268
+ useEffect4(() => {
1269
+ registry.set(stateAtom, {
1225
1270
  viewDirty
1226
- }), []);
1227
- const actionsCreator = useMemo6(() => createTableToolbarActions({
1228
- state,
1229
- onAdd,
1230
- onSave,
1231
- customActions
1232
- }), [
1233
- state,
1234
- onAdd,
1235
- onSave,
1236
- customActions
1237
- ]);
1238
- const menu = useMenuActions(actionsCreator);
1239
- return /* @__PURE__ */ React9.createElement(MenuProvider, {
1240
- ...menu,
1241
- attendableId
1242
- }, /* @__PURE__ */ React9.createElement(ToolbarMenu, {
1243
- classNames
1271
+ });
1272
+ }, [
1273
+ registry,
1274
+ stateAtom,
1275
+ viewDirty
1276
+ ]);
1277
+ const actionsCreator = useMemo5(() => createTableToolbarActions({
1278
+ stateAtom,
1279
+ onAdd,
1280
+ onSave,
1281
+ customActions
1282
+ }), [
1283
+ stateAtom,
1284
+ onAdd,
1285
+ onSave,
1286
+ customActions
1287
+ ]);
1288
+ const menuActions = useMenuActions(actionsCreator);
1289
+ return /* @__PURE__ */ React8.createElement(Menu.Root, {
1290
+ ...menuActions,
1291
+ attendableId
1292
+ }, /* @__PURE__ */ React8.createElement(Menu.Toolbar, {
1293
+ ...composableProps2(props),
1294
+ ref: forwardedRef
1295
+ }));
1296
+ });
1297
+ TableToolbar.displayName = "TableToolbar";
1298
+
1299
+ // src/components/Table/Table.tsx
1300
+ var emptyColumnMeta2 = Atom4.make({
1301
+ grid: {}
1302
+ });
1303
+ var [TableContextProvider, useTableContext] = createContext("Table");
1304
+ var TABLE_ROOT_NAME = "Table.Root";
1305
+ var TableRoot = /* @__PURE__ */ forwardRef(({ children }, forwardedRef) => {
1306
+ const controllerRef = useRef3({});
1307
+ useImperativeHandle(forwardedRef, () => ({
1308
+ update: (cell) => controllerRef.current?.update?.(cell),
1309
+ handleInsertRowResult: (result) => controllerRef.current?.handleInsertRowResult?.(result)
1310
+ }), []);
1311
+ return /* @__PURE__ */ React9.createElement(TableContextProvider, {
1312
+ controllerRef
1313
+ }, children);
1314
+ });
1315
+ TableRoot.displayName = TABLE_ROOT_NAME;
1316
+ var Table = {
1317
+ Root: TableRoot,
1318
+ Toolbar: TableToolbar,
1319
+ Content: TableContent
1320
+ };
1321
+
1322
+ // src/components/Table/DynamicTable.tsx
1323
+ import { RegistryContext as RegistryContext3 } from "@effect-atom/atom-react";
1324
+ import React10, { useCallback as useCallback5, useContext as useContext3, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef4, useState as useState5 } from "react";
1325
+ import { useDefaultValue } from "@dxos/react-ui";
1326
+ import { mx as mx2 } from "@dxos/ui-theme";
1327
+ var DynamicTable = ({ classNames, schema, name = "com.example.dynamic-table", rows, properties, jsonSchema: jsonSchemaProp, rowActions, onRowClick, onRowAction, ...props }) => {
1328
+ const registry = useContext3(RegistryContext3);
1329
+ const [dynamicTable, setDynamicTable] = useState5();
1330
+ const { jsonSchema } = useMemo6(() => getBaseSchema({
1331
+ typename: name,
1332
+ properties,
1333
+ jsonSchema: jsonSchemaProp,
1334
+ schema
1335
+ }), [
1336
+ name,
1337
+ properties,
1338
+ jsonSchemaProp,
1339
+ schema
1340
+ ]);
1341
+ useEffect5(() => {
1342
+ setDynamicTable(makeDynamicTable({
1343
+ registry,
1344
+ jsonSchema,
1345
+ properties
1244
1346
  }));
1245
- } finally {
1246
- _effect.f();
1247
- }
1347
+ }, [
1348
+ registry,
1349
+ jsonSchema,
1350
+ properties
1351
+ ]);
1352
+ const tableRef = useRef4(null);
1353
+ const handleCellUpdate = useCallback5((cell) => {
1354
+ tableRef.current?.update?.(cell);
1355
+ }, []);
1356
+ const handleRowOrderChange = useCallback5(() => {
1357
+ tableRef.current?.update?.();
1358
+ }, []);
1359
+ const features = useDefaultValue(props.features, () => ({
1360
+ selection: {
1361
+ enabled: false
1362
+ },
1363
+ dataEditable: false
1364
+ }));
1365
+ const model = useTableModel({
1366
+ rows,
1367
+ object: dynamicTable?.object,
1368
+ projection: dynamicTable?.projection,
1369
+ features,
1370
+ rowActions,
1371
+ onCellUpdate: handleCellUpdate,
1372
+ onRowOrderChange: handleRowOrderChange,
1373
+ onRowAction
1374
+ });
1375
+ const presentation = useMemo6(() => {
1376
+ if (model) {
1377
+ return new TablePresentation(registry, model);
1378
+ }
1379
+ }, [
1380
+ registry,
1381
+ model
1382
+ ]);
1383
+ return /* @__PURE__ */ React10.createElement("div", {
1384
+ role: "none",
1385
+ className: mx2("dx-expander grid", classNames)
1386
+ }, /* @__PURE__ */ React10.createElement("div", {
1387
+ role: "none",
1388
+ className: "grid min-h-0 overflow-hidden"
1389
+ }, /* @__PURE__ */ React10.createElement(Table.Root, {
1390
+ ref: tableRef
1391
+ }, /* @__PURE__ */ React10.createElement(Table.Content, {
1392
+ model,
1393
+ presentation,
1394
+ ignoreAttention: true,
1395
+ onRowClick
1396
+ }))));
1248
1397
  };
1249
1398
  export {
1250
1399
  BUTTON_IDENTIFIERS,
@@ -1256,9 +1405,13 @@ export {
1256
1405
  Table,
1257
1406
  TableModel,
1258
1407
  TablePresentation,
1259
- TableToolbar,
1260
1408
  cellClassesForRowSelection,
1409
+ compareValues,
1410
+ createDirectChangeCallback,
1411
+ createEchoChangeCallback,
1412
+ extractOrder,
1261
1413
  getBaseSchema,
1414
+ getSortValue,
1262
1415
  makeDynamicTable,
1263
1416
  narrowSchema,
1264
1417
  tableButtons,
@@ -1266,6 +1419,8 @@ export {
1266
1419
  touch,
1267
1420
  translations,
1268
1421
  useAddRow,
1422
+ useProjectionModel,
1423
+ useTableContext,
1269
1424
  useTableModel
1270
1425
  };
1271
1426
  //# sourceMappingURL=index.mjs.map