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