@mui/x-data-grid 9.10.0 → 9.11.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 +224 -0
- package/README.md +1 -11
- package/components/cell/GridEditInputCell.js +1 -1
- package/components/cell/GridEditInputCell.mjs +1 -1
- package/components/cell/GridEditLongTextCell.js +1 -1
- package/components/cell/GridEditLongTextCell.mjs +1 -1
- package/components/toolbarV8/Toolbar.js +2 -125
- package/components/toolbarV8/Toolbar.mjs +2 -125
- package/components/toolbarV8/ToolbarButton.js +11 -50
- package/components/toolbarV8/ToolbarButton.mjs +11 -50
- package/hooks/features/columnResize/useGridColumnResize.js +3 -0
- package/hooks/features/columnResize/useGridColumnResize.mjs +3 -0
- package/hooks/features/columns/useGridColumns.js +5 -1
- package/hooks/features/columns/useGridColumns.mjs +5 -1
- package/hooks/features/dataSource/useGridDataSourceBase.js +33 -4
- package/hooks/features/dataSource/useGridDataSourceBase.mjs +33 -4
- package/hooks/features/editing/useGridCellEditing.js +9 -3
- package/hooks/features/editing/useGridCellEditing.mjs +9 -3
- package/hooks/features/editing/useGridRowEditing.js +7 -5
- package/hooks/features/editing/useGridRowEditing.mjs +7 -5
- package/hooks/features/filter/useGridFilter.js +1 -1
- package/hooks/features/filter/useGridFilter.mjs +1 -1
- package/hooks/features/rows/gridRowsUtils.js +17 -1
- package/hooks/features/rows/gridRowsUtils.mjs +17 -1
- package/hooks/features/rows/useGridParamsApi.d.mts +1 -1
- package/hooks/features/rows/useGridParamsApi.d.ts +1 -1
- package/hooks/features/rows/useGridParamsApi.js +1 -0
- package/hooks/features/rows/useGridParamsApi.mjs +1 -0
- package/hooks/features/sorting/useGridSorting.js +3 -0
- package/hooks/features/sorting/useGridSorting.mjs +3 -0
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/models/api/gridColumnApi.d.mts +2 -2
- package/models/api/gridColumnApi.d.ts +2 -2
- package/package.json +4 -4
- package/components/toolbarV8/ToolbarContext.d.mts +0 -11
- package/components/toolbarV8/ToolbarContext.d.ts +0 -11
- package/components/toolbarV8/ToolbarContext.js +0 -21
- package/components/toolbarV8/ToolbarContext.mjs +0 -13
- package/components/toolbarV8/utils.d.mts +0 -5
- package/components/toolbarV8/utils.d.ts +0 -5
- package/components/toolbarV8/utils.js +0 -23
- package/components/toolbarV8/utils.mjs +0 -17
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
4
4
|
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
5
|
-
const _excluded = ["render", "onKeyDown", "onFocus", "disabled", "aria-disabled"]
|
|
5
|
+
const _excluded = ["render", "onKeyDown", "onFocus", "onBlur", "disabled", "aria-disabled"],
|
|
6
|
+
_excluded2 = ["tabIndex"];
|
|
6
7
|
import * as React from 'react';
|
|
7
8
|
import PropTypes from 'prop-types';
|
|
8
9
|
import useForkRef from '@mui/utils/useForkRef';
|
|
9
|
-
import useId from '@mui/utils/useId';
|
|
10
10
|
import { forwardRef } from '@mui/x-internals/forwardRef';
|
|
11
11
|
import { useComponentRenderer } from '@mui/x-internals/useComponentRenderer';
|
|
12
|
+
import { useRegisterToolbarButton } from '@mui/x-internals/ToolbarContext';
|
|
12
13
|
import { useGridRootProps } from "../../hooks/utils/useGridRootProps.mjs";
|
|
13
|
-
import { useToolbarContext } from "./ToolbarContext.mjs";
|
|
14
14
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
15
15
|
/**
|
|
16
16
|
* A button for performing actions from the toolbar.
|
|
@@ -26,59 +26,20 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
26
26
|
*/
|
|
27
27
|
const ToolbarButton = forwardRef(function ToolbarButton(props, ref) {
|
|
28
28
|
const {
|
|
29
|
-
render
|
|
30
|
-
onKeyDown,
|
|
31
|
-
onFocus,
|
|
32
|
-
disabled,
|
|
33
|
-
'aria-disabled': ariaDisabled
|
|
29
|
+
render
|
|
34
30
|
} = props,
|
|
35
31
|
other = _objectWithoutPropertiesLoose(props, _excluded);
|
|
36
|
-
const id = useId();
|
|
37
32
|
const rootProps = useGridRootProps();
|
|
38
33
|
const buttonRef = React.useRef(null);
|
|
39
34
|
const handleRef = useForkRef(buttonRef, ref);
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
onItemFocus,
|
|
46
|
-
onItemDisabled
|
|
47
|
-
} = useToolbarContext();
|
|
48
|
-
const handleKeyDown = event => {
|
|
49
|
-
onItemKeyDown(event);
|
|
50
|
-
onKeyDown?.(event);
|
|
51
|
-
};
|
|
52
|
-
const handleFocus = event => {
|
|
53
|
-
onItemFocus(id);
|
|
54
|
-
onFocus?.(event);
|
|
55
|
-
};
|
|
56
|
-
React.useEffect(() => {
|
|
57
|
-
registerItem(id, buttonRef);
|
|
58
|
-
return () => unregisterItem(id);
|
|
59
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
60
|
-
}, []);
|
|
61
|
-
const previousDisabled = React.useRef(disabled);
|
|
62
|
-
React.useEffect(() => {
|
|
63
|
-
if (previousDisabled.current !== disabled && disabled === true) {
|
|
64
|
-
onItemDisabled(id, disabled);
|
|
65
|
-
}
|
|
66
|
-
previousDisabled.current = disabled;
|
|
67
|
-
}, [disabled, id, onItemDisabled]);
|
|
68
|
-
const previousAriaDisabled = React.useRef(ariaDisabled);
|
|
69
|
-
React.useEffect(() => {
|
|
70
|
-
if (previousAriaDisabled.current !== ariaDisabled && ariaDisabled === true) {
|
|
71
|
-
onItemDisabled(id, true);
|
|
72
|
-
}
|
|
73
|
-
previousAriaDisabled.current = ariaDisabled;
|
|
74
|
-
}, [ariaDisabled, id, onItemDisabled]);
|
|
35
|
+
const _useRegisterToolbarBu = useRegisterToolbarButton(props, buttonRef),
|
|
36
|
+
{
|
|
37
|
+
tabIndex
|
|
38
|
+
} = _useRegisterToolbarBu,
|
|
39
|
+
toolbarButtonProps = _objectWithoutPropertiesLoose(_useRegisterToolbarBu, _excluded2);
|
|
75
40
|
const element = useComponentRenderer(rootProps.slots.baseIconButton, render, _extends({}, rootProps.slotProps?.baseIconButton, {
|
|
76
|
-
tabIndex
|
|
77
|
-
}, other, {
|
|
78
|
-
disabled,
|
|
79
|
-
'aria-disabled': ariaDisabled,
|
|
80
|
-
onKeyDown: handleKeyDown,
|
|
81
|
-
onFocus: handleFocus,
|
|
41
|
+
tabIndex
|
|
42
|
+
}, other, toolbarButtonProps, {
|
|
82
43
|
ref: handleRef
|
|
83
44
|
}));
|
|
84
45
|
return /*#__PURE__*/_jsx(React.Fragment, {
|
|
@@ -450,6 +450,9 @@ const useGridColumnResize = (apiRef, props) => {
|
|
|
450
450
|
const columnHeaderElement = (0, _domUtils.findParentElementFromClassName)(event.target, _gridClasses.gridClasses.columnHeader);
|
|
451
451
|
const field = (0, _domUtils.getFieldFromHeaderElem)(columnHeaderElement);
|
|
452
452
|
const colDef = apiRef.current.getColumn(field);
|
|
453
|
+
if (!colDef) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
453
456
|
logger.debug(`Start Resize on col ${colDef.field}`);
|
|
454
457
|
apiRef.current.publishEvent('columnResizeStart', {
|
|
455
458
|
field
|
|
@@ -442,6 +442,9 @@ export const useGridColumnResize = (apiRef, props) => {
|
|
|
442
442
|
const columnHeaderElement = findParentElementFromClassName(event.target, gridClasses.columnHeader);
|
|
443
443
|
const field = getFieldFromHeaderElem(columnHeaderElement);
|
|
444
444
|
const colDef = apiRef.current.getColumn(field);
|
|
445
|
+
if (!colDef) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
445
448
|
logger.debug(`Start Resize on col ${colDef.field}`);
|
|
446
449
|
apiRef.current.publishEvent('columnResizeStart', {
|
|
447
450
|
field
|
|
@@ -137,6 +137,10 @@ function useGridColumns(apiRef, props) {
|
|
|
137
137
|
return allColumns.findIndex(col => col === field);
|
|
138
138
|
}, [apiRef]);
|
|
139
139
|
const setColumnIndex = React.useCallback((field, targetIndexPosition) => {
|
|
140
|
+
const column = apiRef.current.getColumn(field);
|
|
141
|
+
if (!column) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
140
144
|
const allColumns = (0, _gridColumnsSelector.gridColumnFieldsSelector)(apiRef);
|
|
141
145
|
const oldIndexPosition = getColumnIndexRelativeToVisibleColumns(field);
|
|
142
146
|
if (oldIndexPosition === targetIndexPosition) {
|
|
@@ -150,7 +154,7 @@ function useGridColumns(apiRef, props) {
|
|
|
150
154
|
orderedFields: updatedColumns
|
|
151
155
|
}));
|
|
152
156
|
const params = {
|
|
153
|
-
column
|
|
157
|
+
column,
|
|
154
158
|
targetIndex: apiRef.current.getColumnIndexRelativeToVisibleColumns(field),
|
|
155
159
|
oldIndex: oldIndexPosition
|
|
156
160
|
};
|
|
@@ -128,6 +128,10 @@ export function useGridColumns(apiRef, props) {
|
|
|
128
128
|
return allColumns.findIndex(col => col === field);
|
|
129
129
|
}, [apiRef]);
|
|
130
130
|
const setColumnIndex = React.useCallback((field, targetIndexPosition) => {
|
|
131
|
+
const column = apiRef.current.getColumn(field);
|
|
132
|
+
if (!column) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
131
135
|
const allColumns = gridColumnFieldsSelector(apiRef);
|
|
132
136
|
const oldIndexPosition = getColumnIndexRelativeToVisibleColumns(field);
|
|
133
137
|
if (oldIndexPosition === targetIndexPosition) {
|
|
@@ -141,7 +145,7 @@ export function useGridColumns(apiRef, props) {
|
|
|
141
145
|
orderedFields: updatedColumns
|
|
142
146
|
}));
|
|
143
147
|
const params = {
|
|
144
|
-
column
|
|
148
|
+
column,
|
|
145
149
|
targetIndex: apiRef.current.getColumnIndexRelativeToVisibleColumns(field),
|
|
146
150
|
oldIndex: oldIndexPosition
|
|
147
151
|
};
|
|
@@ -47,6 +47,11 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
47
47
|
}, [currentStrategy]);
|
|
48
48
|
const paginationModel = (0, _useGridSelector.useGridSelector)(apiRef, _gridPaginationSelector.gridPaginationModelSelector);
|
|
49
49
|
const lastRequestId = React.useRef(0);
|
|
50
|
+
// `false` while a request is in flight, and for any request that errors or is discarded as
|
|
51
|
+
// stale. Lets the mount effect tell "rows are already displayed" from "the fetch never landed".
|
|
52
|
+
const rowsAreUpToDate = React.useRef(false);
|
|
53
|
+
// Requests that are still running and will apply their response when they settle.
|
|
54
|
+
const pendingRequestCount = React.useRef(0);
|
|
50
55
|
const pollingIntervalRef = React.useRef(null);
|
|
51
56
|
const onDataSourceErrorProp = props.onDataSourceError;
|
|
52
57
|
const revalidateMs = props.dataSourceRevalidateMs;
|
|
@@ -91,6 +96,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
91
96
|
keepChildrenExpanded
|
|
92
97
|
}
|
|
93
98
|
});
|
|
99
|
+
rowsAreUpToDate.current = true;
|
|
94
100
|
if (standardRowsUpdateStrategyActive) {
|
|
95
101
|
apiRef.current.setLoading(false);
|
|
96
102
|
}
|
|
@@ -103,6 +109,8 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
103
109
|
}
|
|
104
110
|
const requestId = lastRequestId.current + 1;
|
|
105
111
|
lastRequestId.current = requestId;
|
|
112
|
+
rowsAreUpToDate.current = false;
|
|
113
|
+
pendingRequestCount.current += 1;
|
|
106
114
|
try {
|
|
107
115
|
const getRowsResponse = await getRows(fetchParams);
|
|
108
116
|
const cacheResponses = cacheChunkManager.splitResponse(fetchParams, getRowsResponse);
|
|
@@ -116,6 +124,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
116
124
|
keepChildrenExpanded
|
|
117
125
|
}
|
|
118
126
|
});
|
|
127
|
+
rowsAreUpToDate.current = true;
|
|
119
128
|
}
|
|
120
129
|
} catch (originalError) {
|
|
121
130
|
if (lastRequestId.current === requestId) {
|
|
@@ -138,6 +147,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
149
|
} finally {
|
|
150
|
+
pendingRequestCount.current -= 1;
|
|
141
151
|
if (standardRowsUpdateStrategyActive && lastRequestId.current === requestId) {
|
|
142
152
|
apiRef.current.setLoading(false);
|
|
143
153
|
}
|
|
@@ -313,12 +323,34 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
313
323
|
}
|
|
314
324
|
}, [revalidateMs, stopPolling]);
|
|
315
325
|
React.useEffect(() => stopPolling, [stopPolling]);
|
|
326
|
+
const lastApiRef = React.useRef(apiRef);
|
|
327
|
+
const lastStrategy = React.useRef(currentStrategy);
|
|
328
|
+
const lastDataSource = React.useRef(props.dataSource);
|
|
316
329
|
React.useEffect(() => {
|
|
330
|
+
// `<Activity mode="hidden">` leaves the root element in the document, a real unmount does not.
|
|
331
|
+
// Only discard the in-flight response in the latter case, so hiding lets the request land.
|
|
332
|
+
const rootElement = apiRef.current?.rootElementRef?.current ?? null;
|
|
333
|
+
const ignoreInFlightRequest = () => {
|
|
334
|
+
if (!rootElement?.isConnected) {
|
|
335
|
+
lastRequestId.current += 1;
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
|
|
317
339
|
// Return early if the proper strategy isn't set yet
|
|
318
340
|
// Context: https://github.com/mui/mui-x/issues/19650
|
|
319
341
|
if (currentStrategy !== _utils2.DataSourceRowsUpdateStrategy.Default && currentStrategy !== _utils2.DataSourceRowsUpdateStrategy.LazyLoading && currentStrategy !== _utils2.DataSourceRowsUpdateStrategy.GroupedData && currentStrategy !== _utils2.DataSourceRowsUpdateStrategy.LazyLoadedGroupedData) {
|
|
320
342
|
return undefined;
|
|
321
343
|
}
|
|
344
|
+
const dependenciesChanged = lastApiRef.current !== apiRef || lastStrategy.current !== currentStrategy || lastDataSource.current !== props.dataSource;
|
|
345
|
+
lastApiRef.current = apiRef;
|
|
346
|
+
lastStrategy.current = currentStrategy;
|
|
347
|
+
lastDataSource.current = props.dataSource;
|
|
348
|
+
|
|
349
|
+
// Re-mounting the effect (`<Activity />` becoming visible again, for instance) must not
|
|
350
|
+
// re-fetch data that is already displayed.
|
|
351
|
+
if (!dependenciesChanged && (rowsAreUpToDate.current || pendingRequestCount.current > 0)) {
|
|
352
|
+
return ignoreInFlightRequest;
|
|
353
|
+
}
|
|
322
354
|
if (props.dataSource) {
|
|
323
355
|
stopPolling();
|
|
324
356
|
// `dataSourceKeepPreviousData` only applies to the flat `Default` strategy (mirroring
|
|
@@ -332,10 +364,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
332
364
|
apiRef.current.dataSource.cache.clear();
|
|
333
365
|
apiRef.current.dataSource.fetchRows();
|
|
334
366
|
}
|
|
335
|
-
return
|
|
336
|
-
// ignore the current request on unmount
|
|
337
|
-
lastRequestId.current += 1;
|
|
338
|
-
};
|
|
367
|
+
return ignoreInFlightRequest;
|
|
339
368
|
}, [apiRef, props.dataSource, props.dataSourceKeepPreviousData, currentStrategy, stopPolling]);
|
|
340
369
|
React.useEffect(() => {
|
|
341
370
|
// `dataSourceKeepPreviousData` is a no-op for tree data and row grouping: those
|
|
@@ -40,6 +40,11 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
40
40
|
}, [currentStrategy]);
|
|
41
41
|
const paginationModel = useGridSelector(apiRef, gridPaginationModelSelector);
|
|
42
42
|
const lastRequestId = React.useRef(0);
|
|
43
|
+
// `false` while a request is in flight, and for any request that errors or is discarded as
|
|
44
|
+
// stale. Lets the mount effect tell "rows are already displayed" from "the fetch never landed".
|
|
45
|
+
const rowsAreUpToDate = React.useRef(false);
|
|
46
|
+
// Requests that are still running and will apply their response when they settle.
|
|
47
|
+
const pendingRequestCount = React.useRef(0);
|
|
43
48
|
const pollingIntervalRef = React.useRef(null);
|
|
44
49
|
const onDataSourceErrorProp = props.onDataSourceError;
|
|
45
50
|
const revalidateMs = props.dataSourceRevalidateMs;
|
|
@@ -84,6 +89,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
84
89
|
keepChildrenExpanded
|
|
85
90
|
}
|
|
86
91
|
});
|
|
92
|
+
rowsAreUpToDate.current = true;
|
|
87
93
|
if (standardRowsUpdateStrategyActive) {
|
|
88
94
|
apiRef.current.setLoading(false);
|
|
89
95
|
}
|
|
@@ -96,6 +102,8 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
96
102
|
}
|
|
97
103
|
const requestId = lastRequestId.current + 1;
|
|
98
104
|
lastRequestId.current = requestId;
|
|
105
|
+
rowsAreUpToDate.current = false;
|
|
106
|
+
pendingRequestCount.current += 1;
|
|
99
107
|
try {
|
|
100
108
|
const getRowsResponse = await getRows(fetchParams);
|
|
101
109
|
const cacheResponses = cacheChunkManager.splitResponse(fetchParams, getRowsResponse);
|
|
@@ -109,6 +117,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
109
117
|
keepChildrenExpanded
|
|
110
118
|
}
|
|
111
119
|
});
|
|
120
|
+
rowsAreUpToDate.current = true;
|
|
112
121
|
}
|
|
113
122
|
} catch (originalError) {
|
|
114
123
|
if (lastRequestId.current === requestId) {
|
|
@@ -131,6 +140,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
131
140
|
}
|
|
132
141
|
}
|
|
133
142
|
} finally {
|
|
143
|
+
pendingRequestCount.current -= 1;
|
|
134
144
|
if (standardRowsUpdateStrategyActive && lastRequestId.current === requestId) {
|
|
135
145
|
apiRef.current.setLoading(false);
|
|
136
146
|
}
|
|
@@ -306,12 +316,34 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
306
316
|
}
|
|
307
317
|
}, [revalidateMs, stopPolling]);
|
|
308
318
|
React.useEffect(() => stopPolling, [stopPolling]);
|
|
319
|
+
const lastApiRef = React.useRef(apiRef);
|
|
320
|
+
const lastStrategy = React.useRef(currentStrategy);
|
|
321
|
+
const lastDataSource = React.useRef(props.dataSource);
|
|
309
322
|
React.useEffect(() => {
|
|
323
|
+
// `<Activity mode="hidden">` leaves the root element in the document, a real unmount does not.
|
|
324
|
+
// Only discard the in-flight response in the latter case, so hiding lets the request land.
|
|
325
|
+
const rootElement = apiRef.current?.rootElementRef?.current ?? null;
|
|
326
|
+
const ignoreInFlightRequest = () => {
|
|
327
|
+
if (!rootElement?.isConnected) {
|
|
328
|
+
lastRequestId.current += 1;
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
310
332
|
// Return early if the proper strategy isn't set yet
|
|
311
333
|
// Context: https://github.com/mui/mui-x/issues/19650
|
|
312
334
|
if (currentStrategy !== DataSourceRowsUpdateStrategy.Default && currentStrategy !== DataSourceRowsUpdateStrategy.LazyLoading && currentStrategy !== DataSourceRowsUpdateStrategy.GroupedData && currentStrategy !== DataSourceRowsUpdateStrategy.LazyLoadedGroupedData) {
|
|
313
335
|
return undefined;
|
|
314
336
|
}
|
|
337
|
+
const dependenciesChanged = lastApiRef.current !== apiRef || lastStrategy.current !== currentStrategy || lastDataSource.current !== props.dataSource;
|
|
338
|
+
lastApiRef.current = apiRef;
|
|
339
|
+
lastStrategy.current = currentStrategy;
|
|
340
|
+
lastDataSource.current = props.dataSource;
|
|
341
|
+
|
|
342
|
+
// Re-mounting the effect (`<Activity />` becoming visible again, for instance) must not
|
|
343
|
+
// re-fetch data that is already displayed.
|
|
344
|
+
if (!dependenciesChanged && (rowsAreUpToDate.current || pendingRequestCount.current > 0)) {
|
|
345
|
+
return ignoreInFlightRequest;
|
|
346
|
+
}
|
|
315
347
|
if (props.dataSource) {
|
|
316
348
|
stopPolling();
|
|
317
349
|
// `dataSourceKeepPreviousData` only applies to the flat `Default` strategy (mirroring
|
|
@@ -325,10 +357,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
|
|
|
325
357
|
apiRef.current.dataSource.cache.clear();
|
|
326
358
|
apiRef.current.dataSource.fetchRows();
|
|
327
359
|
}
|
|
328
|
-
return
|
|
329
|
-
// ignore the current request on unmount
|
|
330
|
-
lastRequestId.current += 1;
|
|
331
|
-
};
|
|
360
|
+
return ignoreInFlightRequest;
|
|
332
361
|
}, [apiRef, props.dataSource, props.dataSourceKeepPreviousData, currentStrategy, stopPolling]);
|
|
333
362
|
React.useEffect(() => {
|
|
334
363
|
// `dataSourceKeepPreviousData` is a no-op for tree data and row grouping: those
|
|
@@ -260,14 +260,17 @@ const useGridCellEditing = (apiRef, props) => {
|
|
|
260
260
|
deleteValue,
|
|
261
261
|
initialValue
|
|
262
262
|
} = params;
|
|
263
|
+
const column = apiRef.current.getColumn(field);
|
|
264
|
+
if (!column) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
263
267
|
const value = apiRef.current.getCellValue(id, field);
|
|
264
268
|
let newValue = value;
|
|
265
269
|
if (deleteValue) {
|
|
266
|
-
newValue = (0, _utils2.getDefaultCellValue)(
|
|
270
|
+
newValue = (0, _utils2.getDefaultCellValue)(column);
|
|
267
271
|
} else if (initialValue) {
|
|
268
272
|
newValue = initialValue;
|
|
269
273
|
}
|
|
270
|
-
const column = apiRef.current.getColumn(field);
|
|
271
274
|
const shouldProcessEditCellProps = !!column.preProcessEditCellProps && deleteValue;
|
|
272
275
|
let newProps = {
|
|
273
276
|
value: newValue,
|
|
@@ -410,6 +413,9 @@ const useGridCellEditing = (apiRef, props) => {
|
|
|
410
413
|
throwIfNotEditable(id, field);
|
|
411
414
|
throwIfNotInMode(id, field, _gridEditRowModel.GridCellModes.Edit);
|
|
412
415
|
const column = apiRef.current.getColumn(field);
|
|
416
|
+
if (!column) {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
413
419
|
const row = apiRef.current.getRow(id);
|
|
414
420
|
let parsedValue = value;
|
|
415
421
|
if (column.valueParser && !skipValueParser) {
|
|
@@ -461,7 +467,7 @@ const useGridCellEditing = (apiRef, props) => {
|
|
|
461
467
|
const {
|
|
462
468
|
value
|
|
463
469
|
} = editingState[id][field];
|
|
464
|
-
return column
|
|
470
|
+
return column?.valueSetter ? column.valueSetter(value, row, column, apiRef) : (0, _extends2.default)({}, row, {
|
|
465
471
|
[field]: value
|
|
466
472
|
});
|
|
467
473
|
}, [apiRef]);
|
|
@@ -253,14 +253,17 @@ export const useGridCellEditing = (apiRef, props) => {
|
|
|
253
253
|
deleteValue,
|
|
254
254
|
initialValue
|
|
255
255
|
} = params;
|
|
256
|
+
const column = apiRef.current.getColumn(field);
|
|
257
|
+
if (!column) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
256
260
|
const value = apiRef.current.getCellValue(id, field);
|
|
257
261
|
let newValue = value;
|
|
258
262
|
if (deleteValue) {
|
|
259
|
-
newValue = getDefaultCellValue(
|
|
263
|
+
newValue = getDefaultCellValue(column);
|
|
260
264
|
} else if (initialValue) {
|
|
261
265
|
newValue = initialValue;
|
|
262
266
|
}
|
|
263
|
-
const column = apiRef.current.getColumn(field);
|
|
264
267
|
const shouldProcessEditCellProps = !!column.preProcessEditCellProps && deleteValue;
|
|
265
268
|
let newProps = {
|
|
266
269
|
value: newValue,
|
|
@@ -403,6 +406,9 @@ export const useGridCellEditing = (apiRef, props) => {
|
|
|
403
406
|
throwIfNotEditable(id, field);
|
|
404
407
|
throwIfNotInMode(id, field, GridCellModes.Edit);
|
|
405
408
|
const column = apiRef.current.getColumn(field);
|
|
409
|
+
if (!column) {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
406
412
|
const row = apiRef.current.getRow(id);
|
|
407
413
|
let parsedValue = value;
|
|
408
414
|
if (column.valueParser && !skipValueParser) {
|
|
@@ -454,7 +460,7 @@ export const useGridCellEditing = (apiRef, props) => {
|
|
|
454
460
|
const {
|
|
455
461
|
value
|
|
456
462
|
} = editingState[id][field];
|
|
457
|
-
return column
|
|
463
|
+
return column?.valueSetter ? column.valueSetter(value, row, column, apiRef) : _extends({}, row, {
|
|
458
464
|
[field]: value
|
|
459
465
|
});
|
|
460
466
|
}, [apiRef]);
|
|
@@ -135,7 +135,7 @@ const useGridRowEditing = (apiRef, props) => {
|
|
|
135
135
|
} else if (event.key === 'Tab') {
|
|
136
136
|
const columnFields = (0, _gridColumnsSelector.gridVisibleColumnFieldsSelector)(apiRef).filter(field => {
|
|
137
137
|
const column = apiRef.current.getColumn(field);
|
|
138
|
-
if (column
|
|
138
|
+
if (column?.type === _colDef.GRID_ACTIONS_COLUMN_TYPE) {
|
|
139
139
|
return true;
|
|
140
140
|
}
|
|
141
141
|
return apiRef.current.isCellEditable(apiRef.current.getCellParams(params.id, field));
|
|
@@ -340,11 +340,10 @@ const useGridRowEditing = (apiRef, props) => {
|
|
|
340
340
|
if (!cellParams.isEditable) {
|
|
341
341
|
return acc;
|
|
342
342
|
}
|
|
343
|
-
const column = apiRef.current.getColumn(field);
|
|
344
343
|
let newValue = apiRef.current.getCellValue(id, field);
|
|
345
344
|
if (fieldToFocus === field && (deleteValue || initialValue)) {
|
|
346
345
|
if (deleteValue) {
|
|
347
|
-
newValue = (0, _utils2.getDefaultCellValue)(
|
|
346
|
+
newValue = (0, _utils2.getDefaultCellValue)(col);
|
|
348
347
|
} else if (initialValue) {
|
|
349
348
|
newValue = initialValue;
|
|
350
349
|
}
|
|
@@ -352,7 +351,7 @@ const useGridRowEditing = (apiRef, props) => {
|
|
|
352
351
|
acc[field] = {
|
|
353
352
|
value: newValue,
|
|
354
353
|
error: false,
|
|
355
|
-
isProcessingProps:
|
|
354
|
+
isProcessingProps: col.editable && !!col.preProcessEditCellProps && deleteValue
|
|
356
355
|
};
|
|
357
356
|
return acc;
|
|
358
357
|
}, {});
|
|
@@ -503,6 +502,9 @@ const useGridRowEditing = (apiRef, props) => {
|
|
|
503
502
|
} = params;
|
|
504
503
|
throwIfNotEditable(id, field);
|
|
505
504
|
const column = apiRef.current.getColumn(field);
|
|
505
|
+
if (!column) {
|
|
506
|
+
return Promise.resolve(false);
|
|
507
|
+
}
|
|
506
508
|
const row = apiRef.current.getRow(id);
|
|
507
509
|
let parsedValue = value;
|
|
508
510
|
if (column.valueParser && !skipValueParser) {
|
|
@@ -556,7 +558,7 @@ const useGridRowEditing = (apiRef, props) => {
|
|
|
556
558
|
return;
|
|
557
559
|
}
|
|
558
560
|
const fieldColumn = apiRef.current.getColumn(thisField);
|
|
559
|
-
if (!fieldColumn
|
|
561
|
+
if (!fieldColumn?.preProcessEditCellProps) {
|
|
560
562
|
return;
|
|
561
563
|
}
|
|
562
564
|
fieldProps = (0, _extends2.default)({}, fieldProps, {
|
|
@@ -128,7 +128,7 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
128
128
|
} else if (event.key === 'Tab') {
|
|
129
129
|
const columnFields = gridVisibleColumnFieldsSelector(apiRef).filter(field => {
|
|
130
130
|
const column = apiRef.current.getColumn(field);
|
|
131
|
-
if (column
|
|
131
|
+
if (column?.type === GRID_ACTIONS_COLUMN_TYPE) {
|
|
132
132
|
return true;
|
|
133
133
|
}
|
|
134
134
|
return apiRef.current.isCellEditable(apiRef.current.getCellParams(params.id, field));
|
|
@@ -333,11 +333,10 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
333
333
|
if (!cellParams.isEditable) {
|
|
334
334
|
return acc;
|
|
335
335
|
}
|
|
336
|
-
const column = apiRef.current.getColumn(field);
|
|
337
336
|
let newValue = apiRef.current.getCellValue(id, field);
|
|
338
337
|
if (fieldToFocus === field && (deleteValue || initialValue)) {
|
|
339
338
|
if (deleteValue) {
|
|
340
|
-
newValue = getDefaultCellValue(
|
|
339
|
+
newValue = getDefaultCellValue(col);
|
|
341
340
|
} else if (initialValue) {
|
|
342
341
|
newValue = initialValue;
|
|
343
342
|
}
|
|
@@ -345,7 +344,7 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
345
344
|
acc[field] = {
|
|
346
345
|
value: newValue,
|
|
347
346
|
error: false,
|
|
348
|
-
isProcessingProps:
|
|
347
|
+
isProcessingProps: col.editable && !!col.preProcessEditCellProps && deleteValue
|
|
349
348
|
};
|
|
350
349
|
return acc;
|
|
351
350
|
}, {});
|
|
@@ -496,6 +495,9 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
496
495
|
} = params;
|
|
497
496
|
throwIfNotEditable(id, field);
|
|
498
497
|
const column = apiRef.current.getColumn(field);
|
|
498
|
+
if (!column) {
|
|
499
|
+
return Promise.resolve(false);
|
|
500
|
+
}
|
|
499
501
|
const row = apiRef.current.getRow(id);
|
|
500
502
|
let parsedValue = value;
|
|
501
503
|
if (column.valueParser && !skipValueParser) {
|
|
@@ -549,7 +551,7 @@ export const useGridRowEditing = (apiRef, props) => {
|
|
|
549
551
|
return;
|
|
550
552
|
}
|
|
551
553
|
const fieldColumn = apiRef.current.getColumn(thisField);
|
|
552
|
-
if (!fieldColumn
|
|
554
|
+
if (!fieldColumn?.preProcessEditCellProps) {
|
|
553
555
|
return;
|
|
554
556
|
}
|
|
555
557
|
fieldProps = _extends({}, fieldProps, {
|
|
@@ -113,7 +113,7 @@ const useGridFilter = (apiRef, props, configuration) => {
|
|
|
113
113
|
return true;
|
|
114
114
|
}
|
|
115
115
|
const column = apiRef.current.getColumn(item.field);
|
|
116
|
-
const filterOperator = column
|
|
116
|
+
const filterOperator = column?.filterOperators?.find(operator => operator.value === item.operator);
|
|
117
117
|
const requiresFilterValue = typeof filterOperator?.requiresFilterValue === 'undefined' ? true : filterOperator?.requiresFilterValue;
|
|
118
118
|
|
|
119
119
|
// Operators like `isEmpty` don't have and don't require `item.value`.
|
|
@@ -104,7 +104,7 @@ export const useGridFilter = (apiRef, props, configuration) => {
|
|
|
104
104
|
return true;
|
|
105
105
|
}
|
|
106
106
|
const column = apiRef.current.getColumn(item.field);
|
|
107
|
-
const filterOperator = column
|
|
107
|
+
const filterOperator = column?.filterOperators?.find(operator => operator.value === item.operator);
|
|
108
108
|
const requiresFilterValue = typeof filterOperator?.requiresFilterValue === 'undefined' ? true : filterOperator?.requiresFilterValue;
|
|
109
109
|
|
|
110
110
|
// Operators like `isEmpty` don't have and don't require `item.value`.
|
|
@@ -261,7 +261,23 @@ const updateCacheWithNewRows = ({
|
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
// Update the data row lookups.
|
|
264
|
-
|
|
264
|
+
// Prototype-preservation rules:
|
|
265
|
+
// 1. If partialRow is a class instance (non-plain object), use its prototype — the
|
|
266
|
+
// caller is passing in a fully-constructed instance and owns the prototype chain.
|
|
267
|
+
// 2. If partialRow is a plain object (Object.prototype), prefer oldRow's prototype so
|
|
268
|
+
// that a partial-update object does not silently discard the existing row's class.
|
|
269
|
+
// 3. If both are plain objects the result is also a plain object (no-op).
|
|
270
|
+
//
|
|
271
|
+
// Note: private class fields (#field syntax) cannot be preserved through a spread-style
|
|
272
|
+
// merge because the brand check is tied to the original instance. Rows that rely on
|
|
273
|
+
// private fields must supply a fully-constructed instance as partialRow (rule 1 above)
|
|
274
|
+
// rather than a plain-object partial update.
|
|
275
|
+
const partialRowProto = Object.getPrototypeOf(partialRow);
|
|
276
|
+
const isPartialRowPlain = partialRowProto === Object.prototype || partialRowProto === null;
|
|
277
|
+
const proto = isPartialRowPlain ? Object.getPrototypeOf(oldRow) : partialRowProto;
|
|
278
|
+
const merged = Object.create(proto);
|
|
279
|
+
Object.assign(merged, oldRow, partialRow);
|
|
280
|
+
dataRowIdToModelLookup[id] = merged;
|
|
265
281
|
return;
|
|
266
282
|
}
|
|
267
283
|
|
|
@@ -242,7 +242,23 @@ export const updateCacheWithNewRows = ({
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
// Update the data row lookups.
|
|
245
|
-
|
|
245
|
+
// Prototype-preservation rules:
|
|
246
|
+
// 1. If partialRow is a class instance (non-plain object), use its prototype — the
|
|
247
|
+
// caller is passing in a fully-constructed instance and owns the prototype chain.
|
|
248
|
+
// 2. If partialRow is a plain object (Object.prototype), prefer oldRow's prototype so
|
|
249
|
+
// that a partial-update object does not silently discard the existing row's class.
|
|
250
|
+
// 3. If both are plain objects the result is also a plain object (no-op).
|
|
251
|
+
//
|
|
252
|
+
// Note: private class fields (#field syntax) cannot be preserved through a spread-style
|
|
253
|
+
// merge because the brand check is tied to the original instance. Rows that rely on
|
|
254
|
+
// private fields must supply a fully-constructed instance as partialRow (rule 1 above)
|
|
255
|
+
// rather than a plain-object partial update.
|
|
256
|
+
const partialRowProto = Object.getPrototypeOf(partialRow);
|
|
257
|
+
const isPartialRowPlain = partialRowProto === Object.prototype || partialRowProto === null;
|
|
258
|
+
const proto = isPartialRowPlain ? Object.getPrototypeOf(oldRow) : partialRowProto;
|
|
259
|
+
const merged = Object.create(proto);
|
|
260
|
+
Object.assign(merged, oldRow, partialRow);
|
|
261
|
+
dataRowIdToModelLookup[id] = merged;
|
|
246
262
|
return;
|
|
247
263
|
}
|
|
248
264
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RefObject } from '@mui/x-internals/types';
|
|
2
2
|
import type { GridPrivateApiCommunity } from "../../../models/api/gridApiCommunity.mjs";
|
|
3
|
-
import type { DataGridProcessedProps } from "../../../models/props/DataGridProps.mjs";
|
|
4
3
|
import type { GridConfiguration } from "../../../models/configuration/gridConfiguration.mjs";
|
|
4
|
+
import type { DataGridProcessedProps } from "../../../models/props/DataGridProps.mjs";
|
|
5
5
|
/**
|
|
6
6
|
* @requires useGridColumns (method)
|
|
7
7
|
* @requires useGridRows (method)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RefObject } from '@mui/x-internals/types';
|
|
2
2
|
import type { GridPrivateApiCommunity } from "../../../models/api/gridApiCommunity.js";
|
|
3
|
-
import type { DataGridProcessedProps } from "../../../models/props/DataGridProps.js";
|
|
4
3
|
import type { GridConfiguration } from "../../../models/configuration/gridConfiguration.js";
|
|
4
|
+
import type { DataGridProcessedProps } from "../../../models/props/DataGridProps.js";
|
|
5
5
|
/**
|
|
6
6
|
* @requires useGridColumns (method)
|
|
7
7
|
* @requires useGridRows (method)
|
|
@@ -76,6 +76,7 @@ function useGridParamsApi(apiRef, props, configuration) {
|
|
|
76
76
|
const cellTabIndex = (0, _gridFocusStateSelector.gridTabIndexCellSelector)(apiRef);
|
|
77
77
|
const cellMode = apiRef.current.getCellMode(id, field);
|
|
78
78
|
return apiRef.current.getCellParamsForRow(id, field, row, {
|
|
79
|
+
// Params keep a non-nullable `colDef`, but it can be `undefined` at runtime for an unknown field.
|
|
79
80
|
colDef: props.listView && props.listViewColumn?.field === field ? (0, _gridListViewSelectors.gridListColumnSelector)(apiRef) : apiRef.current.getColumn(field),
|
|
80
81
|
rowNode,
|
|
81
82
|
hasFocus: cellFocus !== null && cellFocus.field === field && cellFocus.id === id,
|
|
@@ -69,6 +69,7 @@ export function useGridParamsApi(apiRef, props, configuration) {
|
|
|
69
69
|
const cellTabIndex = gridTabIndexCellSelector(apiRef);
|
|
70
70
|
const cellMode = apiRef.current.getCellMode(id, field);
|
|
71
71
|
return apiRef.current.getCellParamsForRow(id, field, row, {
|
|
72
|
+
// Params keep a non-nullable `colDef`, but it can be `undefined` at runtime for an unknown field.
|
|
72
73
|
colDef: props.listView && props.listViewColumn?.field === field ? gridListColumnSelector(apiRef) : apiRef.current.getColumn(field),
|
|
73
74
|
rowNode,
|
|
74
75
|
hasFocus: cellFocus !== null && cellFocus.field === field && cellFocus.id === id,
|
|
@@ -120,6 +120,9 @@ const useGridSorting = (apiRef, props) => {
|
|
|
120
120
|
}, [apiRef, logger, props.disableMultipleColumnsSorting]);
|
|
121
121
|
const sortColumn = React.useCallback((field, direction, allowMultipleSorting) => {
|
|
122
122
|
const column = apiRef.current.getColumn(field);
|
|
123
|
+
if (!column) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
123
126
|
const sortItem = createSortItem(column, direction);
|
|
124
127
|
let sortModel;
|
|
125
128
|
if (!allowMultipleSorting || props.disableMultipleColumnsSorting) {
|
|
@@ -111,6 +111,9 @@ export const useGridSorting = (apiRef, props) => {
|
|
|
111
111
|
}, [apiRef, logger, props.disableMultipleColumnsSorting]);
|
|
112
112
|
const sortColumn = React.useCallback((field, direction, allowMultipleSorting) => {
|
|
113
113
|
const column = apiRef.current.getColumn(field);
|
|
114
|
+
if (!column) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
114
117
|
const sortItem = createSortItem(column, direction);
|
|
115
118
|
let sortModel;
|
|
116
119
|
if (!allowMultipleSorting || props.disableMultipleColumnsSorting) {
|
package/index.js
CHANGED
package/index.mjs
CHANGED