@mui/x-data-grid-premium 8.18.0 → 8.20.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +175 -0
  2. package/DataGridPremium/DataGridPremium.d.ts +1 -1
  3. package/DataGridPremium/DataGridPremium.js +40 -7
  4. package/DataGridPremium/useDataGridPremiumComponent.d.ts +1 -1
  5. package/DataGridPremium/useDataGridPremiumComponent.js +3 -2
  6. package/components/GridFooterCell.js +1 -1
  7. package/esm/DataGridPremium/DataGridPremium.d.ts +1 -1
  8. package/esm/DataGridPremium/DataGridPremium.js +40 -7
  9. package/esm/DataGridPremium/useDataGridPremiumComponent.d.ts +1 -1
  10. package/esm/DataGridPremium/useDataGridPremiumComponent.js +4 -3
  11. package/esm/components/GridFooterCell.js +1 -1
  12. package/esm/hooks/features/aggregation/useGridAggregation.js +38 -17
  13. package/esm/hooks/features/chartsIntegration/useGridChartsIntegration.js +1 -0
  14. package/esm/hooks/features/rowGrouping/useGridRowGrouping.d.ts +1 -1
  15. package/esm/hooks/features/rowGrouping/useGridRowGrouping.js +21 -17
  16. package/esm/hooks/features/rowReorder/operations.d.ts +7 -27
  17. package/esm/hooks/features/rowReorder/operations.js +133 -274
  18. package/esm/hooks/features/rowReorder/rowGroupingReorderExecutor.d.ts +2 -0
  19. package/esm/hooks/features/rowReorder/rowGroupingReorderExecutor.js +3 -0
  20. package/esm/hooks/features/rowReorder/rowGroupingReorderValidator.d.ts +2 -0
  21. package/esm/hooks/features/rowReorder/{reorderValidator.js → rowGroupingReorderValidator.js} +2 -22
  22. package/esm/hooks/features/rows/useGridRowsOverridableMethods.d.ts +3 -3
  23. package/esm/hooks/features/rows/useGridRowsOverridableMethods.js +61 -7
  24. package/esm/index.js +1 -1
  25. package/hooks/features/aggregation/useGridAggregation.js +37 -16
  26. package/hooks/features/chartsIntegration/useGridChartsIntegration.js +1 -0
  27. package/hooks/features/rowGrouping/useGridRowGrouping.d.ts +1 -1
  28. package/hooks/features/rowGrouping/useGridRowGrouping.js +20 -16
  29. package/hooks/features/rowReorder/operations.d.ts +7 -27
  30. package/hooks/features/rowReorder/operations.js +136 -279
  31. package/hooks/features/rowReorder/rowGroupingReorderExecutor.d.ts +2 -0
  32. package/hooks/features/rowReorder/rowGroupingReorderExecutor.js +9 -0
  33. package/hooks/features/rowReorder/rowGroupingReorderValidator.d.ts +2 -0
  34. package/hooks/features/rowReorder/rowGroupingReorderValidator.js +102 -0
  35. package/hooks/features/rows/useGridRowsOverridableMethods.d.ts +3 -3
  36. package/hooks/features/rows/useGridRowsOverridableMethods.js +61 -7
  37. package/index.js +1 -1
  38. package/package.json +6 -6
  39. package/esm/hooks/features/rowReorder/reorderExecutor.d.ts +0 -15
  40. package/esm/hooks/features/rowReorder/reorderExecutor.js +0 -25
  41. package/esm/hooks/features/rowReorder/reorderValidator.d.ts +0 -16
  42. package/esm/hooks/features/rowReorder/types.d.ts +0 -42
  43. package/esm/hooks/features/rowReorder/types.js +0 -1
  44. package/esm/hooks/features/rowReorder/utils.d.ts +0 -127
  45. package/esm/hooks/features/rowReorder/utils.js +0 -343
  46. package/hooks/features/rowReorder/reorderExecutor.d.ts +0 -15
  47. package/hooks/features/rowReorder/reorderExecutor.js +0 -31
  48. package/hooks/features/rowReorder/reorderValidator.d.ts +0 -16
  49. package/hooks/features/rowReorder/reorderValidator.js +0 -122
  50. package/hooks/features/rowReorder/types.d.ts +0 -42
  51. package/hooks/features/rowReorder/types.js +0 -5
  52. package/hooks/features/rowReorder/utils.d.ts +0 -127
  53. package/hooks/features/rowReorder/utils.js +0 -360
@@ -2,11 +2,11 @@
2
2
 
3
3
  import _extends from "@babel/runtime/helpers/esm/extends";
4
4
  import * as React from 'react';
5
- import { useGridEvent, useGridApiMethod, gridColumnLookupSelector, gridRowMaximumTreeDepthSelector, gridRowTreeSelector, gridExpandedSortedRowIdsSelector } from '@mui/x-data-grid-pro';
6
- import { useGridRegisterPipeProcessor, GridStrategyGroup, gridExpandedSortedRowIndexLookupSelector, RowGroupingStrategy } from '@mui/x-data-grid-pro/internals';
5
+ import { useGridEvent, useGridApiMethod, gridColumnLookupSelector, gridRowMaximumTreeDepthSelector, gridRowTreeSelector, gridExpandedSortedRowIdsSelector, gridExpandedSortedRowIndexLookupSelector } from '@mui/x-data-grid-pro';
6
+ import { useGridRegisterPipeProcessor, GridStrategyGroup, RowGroupingStrategy } from '@mui/x-data-grid-pro/internals';
7
7
  import { gridRowGroupingModelSelector, gridRowGroupingSanitizedModelSelector } from "./gridRowGroupingSelector.js";
8
8
  import { getRowGroupingFieldFromGroupingCriteria, isGroupingColumn, mergeStateWithRowGroupingModel, setStrategyAvailability, getGroupingRules, areGroupingRulesEqual } from "./gridRowGroupingUtils.js";
9
- import { rowGroupingReorderValidator } from "../rowReorder/reorderValidator.js";
9
+ import { rowGroupingReorderValidator } from "../rowReorder/rowGroupingReorderValidator.js";
10
10
  export const rowGroupingStateInitializer = (state, props, apiRef) => {
11
11
  apiRef.current.caches.rowGrouping = {
12
12
  rulesOnLastRowTreeCreation: []
@@ -169,7 +169,8 @@ export const useGridRowGrouping = (apiRef, props) => {
169
169
  }
170
170
  }
171
171
  }, [apiRef, props.disableRowGrouping]);
172
- const getRowReorderTargetIndex = React.useCallback((initialValue, {
172
+ const isValidRowReorderProp = props.isValidRowReorder;
173
+ const isRowReorderValid = React.useCallback((initialValue, {
173
174
  sourceRowId,
174
175
  targetRowId,
175
176
  dropPosition,
@@ -181,7 +182,6 @@ export const useGridRowGrouping = (apiRef, props) => {
181
182
  const expandedSortedRowIndexLookup = gridExpandedSortedRowIndexLookupSelector(apiRef);
182
183
  const expandedSortedRowIds = gridExpandedSortedRowIdsSelector(apiRef);
183
184
  const rowTree = gridRowTreeSelector(apiRef);
184
- const sourceRowIndex = expandedSortedRowIndexLookup[sourceRowId];
185
185
  const targetRowIndex = expandedSortedRowIndexLookup[targetRowId];
186
186
  const sourceNode = rowTree[sourceRowId];
187
187
  const targetNode = rowTree[targetRowId];
@@ -190,30 +190,34 @@ export const useGridRowGrouping = (apiRef, props) => {
190
190
 
191
191
  // Basic validity checks
192
192
  if (!sourceNode || !targetNode) {
193
- return -1;
193
+ return false;
194
194
  }
195
195
 
196
196
  // Create context object
197
197
  const context = {
198
+ apiRef,
198
199
  sourceNode,
199
200
  targetNode,
200
201
  prevNode,
201
202
  nextNode,
202
- rowTree,
203
203
  dropPosition,
204
- dragDirection,
205
- targetRowIndex,
206
- sourceRowIndex,
207
- expandedSortedRowIndexLookup
204
+ dragDirection
208
205
  };
209
206
 
210
- // Check if the reorder is valid
211
- if (rowGroupingReorderValidator.validate(context)) {
212
- return dropPosition === 'below' ? targetRowIndex + 1 : targetRowIndex;
207
+ // First apply internal validation
208
+ let isValid = rowGroupingReorderValidator.validate(context);
209
+
210
+ // If internal validation passes AND user provided additional validation
211
+ if (isValid && isValidRowReorderProp) {
212
+ // Apply additional user restrictions
213
+ isValid = isValidRowReorderProp(context);
214
+ }
215
+ if (isValid) {
216
+ return true;
213
217
  }
214
- return -1;
215
- }, [apiRef, props.treeData]);
216
- useGridRegisterPipeProcessor(apiRef, 'getRowReorderTargetIndex', getRowReorderTargetIndex);
218
+ return false;
219
+ }, [apiRef, props.treeData, isValidRowReorderProp]);
220
+ useGridRegisterPipeProcessor(apiRef, 'isRowReorderValid', isRowReorderValid);
217
221
  useGridEvent(apiRef, 'cellKeyDown', handleCellKeyDown);
218
222
  useGridEvent(apiRef, 'columnsChange', checkGroupingColumnsModelDiff);
219
223
  useGridEvent(apiRef, 'rowGroupingModelChange', checkGroupingColumnsModelDiff);
@@ -1,34 +1,13 @@
1
- import type { ReorderOperation, ReorderExecutionContext } from "./types.js";
2
- /**
3
- * Base class for all reorder operations.
4
- * Provides abstract methods for operation detection and execution.
5
- */
6
- export declare abstract class BaseReorderOperation {
7
- abstract readonly operationType: string;
8
- /**
9
- * Detects if this operation can handle the given context.
10
- */
11
- abstract detectOperation(ctx: ReorderExecutionContext): ReorderOperation | null;
12
- /**
13
- * Executes the detected operation.
14
- */
15
- abstract executeOperation(operation: ReorderOperation, ctx: ReorderExecutionContext): Promise<void> | void;
16
- }
17
- /**
18
- * Handles reordering of items within the same parent group.
19
- */
20
- export declare class SameParentSwapOperation extends BaseReorderOperation {
21
- readonly operationType = "same-parent-swap";
22
- detectOperation(ctx: ReorderExecutionContext): ReorderOperation | null;
23
- executeOperation(operation: ReorderOperation, ctx: ReorderExecutionContext): void;
24
- }
1
+ import { BaseReorderOperation, type ReorderOperation, type ReorderExecutionContext } from '@mui/x-data-grid-pro/internals';
2
+ import { GridPrivateApiPremium } from "../../../models/gridApiPremium.js";
3
+ type ReorderExecutionContextType = ReorderExecutionContext<GridPrivateApiPremium>;
25
4
  /**
26
5
  * Handles moving leaf nodes between different parent groups.
27
6
  */
28
7
  export declare class CrossParentLeafOperation extends BaseReorderOperation {
29
8
  readonly operationType = "cross-parent-leaf";
30
9
  detectOperation(ctx: ReorderExecutionContext): ReorderOperation | null;
31
- executeOperation(operation: ReorderOperation, ctx: ReorderExecutionContext): Promise<void>;
10
+ executeOperation(operation: ReorderOperation, ctx: ReorderExecutionContextType): Promise<void>;
32
11
  }
33
12
  /**
34
13
  * Handles moving entire groups between different parents.
@@ -36,5 +15,6 @@ export declare class CrossParentLeafOperation extends BaseReorderOperation {
36
15
  export declare class CrossParentGroupOperation extends BaseReorderOperation {
37
16
  readonly operationType = "cross-parent-group";
38
17
  detectOperation(ctx: ReorderExecutionContext): ReorderOperation | null;
39
- executeOperation(operation: ReorderOperation, ctx: ReorderExecutionContext): Promise<void>;
40
- }
18
+ executeOperation(operation: ReorderOperation, ctx: ReorderExecutionContextType): Promise<void>;
19
+ }
20
+ export {};
@@ -1,128 +1,8 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { gridRowNodeSelector, gridRowTreeSelector, gridRowsLookupSelector, gridColumnLookupSelector } from '@mui/x-data-grid-pro';
3
- import { warnOnce } from '@mui/x-internals/warning';
4
- import { isDeepEqual } from '@mui/x-internals/isDeepEqual';
3
+ import { BaseReorderOperation, rowReorderUtils } from '@mui/x-data-grid-pro/internals';
5
4
  import { gridRowGroupingSanitizedModelSelector } from "../rowGrouping/index.js";
6
5
  import { getGroupingRules, getCellGroupingCriteria } from "../rowGrouping/gridRowGroupingUtils.js";
7
- import { determineOperationType, calculateTargetIndex, collectAllLeafDescendants, getNodePathInTree, removeEmptyAncestors, findExistingGroupWithSameKey, BatchRowUpdater } from "./utils.js";
8
- /**
9
- * Base class for all reorder operations.
10
- * Provides abstract methods for operation detection and execution.
11
- */
12
- export class BaseReorderOperation {}
13
-
14
- /**
15
- * Handles reordering of items within the same parent group.
16
- */
17
- export class SameParentSwapOperation extends BaseReorderOperation {
18
- operationType = 'same-parent-swap';
19
- detectOperation(ctx) {
20
- const {
21
- sourceRowId,
22
- placeholderIndex,
23
- sortedFilteredRowIds,
24
- sortedFilteredRowIndexLookup,
25
- rowTree,
26
- apiRef
27
- } = ctx;
28
- const sourceNode = gridRowNodeSelector(apiRef, sourceRowId);
29
- if (!sourceNode || sourceNode.type === 'footer') {
30
- return null;
31
- }
32
- let targetIndex = placeholderIndex;
33
- const sourceIndex = sortedFilteredRowIndexLookup[sourceRowId];
34
- if (targetIndex === sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
35
- targetIndex -= 1;
36
- }
37
- let targetNode = gridRowNodeSelector(apiRef, sortedFilteredRowIds[targetIndex]);
38
- if (placeholderIndex > sourceIndex && sourceNode.parent === targetNode.parent) {
39
- targetIndex = placeholderIndex - 1;
40
- targetNode = gridRowNodeSelector(apiRef, sortedFilteredRowIds[targetIndex]);
41
- if (targetNode && targetNode.depth !== sourceNode.depth) {
42
- while (targetNode.depth > sourceNode.depth && targetIndex >= 0) {
43
- targetIndex -= 1;
44
- targetNode = gridRowNodeSelector(apiRef, sortedFilteredRowIds[targetIndex]);
45
- }
46
- }
47
- if (targetIndex === -1) {
48
- return null;
49
- }
50
- }
51
- let isLastChild = false;
52
- if (!targetNode) {
53
- if (placeholderIndex >= sortedFilteredRowIds.length && sortedFilteredRowIds.length > 0) {
54
- targetNode = gridRowNodeSelector(apiRef, sortedFilteredRowIds[sortedFilteredRowIds.length - 1]);
55
- isLastChild = true;
56
- } else {
57
- return null;
58
- }
59
- }
60
- let adjustedTargetNode = targetNode;
61
-
62
- // Case A and B adjustment
63
- if (targetNode.type === 'group' && sourceNode.parent !== targetNode.parent && sourceNode.depth > targetNode.depth) {
64
- let i = targetIndex - 1;
65
- while (i >= 0) {
66
- const node = gridRowNodeSelector(apiRef, sortedFilteredRowIds[i]);
67
- if (node && node.depth < sourceNode.depth) {
68
- return null;
69
- }
70
- if (node && node.depth === sourceNode.depth) {
71
- targetIndex = i;
72
- adjustedTargetNode = node;
73
- break;
74
- }
75
- i -= 1;
76
- }
77
- }
78
- const operationType = determineOperationType(sourceNode, adjustedTargetNode);
79
- if (operationType !== 'same-parent-swap') {
80
- return null;
81
- }
82
- const actualTargetIndex = calculateTargetIndex(sourceNode, adjustedTargetNode, isLastChild, rowTree);
83
- targetNode = adjustedTargetNode;
84
- if (sourceNode.type !== targetNode.type) {
85
- return null;
86
- }
87
- return {
88
- sourceNode,
89
- targetNode,
90
- actualTargetIndex,
91
- isLastChild,
92
- operationType
93
- };
94
- }
95
- executeOperation(operation, ctx) {
96
- const {
97
- sourceNode,
98
- actualTargetIndex
99
- } = operation;
100
- const {
101
- apiRef,
102
- sourceRowId
103
- } = ctx;
104
- apiRef.current.setState(state => {
105
- const group = gridRowTreeSelector(apiRef)[sourceNode.parent];
106
- const currentChildren = [...group.children];
107
- const oldIndex = currentChildren.findIndex(row => row === sourceRowId);
108
- if (oldIndex === -1 || actualTargetIndex === -1 || oldIndex === actualTargetIndex) {
109
- return state;
110
- }
111
- currentChildren.splice(actualTargetIndex, 0, currentChildren.splice(oldIndex, 1)[0]);
112
- return _extends({}, state, {
113
- rows: _extends({}, state.rows, {
114
- tree: _extends({}, state.rows.tree, {
115
- [sourceNode.parent]: _extends({}, group, {
116
- children: currentChildren
117
- })
118
- })
119
- })
120
- });
121
- });
122
- apiRef.current.publishEvent('rowsSet');
123
- }
124
- }
125
-
126
6
  /**
127
7
  * Handles moving leaf nodes between different parent groups.
128
8
  */
@@ -164,11 +44,11 @@ export class CrossParentLeafOperation extends BaseReorderOperation {
164
44
  }
165
45
  }
166
46
  }
167
- const operationType = determineOperationType(sourceNode, adjustedTargetNode);
47
+ const operationType = rowReorderUtils.determineOperationType(sourceNode, adjustedTargetNode);
168
48
  if (operationType !== 'cross-parent-leaf') {
169
49
  return null;
170
50
  }
171
- const actualTargetIndex = calculateTargetIndex(sourceNode, adjustedTargetNode, isLastChild, rowTree);
51
+ const actualTargetIndex = rowReorderUtils.calculateTargetIndex(sourceNode, adjustedTargetNode, isLastChild, rowTree);
172
52
  targetNode = adjustedTargetNode;
173
53
 
174
54
  // Validate depth constraints
@@ -246,72 +126,56 @@ export class CrossParentLeafOperation extends BaseReorderOperation {
246
126
  updatedSourceRow[groupingRule.field] = targetRow[groupingRule.field];
247
127
  }
248
128
  }
249
- const commitStateUpdate = finalSourceRow => {
250
- apiRef.current.setState(state => {
251
- const updatedSourceChildren = sourceChildren.filter(rowId => rowId !== sourceRowId);
252
- const updatedTree = _extends({}, state.rows.tree);
253
- const removedGroups = new Set();
254
- let rootLevelRemovals = 0;
255
- if (updatedSourceChildren.length === 0) {
256
- removedGroups.add(sourceGroup.id);
257
- rootLevelRemovals = removeEmptyAncestors(sourceGroup.parent, updatedTree, removedGroups);
258
- }
259
- removedGroups.forEach(groupId => {
260
- const group = updatedTree[groupId];
261
- if (group && group.parent && updatedTree[group.parent]) {
262
- const parent = updatedTree[group.parent];
263
- updatedTree[group.parent] = _extends({}, parent, {
264
- children: parent.children.filter(childId => childId !== groupId)
265
- });
266
- }
267
- delete updatedTree[groupId];
268
- });
269
- if (!removedGroups.has(sourceGroup.id)) {
270
- updatedTree[sourceNode.parent] = _extends({}, sourceGroup, {
271
- children: updatedSourceChildren
129
+ const updater = new rowReorderUtils.BatchRowUpdater(apiRef, processRowUpdate, onProcessRowUpdateError);
130
+ updater.queueUpdate(sourceRowId, originalSourceRow, updatedSourceRow);
131
+ const {
132
+ successful,
133
+ updates
134
+ } = await updater.executeAll();
135
+ if (successful.length === 0) {
136
+ return;
137
+ }
138
+ const finalSourceRow = updates[0];
139
+ apiRef.current.setState(state => {
140
+ const updatedSourceChildren = sourceChildren.filter(rowId => rowId !== sourceRowId);
141
+ const updatedTree = _extends({}, state.rows.tree);
142
+ const removedGroups = new Set();
143
+ let rootLevelRemovals = 0;
144
+ if (updatedSourceChildren.length === 0) {
145
+ removedGroups.add(sourceGroup.id);
146
+ rootLevelRemovals = rowReorderUtils.removeEmptyAncestors(sourceGroup.parent, updatedTree, removedGroups);
147
+ }
148
+ removedGroups.forEach(groupId => {
149
+ const group = updatedTree[groupId];
150
+ if (group && group.parent && updatedTree[group.parent]) {
151
+ const parent = updatedTree[group.parent];
152
+ updatedTree[group.parent] = _extends({}, parent, {
153
+ children: parent.children.filter(childId => childId !== groupId)
272
154
  });
273
155
  }
274
- const updatedTargetChildren = isLastChild ? [...targetChildren, sourceRowId] : [...targetChildren.slice(0, targetIndex), sourceRowId, ...targetChildren.slice(targetIndex)];
275
- updatedTree[target.parent] = _extends({}, targetGroup, {
276
- children: updatedTargetChildren
277
- });
278
- updatedTree[sourceNode.id] = _extends({}, sourceNode, {
279
- parent: target.parent
280
- });
281
- return _extends({}, state, {
282
- rows: _extends({}, state.rows, {
283
- totalTopLevelRowCount: state.rows.totalTopLevelRowCount - rootLevelRemovals,
284
- tree: updatedTree
285
- })
286
- });
156
+ delete updatedTree[groupId];
287
157
  });
288
- apiRef.current.updateRows([finalSourceRow]);
289
- apiRef.current.publishEvent('rowsSet');
290
- };
291
- if (processRowUpdate && !isDeepEqual(originalSourceRow, updatedSourceRow)) {
292
- const params = {
293
- rowId: sourceRowId,
294
- previousRow: originalSourceRow,
295
- updatedRow: updatedSourceRow
296
- };
297
- apiRef.current.setLoading(true);
298
- try {
299
- const processedRow = await processRowUpdate(updatedSourceRow, originalSourceRow, params);
300
- const finalRow = processedRow || updatedSourceRow;
301
- commitStateUpdate(finalRow);
302
- } catch (error) {
303
- apiRef.current.setLoading(false);
304
- if (onProcessRowUpdateError) {
305
- onProcessRowUpdateError(error);
306
- } else if (process.env.NODE_ENV !== 'production') {
307
- warnOnce(['MUI X: A call to `processRowUpdate()` threw an error which was not handled because `onProcessRowUpdateError()` is missing.', 'To handle the error pass a callback to the `onProcessRowUpdateError()` prop, for example `<DataGrid onProcessRowUpdateError={(error) => ...} />`.', 'For more detail, see https://mui.com/x/react-data-grid/editing/persistence/.'], 'error');
308
- }
309
- } finally {
310
- apiRef.current.setLoading(false);
158
+ if (!removedGroups.has(sourceGroup.id)) {
159
+ updatedTree[sourceNode.parent] = _extends({}, sourceGroup, {
160
+ children: updatedSourceChildren
161
+ });
311
162
  }
312
- } else {
313
- commitStateUpdate(updatedSourceRow);
314
- }
163
+ const updatedTargetChildren = isLastChild ? [...targetChildren, sourceRowId] : [...targetChildren.slice(0, targetIndex), sourceRowId, ...targetChildren.slice(targetIndex)];
164
+ updatedTree[target.parent] = _extends({}, targetGroup, {
165
+ children: updatedTargetChildren
166
+ });
167
+ updatedTree[sourceNode.id] = _extends({}, sourceNode, {
168
+ parent: target.parent
169
+ });
170
+ return _extends({}, state, {
171
+ rows: _extends({}, state.rows, {
172
+ totalTopLevelRowCount: state.rows.totalTopLevelRowCount - rootLevelRemovals,
173
+ tree: updatedTree
174
+ })
175
+ });
176
+ });
177
+ apiRef.current.updateRows([finalSourceRow]);
178
+ apiRef.current.publishEvent('rowsSet');
315
179
  }
316
180
  }
317
181
 
@@ -365,11 +229,11 @@ export class CrossParentGroupOperation extends BaseReorderOperation {
365
229
  isLastChild = true;
366
230
  adjustedTargetNode = prevNode;
367
231
  }
368
- const operationType = determineOperationType(sourceNode, adjustedTargetNode);
232
+ const operationType = rowReorderUtils.determineOperationType(sourceNode, adjustedTargetNode);
369
233
  if (operationType !== 'cross-parent-group') {
370
234
  return null;
371
235
  }
372
- const actualTargetIndex = calculateTargetIndex(sourceNode, adjustedTargetNode, isLastChild, rowTree);
236
+ const actualTargetIndex = rowReorderUtils.calculateTargetIndex(sourceNode, adjustedTargetNode, isLastChild, rowTree);
373
237
  const operation = {
374
238
  sourceNode,
375
239
  targetNode: adjustedTargetNode,
@@ -398,16 +262,16 @@ export class CrossParentGroupOperation extends BaseReorderOperation {
398
262
  const dataRowIdToModelLookup = gridRowsLookupSelector(apiRef);
399
263
  const columnsLookup = gridColumnLookupSelector(apiRef);
400
264
  const sanitizedRowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef);
401
- const allLeafIds = collectAllLeafDescendants(sourceNode, tree);
265
+ const allLeafIds = rowReorderUtils.collectAllLeafDescendants(sourceNode, tree);
402
266
  if (allLeafIds.length === 0) {
403
267
  return;
404
268
  }
405
- const updater = new BatchRowUpdater(processRowUpdate, onProcessRowUpdateError);
269
+ const updater = new rowReorderUtils.BatchRowUpdater(apiRef, processRowUpdate, onProcessRowUpdateError);
406
270
  const groupingRules = getGroupingRules({
407
271
  sanitizedRowGroupingModel,
408
272
  columnsLookup
409
273
  });
410
- const targetParentPath = getNodePathInTree({
274
+ const targetParentPath = rowReorderUtils.getNodePathInTree({
411
275
  id: targetNode.parent,
412
276
  tree
413
277
  });
@@ -430,22 +294,75 @@ export class CrossParentGroupOperation extends BaseReorderOperation {
430
294
  }
431
295
  updater.queueUpdate(leafId, originalRow, updatedRow);
432
296
  }
433
- apiRef.current.setLoading(true);
434
- try {
435
- const {
436
- successful,
437
- failed,
438
- updates
439
- } = await updater.executeAll();
440
- if (successful.length > 0) {
441
- apiRef.current.setState(state => {
442
- const updatedTree = _extends({}, state.rows.tree);
443
- const treeDepths = _extends({}, state.rows.treeDepths);
444
- let rootLevelRemovals = 0;
445
- if (failed.length === 0) {
446
- const sourceParentNode = updatedTree[sourceNode.parent];
447
- if (!sourceParentNode) {
448
- const targetParentNode = updatedTree[targetNode.parent];
297
+ const {
298
+ successful,
299
+ failed,
300
+ updates
301
+ } = await updater.executeAll();
302
+ if (successful.length > 0) {
303
+ apiRef.current.setState(state => {
304
+ const updatedTree = _extends({}, state.rows.tree);
305
+ const treeDepths = _extends({}, state.rows.treeDepths);
306
+ let rootLevelRemovals = 0;
307
+ if (failed.length === 0) {
308
+ const sourceParentNode = updatedTree[sourceNode.parent];
309
+ if (!sourceParentNode) {
310
+ const targetParentNode = updatedTree[targetNode.parent];
311
+ const targetIndex = targetParentNode.children.indexOf(targetNode.id);
312
+ const newTargetChildren = [...targetParentNode.children];
313
+ if (isLastChild) {
314
+ newTargetChildren.push(sourceNode.id);
315
+ } else {
316
+ newTargetChildren.splice(targetIndex, 0, sourceNode.id);
317
+ }
318
+ updatedTree[targetNode.parent] = _extends({}, targetParentNode, {
319
+ children: newTargetChildren
320
+ });
321
+ updatedTree[sourceNode.id] = _extends({}, sourceNode, {
322
+ parent: targetNode.parent
323
+ });
324
+ } else {
325
+ const updatedSourceParentChildren = sourceParentNode.children.filter(id => id !== sourceNode.id);
326
+ if (updatedSourceParentChildren.length === 0) {
327
+ const removedGroups = new Set();
328
+ removedGroups.add(sourceNode.parent);
329
+ const parentOfSourceParent = updatedTree[sourceNode.parent].parent;
330
+ if (parentOfSourceParent) {
331
+ rootLevelRemovals = rowReorderUtils.removeEmptyAncestors(parentOfSourceParent, updatedTree, removedGroups);
332
+ }
333
+ removedGroups.forEach(groupId => {
334
+ const group = updatedTree[groupId];
335
+ if (group && group.parent && updatedTree[group.parent]) {
336
+ const parent = updatedTree[group.parent];
337
+ updatedTree[group.parent] = _extends({}, parent, {
338
+ children: parent.children.filter(childId => childId !== groupId)
339
+ });
340
+ }
341
+ delete updatedTree[groupId];
342
+ });
343
+ } else {
344
+ updatedTree[sourceNode.parent] = _extends({}, sourceParentNode, {
345
+ children: updatedSourceParentChildren
346
+ });
347
+ }
348
+ const targetParentNode = updatedTree[targetNode.parent];
349
+ const sourceGroupNode = sourceNode;
350
+ const existingGroup = sourceGroupNode.groupingKey !== null && sourceGroupNode.groupingField !== null ? rowReorderUtils.findExistingGroupWithSameKey(targetParentNode, sourceGroupNode.groupingKey, sourceGroupNode.groupingField, updatedTree) : null;
351
+ if (existingGroup) {
352
+ const updatedExistingGroup = _extends({}, existingGroup, {
353
+ children: [...existingGroup.children, ...sourceGroupNode.children]
354
+ });
355
+ updatedTree[existingGroup.id] = updatedExistingGroup;
356
+ sourceGroupNode.children.forEach(childId => {
357
+ const childNode = updatedTree[childId];
358
+ if (childNode) {
359
+ updatedTree[childId] = _extends({}, childNode, {
360
+ parent: existingGroup.id
361
+ });
362
+ }
363
+ });
364
+ delete updatedTree[sourceNode.id];
365
+ } else {
449
366
  const targetIndex = targetParentNode.children.indexOf(targetNode.id);
450
367
  const newTargetChildren = [...targetParentNode.children];
451
368
  if (isLastChild) {
@@ -459,77 +376,19 @@ export class CrossParentGroupOperation extends BaseReorderOperation {
459
376
  updatedTree[sourceNode.id] = _extends({}, sourceNode, {
460
377
  parent: targetNode.parent
461
378
  });
462
- } else {
463
- const updatedSourceParentChildren = sourceParentNode.children.filter(id => id !== sourceNode.id);
464
- if (updatedSourceParentChildren.length === 0) {
465
- const removedGroups = new Set();
466
- removedGroups.add(sourceNode.parent);
467
- const parentOfSourceParent = updatedTree[sourceNode.parent].parent;
468
- if (parentOfSourceParent) {
469
- rootLevelRemovals = removeEmptyAncestors(parentOfSourceParent, updatedTree, removedGroups);
470
- }
471
- removedGroups.forEach(groupId => {
472
- const group = updatedTree[groupId];
473
- if (group && group.parent && updatedTree[group.parent]) {
474
- const parent = updatedTree[group.parent];
475
- updatedTree[group.parent] = _extends({}, parent, {
476
- children: parent.children.filter(childId => childId !== groupId)
477
- });
478
- }
479
- delete updatedTree[groupId];
480
- });
481
- } else {
482
- updatedTree[sourceNode.parent] = _extends({}, sourceParentNode, {
483
- children: updatedSourceParentChildren
484
- });
485
- }
486
- const targetParentNode = updatedTree[targetNode.parent];
487
- const sourceGroupNode = sourceNode;
488
- const existingGroup = sourceGroupNode.groupingKey !== null && sourceGroupNode.groupingField !== null ? findExistingGroupWithSameKey(targetParentNode, sourceGroupNode.groupingKey, sourceGroupNode.groupingField, updatedTree) : null;
489
- if (existingGroup) {
490
- const updatedExistingGroup = _extends({}, existingGroup, {
491
- children: [...existingGroup.children, ...sourceGroupNode.children]
492
- });
493
- updatedTree[existingGroup.id] = updatedExistingGroup;
494
- sourceGroupNode.children.forEach(childId => {
495
- const childNode = updatedTree[childId];
496
- if (childNode) {
497
- updatedTree[childId] = _extends({}, childNode, {
498
- parent: existingGroup.id
499
- });
500
- }
501
- });
502
- delete updatedTree[sourceNode.id];
503
- } else {
504
- const targetIndex = targetParentNode.children.indexOf(targetNode.id);
505
- const newTargetChildren = [...targetParentNode.children];
506
- if (isLastChild) {
507
- newTargetChildren.push(sourceNode.id);
508
- } else {
509
- newTargetChildren.splice(targetIndex, 0, sourceNode.id);
510
- }
511
- updatedTree[targetNode.parent] = _extends({}, targetParentNode, {
512
- children: newTargetChildren
513
- });
514
- updatedTree[sourceNode.id] = _extends({}, sourceNode, {
515
- parent: targetNode.parent
516
- });
517
- }
518
379
  }
519
380
  }
520
- return _extends({}, state, {
521
- rows: _extends({}, state.rows, {
522
- totalTopLevelRowCount: state.rows.totalTopLevelRowCount - rootLevelRemovals,
523
- tree: updatedTree,
524
- treeDepths
525
- })
526
- });
381
+ }
382
+ return _extends({}, state, {
383
+ rows: _extends({}, state.rows, {
384
+ totalTopLevelRowCount: state.rows.totalTopLevelRowCount - rootLevelRemovals,
385
+ tree: updatedTree,
386
+ treeDepths
387
+ })
527
388
  });
528
- apiRef.current.updateRows(updates);
529
- apiRef.current.publishEvent('rowsSet');
530
- }
531
- } finally {
532
- apiRef.current.setLoading(false);
389
+ });
390
+ apiRef.current.updateRows(updates);
391
+ apiRef.current.publishEvent('rowsSet');
533
392
  }
534
393
  }
535
394
  }
@@ -0,0 +1,2 @@
1
+ import { RowReorderExecutor } from '@mui/x-data-grid-pro/internals';
2
+ export declare const rowGroupingReorderExecutor: RowReorderExecutor;
@@ -0,0 +1,3 @@
1
+ import { RowReorderExecutor, SameParentSwapOperation } from '@mui/x-data-grid-pro/internals';
2
+ import { CrossParentLeafOperation, CrossParentGroupOperation } from "./operations.js";
3
+ export const rowGroupingReorderExecutor = new RowReorderExecutor([new SameParentSwapOperation(), new CrossParentLeafOperation(), new CrossParentGroupOperation()]);
@@ -0,0 +1,2 @@
1
+ import { RowReorderValidator } from '@mui/x-data-grid-pro/internals';
2
+ export declare const rowGroupingReorderValidator: RowReorderValidator;
@@ -1,9 +1,9 @@
1
- import { conditions } from "./utils.js";
1
+ import { commonReorderConditions as conditions, RowReorderValidator } from '@mui/x-data-grid-pro/internals';
2
2
  const validationRules = [
3
3
  // ===== Basic invalid cases =====
4
4
  {
5
5
  name: 'same-position',
6
- applies: ctx => ctx.sourceRowIndex === ctx.targetRowIndex,
6
+ applies: ctx => ctx.sourceNode.id === ctx.targetNode.id,
7
7
  isInvalid: () => true,
8
8
  message: 'Source and target are the same'
9
9
  }, {
@@ -93,24 +93,4 @@ const validationRules = [
93
93
  },
94
94
  message: 'Invalid depth configuration for leaf below group'
95
95
  }];
96
- class RowReorderValidator {
97
- constructor(rules = validationRules) {
98
- this.rules = rules;
99
- }
100
- addRule(rule) {
101
- this.rules.push(rule);
102
- }
103
- removeRule(ruleName) {
104
- this.rules = this.rules.filter(r => r.name !== ruleName);
105
- }
106
- validate(context) {
107
- // Check all validation rules
108
- for (const rule of this.rules) {
109
- if (rule.applies(context) && rule.isInvalid(context)) {
110
- return false;
111
- }
112
- }
113
- return true;
114
- }
115
- }
116
96
  export const rowGroupingReorderValidator = new RowReorderValidator(validationRules);
@@ -1,7 +1,7 @@
1
- import { GridRowId } from '@mui/x-data-grid-pro';
2
1
  import type { RefObject } from '@mui/x-internals/types';
3
2
  import type { GridPrivateApiPremium } from "../../../models/gridApiPremium.js";
4
3
  import type { DataGridPremiumProcessedProps } from "../../../models/dataGridPremiumProps.js";
5
- export declare const useGridRowsOverridableMethods: (apiRef: RefObject<GridPrivateApiPremium>, props: Pick<DataGridPremiumProcessedProps, "processRowUpdate" | "onProcessRowUpdateError">) => {
6
- setRowIndex: (rowId: GridRowId, targetIndex: number) => void;
4
+ export declare const useGridRowsOverridableMethods: (apiRef: RefObject<GridPrivateApiPremium>, props: Pick<DataGridPremiumProcessedProps, "processRowUpdate" | "onProcessRowUpdateError" | "treeData">) => {
5
+ setRowIndex: (rowId: import("@mui/x-data-grid").GridRowId, targetIndex: number) => void;
6
+ setRowPosition: (sourceRowId: import("@mui/x-data-grid").GridRowId, targetRowId: import("@mui/x-data-grid").GridRowId, position: import("@mui/x-data-grid/internals").RowReorderDropPosition) => void | Promise<void>;
7
7
  };