@dxos/react-ui-table 0.8.4-main.c4373fc → 0.8.4-main.d05539e30a

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