@mui/x-data-grid-pro 8.19.0 → 8.21.0
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.
- package/CHANGELOG.md +174 -0
- package/DataGridPro/DataGridPro.js +29 -2
- package/components/GridRowReorderCell.js +15 -3
- package/components/headerFiltering/GridHeaderFilterCell.js +2 -3
- package/esm/DataGridPro/DataGridPro.js +29 -2
- package/esm/components/GridRowReorderCell.js +15 -3
- package/esm/components/headerFiltering/GridHeaderFilterCell.js +2 -3
- package/esm/hooks/features/dataSource/useGridDataSourceBasePro.js +1 -1
- package/esm/hooks/features/rowReorder/commonReorderConditions.d.ts +30 -0
- package/esm/hooks/features/rowReorder/commonReorderConditions.js +78 -0
- package/esm/hooks/features/rowReorder/index.d.ts +2 -1
- package/esm/hooks/features/rowReorder/index.js +2 -1
- package/esm/hooks/features/rowReorder/models.d.ts +17 -0
- package/esm/hooks/features/rowReorder/models.js +1 -0
- package/esm/hooks/features/rowReorder/reorderExecutor.d.ts +27 -0
- package/esm/hooks/features/rowReorder/reorderExecutor.js +29 -0
- package/esm/hooks/features/rowReorder/reorderValidator.d.ts +12 -0
- package/esm/hooks/features/rowReorder/reorderValidator.js +14 -0
- package/esm/hooks/features/rowReorder/types.d.ts +25 -0
- package/esm/hooks/features/rowReorder/types.js +1 -0
- package/esm/hooks/features/rowReorder/useGridRowReorder.d.ts +1 -1
- package/esm/hooks/features/rowReorder/useGridRowReorder.js +167 -80
- package/esm/hooks/features/rowReorder/utils.d.ts +82 -0
- package/esm/hooks/features/rowReorder/utils.js +259 -0
- package/esm/hooks/features/rows/useGridRowsOverridableMethods.d.ts +7 -0
- package/esm/hooks/features/rows/useGridRowsOverridableMethods.js +59 -0
- package/esm/hooks/features/treeData/treeDataReorderExecutor.d.ts +11 -0
- package/esm/hooks/features/treeData/treeDataReorderExecutor.js +534 -0
- package/esm/hooks/features/treeData/treeDataReorderValidator.d.ts +2 -0
- package/esm/hooks/features/treeData/treeDataReorderValidator.js +35 -0
- package/esm/hooks/features/treeData/useGridTreeData.d.ts +3 -3
- package/esm/hooks/features/treeData/useGridTreeData.js +49 -4
- package/esm/hooks/features/treeData/utils.d.ts +8 -0
- package/esm/hooks/features/treeData/utils.js +96 -0
- package/esm/index.js +1 -1
- package/esm/internals/index.d.ts +8 -0
- package/esm/internals/index.js +6 -0
- package/esm/models/dataGridProProps.d.ts +32 -4
- package/esm/models/gridRowOrderChangeParams.d.ts +29 -5
- package/hooks/features/dataSource/useGridDataSourceBasePro.js +1 -1
- package/hooks/features/rowReorder/commonReorderConditions.d.ts +30 -0
- package/hooks/features/rowReorder/commonReorderConditions.js +84 -0
- package/hooks/features/rowReorder/index.d.ts +2 -1
- package/hooks/features/rowReorder/models.d.ts +17 -0
- package/hooks/features/rowReorder/models.js +5 -0
- package/hooks/features/rowReorder/reorderExecutor.d.ts +27 -0
- package/hooks/features/rowReorder/reorderExecutor.js +37 -0
- package/hooks/features/rowReorder/reorderValidator.d.ts +12 -0
- package/hooks/features/rowReorder/reorderValidator.js +21 -0
- package/hooks/features/rowReorder/types.d.ts +25 -0
- package/hooks/features/rowReorder/types.js +5 -0
- package/hooks/features/rowReorder/useGridRowReorder.d.ts +1 -1
- package/hooks/features/rowReorder/useGridRowReorder.js +168 -81
- package/hooks/features/rowReorder/utils.d.ts +82 -0
- package/hooks/features/rowReorder/utils.js +286 -0
- package/hooks/features/rows/useGridRowsOverridableMethods.d.ts +7 -0
- package/hooks/features/rows/useGridRowsOverridableMethods.js +67 -0
- package/hooks/features/treeData/treeDataReorderExecutor.d.ts +11 -0
- package/hooks/features/treeData/treeDataReorderExecutor.js +541 -0
- package/hooks/features/treeData/treeDataReorderValidator.d.ts +2 -0
- package/hooks/features/treeData/treeDataReorderValidator.js +41 -0
- package/hooks/features/treeData/useGridTreeData.d.ts +3 -3
- package/hooks/features/treeData/useGridTreeData.js +48 -3
- package/hooks/features/treeData/utils.d.ts +8 -0
- package/hooks/features/treeData/utils.js +109 -0
- package/index.js +1 -1
- package/internals/index.d.ts +8 -0
- package/internals/index.js +53 -1
- package/models/dataGridProProps.d.ts +32 -4
- package/models/gridRowOrderChangeParams.d.ts +29 -5
- package/package.json +4 -4
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.treeDataReorderExecutor = exports.SameParentSwapOperation = void 0;
|
|
8
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
|
+
var _xDataGrid = require("@mui/x-data-grid");
|
|
10
|
+
var _reorderExecutor = require("../rowReorder/reorderExecutor");
|
|
11
|
+
var _utils = require("../rowReorder/utils");
|
|
12
|
+
var _utils2 = require("./utils");
|
|
13
|
+
/**
|
|
14
|
+
* Handles reordering of items within the same parent group.
|
|
15
|
+
*/
|
|
16
|
+
class SameParentSwapOperation extends _reorderExecutor.BaseReorderOperation {
|
|
17
|
+
operationType = 'same-parent-swap';
|
|
18
|
+
detectOperation(ctx) {
|
|
19
|
+
if (ctx.dropPosition === 'inside') {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const {
|
|
23
|
+
sourceRowId,
|
|
24
|
+
placeholderIndex,
|
|
25
|
+
sortedFilteredRowIds,
|
|
26
|
+
sortedFilteredRowIndexLookup,
|
|
27
|
+
rowTree,
|
|
28
|
+
apiRef
|
|
29
|
+
} = ctx;
|
|
30
|
+
const sourceNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sourceRowId);
|
|
31
|
+
if (!sourceNode || sourceNode.type === 'footer') {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
let targetIndex = placeholderIndex;
|
|
35
|
+
const sourceIndex = sortedFilteredRowIndexLookup[sourceRowId];
|
|
36
|
+
if (targetIndex === sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
|
|
37
|
+
targetIndex -= 1;
|
|
38
|
+
}
|
|
39
|
+
let targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[targetIndex]);
|
|
40
|
+
if (placeholderIndex > sourceIndex && sourceNode.parent === targetNode.parent) {
|
|
41
|
+
targetIndex = placeholderIndex - 1;
|
|
42
|
+
targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[targetIndex]);
|
|
43
|
+
if (targetNode && targetNode.depth !== sourceNode.depth) {
|
|
44
|
+
while (targetNode.depth > sourceNode.depth && targetIndex >= 0) {
|
|
45
|
+
targetIndex -= 1;
|
|
46
|
+
targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[targetIndex]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (targetIndex === -1) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
let isLastChild = false;
|
|
54
|
+
if (!targetNode) {
|
|
55
|
+
if (placeholderIndex >= sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
|
|
56
|
+
targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[sortedFilteredRowIds.length - 1]);
|
|
57
|
+
isLastChild = true;
|
|
58
|
+
} else {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
let adjustedTargetNode = targetNode;
|
|
63
|
+
|
|
64
|
+
// Case A and B adjustment
|
|
65
|
+
if (targetNode.type === 'group' && sourceNode.parent !== targetNode.parent && sourceNode.depth > targetNode.depth) {
|
|
66
|
+
let i = targetIndex - 1;
|
|
67
|
+
while (i >= 0) {
|
|
68
|
+
const node = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[i]);
|
|
69
|
+
if (node && node.depth < sourceNode.depth) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (node && node.depth === sourceNode.depth) {
|
|
73
|
+
targetIndex = i;
|
|
74
|
+
adjustedTargetNode = node;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
i -= 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check if below last node in the same group as source node
|
|
82
|
+
const isBelowPosition = ctx.dropPosition === 'below';
|
|
83
|
+
if (isBelowPosition && sourceNode.parent !== adjustedTargetNode.parent) {
|
|
84
|
+
const unAdjustedTargetIndex = placeholderIndex - 1;
|
|
85
|
+
const unAdjustedTargetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[unAdjustedTargetIndex]);
|
|
86
|
+
if (unAdjustedTargetNode && unAdjustedTargetNode.parent === sourceNode.parent) {
|
|
87
|
+
adjustedTargetNode = unAdjustedTargetNode;
|
|
88
|
+
isLastChild = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (sourceNode.parent !== adjustedTargetNode.parent) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const actualTargetIndex = (0, _utils.calculateTargetIndex)(sourceNode, adjustedTargetNode, isLastChild, rowTree);
|
|
95
|
+
targetNode = adjustedTargetNode;
|
|
96
|
+
return {
|
|
97
|
+
sourceNode,
|
|
98
|
+
targetNode,
|
|
99
|
+
actualTargetIndex,
|
|
100
|
+
isLastChild,
|
|
101
|
+
operationType: this.operationType
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
executeOperation(operation, ctx) {
|
|
105
|
+
const {
|
|
106
|
+
sourceNode,
|
|
107
|
+
actualTargetIndex
|
|
108
|
+
} = operation;
|
|
109
|
+
const {
|
|
110
|
+
apiRef,
|
|
111
|
+
sourceRowId
|
|
112
|
+
} = ctx;
|
|
113
|
+
apiRef.current.setState(state => {
|
|
114
|
+
const group = (0, _xDataGrid.gridRowTreeSelector)(apiRef)[sourceNode.parent];
|
|
115
|
+
const currentChildren = [...group.children];
|
|
116
|
+
const oldIndex = currentChildren.findIndex(row => row === sourceRowId);
|
|
117
|
+
if (oldIndex === -1 || actualTargetIndex === -1 || oldIndex === actualTargetIndex) {
|
|
118
|
+
return state;
|
|
119
|
+
}
|
|
120
|
+
currentChildren.splice(actualTargetIndex, 0, currentChildren.splice(oldIndex, 1)[0]);
|
|
121
|
+
return (0, _extends2.default)({}, state, {
|
|
122
|
+
rows: (0, _extends2.default)({}, state.rows, {
|
|
123
|
+
tree: (0, _extends2.default)({}, state.rows.tree, {
|
|
124
|
+
[sourceNode.parent]: (0, _extends2.default)({}, group, {
|
|
125
|
+
children: currentChildren
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
apiRef.current.publishEvent('rowsSet');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Handles moving leaf nodes between different parents.
|
|
137
|
+
*/
|
|
138
|
+
exports.SameParentSwapOperation = SameParentSwapOperation;
|
|
139
|
+
class CrossParentLeafOperation extends _reorderExecutor.BaseReorderOperation {
|
|
140
|
+
operationType = 'cross-parent-leaf';
|
|
141
|
+
detectOperation(ctx) {
|
|
142
|
+
// Fail for "inside" position - let DropOnLeafOperation handle it
|
|
143
|
+
if (ctx.dropPosition === 'inside') {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const {
|
|
147
|
+
sourceRowId,
|
|
148
|
+
placeholderIndex,
|
|
149
|
+
sortedFilteredRowIds,
|
|
150
|
+
rowTree,
|
|
151
|
+
apiRef,
|
|
152
|
+
setTreeDataPath
|
|
153
|
+
} = ctx;
|
|
154
|
+
const sourceNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sourceRowId);
|
|
155
|
+
if (!sourceNode || sourceNode.type !== 'leaf') {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
if (!setTreeDataPath) {
|
|
159
|
+
(0, _utils2.displaySetTreeDataPathWarning)('Cross-parent reordering');
|
|
160
|
+
}
|
|
161
|
+
let targetIndex = placeholderIndex;
|
|
162
|
+
if (targetIndex === sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
|
|
163
|
+
targetIndex = sortedFilteredRowIds.length - 1;
|
|
164
|
+
}
|
|
165
|
+
if (targetIndex < 0) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[targetIndex]);
|
|
169
|
+
if (!targetNode) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
if (sourceNode.parent === targetNode.parent) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const actualTargetIndex = (0, _utils.calculateTargetIndex)(sourceNode, targetNode, placeholderIndex >= sortedFilteredRowIds.length, rowTree);
|
|
176
|
+
return {
|
|
177
|
+
sourceNode,
|
|
178
|
+
targetNode,
|
|
179
|
+
actualTargetIndex,
|
|
180
|
+
isLastChild: placeholderIndex >= sortedFilteredRowIds.length,
|
|
181
|
+
operationType: this.operationType
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
async executeOperation(operation, ctx) {
|
|
185
|
+
const {
|
|
186
|
+
sourceNode,
|
|
187
|
+
targetNode,
|
|
188
|
+
actualTargetIndex
|
|
189
|
+
} = operation;
|
|
190
|
+
const {
|
|
191
|
+
apiRef
|
|
192
|
+
} = ctx;
|
|
193
|
+
const rowTree = (0, _xDataGrid.gridRowTreeSelector)(apiRef);
|
|
194
|
+
const targetParentNode = rowTree[targetNode.parent];
|
|
195
|
+
const targetPath = (0, _utils2.buildTreeDataPath)(targetParentNode, rowTree);
|
|
196
|
+
const updatedRow = await (0, _utils2.updateLeafPath)(sourceNode, targetPath, ctx);
|
|
197
|
+
if (!updatedRow) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Update tree structure
|
|
202
|
+
apiRef.current.setState(state => {
|
|
203
|
+
const updatedTree = (0, _extends2.default)({}, state.rows.tree);
|
|
204
|
+
(0, _utils2.removeNodeFromSourceParent)(updatedTree, sourceNode);
|
|
205
|
+
const targetParent = updatedTree[targetNode.parent];
|
|
206
|
+
const targetChildren = [...targetParent.children];
|
|
207
|
+
targetChildren.splice(actualTargetIndex, 0, sourceNode.id);
|
|
208
|
+
updatedTree[targetNode.parent] = (0, _extends2.default)({}, targetParent, {
|
|
209
|
+
children: targetChildren
|
|
210
|
+
});
|
|
211
|
+
const parentNode = updatedTree[targetNode.parent];
|
|
212
|
+
(0, _utils2.updateNodeParentAndDepth)(updatedTree, sourceNode, targetNode.parent, parentNode.depth + 1);
|
|
213
|
+
return (0, _extends2.default)({}, state, {
|
|
214
|
+
rows: (0, _extends2.default)({}, state.rows, {
|
|
215
|
+
tree: updatedTree
|
|
216
|
+
})
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
apiRef.current.updateRows([updatedRow]);
|
|
220
|
+
apiRef.current.publishEvent('rowsSet');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Handles dropping any node (leaf or group) "inside" a leaf node.
|
|
226
|
+
* This converts the target leaf into a parent group and makes the dragged node its child.
|
|
227
|
+
*/
|
|
228
|
+
class DropOnLeafOperation extends _reorderExecutor.BaseReorderOperation {
|
|
229
|
+
operationType = 'drop-on-leaf';
|
|
230
|
+
detectOperation(ctx) {
|
|
231
|
+
const {
|
|
232
|
+
sourceRowId,
|
|
233
|
+
dropPosition,
|
|
234
|
+
placeholderIndex,
|
|
235
|
+
sortedFilteredRowIds,
|
|
236
|
+
apiRef,
|
|
237
|
+
setTreeDataPath
|
|
238
|
+
} = ctx;
|
|
239
|
+
if (dropPosition !== 'inside') {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
const sourceNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sourceRowId);
|
|
243
|
+
if (!sourceNode || sourceNode.type === 'footer') {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
if (!setTreeDataPath) {
|
|
247
|
+
(0, _utils2.displaySetTreeDataPathWarning)('Drop on leaf reordering');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Find target node
|
|
251
|
+
let targetIndex = placeholderIndex;
|
|
252
|
+
if (targetIndex === sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
|
|
253
|
+
targetIndex = sortedFilteredRowIds.length - 1;
|
|
254
|
+
}
|
|
255
|
+
if (targetIndex < 0) {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
const targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[targetIndex]);
|
|
259
|
+
if (!targetNode || targetNode.type !== 'leaf') {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Target leaf will become a parent, so the actual target index is 0 (first child)
|
|
264
|
+
const actualTargetIndex = 0;
|
|
265
|
+
return {
|
|
266
|
+
sourceNode,
|
|
267
|
+
targetNode,
|
|
268
|
+
actualTargetIndex,
|
|
269
|
+
isLastChild: false,
|
|
270
|
+
operationType: this.operationType
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
async executeOperation(operation, ctx) {
|
|
274
|
+
const {
|
|
275
|
+
sourceNode,
|
|
276
|
+
targetNode
|
|
277
|
+
} = operation;
|
|
278
|
+
const {
|
|
279
|
+
apiRef
|
|
280
|
+
} = ctx;
|
|
281
|
+
const rowTree = (0, _xDataGrid.gridRowTreeSelector)(apiRef);
|
|
282
|
+
|
|
283
|
+
// Build target path for the new structure
|
|
284
|
+
const targetPath = (0, _utils2.buildTreeDataPath)(targetNode, rowTree);
|
|
285
|
+
let rowsToUpdate = [];
|
|
286
|
+
|
|
287
|
+
// Handle source node path updates
|
|
288
|
+
if (sourceNode.type === 'leaf') {
|
|
289
|
+
// Simple leaf move
|
|
290
|
+
const updatedRow = await (0, _utils2.updateLeafPath)(sourceNode, targetPath, ctx);
|
|
291
|
+
if (!updatedRow) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
rowsToUpdate.push(updatedRow);
|
|
295
|
+
} else {
|
|
296
|
+
// Group move - update entire hierarchy
|
|
297
|
+
const sourceParentNode = rowTree[sourceNode.parent];
|
|
298
|
+
const sourceBasePath = (0, _utils2.buildTreeDataPath)(sourceParentNode, rowTree);
|
|
299
|
+
rowsToUpdate = await (0, _utils2.updateGroupHierarchyPaths)(sourceNode, sourceBasePath, targetPath, ctx);
|
|
300
|
+
if (rowsToUpdate.length === 0) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
apiRef.current.setState(state => {
|
|
305
|
+
const updatedTree = (0, _extends2.default)({}, state.rows.tree);
|
|
306
|
+
(0, _utils2.removeNodeFromSourceParent)(updatedTree, sourceNode);
|
|
307
|
+
updatedTree[targetNode.id] = (0, _extends2.default)({}, targetNode, {
|
|
308
|
+
type: 'group',
|
|
309
|
+
children: [sourceNode.id],
|
|
310
|
+
childrenFromPath: {},
|
|
311
|
+
groupingField: null,
|
|
312
|
+
isAutoGenerated: false,
|
|
313
|
+
childrenExpanded: true
|
|
314
|
+
});
|
|
315
|
+
(0, _utils2.updateNodeParentAndDepth)(updatedTree, sourceNode, targetNode.id, targetNode.depth + 1);
|
|
316
|
+
return (0, _extends2.default)({}, state, {
|
|
317
|
+
rows: (0, _extends2.default)({}, state.rows, {
|
|
318
|
+
tree: updatedTree
|
|
319
|
+
})
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Update rows in the grid
|
|
324
|
+
apiRef.current.updateRows(rowsToUpdate);
|
|
325
|
+
apiRef.current.publishEvent('rowsSet');
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Handles dropping any node (leaf or group) "inside" a group node.
|
|
331
|
+
* This makes the dragged node the first child of the target group.
|
|
332
|
+
*/
|
|
333
|
+
class DropOnGroupOperation extends _reorderExecutor.BaseReorderOperation {
|
|
334
|
+
operationType = 'drop-on-group';
|
|
335
|
+
detectOperation(ctx) {
|
|
336
|
+
const {
|
|
337
|
+
sourceRowId,
|
|
338
|
+
dropPosition,
|
|
339
|
+
placeholderIndex,
|
|
340
|
+
sortedFilteredRowIds,
|
|
341
|
+
apiRef,
|
|
342
|
+
setTreeDataPath,
|
|
343
|
+
rowTree
|
|
344
|
+
} = ctx;
|
|
345
|
+
|
|
346
|
+
// Only applies to "inside" drop position
|
|
347
|
+
if (dropPosition !== 'inside') {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
const sourceNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sourceRowId);
|
|
351
|
+
if (!sourceNode || sourceNode.type === 'footer') {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
if (!setTreeDataPath) {
|
|
355
|
+
(0, _utils2.displaySetTreeDataPathWarning)('Drop on group reordering');
|
|
356
|
+
}
|
|
357
|
+
let targetIndex = placeholderIndex;
|
|
358
|
+
if (targetIndex === sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
|
|
359
|
+
targetIndex = sortedFilteredRowIds.length - 1;
|
|
360
|
+
}
|
|
361
|
+
if (targetIndex < 0) {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
const targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[targetIndex]);
|
|
365
|
+
if (!targetNode || targetNode.type !== 'group') {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
if ((0, _utils.isDescendantOf)(targetNode, sourceNode, rowTree)) {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
const actualTargetIndex = 0;
|
|
372
|
+
return {
|
|
373
|
+
sourceNode,
|
|
374
|
+
targetNode,
|
|
375
|
+
actualTargetIndex,
|
|
376
|
+
isLastChild: false,
|
|
377
|
+
operationType: this.operationType
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
async executeOperation(operation, ctx) {
|
|
381
|
+
const {
|
|
382
|
+
sourceNode,
|
|
383
|
+
targetNode
|
|
384
|
+
} = operation;
|
|
385
|
+
const {
|
|
386
|
+
apiRef
|
|
387
|
+
} = ctx;
|
|
388
|
+
const rowTree = (0, _xDataGrid.gridRowTreeSelector)(apiRef);
|
|
389
|
+
|
|
390
|
+
// Build target path for the new structure
|
|
391
|
+
const targetPath = (0, _utils2.buildTreeDataPath)(targetNode, rowTree);
|
|
392
|
+
let rowsToUpdate = [];
|
|
393
|
+
|
|
394
|
+
// Handle source node path updates
|
|
395
|
+
if (sourceNode.type === 'leaf') {
|
|
396
|
+
// Simple leaf move
|
|
397
|
+
const updatedRow = await (0, _utils2.updateLeafPath)(sourceNode, targetPath, ctx);
|
|
398
|
+
if (!updatedRow) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
rowsToUpdate.push(updatedRow);
|
|
402
|
+
} else {
|
|
403
|
+
// Group move - update entire hierarchy
|
|
404
|
+
const sourceParentNode = rowTree[sourceNode.parent];
|
|
405
|
+
const sourceBasePath = (0, _utils2.buildTreeDataPath)(sourceParentNode, rowTree);
|
|
406
|
+
rowsToUpdate = await (0, _utils2.updateGroupHierarchyPaths)(sourceNode, sourceBasePath, targetPath, ctx);
|
|
407
|
+
if (rowsToUpdate.length === 0) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Update tree structure
|
|
413
|
+
apiRef.current.setState(state => {
|
|
414
|
+
const updatedTree = (0, _extends2.default)({}, state.rows.tree);
|
|
415
|
+
|
|
416
|
+
// Remove source from its current parent
|
|
417
|
+
(0, _utils2.removeNodeFromSourceParent)(updatedTree, sourceNode);
|
|
418
|
+
|
|
419
|
+
// Add source as first child of target group
|
|
420
|
+
const targetGroup = updatedTree[targetNode.id];
|
|
421
|
+
const targetChildren = [sourceNode.id, ...targetGroup.children];
|
|
422
|
+
updatedTree[targetNode.id] = (0, _extends2.default)({}, targetGroup, {
|
|
423
|
+
children: targetChildren
|
|
424
|
+
});
|
|
425
|
+
(0, _utils2.updateNodeParentAndDepth)(updatedTree, sourceNode, targetNode.id, targetNode.depth + 1);
|
|
426
|
+
return (0, _extends2.default)({}, state, {
|
|
427
|
+
rows: (0, _extends2.default)({}, state.rows, {
|
|
428
|
+
tree: updatedTree
|
|
429
|
+
})
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// Update rows in the grid
|
|
434
|
+
apiRef.current.updateRows(rowsToUpdate);
|
|
435
|
+
apiRef.current.publishEvent('rowsSet');
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Handles moving group nodes (and all their descendants) between different parents.
|
|
441
|
+
*/
|
|
442
|
+
class CrossParentGroupOperation extends _reorderExecutor.BaseReorderOperation {
|
|
443
|
+
operationType = 'cross-parent-group';
|
|
444
|
+
detectOperation(ctx) {
|
|
445
|
+
if (ctx.dropPosition === 'inside') {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
const {
|
|
449
|
+
sourceRowId,
|
|
450
|
+
placeholderIndex,
|
|
451
|
+
sortedFilteredRowIds,
|
|
452
|
+
rowTree,
|
|
453
|
+
apiRef,
|
|
454
|
+
setTreeDataPath
|
|
455
|
+
} = ctx;
|
|
456
|
+
const sourceNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sourceRowId);
|
|
457
|
+
if (!sourceNode || sourceNode.type !== 'group') {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
if (!setTreeDataPath) {
|
|
461
|
+
(0, _utils2.displaySetTreeDataPathWarning)('Cross-parent reordering');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Find target node
|
|
465
|
+
let targetIndex = placeholderIndex;
|
|
466
|
+
if (targetIndex === sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
|
|
467
|
+
targetIndex = sortedFilteredRowIds.length - 1;
|
|
468
|
+
}
|
|
469
|
+
if (targetIndex < 0) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
const targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, sortedFilteredRowIds[targetIndex]);
|
|
473
|
+
if (!targetNode) {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
if (sourceNode.parent === targetNode.parent) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
if ((0, _utils.isDescendantOf)(targetNode, sourceNode, rowTree)) {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
const actualTargetIndex = (0, _utils.calculateTargetIndex)(sourceNode, targetNode, placeholderIndex >= sortedFilteredRowIds.length, rowTree);
|
|
483
|
+
return {
|
|
484
|
+
sourceNode,
|
|
485
|
+
targetNode,
|
|
486
|
+
actualTargetIndex,
|
|
487
|
+
isLastChild: placeholderIndex >= sortedFilteredRowIds.length,
|
|
488
|
+
operationType: this.operationType
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
async executeOperation(operation, ctx) {
|
|
492
|
+
const {
|
|
493
|
+
sourceNode,
|
|
494
|
+
targetNode,
|
|
495
|
+
actualTargetIndex
|
|
496
|
+
} = operation;
|
|
497
|
+
const {
|
|
498
|
+
apiRef
|
|
499
|
+
} = ctx;
|
|
500
|
+
const rowTree = (0, _xDataGrid.gridRowTreeSelector)(apiRef);
|
|
501
|
+
|
|
502
|
+
// Calculate new base path for the moved group
|
|
503
|
+
const targetParentNode = rowTree[targetNode.parent];
|
|
504
|
+
const newBasePath = (0, _utils2.buildTreeDataPath)(targetParentNode, rowTree);
|
|
505
|
+
|
|
506
|
+
// Calculate the original base path depth
|
|
507
|
+
const sourceParentNode = rowTree[sourceNode.parent];
|
|
508
|
+
const sourceBasePath = (0, _utils2.buildTreeDataPath)(sourceParentNode, rowTree);
|
|
509
|
+
|
|
510
|
+
// Update group hierarchy paths
|
|
511
|
+
const updates = await (0, _utils2.updateGroupHierarchyPaths)(sourceNode, sourceBasePath, newBasePath, ctx);
|
|
512
|
+
if (updates.length > 0) {
|
|
513
|
+
// Update tree structure (partial moves are allowed)
|
|
514
|
+
apiRef.current.setState(state => {
|
|
515
|
+
const updatedTree = (0, _extends2.default)({}, state.rows.tree);
|
|
516
|
+
|
|
517
|
+
// Remove from source parent
|
|
518
|
+
(0, _utils2.removeNodeFromSourceParent)(updatedTree, sourceNode);
|
|
519
|
+
|
|
520
|
+
// Add to target parent
|
|
521
|
+
const targetParent = updatedTree[targetNode.parent];
|
|
522
|
+
const targetChildren = [...targetParent.children];
|
|
523
|
+
targetChildren.splice(actualTargetIndex, 0, sourceNode.id);
|
|
524
|
+
updatedTree[targetNode.parent] = (0, _extends2.default)({}, targetParent, {
|
|
525
|
+
children: targetChildren
|
|
526
|
+
});
|
|
527
|
+
const newParentNode = updatedTree[targetNode.parent];
|
|
528
|
+
const newGroupDepth = newParentNode.depth + 1;
|
|
529
|
+
(0, _utils2.updateNodeParentAndDepth)(updatedTree, sourceNode, targetNode.parent, newGroupDepth);
|
|
530
|
+
return (0, _extends2.default)({}, state, {
|
|
531
|
+
rows: (0, _extends2.default)({}, state.rows, {
|
|
532
|
+
tree: updatedTree
|
|
533
|
+
})
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
apiRef.current.updateRows(updates);
|
|
537
|
+
apiRef.current.publishEvent('rowsSet');
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
const treeDataReorderExecutor = exports.treeDataReorderExecutor = new _reorderExecutor.RowReorderExecutor([new SameParentSwapOperation(), new CrossParentLeafOperation(), new DropOnLeafOperation(), new DropOnGroupOperation(), new CrossParentGroupOperation()]);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.treeDataReorderValidator = void 0;
|
|
7
|
+
var _xDataGrid = require("@mui/x-data-grid");
|
|
8
|
+
var _reorderValidator = require("../rowReorder/reorderValidator");
|
|
9
|
+
var _commonReorderConditions = require("../rowReorder/commonReorderConditions");
|
|
10
|
+
const validationRules = [{
|
|
11
|
+
name: 'same-position',
|
|
12
|
+
applies: ctx => ctx.sourceNode.id === ctx.targetNode.id,
|
|
13
|
+
isInvalid: () => true,
|
|
14
|
+
message: 'Source and target are the same'
|
|
15
|
+
}, {
|
|
16
|
+
name: 'adjacent-position',
|
|
17
|
+
applies: ctx => _commonReorderConditions.commonReorderConditions.isAdjacentPosition(ctx),
|
|
18
|
+
isInvalid: () => true,
|
|
19
|
+
message: 'Source and target are adjacent'
|
|
20
|
+
}, {
|
|
21
|
+
name: 'to-descendent',
|
|
22
|
+
applies: ctx => _commonReorderConditions.commonReorderConditions.isGroupToLeaf(ctx) || _commonReorderConditions.commonReorderConditions.isGroupToGroup(ctx),
|
|
23
|
+
isInvalid: ctx => {
|
|
24
|
+
let currentNode = ctx.targetNode;
|
|
25
|
+
const rowTree = (0, _xDataGrid.gridRowTreeSelector)(ctx.apiRef);
|
|
26
|
+
while (currentNode.parent) {
|
|
27
|
+
currentNode = rowTree[currentNode.parent];
|
|
28
|
+
if (currentNode.id === ctx.sourceNode.id) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
},
|
|
34
|
+
message: 'Cannot drop group on one of its descendents'
|
|
35
|
+
}, {
|
|
36
|
+
name: 'group-to-group-above-leaf-belongs-to-source',
|
|
37
|
+
applies: ctx => _commonReorderConditions.commonReorderConditions.isGroupToGroup(ctx) && _commonReorderConditions.commonReorderConditions.isDropAbove(ctx) && _commonReorderConditions.commonReorderConditions.prevIsLeaf(ctx),
|
|
38
|
+
isInvalid: _commonReorderConditions.commonReorderConditions.prevBelongsToSource,
|
|
39
|
+
message: 'Previous leaf belongs to source group or its descendants'
|
|
40
|
+
}];
|
|
41
|
+
const treeDataReorderValidator = exports.treeDataReorderValidator = new _reorderValidator.RowReorderValidator(validationRules);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { RefObject } from '@mui/x-internals/types';
|
|
2
|
-
import {
|
|
3
|
-
import { DataGridProProcessedProps } from "../../../models/dataGridProProps.js";
|
|
4
|
-
export declare const useGridTreeData: (apiRef: RefObject<
|
|
2
|
+
import type { GridPrivateApiPro } from "../../../models/gridApiPro.js";
|
|
3
|
+
import type { DataGridProProcessedProps } from "../../../models/dataGridProProps.js";
|
|
4
|
+
export declare const useGridTreeData: (apiRef: RefObject<GridPrivateApiPro>, props: Pick<DataGridProProcessedProps, "treeData" | "dataSource" | "isValidRowReorder">) => void;
|
|
@@ -7,11 +7,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.useGridTreeData = void 0;
|
|
8
8
|
var React = _interopRequireWildcard(require("react"));
|
|
9
9
|
var _xDataGrid = require("@mui/x-data-grid");
|
|
10
|
+
var _internals = require("@mui/x-data-grid/internals");
|
|
10
11
|
var _gridTreeDataGroupColDef = require("./gridTreeDataGroupColDef");
|
|
12
|
+
var _treeDataReorderValidator = require("./treeDataReorderValidator");
|
|
11
13
|
const useGridTreeData = (apiRef, props) => {
|
|
12
|
-
/**
|
|
13
|
-
* EVENTS
|
|
14
|
-
*/
|
|
15
14
|
const handleCellKeyDown = React.useCallback((params, event) => {
|
|
16
15
|
const cellParams = apiRef.current.getCellParams(params.id, params.field);
|
|
17
16
|
if (cellParams.colDef.field === _gridTreeDataGroupColDef.GRID_TREE_DATA_GROUPING_FIELD && (event.key === ' ' || event.key === 'Enter') && !event.shiftKey) {
|
|
@@ -25,6 +24,52 @@ const useGridTreeData = (apiRef, props) => {
|
|
|
25
24
|
apiRef.current.setRowChildrenExpansion(params.id, !params.rowNode.childrenExpanded);
|
|
26
25
|
}
|
|
27
26
|
}, [apiRef, props.dataSource]);
|
|
27
|
+
const isValidRowReorderProp = props.isValidRowReorder;
|
|
28
|
+
const isRowReorderValid = React.useCallback((initialValue, {
|
|
29
|
+
sourceRowId,
|
|
30
|
+
targetRowId,
|
|
31
|
+
dropPosition,
|
|
32
|
+
dragDirection
|
|
33
|
+
}) => {
|
|
34
|
+
if ((0, _xDataGrid.gridRowMaximumTreeDepthSelector)(apiRef) === 1 || !props.treeData) {
|
|
35
|
+
return initialValue;
|
|
36
|
+
}
|
|
37
|
+
const expandedSortedRowIndexLookup = (0, _xDataGrid.gridExpandedSortedRowIndexLookupSelector)(apiRef);
|
|
38
|
+
const expandedSortedRowIds = (0, _xDataGrid.gridExpandedSortedRowIdsSelector)(apiRef);
|
|
39
|
+
const rowTree = (0, _xDataGrid.gridRowTreeSelector)(apiRef);
|
|
40
|
+
const targetRowIndex = expandedSortedRowIndexLookup[targetRowId];
|
|
41
|
+
const sourceNode = rowTree[sourceRowId];
|
|
42
|
+
const targetNode = rowTree[targetRowId];
|
|
43
|
+
const prevNode = targetRowIndex > 0 ? rowTree[expandedSortedRowIds[targetRowIndex - 1]] : null;
|
|
44
|
+
const nextNode = targetRowIndex < expandedSortedRowIds.length - 1 ? rowTree[expandedSortedRowIds[targetRowIndex + 1]] : null;
|
|
45
|
+
|
|
46
|
+
// Basic validity checks
|
|
47
|
+
if (!sourceNode || !targetNode) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Create context object
|
|
52
|
+
const context = {
|
|
53
|
+
apiRef,
|
|
54
|
+
sourceNode,
|
|
55
|
+
targetNode,
|
|
56
|
+
prevNode,
|
|
57
|
+
nextNode,
|
|
58
|
+
dropPosition,
|
|
59
|
+
dragDirection
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// First apply internal validation
|
|
63
|
+
let isValid = _treeDataReorderValidator.treeDataReorderValidator.validate(context);
|
|
64
|
+
|
|
65
|
+
// If internal validation passes AND user provided additional validation
|
|
66
|
+
if (isValid && isValidRowReorderProp) {
|
|
67
|
+
// Apply additional user restrictions
|
|
68
|
+
isValid = isValidRowReorderProp(context);
|
|
69
|
+
}
|
|
70
|
+
return isValid;
|
|
71
|
+
}, [apiRef, props.treeData, isValidRowReorderProp]);
|
|
72
|
+
(0, _internals.useGridRegisterPipeProcessor)(apiRef, 'isRowReorderValid', isRowReorderValid);
|
|
28
73
|
(0, _xDataGrid.useGridEvent)(apiRef, 'cellKeyDown', handleCellKeyDown);
|
|
29
74
|
};
|
|
30
75
|
exports.useGridTreeData = useGridTreeData;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type GridRowId, type GridTreeNode, type GridGroupNode, type GridValidRowModel, type GridRowTreeConfig } from '@mui/x-data-grid';
|
|
2
|
+
import type { ReorderExecutionContext } from "../rowReorder/types.js";
|
|
3
|
+
export declare const buildTreeDataPath: (node: GridTreeNode, tree: GridRowTreeConfig) => string[];
|
|
4
|
+
export declare function displaySetTreeDataPathWarning(operationName: string): void;
|
|
5
|
+
export declare function removeNodeFromSourceParent(updatedTree: Record<string, GridTreeNode>, sourceNode: GridTreeNode): void;
|
|
6
|
+
export declare function updateLeafPath(sourceNode: GridTreeNode, targetPath: string[], ctx: ReorderExecutionContext): Promise<GridValidRowModel | null>;
|
|
7
|
+
export declare function updateGroupHierarchyPaths(sourceNode: GridGroupNode, sourceBasePath: string[], targetPath: string[], ctx: ReorderExecutionContext): Promise<GridValidRowModel[]>;
|
|
8
|
+
export declare function updateNodeParentAndDepth(updatedTree: Record<string, GridTreeNode>, node: GridTreeNode, newParentId: GridRowId, newDepth: number): void;
|