@dxos/react-ui-table 0.8.4-main.e8ec1fe → 0.8.4-main.effb148878

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