@mui/x-data-grid-pro 8.10.2 → 8.11.1

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.
@@ -9,15 +9,11 @@ Object.defineProperty(exports, "__esModule", {
9
9
  exports.useGridRowReorder = exports.rowReorderStateInitializer = void 0;
10
10
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
11
  var React = _interopRequireWildcard(require("react"));
12
+ var _useTimeout = _interopRequireDefault(require("@mui/utils/useTimeout"));
12
13
  var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses"));
13
14
  var _xDataGrid = require("@mui/x-data-grid");
14
15
  var _internals = require("@mui/x-data-grid/internals");
15
16
  var _gridRowReorderColDef = require("./gridRowReorderColDef");
16
- var Direction = /*#__PURE__*/function (Direction) {
17
- Direction[Direction["UP"] = 0] = "UP";
18
- Direction[Direction["DOWN"] = 1] = "DOWN";
19
- return Direction;
20
- }(Direction || {});
21
17
  const EMPTY_REORDER_STATE = {
22
18
  previousTargetId: null,
23
19
  dragDirection: null,
@@ -42,14 +38,13 @@ const rowReorderStateInitializer = state => (0, _extends2.default)({}, state, {
42
38
  });
43
39
 
44
40
  /**
45
- * Only available in DataGridPro
41
+ * Hook for row reordering (Pro package)
46
42
  * @requires useGridRows (method)
47
43
  */
48
44
  exports.rowReorderStateInitializer = rowReorderStateInitializer;
49
45
  const useGridRowReorder = (apiRef, props) => {
50
46
  const logger = (0, _xDataGrid.useGridLogger)(apiRef, 'useGridRowReorder');
51
47
  const sortModel = (0, _xDataGrid.useGridSelector)(apiRef, _xDataGrid.gridSortModelSelector);
52
- const treeDepth = (0, _xDataGrid.useGridSelector)(apiRef, _xDataGrid.gridRowMaximumTreeDepthSelector);
53
48
  const dragRowNode = React.useRef(null);
54
49
  const originRowIndex = React.useRef(null);
55
50
  const removeDnDStylesTimeout = React.useRef(undefined);
@@ -59,9 +54,11 @@ const useGridRowReorder = (apiRef, props) => {
59
54
  };
60
55
  const classes = useUtilityClasses(ownerState);
61
56
  const [dragRowId, setDragRowId] = React.useState('');
62
- const sortedRowIndexLookup = (0, _xDataGrid.useGridSelector)(apiRef, _internals.gridSortedRowIndexLookupSelector);
57
+ const sortedRowIndexLookup = (0, _xDataGrid.useGridSelector)(apiRef, _internals.gridExpandedSortedRowIndexLookupSelector);
58
+ const timeoutRowId = React.useRef('');
59
+ const timeout = (0, _useTimeout.default)();
63
60
  const previousReorderState = React.useRef(EMPTY_REORDER_STATE);
64
- const [dropTarget, setDropTarget] = React.useState({
61
+ const dropTarget = React.useRef({
65
62
  targetRowId: null,
66
63
  targetRowIndex: null,
67
64
  dropPosition: null
@@ -73,10 +70,10 @@ const useGridRowReorder = (apiRef, props) => {
73
70
  }, []);
74
71
 
75
72
  // TODO: remove sortModel check once row reorder is sorting compatible
76
- // remove treeDepth once row reorder is tree compatible
73
+ // remove treeData check once row reorder is treeData compatible
77
74
  const isRowReorderDisabled = React.useMemo(() => {
78
- return !props.rowReordering || !!sortModel.length || treeDepth !== 1;
79
- }, [props.rowReordering, sortModel, treeDepth]);
75
+ return !props.rowReordering || !!sortModel.length || props.treeData;
76
+ }, [props.rowReordering, sortModel, props.treeData]);
80
77
  const applyDropIndicator = React.useCallback((targetRowId, position) => {
81
78
  // Remove existing drop indicator from previous target
82
79
  if (previousDropIndicatorRef.current) {
@@ -85,7 +82,7 @@ const useGridRowReorder = (apiRef, props) => {
85
82
  }
86
83
 
87
84
  // Apply new drop indicator
88
- if (targetRowId && position) {
85
+ if (targetRowId !== undefined && position !== null) {
89
86
  const targetRow = apiRef.current.rootElementRef?.current?.querySelector(`[data-id="${targetRowId}"]`);
90
87
  if (targetRow) {
91
88
  targetRow.classList.add(position === 'above' ? classes.rowDropAbove : classes.rowDropBelow);
@@ -160,9 +157,14 @@ const useGridRowReorder = (apiRef, props) => {
160
157
  const handleDragStart = React.useCallback((params, event) => {
161
158
  // Call the gridEditRowsStateSelector directly to avoid infnite loop
162
159
  const editRowsState = (0, _internals.gridEditRowsStateSelector)(apiRef);
160
+ event.dataTransfer.effectAllowed = 'copy';
163
161
  if (isRowReorderDisabled || Object.keys(editRowsState).length !== 0) {
164
162
  return;
165
163
  }
164
+ if (timeoutRowId.current) {
165
+ timeout.clear();
166
+ timeoutRowId.current = '';
167
+ }
166
168
  logger.debug(`Start dragging row ${params.id}`);
167
169
  // Prevent drag events propagation.
168
170
  // For more information check here https://github.com/mui/mui-x/issues/2680.
@@ -180,13 +182,14 @@ const useGridRowReorder = (apiRef, props) => {
180
182
  });
181
183
  originRowIndex.current = sortedRowIndexLookup[params.id];
182
184
  apiRef.current.setCellFocus(params.id, _gridRowReorderColDef.GRID_REORDER_COL_DEF.field);
183
- }, [apiRef, isRowReorderDisabled, logger, classes.rowDragging, sortedRowIndexLookup, applyDraggedState]);
185
+ }, [apiRef, isRowReorderDisabled, logger, classes.rowDragging, applyDraggedState, sortedRowIndexLookup, timeout]);
184
186
  const handleDragOver = React.useCallback((params, event) => {
185
187
  if (dragRowId === '') {
186
188
  return;
187
189
  }
188
- const rowNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, params.id);
189
- if (!rowNode || rowNode.type === 'footer' || rowNode.type === 'pinnedRow' || !event.target) {
190
+ const targetNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, params.id);
191
+ const sourceNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, dragRowId);
192
+ if (!sourceNode || !targetNode || targetNode.type === 'footer' || targetNode.type === 'pinnedRow' || !event.target) {
190
193
  return;
191
194
  }
192
195
 
@@ -199,66 +202,80 @@ const useGridRowReorder = (apiRef, props) => {
199
202
  // Prevent drag events propagation.
200
203
  // For more information check here https://github.com/mui/mui-x/issues/2680.
201
204
  event.stopPropagation();
202
- if (params.id !== dragRowId) {
203
- const targetRowIndex = sortedRowIndexLookup[params.id];
204
- const sourceRowIndex = sortedRowIndexLookup[dragRowId];
205
+ if (timeoutRowId.current && timeoutRowId.current !== params.id) {
206
+ timeout.clear();
207
+ timeoutRowId.current = '';
208
+ }
209
+ if (targetNode.type === 'group' && targetNode.depth < sourceNode.depth && !targetNode.childrenExpanded && !timeoutRowId.current) {
210
+ timeout.start(500, () => {
211
+ const rowNode = (0, _xDataGrid.gridRowNodeSelector)(apiRef, params.id);
212
+ // TODO: Handle `dataSource` case with https://github.com/mui/mui-x/issues/18947
213
+ apiRef.current.setRowChildrenExpansion(params.id, !rowNode.childrenExpanded);
214
+ });
215
+ timeoutRowId.current = params.id;
216
+ return;
217
+ }
218
+ const targetRowIndex = sortedRowIndexLookup[params.id];
219
+ const sourceRowIndex = sortedRowIndexLookup[dragRowId];
205
220
 
206
- // Determine drop position based on relativeY position within the row
207
- const dropPosition = relativeY < midPoint ? 'above' : 'below';
221
+ // Determine drop position based on relativeY position within the row
222
+ const dropPosition = relativeY < midPoint ? 'above' : 'below';
223
+ const currentReorderState = {
224
+ dragDirection: targetRowIndex < sourceRowIndex ? 'up' : 'down',
225
+ previousTargetId: params.id,
226
+ previousDropPosition: dropPosition
227
+ };
208
228
 
209
- // Check if this drop would result in no actual movement
210
- const wouldResultInNoMovement = dropPosition === 'above' && targetRowIndex === sourceRowIndex + 1 ||
211
- // dragging to immediately below (above next row)
212
- dropPosition === 'below' && targetRowIndex === sourceRowIndex - 1; // dragging to immediately above (below previous row)
229
+ // Update visual indicator when dragging over a different row or position
230
+ if (previousReorderState.current.previousTargetId !== params.id || previousReorderState.current.previousDropPosition !== dropPosition) {
231
+ const isSameNode = targetRowIndex === sourceRowIndex;
213
232
 
214
- const currentReorderState = {
215
- dragDirection: targetRowIndex < sourceRowIndex ? Direction.UP : Direction.DOWN,
216
- previousTargetId: params.id,
217
- previousDropPosition: dropPosition
218
- };
233
+ // Check if this is an adjacent position
234
+ const isAdjacentPosition = dropPosition === 'above' && targetRowIndex === sourceRowIndex + 1 || dropPosition === 'below' && targetRowIndex === sourceRowIndex - 1;
235
+ const validatedIndex = apiRef.current.unstable_applyPipeProcessors('getRowReorderTargetIndex', -1, {
236
+ sourceRowId: dragRowId,
237
+ targetRowId: params.id,
238
+ dropPosition,
239
+ dragDirection: currentReorderState.dragDirection
240
+ });
219
241
 
220
- // Only update visual indicator:
221
- // 1. When dragging over a different row
222
- // 2. When it would result in actual movement
223
- if (previousReorderState.current.previousTargetId !== params.id || previousReorderState.current.previousDropPosition !== dropPosition) {
224
- if (wouldResultInNoMovement) {
225
- // Clear any existing indicators since this wouldn't result in movement
226
- setDropTarget({
227
- targetRowId: null,
228
- targetRowIndex: null,
229
- dropPosition: null
230
- });
231
- applyDropIndicator(null, null);
232
- } else {
233
- setDropTarget({
234
- targetRowId: params.id,
235
- targetRowIndex,
236
- dropPosition
237
- });
238
- applyDropIndicator(params.id, dropPosition);
239
- }
240
- previousReorderState.current = currentReorderState;
242
+ // Show drop indicator for valid drops OR adjacent positions OR same node
243
+ if (validatedIndex !== -1 || isAdjacentPosition || isSameNode) {
244
+ dropTarget.current = {
245
+ targetRowId: params.id,
246
+ targetRowIndex,
247
+ dropPosition
248
+ };
249
+ applyDropIndicator(params.id, dropPosition);
250
+ } else {
251
+ // Clear indicators for invalid drops
252
+ dropTarget.current = {
253
+ targetRowId: null,
254
+ targetRowIndex: null,
255
+ dropPosition: null
256
+ };
257
+ applyDropIndicator(null, null);
241
258
  }
242
- } else if (previousReorderState.current.previousTargetId !== null) {
243
- setDropTarget({
244
- targetRowId: null,
245
- targetRowIndex: null,
246
- dropPosition: null
247
- });
248
- applyDropIndicator(null, null);
249
- previousReorderState.current = {
250
- previousTargetId: null,
251
- dragDirection: null,
252
- previousDropPosition: null
253
- };
259
+ previousReorderState.current = currentReorderState;
254
260
  }
255
- }, [dragRowId, apiRef, logger, sortedRowIndexLookup, applyDropIndicator]);
261
+
262
+ // Render the native 'copy' cursor for additional visual feedback
263
+ if (dropTarget.current.targetRowId === null) {
264
+ event.dataTransfer.dropEffect = 'none';
265
+ } else {
266
+ event.dataTransfer.dropEffect = 'copy';
267
+ }
268
+ }, [dragRowId, apiRef, logger, timeout, sortedRowIndexLookup, applyDropIndicator]);
256
269
  const handleDragEnd = React.useCallback((_, event) => {
257
270
  // Call the gridEditRowsStateSelector directly to avoid infnite loop
258
271
  const editRowsState = (0, _internals.gridEditRowsStateSelector)(apiRef);
259
272
  if (dragRowId === '' || isRowReorderDisabled || Object.keys(editRowsState).length !== 0) {
260
273
  return;
261
274
  }
275
+ if (timeoutRowId.current) {
276
+ timeout.clear();
277
+ timeoutRowId.current = '';
278
+ }
262
279
  logger.debug('End dragging row');
263
280
  event.preventDefault();
264
281
  // Prevent drag events propagation.
@@ -277,55 +294,77 @@ const useGridRowReorder = (apiRef, props) => {
277
294
  // Check if the row was dropped outside the grid.
278
295
  if (!event.dataTransfer || event.dataTransfer.dropEffect === 'none') {
279
296
  // Reset drop target state
280
- setDropTarget({
297
+ dropTarget.current = {
281
298
  targetRowId: null,
282
299
  targetRowIndex: null,
283
300
  dropPosition: null
284
- });
301
+ };
285
302
  originRowIndex.current = null;
286
- } else {
287
- if (dropTarget.targetRowIndex !== null && dropTarget.targetRowId !== null) {
288
- const sourceRowIndex = originRowIndex.current;
289
- const targetRowIndex = dropTarget.targetRowIndex;
290
- const dropPosition = dropTarget.dropPosition;
303
+ setDragRowId('');
304
+ return;
305
+ }
306
+ if (dropTarget.current.targetRowIndex !== null && dropTarget.current.targetRowId !== null) {
307
+ const sourceRowIndex = originRowIndex.current;
308
+ const targetRowIndex = dropTarget.current.targetRowIndex;
309
+ const validatedIndex = apiRef.current.unstable_applyPipeProcessors('getRowReorderTargetIndex', targetRowIndex, {
310
+ sourceRowId: dragRowId,
311
+ targetRowId: dropTarget.current.targetRowId,
312
+ dropPosition: dropTarget.current.dropPosition,
313
+ dragDirection: dragDirection
314
+ });
315
+ if (validatedIndex !== -1) {
316
+ applyRowAnimation(() => {
317
+ apiRef.current.setRowIndex(dragRowId, validatedIndex);
291
318
 
292
- // Calculate the correct target index based on drop position
293
- let finalTargetIndex;
294
- if (dragDirection === Direction.UP) {
295
- finalTargetIndex = dropPosition === 'above' ? targetRowIndex : targetRowIndex + 1;
296
- } else {
297
- finalTargetIndex = dropPosition === 'above' ? targetRowIndex - 1 : targetRowIndex;
298
- }
299
- const isReorderInvalid = dropPosition === 'above' && targetRowIndex === sourceRowIndex + 1 ||
300
- // dragging to immediately below (above next row)
301
- dropPosition === 'below' && targetRowIndex === sourceRowIndex - 1 ||
302
- // dragging to immediately above (below previous row)
303
- dropTarget.targetRowId === dragRowId; // dragging to the same row
319
+ // Emit the rowOrderChange event only once when the reordering stops.
320
+ const rowOrderChangeParams = {
321
+ row: apiRef.current.getRow(dragRowId),
322
+ targetIndex: validatedIndex,
323
+ oldIndex: sourceRowIndex
324
+ };
325
+ apiRef.current.publishEvent('rowOrderChange', rowOrderChangeParams);
326
+ });
327
+ }
328
+ }
304
329
 
305
- if (!isReorderInvalid) {
306
- applyRowAnimation(() => {
307
- apiRef.current.setRowIndex(dragRowId, finalTargetIndex);
330
+ // Reset drop target state
331
+ dropTarget.current = {
332
+ targetRowId: null,
333
+ targetRowIndex: null,
334
+ dropPosition: null
335
+ };
336
+ setDragRowId('');
337
+ }, [apiRef, dragRowId, isRowReorderDisabled, logger, applyDropIndicator, applyDraggedState, timeout, applyRowAnimation]);
338
+ const getRowReorderTargetIndex = React.useCallback((initialValue, {
339
+ sourceRowId,
340
+ targetRowId,
341
+ dropPosition,
342
+ dragDirection
343
+ }) => {
344
+ if ((0, _xDataGrid.gridRowMaximumTreeDepthSelector)(apiRef) > 1) {
345
+ return initialValue;
346
+ }
347
+ const targetRowIndex = sortedRowIndexLookup[targetRowId];
348
+ const sourceRowIndex = sortedRowIndexLookup[sourceRowId];
308
349
 
309
- // Emit the rowOrderChange event only once when the reordering stops.
310
- const rowOrderChangeParams = {
311
- row: apiRef.current.getRow(dragRowId),
312
- targetIndex: finalTargetIndex,
313
- oldIndex: sourceRowIndex
314
- };
315
- apiRef.current.publishEvent('rowOrderChange', rowOrderChangeParams);
316
- });
317
- }
318
- }
350
+ // Check if this drop would result in no actual movement
351
+ const isAdjacentNode = dropPosition === 'above' && targetRowIndex === sourceRowIndex + 1 ||
352
+ // dragging to immediately below (above next row)
353
+ dropPosition === 'below' && targetRowIndex === sourceRowIndex - 1; // dragging to immediately above (below previous row)
319
354
 
320
- // Reset drop target state
321
- setDropTarget({
322
- targetRowId: null,
323
- targetRowIndex: null,
324
- dropPosition: null
325
- });
355
+ if (isAdjacentNode || sourceRowIndex === targetRowIndex) {
356
+ // Return -1 to prevent actual movement (indicators handled separately)
357
+ return -1;
326
358
  }
327
- setDragRowId('');
328
- }, [apiRef, dragRowId, isRowReorderDisabled, logger, dropTarget, applyDropIndicator, applyDraggedState, applyRowAnimation]);
359
+ let finalTargetIndex;
360
+ if (dragDirection === 'up') {
361
+ finalTargetIndex = dropPosition === 'above' ? targetRowIndex : targetRowIndex + 1;
362
+ } else {
363
+ finalTargetIndex = dropPosition === 'above' ? targetRowIndex - 1 : targetRowIndex;
364
+ }
365
+ return finalTargetIndex;
366
+ }, [apiRef, sortedRowIndexLookup]);
367
+ (0, _internals.useGridRegisterPipeProcessor)(apiRef, 'getRowReorderTargetIndex', getRowReorderTargetIndex);
329
368
  (0, _xDataGrid.useGridEvent)(apiRef, 'rowDragStart', handleDragStart);
330
369
  (0, _xDataGrid.useGridEvent)(apiRef, 'rowDragOver', handleDragOver);
331
370
  (0, _xDataGrid.useGridEvent)(apiRef, 'rowDragEnd', handleDragEnd);
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid-pro v8.10.2
2
+ * @mui/x-data-grid-pro v8.11.1
3
3
  *
4
4
  * @license SEE LICENSE IN LICENSE
5
5
  * This source code is licensed under the SEE LICENSE IN LICENSE license found in the
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@mui/x-data-grid-pro",
3
- "version": "8.10.2",
3
+ "version": "8.11.1",
4
4
  "author": "MUI Team",
5
5
  "description": "The Pro plan edition of the MUI X Data Grid components.",
6
- "main": "./index.js",
7
6
  "license": "SEE LICENSE IN LICENSE",
8
7
  "bugs": {
9
8
  "url": "https://github.com/mui/mui-x/issues"
@@ -39,9 +38,9 @@
39
38
  "@types/format-util": "^1.0.4",
40
39
  "clsx": "^2.1.1",
41
40
  "prop-types": "^15.8.1",
42
- "@mui/x-internals": "8.10.2",
43
- "@mui/x-license": "8.10.2",
44
- "@mui/x-data-grid": "8.10.2"
41
+ "@mui/x-data-grid": "8.11.1",
42
+ "@mui/x-license": "8.11.1",
43
+ "@mui/x-internals": "8.11.1"
45
44
  },
46
45
  "peerDependencies": {
47
46
  "@emotion/react": "^11.9.0",
@@ -63,27 +62,28 @@
63
62
  "node": ">=14.0.0"
64
63
  },
65
64
  "type": "commonjs",
65
+ "main": "./index.js",
66
66
  "types": "./index.d.ts",
67
67
  "exports": {
68
68
  "./package.json": "./package.json",
69
69
  ".": {
70
- "import": {
71
- "types": "./esm/index.d.ts",
72
- "default": "./esm/index.js"
73
- },
74
70
  "require": {
75
71
  "types": "./index.d.ts",
76
72
  "default": "./index.js"
73
+ },
74
+ "default": {
75
+ "types": "./esm/index.d.ts",
76
+ "default": "./esm/index.js"
77
77
  }
78
78
  },
79
79
  "./*": {
80
- "import": {
81
- "types": "./esm/*/index.d.ts",
82
- "default": "./esm/*/index.js"
83
- },
84
80
  "require": {
85
81
  "types": "./*/index.d.ts",
86
82
  "default": "./*/index.js"
83
+ },
84
+ "default": {
85
+ "types": "./esm/*/index.d.ts",
86
+ "default": "./esm/*/index.js"
87
87
  }
88
88
  },
89
89
  "./esm": null