@dxos/react-ui-table 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5

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