@dxos/react-ui-table 0.8.4-main.7ace549 → 0.8.4-main.8baae0fced

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