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

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