@dxos/react-ui-table 0.8.4-main.66e292d → 0.8.4-main.69d29f4

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