@dxos/react-ui-table 0.8.4-main.72ec0f3 → 0.8.4-main.765dc60934

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