@mui/x-data-grid 9.11.0 → 9.13.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 +317 -0
- package/DataGrid/DataGrid.js +4 -2
- package/DataGrid/DataGrid.mjs +4 -2
- package/DataGrid/useDataGridProps.d.mts +1 -1
- package/DataGrid/useDataGridProps.d.ts +1 -1
- package/components/GridPagination.js +1 -1
- package/components/GridPagination.mjs +1 -1
- package/components/GridRow.d.mts +1 -0
- package/components/GridRow.d.ts +1 -0
- package/components/GridRow.js +41 -6
- package/components/GridRow.mjs +41 -6
- package/components/cell/GridCell.js +21 -5
- package/components/cell/GridCell.mjs +21 -5
- package/components/cell/GridEditBooleanCell.d.mts +1 -1
- package/components/cell/GridEditBooleanCell.d.ts +1 -1
- package/components/cell/GridEditBooleanCell.js +4 -4
- package/components/cell/GridEditBooleanCell.mjs +4 -4
- package/components/cell/GridEditDateCell.d.mts +1 -1
- package/components/cell/GridEditDateCell.d.ts +1 -1
- package/components/cell/GridEditDateCell.js +5 -5
- package/components/cell/GridEditDateCell.mjs +5 -5
- package/components/cell/GridEditInputCell.d.mts +1 -1
- package/components/cell/GridEditInputCell.d.ts +1 -1
- package/components/cell/GridEditInputCell.js +1 -1
- package/components/cell/GridEditInputCell.mjs +1 -1
- package/components/cell/GridEditLongTextCell.d.mts +1 -1
- package/components/cell/GridEditLongTextCell.d.ts +1 -1
- package/components/cell/GridEditLongTextCell.js +2 -2
- package/components/cell/GridEditLongTextCell.mjs +2 -2
- package/components/cell/GridEditSingleSelectCell.d.mts +1 -1
- package/components/cell/GridEditSingleSelectCell.d.ts +1 -1
- package/components/cell/GridEditSingleSelectCell.js +4 -4
- package/components/cell/GridEditSingleSelectCell.mjs +4 -4
- package/components/columnHeaders/GridBaseColumnHeaders.js +1 -1
- package/components/columnHeaders/GridBaseColumnHeaders.mjs +1 -1
- package/components/columnHeaders/GridColumnHeaderItem.js +4 -0
- package/components/columnHeaders/GridColumnHeaderItem.mjs +4 -0
- package/components/columnHeaders/GridGenericColumnHeaderItem.d.mts +7 -0
- package/components/columnHeaders/GridGenericColumnHeaderItem.d.ts +7 -0
- package/components/columnHeaders/GridGenericColumnHeaderItem.js +5 -4
- package/components/columnHeaders/GridGenericColumnHeaderItem.mjs +5 -4
- package/components/panel/filterPanel/GridFilterInputSingleSelect.js +18 -6
- package/components/panel/filterPanel/GridFilterInputSingleSelect.mjs +18 -6
- package/components/toolbarV8/Toolbar.d.mts +5 -1
- package/components/toolbarV8/Toolbar.d.ts +5 -1
- package/components/toolbarV8/Toolbar.js +34 -12
- package/components/toolbarV8/Toolbar.mjs +33 -11
- package/constants/gridClasses.d.mts +12 -0
- package/constants/gridClasses.d.ts +12 -0
- package/constants/gridClasses.js +1 -1
- package/constants/gridClasses.mjs +1 -1
- package/constants/localeTextConstants.js +4 -0
- package/constants/localeTextConstants.mjs +4 -0
- package/hooks/core/useGridApiInitialization.js +5 -1
- package/hooks/core/useGridApiInitialization.mjs +5 -1
- package/hooks/core/useGridStateInitialization.js +3 -1
- package/hooks/core/useGridStateInitialization.mjs +3 -1
- package/hooks/core/useGridVirtualizer.js +17 -1
- package/hooks/core/useGridVirtualizer.mjs +17 -1
- package/hooks/features/columnResize/useGridColumnResize.js +5 -0
- package/hooks/features/columnResize/useGridColumnResize.mjs +5 -0
- package/hooks/features/columns/gridColumnsUtils.d.mts +1 -1
- package/hooks/features/columns/gridColumnsUtils.d.ts +1 -1
- package/hooks/features/columns/gridColumnsUtils.js +2 -2
- package/hooks/features/columns/gridColumnsUtils.mjs +2 -2
- package/hooks/features/dataSource/gridDataSourceSelector.js +6 -2
- package/hooks/features/dataSource/gridDataSourceSelector.mjs +6 -2
- package/hooks/features/dataSource/models.d.mts +2 -2
- package/hooks/features/dataSource/models.d.ts +2 -2
- package/hooks/features/dataSource/useGridDataSourceBase.js +25 -8
- package/hooks/features/dataSource/useGridDataSourceBase.mjs +26 -9
- package/hooks/features/dataSource/useGridDataSourceFilterModelChange.d.mts +9 -0
- package/hooks/features/dataSource/useGridDataSourceFilterModelChange.d.ts +9 -0
- package/hooks/features/dataSource/useGridDataSourceFilterModelChange.js +57 -0
- package/hooks/features/dataSource/useGridDataSourceFilterModelChange.mjs +49 -0
- package/hooks/features/editing/useGridCellEditing.js +3 -1
- package/hooks/features/editing/useGridCellEditing.mjs +3 -1
- package/hooks/features/editing/useGridRowEditing.js +3 -1
- package/hooks/features/editing/useGridRowEditing.mjs +3 -1
- package/hooks/features/filter/gridFilterUtils.d.mts +13 -0
- package/hooks/features/filter/gridFilterUtils.d.ts +13 -0
- package/hooks/features/filter/gridFilterUtils.js +32 -1
- package/hooks/features/filter/gridFilterUtils.mjs +29 -1
- package/hooks/features/filter/useGridFilter.js +1 -21
- package/hooks/features/filter/useGridFilter.mjs +2 -22
- package/hooks/features/headerFiltering/gridHeaderFilteringSelectors.js +1 -1
- package/hooks/features/headerFiltering/gridHeaderFilteringSelectors.mjs +1 -1
- package/hooks/features/pivoting/gridPivotingInterfaces.d.mts +2 -2
- package/hooks/features/pivoting/gridPivotingInterfaces.d.ts +2 -2
- package/hooks/features/rowSelection/useGridRowSelection.js +1 -1
- package/hooks/features/rowSelection/useGridRowSelection.mjs +2 -2
- package/hooks/features/rows/gridRowsUtils.d.mts +37 -3
- package/hooks/features/rows/gridRowsUtils.d.ts +37 -3
- package/hooks/features/rows/gridRowsUtils.js +120 -23
- package/hooks/features/rows/gridRowsUtils.mjs +115 -22
- package/hooks/features/rows/useGridRowSpanning.js +5 -0
- package/hooks/features/rows/useGridRowSpanning.mjs +5 -0
- package/hooks/features/rows/useGridRows.js +10 -1
- package/hooks/features/rows/useGridRows.mjs +10 -1
- package/hooks/features/virtualization/gridVirtualizationSelectors.d.mts +1 -1
- package/hooks/features/virtualization/gridVirtualizationSelectors.d.ts +1 -1
- package/hooks/utils/useGridEvent.d.mts +2 -2
- package/hooks/utils/useGridEvent.d.ts +2 -2
- package/hooks/utils/useGridEvent.js +2 -0
- package/hooks/utils/useGridEvent.mjs +2 -0
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/internals/index.d.mts +4 -2
- package/internals/index.d.ts +4 -2
- package/internals/index.js +48 -0
- package/internals/index.mjs +4 -2
- package/locales/arSD.js +5 -0
- package/locales/arSD.mjs +5 -0
- package/locales/beBY.js +5 -0
- package/locales/beBY.mjs +5 -0
- package/locales/bgBG.js +5 -0
- package/locales/bgBG.mjs +5 -0
- package/locales/bnBD.js +5 -0
- package/locales/bnBD.mjs +5 -0
- package/locales/caES.js +5 -0
- package/locales/caES.mjs +5 -0
- package/locales/csCZ.js +5 -0
- package/locales/csCZ.mjs +5 -0
- package/locales/daDK.js +5 -0
- package/locales/daDK.mjs +5 -0
- package/locales/deDE.js +5 -0
- package/locales/deDE.mjs +5 -0
- package/locales/elGR.js +5 -0
- package/locales/elGR.mjs +5 -0
- package/locales/esES.js +5 -0
- package/locales/esES.mjs +5 -0
- package/locales/faIR.js +5 -0
- package/locales/faIR.mjs +5 -0
- package/locales/fiFI.js +5 -0
- package/locales/fiFI.mjs +5 -0
- package/locales/frFR.js +5 -0
- package/locales/frFR.mjs +5 -0
- package/locales/heIL.js +5 -0
- package/locales/heIL.mjs +5 -0
- package/locales/hrHR.js +5 -0
- package/locales/hrHR.mjs +5 -0
- package/locales/huHU.js +5 -0
- package/locales/huHU.mjs +5 -0
- package/locales/hyAM.js +5 -0
- package/locales/hyAM.mjs +5 -0
- package/locales/idID.js +5 -0
- package/locales/idID.mjs +5 -0
- package/locales/isIS.js +5 -0
- package/locales/isIS.mjs +5 -0
- package/locales/itIT.js +5 -0
- package/locales/itIT.mjs +5 -0
- package/locales/jaJP.js +5 -0
- package/locales/jaJP.mjs +5 -0
- package/locales/koKR.js +5 -0
- package/locales/koKR.mjs +5 -0
- package/locales/nbNO.js +5 -0
- package/locales/nbNO.mjs +5 -0
- package/locales/nlNL.js +5 -0
- package/locales/nlNL.mjs +5 -0
- package/locales/nnNO.js +5 -0
- package/locales/nnNO.mjs +5 -0
- package/locales/plPL.js +5 -0
- package/locales/plPL.mjs +5 -0
- package/locales/ptBR.js +5 -0
- package/locales/ptBR.mjs +5 -0
- package/locales/ptPT.js +5 -0
- package/locales/ptPT.mjs +5 -0
- package/locales/roRO.js +5 -0
- package/locales/roRO.mjs +5 -0
- package/locales/ruRU.js +5 -0
- package/locales/ruRU.mjs +5 -0
- package/locales/skSK.js +5 -0
- package/locales/skSK.mjs +5 -0
- package/locales/svSE.js +5 -0
- package/locales/svSE.mjs +5 -0
- package/locales/thTH.js +5 -0
- package/locales/thTH.mjs +5 -0
- package/locales/trTR.js +5 -0
- package/locales/trTR.mjs +5 -0
- package/locales/ukUA.js +5 -0
- package/locales/ukUA.mjs +5 -0
- package/locales/urPK.js +5 -0
- package/locales/urPK.mjs +5 -0
- package/locales/viVN.js +5 -0
- package/locales/viVN.mjs +5 -0
- package/locales/zhCN.js +5 -0
- package/locales/zhCN.mjs +5 -0
- package/locales/zhHK.js +5 -0
- package/locales/zhHK.mjs +5 -0
- package/locales/zhTW.js +5 -0
- package/locales/zhTW.mjs +5 -0
- package/material/variables.d.mts +6 -1
- package/material/variables.d.ts +6 -1
- package/material/variables.js +17 -3
- package/material/variables.mjs +14 -4
- package/models/api/gridApiCommon.d.mts +2 -2
- package/models/api/gridApiCommon.d.ts +2 -2
- package/models/api/gridCallbackDetails.d.mts +11 -1
- package/models/api/gridCallbackDetails.d.ts +11 -1
- package/models/api/gridLocaleTextApi.d.mts +3 -0
- package/models/api/gridLocaleTextApi.d.ts +3 -0
- package/models/api/gridRowApi.d.mts +19 -7
- package/models/api/gridRowApi.d.ts +19 -7
- package/models/api/gridStateApi.d.mts +3 -2
- package/models/api/gridStateApi.d.ts +3 -2
- package/models/api/index.d.mts +1 -1
- package/models/api/index.d.ts +1 -1
- package/models/colDef/gridColDef.d.mts +5 -0
- package/models/colDef/gridColDef.d.ts +5 -0
- package/models/configuration/gridConfiguration.d.mts +13 -1
- package/models/configuration/gridConfiguration.d.ts +13 -1
- package/models/controlStateItem.d.mts +3 -2
- package/models/controlStateItem.d.ts +3 -2
- package/models/events/gridEventListener.d.mts +3 -2
- package/models/events/gridEventListener.d.ts +3 -2
- package/models/gridDataSource.d.mts +3 -0
- package/models/gridDataSource.d.ts +3 -0
- package/models/gridRows.d.mts +28 -1
- package/models/gridRows.d.ts +28 -1
- package/models/props/DataGridProps.d.mts +41 -38
- package/models/props/DataGridProps.d.ts +41 -38
- package/package.json +6 -6
- package/utils/domUtils.js +1 -1
- package/utils/domUtils.mjs +1 -1
- package/utils/getPublicApiRef.d.mts +2 -2
- package/utils/getPublicApiRef.d.ts +2 -2
- package/utils/getPublicApiRef.js +15 -3
- package/utils/getPublicApiRef.mjs +15 -3
- package/utils/keyboardUtils.d.mts +1 -0
- package/utils/keyboardUtils.d.ts +1 -0
- package/utils/keyboardUtils.js +6 -0
- package/utils/keyboardUtils.mjs +5 -0
|
@@ -15,7 +15,7 @@ import { useFirstRender } from "../../utils/useFirstRender.mjs";
|
|
|
15
15
|
import { gridRowsLookupSelector } from "../rows/index.mjs";
|
|
16
16
|
import { useGridRegisterPipeProcessor } from "../../core/pipeProcessing/index.mjs";
|
|
17
17
|
import { GRID_DEFAULT_STRATEGY, useGridRegisterStrategyProcessor } from "../../core/strategyProcessing/index.mjs";
|
|
18
|
-
import { buildAggregatedFilterApplier, sanitizeFilterModel, mergeStateWithFilterModel, cleanFilterItem, passFilterLogic, shouldQuickFilterExcludeHiddenColumns, upsertFilterItemInModel, upsertFilterItemsInModel, deleteFilterItemFromModel, setFilterLogicOperatorInModel } from "./gridFilterUtils.mjs";
|
|
18
|
+
import { buildAggregatedFilterApplier, sanitizeFilterModel, mergeStateWithFilterModel, cleanFilterItem, passFilterLogic, shouldQuickFilterExcludeHiddenColumns, upsertFilterItemInModel, upsertFilterItemsInModel, deleteFilterItemFromModel, setFilterLogicOperatorInModel, isFilterItemComplete } from "./gridFilterUtils.mjs";
|
|
19
19
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
20
20
|
export const filterStateInitializer = (state, props, apiRef) => {
|
|
21
21
|
const filterModel = props.filterModel ?? props.initialState?.filter?.filterModel ?? getDefaultGridFilterModel();
|
|
@@ -94,27 +94,7 @@ export const useGridFilter = (apiRef, props, configuration) => {
|
|
|
94
94
|
logger.debug('Displaying filter panel');
|
|
95
95
|
if (targetColumnField) {
|
|
96
96
|
const filterModel = gridFilterModelSelector(apiRef);
|
|
97
|
-
const filterItemsWithValue = filterModel.items.filter(item =>
|
|
98
|
-
if (item.value !== undefined) {
|
|
99
|
-
// Some filters like `isAnyOf` support array as `item.value`.
|
|
100
|
-
// If array is empty, we want to remove it from the filter model.
|
|
101
|
-
if (Array.isArray(item.value) && item.value.length === 0) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
106
|
-
const column = apiRef.current.getColumn(item.field);
|
|
107
|
-
const filterOperator = column?.filterOperators?.find(operator => operator.value === item.operator);
|
|
108
|
-
const requiresFilterValue = typeof filterOperator?.requiresFilterValue === 'undefined' ? true : filterOperator?.requiresFilterValue;
|
|
109
|
-
|
|
110
|
-
// Operators like `isEmpty` don't have and don't require `item.value`.
|
|
111
|
-
// So we don't want to remove them from the filter model if `item.value === undefined`.
|
|
112
|
-
// See https://github.com/mui/mui-x/issues/5402
|
|
113
|
-
if (requiresFilterValue) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
return true;
|
|
117
|
-
});
|
|
97
|
+
const filterItemsWithValue = filterModel.items.filter(item => isFilterItemComplete(item, apiRef.current.getColumn(item.field)));
|
|
118
98
|
let newFilterItems;
|
|
119
99
|
const filterItemOnTarget = filterItemsWithValue.find(item => item.field === targetColumnField);
|
|
120
100
|
const targetColumn = apiRef.current.getColumn(targetColumnField);
|
|
@@ -7,7 +7,7 @@ exports.gridHeaderFilteringStateSelector = exports.gridHeaderFilteringMenuSelect
|
|
|
7
7
|
var _createSelector = require("../../../utils/createSelector");
|
|
8
8
|
const gridHeaderFilteringStateSelector = exports.gridHeaderFilteringStateSelector = (0, _createSelector.createRootSelector)(state => state.headerFiltering);
|
|
9
9
|
const gridHeaderFilteringEnabledSelector = exports.gridHeaderFilteringEnabledSelector = (0, _createSelector.createSelector)(gridHeaderFilteringStateSelector,
|
|
10
|
-
//
|
|
10
|
+
// The state is only initialized in Pro, so it is `undefined` on the MIT grid.
|
|
11
11
|
headerFilteringState => headerFilteringState?.enabled ?? false);
|
|
12
12
|
const gridHeaderFilteringEditFieldSelector = exports.gridHeaderFilteringEditFieldSelector = (0, _createSelector.createSelector)(gridHeaderFilteringStateSelector, headerFilteringState => headerFilteringState.editing);
|
|
13
13
|
const gridHeaderFilteringMenuSelector = exports.gridHeaderFilteringMenuSelector = (0, _createSelector.createSelector)(gridHeaderFilteringStateSelector, headerFilteringState => headerFilteringState.menuOpen);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSelector, createRootSelector } from "../../../utils/createSelector.mjs";
|
|
2
2
|
export const gridHeaderFilteringStateSelector = createRootSelector(state => state.headerFiltering);
|
|
3
3
|
export const gridHeaderFilteringEnabledSelector = createSelector(gridHeaderFilteringStateSelector,
|
|
4
|
-
//
|
|
4
|
+
// The state is only initialized in Pro, so it is `undefined` on the MIT grid.
|
|
5
5
|
headerFilteringState => headerFilteringState?.enabled ?? false);
|
|
6
6
|
export const gridHeaderFilteringEditFieldSelector = createSelector(gridHeaderFilteringStateSelector, headerFilteringState => headerFilteringState.editing);
|
|
7
7
|
export const gridHeaderFilteringMenuSelector = createSelector(gridHeaderFilteringStateSelector, headerFilteringState => headerFilteringState.menuOpen);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { GridRowModelUpdate } from '@mui/x-data-grid';
|
|
1
|
+
import type { GridRowModelUpdate, GridRowModelReplace } from '@mui/x-data-grid';
|
|
2
2
|
import type { GridColDef } from "../../../models/colDef/index.mjs";
|
|
3
3
|
export interface GridPivotingStatePartial {
|
|
4
4
|
active: boolean;
|
|
5
5
|
initialColumns: Map<string, GridColDef> | undefined;
|
|
6
6
|
}
|
|
7
7
|
export interface GridPivotingPrivateApiCommunity {
|
|
8
|
-
updateNonPivotRows: (rows:
|
|
8
|
+
updateNonPivotRows: (rows: ReadonlyArray<GridRowModelUpdate | GridRowModelReplace>, keepPreviousRows?: boolean) => void;
|
|
9
9
|
updateNonPivotColumns: (columns: readonly GridColDef[], keepPreviousColumns?: boolean) => void;
|
|
10
10
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { GridRowModelUpdate } from '@mui/x-data-grid';
|
|
1
|
+
import type { GridRowModelUpdate, GridRowModelReplace } from '@mui/x-data-grid';
|
|
2
2
|
import type { GridColDef } from "../../../models/colDef/index.js";
|
|
3
3
|
export interface GridPivotingStatePartial {
|
|
4
4
|
active: boolean;
|
|
5
5
|
initialColumns: Map<string, GridColDef> | undefined;
|
|
6
6
|
}
|
|
7
7
|
export interface GridPivotingPrivateApiCommunity {
|
|
8
|
-
updateNonPivotRows: (rows:
|
|
8
|
+
updateNonPivotRows: (rows: ReadonlyArray<GridRowModelUpdate | GridRowModelReplace>, keepPreviousRows?: boolean) => void;
|
|
9
9
|
updateNonPivotColumns: (columns: readonly GridColDef[], keepPreviousColumns?: boolean) => void;
|
|
10
10
|
}
|
|
@@ -542,7 +542,7 @@ You need to upgrade to DataGridPro or DataGridPremium component to unlock multip
|
|
|
542
542
|
handleSingleRowSelection(params.id, event);
|
|
543
543
|
return;
|
|
544
544
|
}
|
|
545
|
-
if (
|
|
545
|
+
if ((0, _keyboardUtils.isSelectAllShortcut)(event)) {
|
|
546
546
|
event.preventDefault();
|
|
547
547
|
if (canHaveMultipleSelection) {
|
|
548
548
|
toggleAllRows(true);
|
|
@@ -15,7 +15,7 @@ import { gridFocusCellSelector } from "../focus/gridFocusStateSelector.mjs";
|
|
|
15
15
|
import { gridExpandedSortedRowIdsSelector, gridFilteredRowsLookupSelector, gridFilterModelSelector, gridQuickFilterValuesSelector } from "../filter/gridFilterSelector.mjs";
|
|
16
16
|
import { GRID_CHECKBOX_SELECTION_COL_DEF, GRID_ACTIONS_COLUMN_TYPE } from "../../../colDef/index.mjs";
|
|
17
17
|
import { GridCellModes } from "../../../models/gridEditRowModel.mjs";
|
|
18
|
-
import { isKeyboardEvent, isNavigationKey } from "../../../utils/keyboardUtils.mjs";
|
|
18
|
+
import { isKeyboardEvent, isNavigationKey, isSelectAllShortcut } from "../../../utils/keyboardUtils.mjs";
|
|
19
19
|
import { getVisibleRows } from "../../utils/useGridVisibleRows.mjs";
|
|
20
20
|
import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from "../../../internals/constants.mjs";
|
|
21
21
|
import { gridClasses } from "../../../constants/gridClasses.mjs";
|
|
@@ -534,7 +534,7 @@ You need to upgrade to DataGridPro or DataGridPremium component to unlock multip
|
|
|
534
534
|
handleSingleRowSelection(params.id, event);
|
|
535
535
|
return;
|
|
536
536
|
}
|
|
537
|
-
if (
|
|
537
|
+
if (isSelectAllShortcut(event)) {
|
|
538
538
|
event.preventDefault();
|
|
539
539
|
if (canHaveMultipleSelection) {
|
|
540
540
|
toggleAllRows(true);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RefObject } from '@mui/x-internals/types';
|
|
2
|
-
import type { GridAutoGeneratedGroupNode, GridAutoGeneratedPinnedRowNode, GridColDef, GridFooterNode, GridGroupNode, GridRowId, GridRowIdGetter, GridRowModel, GridRowModelUpdate, GridRowTreeConfig, GridSkeletonRowNode, GridTreeNode, GridValidRowModel } from "../../../models/index.mjs";
|
|
2
|
+
import type { GridAutoGeneratedGroupNode, GridAutoGeneratedPinnedRowNode, GridColDef, GridFooterNode, GridGroupNode, GridRowId, GridRowIdGetter, GridRowModel, GridRowModelUpdate, GridRowModelReplace, GridRowTreeConfig, GridSkeletonRowNode, GridTreeNode, GridValidRowModel } from "../../../models/index.mjs";
|
|
3
3
|
import type { DataGridProcessedProps } from "../../../models/props/DataGridProps.mjs";
|
|
4
4
|
import type { GridApiCommunity, GridPrivateApiCommunity } from "../../../models/api/gridApiCommunity.mjs";
|
|
5
5
|
import type { GridRowsInternalCache, GridRowsState, GridRowTreeCreationParams } from "./gridRowsInterfaces.mjs";
|
|
@@ -43,6 +43,40 @@ export declare const getRowsStateFromCache: ({
|
|
|
43
43
|
export declare const isAutogeneratedRow: (row: GridRowModel) => boolean;
|
|
44
44
|
export declare const isAutogeneratedRowNode: (rowNode: GridTreeNode) => rowNode is GridFooterNode | GridSkeletonRowNode | GridAutoGeneratedGroupNode | GridAutoGeneratedPinnedRowNode;
|
|
45
45
|
export declare const getTreeNodeDescendants: (tree: GridRowTreeConfig, parentId: GridRowId, skipAutoGeneratedRows: boolean, directChildrenOnly?: boolean) => GridRowId[];
|
|
46
|
+
export declare const isReplaceUpdate: (update: GridRowModelUpdate | GridRowModelReplace) => update is GridRowModelReplace;
|
|
47
|
+
/**
|
|
48
|
+
* Extracts the replacement row from a `{ _action: 'replace', row }` update.
|
|
49
|
+
* The marker lives on the throwaway envelope, so the row object itself is never touched.
|
|
50
|
+
* @param {GridRowModelReplace} update The update provided to `updateRows()`.
|
|
51
|
+
* @returns {GridRowModel} The object to store as the row, verbatim.
|
|
52
|
+
*/
|
|
53
|
+
export declare const getReplaceRow: (update: GridRowModelReplace) => GridRowModel;
|
|
54
|
+
/**
|
|
55
|
+
* Merges a partial update into the existing row.
|
|
56
|
+
* Prototype-preservation rules:
|
|
57
|
+
* 1. If partialRow is a class instance (non-plain object), use its prototype — the
|
|
58
|
+
* caller is passing in a fully-constructed instance and owns the prototype chain.
|
|
59
|
+
* 2. If partialRow is a plain object (Object.prototype), prefer oldRow's prototype so
|
|
60
|
+
* that a partial-update object does not silently discard the existing row's class.
|
|
61
|
+
* 3. If both are plain objects the result is also a plain object (no-op).
|
|
62
|
+
*
|
|
63
|
+
* Note: private class fields (#field syntax) cannot be preserved through a spread-style
|
|
64
|
+
* merge because the brand check is tied to the original instance. Rows that rely on
|
|
65
|
+
* private fields must either supply a fully-constructed instance as partialRow (rule 1
|
|
66
|
+
* above) or use `_action: 'replace'` rather than a plain-object partial update.
|
|
67
|
+
* @param {GridRowModel} oldRow The row currently stored in the lookup.
|
|
68
|
+
* @param {GridRowModelUpdate} partialRow The update to merge into it.
|
|
69
|
+
* @returns {GridRowModel} The merged row.
|
|
70
|
+
*/
|
|
71
|
+
export declare const mergeRowUpdate: (oldRow: GridRowModel, partialRow: GridRowModelUpdate) => GridRowModel;
|
|
72
|
+
/**
|
|
73
|
+
* Warns when a replace demotes a class instance to a plain object, which happens when the
|
|
74
|
+
* replacement was built with a spread instead of being passed as-is.
|
|
75
|
+
* Dev-only, does nothing in production.
|
|
76
|
+
* @param {GridRowModel | undefined} oldRow The row being replaced, if any.
|
|
77
|
+
* @param {GridRowModel} replacement The row provided in a `{ _action: 'replace', row }` update.
|
|
78
|
+
*/
|
|
79
|
+
export declare const warnIfReplaceLosesPrototype: (oldRow: GridRowModel | undefined, replacement: GridRowModel) => void;
|
|
46
80
|
export declare const updateCacheWithNewRows: ({
|
|
47
81
|
previousCache,
|
|
48
82
|
getRowId,
|
|
@@ -51,10 +85,10 @@ export declare const updateCacheWithNewRows: ({
|
|
|
51
85
|
}: {
|
|
52
86
|
previousCache: GridRowsInternalCache;
|
|
53
87
|
getRowId: DataGridProcessedProps['getRowId'];
|
|
54
|
-
updates: GridRowModelUpdate
|
|
88
|
+
updates: Array<GridRowModelUpdate | GridRowModelReplace>;
|
|
55
89
|
groupKeys?: string[];
|
|
56
90
|
}) => GridRowsInternalCache;
|
|
57
91
|
export declare const minimalContentHeight = "var(--DataGrid-overlayHeight, calc(var(--height) * 2))";
|
|
58
|
-
export declare function computeRowsUpdates(apiRef: RefObject<GridApiCommunity>, updates: GridRowModelUpdate
|
|
92
|
+
export declare function computeRowsUpdates(apiRef: RefObject<GridApiCommunity>, updates: Array<GridRowModelUpdate | GridRowModelReplace>, getRowId: DataGridProcessedProps['getRowId']): (GridRowModelReplace<GridValidRowModel> | GridRowModelUpdate)[];
|
|
59
93
|
export declare const getValidRowHeight: (rowHeightProp: any, defaultRowHeight: number, warningMessage: string) => number;
|
|
60
94
|
export declare const rowHeightWarning: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RefObject } from '@mui/x-internals/types';
|
|
2
|
-
import type { GridAutoGeneratedGroupNode, GridAutoGeneratedPinnedRowNode, GridColDef, GridFooterNode, GridGroupNode, GridRowId, GridRowIdGetter, GridRowModel, GridRowModelUpdate, GridRowTreeConfig, GridSkeletonRowNode, GridTreeNode, GridValidRowModel } from "../../../models/index.js";
|
|
2
|
+
import type { GridAutoGeneratedGroupNode, GridAutoGeneratedPinnedRowNode, GridColDef, GridFooterNode, GridGroupNode, GridRowId, GridRowIdGetter, GridRowModel, GridRowModelUpdate, GridRowModelReplace, GridRowTreeConfig, GridSkeletonRowNode, GridTreeNode, GridValidRowModel } from "../../../models/index.js";
|
|
3
3
|
import type { DataGridProcessedProps } from "../../../models/props/DataGridProps.js";
|
|
4
4
|
import type { GridApiCommunity, GridPrivateApiCommunity } from "../../../models/api/gridApiCommunity.js";
|
|
5
5
|
import type { GridRowsInternalCache, GridRowsState, GridRowTreeCreationParams } from "./gridRowsInterfaces.js";
|
|
@@ -43,6 +43,40 @@ export declare const getRowsStateFromCache: ({
|
|
|
43
43
|
export declare const isAutogeneratedRow: (row: GridRowModel) => boolean;
|
|
44
44
|
export declare const isAutogeneratedRowNode: (rowNode: GridTreeNode) => rowNode is GridFooterNode | GridSkeletonRowNode | GridAutoGeneratedGroupNode | GridAutoGeneratedPinnedRowNode;
|
|
45
45
|
export declare const getTreeNodeDescendants: (tree: GridRowTreeConfig, parentId: GridRowId, skipAutoGeneratedRows: boolean, directChildrenOnly?: boolean) => GridRowId[];
|
|
46
|
+
export declare const isReplaceUpdate: (update: GridRowModelUpdate | GridRowModelReplace) => update is GridRowModelReplace;
|
|
47
|
+
/**
|
|
48
|
+
* Extracts the replacement row from a `{ _action: 'replace', row }` update.
|
|
49
|
+
* The marker lives on the throwaway envelope, so the row object itself is never touched.
|
|
50
|
+
* @param {GridRowModelReplace} update The update provided to `updateRows()`.
|
|
51
|
+
* @returns {GridRowModel} The object to store as the row, verbatim.
|
|
52
|
+
*/
|
|
53
|
+
export declare const getReplaceRow: (update: GridRowModelReplace) => GridRowModel;
|
|
54
|
+
/**
|
|
55
|
+
* Merges a partial update into the existing row.
|
|
56
|
+
* Prototype-preservation rules:
|
|
57
|
+
* 1. If partialRow is a class instance (non-plain object), use its prototype — the
|
|
58
|
+
* caller is passing in a fully-constructed instance and owns the prototype chain.
|
|
59
|
+
* 2. If partialRow is a plain object (Object.prototype), prefer oldRow's prototype so
|
|
60
|
+
* that a partial-update object does not silently discard the existing row's class.
|
|
61
|
+
* 3. If both are plain objects the result is also a plain object (no-op).
|
|
62
|
+
*
|
|
63
|
+
* Note: private class fields (#field syntax) cannot be preserved through a spread-style
|
|
64
|
+
* merge because the brand check is tied to the original instance. Rows that rely on
|
|
65
|
+
* private fields must either supply a fully-constructed instance as partialRow (rule 1
|
|
66
|
+
* above) or use `_action: 'replace'` rather than a plain-object partial update.
|
|
67
|
+
* @param {GridRowModel} oldRow The row currently stored in the lookup.
|
|
68
|
+
* @param {GridRowModelUpdate} partialRow The update to merge into it.
|
|
69
|
+
* @returns {GridRowModel} The merged row.
|
|
70
|
+
*/
|
|
71
|
+
export declare const mergeRowUpdate: (oldRow: GridRowModel, partialRow: GridRowModelUpdate) => GridRowModel;
|
|
72
|
+
/**
|
|
73
|
+
* Warns when a replace demotes a class instance to a plain object, which happens when the
|
|
74
|
+
* replacement was built with a spread instead of being passed as-is.
|
|
75
|
+
* Dev-only, does nothing in production.
|
|
76
|
+
* @param {GridRowModel | undefined} oldRow The row being replaced, if any.
|
|
77
|
+
* @param {GridRowModel} replacement The row provided in a `{ _action: 'replace', row }` update.
|
|
78
|
+
*/
|
|
79
|
+
export declare const warnIfReplaceLosesPrototype: (oldRow: GridRowModel | undefined, replacement: GridRowModel) => void;
|
|
46
80
|
export declare const updateCacheWithNewRows: ({
|
|
47
81
|
previousCache,
|
|
48
82
|
getRowId,
|
|
@@ -51,10 +85,10 @@ export declare const updateCacheWithNewRows: ({
|
|
|
51
85
|
}: {
|
|
52
86
|
previousCache: GridRowsInternalCache;
|
|
53
87
|
getRowId: DataGridProcessedProps['getRowId'];
|
|
54
|
-
updates: GridRowModelUpdate
|
|
88
|
+
updates: Array<GridRowModelUpdate | GridRowModelReplace>;
|
|
55
89
|
groupKeys?: string[];
|
|
56
90
|
}) => GridRowsInternalCache;
|
|
57
91
|
export declare const minimalContentHeight = "var(--DataGrid-overlayHeight, calc(var(--height) * 2))";
|
|
58
|
-
export declare function computeRowsUpdates(apiRef: RefObject<GridApiCommunity>, updates: GridRowModelUpdate
|
|
92
|
+
export declare function computeRowsUpdates(apiRef: RefObject<GridApiCommunity>, updates: Array<GridRowModelUpdate | GridRowModelReplace>, getRowId: DataGridProcessedProps['getRowId']): (GridRowModelReplace<GridValidRowModel> | GridRowModelUpdate)[];
|
|
59
93
|
export declare const getValidRowHeight: (rowHeightProp: any, defaultRowHeight: number, warningMessage: string) => number;
|
|
60
94
|
export declare const rowHeightWarning: string;
|
|
@@ -7,9 +7,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.buildRootGroup = exports.GRID_ROOT_GROUP_ID = exports.GRID_ID_AUTOGENERATED = void 0;
|
|
8
8
|
exports.checkGridRowIdIsValid = checkGridRowIdIsValid;
|
|
9
9
|
exports.computeRowsUpdates = computeRowsUpdates;
|
|
10
|
-
exports.updateCacheWithNewRows = exports.rowHeightWarning = exports.minimalContentHeight = exports.isAutogeneratedRowNode = exports.isAutogeneratedRow = exports.getValidRowHeight = exports.getTreeNodeDescendants = exports.getTopLevelRowCount = exports.getRowsStateFromCache = exports.getRowValue = exports.getRowIdFromRowModel = exports.createRowsInternalCache = void 0;
|
|
10
|
+
exports.warnIfReplaceLosesPrototype = exports.updateCacheWithNewRows = exports.rowHeightWarning = exports.minimalContentHeight = exports.mergeRowUpdate = exports.isReplaceUpdate = exports.isAutogeneratedRowNode = exports.isAutogeneratedRow = exports.getValidRowHeight = exports.getTreeNodeDescendants = exports.getTopLevelRowCount = exports.getRowsStateFromCache = exports.getRowValue = exports.getRowIdFromRowModel = exports.getReplaceRow = exports.createRowsInternalCache = void 0;
|
|
11
11
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
12
12
|
var _formatErrorMessage2 = _interopRequireDefault(require("@mui/x-internals/formatErrorMessage"));
|
|
13
|
+
var _warning = require("@mui/x-internals/warning");
|
|
13
14
|
var _gridRowsSelector = require("./gridRowsSelector");
|
|
14
15
|
const GRID_ROOT_GROUP_ID = exports.GRID_ROOT_GROUP_ID = `auto-generated-group-node-root`;
|
|
15
16
|
const GRID_ID_AUTOGENERATED = exports.GRID_ID_AUTOGENERATED = Symbol('mui.id_autogenerated');
|
|
@@ -178,6 +179,83 @@ const getTreeNodeDescendants = (tree, parentId, skipAutoGeneratedRows, directChi
|
|
|
178
179
|
return validDescendants;
|
|
179
180
|
};
|
|
180
181
|
exports.getTreeNodeDescendants = getTreeNodeDescendants;
|
|
182
|
+
const isReplaceUpdate = update =>
|
|
183
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
184
|
+
update._action === 'replace';
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Extracts the replacement row from a `{ _action: 'replace', row }` update.
|
|
188
|
+
* The marker lives on the throwaway envelope, so the row object itself is never touched.
|
|
189
|
+
* @param {GridRowModelReplace} update The update provided to `updateRows()`.
|
|
190
|
+
* @returns {GridRowModel} The object to store as the row, verbatim.
|
|
191
|
+
*/
|
|
192
|
+
exports.isReplaceUpdate = isReplaceUpdate;
|
|
193
|
+
const getReplaceRow = update => {
|
|
194
|
+
const {
|
|
195
|
+
row
|
|
196
|
+
} = update;
|
|
197
|
+
if (row == null) {
|
|
198
|
+
throw new Error(process.env.NODE_ENV !== "production" ? `MUI X Data Grid: A row update with \`_action: 'replace'\` was provided without a \`row\` property.
|
|
199
|
+
Without it, the Data Grid does not know which object to store for that row.
|
|
200
|
+
Provide the replacement object in the \`row\` property, for example \`updateRows([{ _action: 'replace', row }])\`.
|
|
201
|
+
For more detail, see https://mui.com/x/react-data-grid/row-updates/.` : (0, _formatErrorMessage2.default)(304));
|
|
202
|
+
}
|
|
203
|
+
return row;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Merges a partial update into the existing row.
|
|
208
|
+
* Prototype-preservation rules:
|
|
209
|
+
* 1. If partialRow is a class instance (non-plain object), use its prototype — the
|
|
210
|
+
* caller is passing in a fully-constructed instance and owns the prototype chain.
|
|
211
|
+
* 2. If partialRow is a plain object (Object.prototype), prefer oldRow's prototype so
|
|
212
|
+
* that a partial-update object does not silently discard the existing row's class.
|
|
213
|
+
* 3. If both are plain objects the result is also a plain object (no-op).
|
|
214
|
+
*
|
|
215
|
+
* Note: private class fields (#field syntax) cannot be preserved through a spread-style
|
|
216
|
+
* merge because the brand check is tied to the original instance. Rows that rely on
|
|
217
|
+
* private fields must either supply a fully-constructed instance as partialRow (rule 1
|
|
218
|
+
* above) or use `_action: 'replace'` rather than a plain-object partial update.
|
|
219
|
+
* @param {GridRowModel} oldRow The row currently stored in the lookup.
|
|
220
|
+
* @param {GridRowModelUpdate} partialRow The update to merge into it.
|
|
221
|
+
* @returns {GridRowModel} The merged row.
|
|
222
|
+
*/
|
|
223
|
+
exports.getReplaceRow = getReplaceRow;
|
|
224
|
+
const mergeRowUpdate = (oldRow, partialRow) => {
|
|
225
|
+
const partialRowProto = Object.getPrototypeOf(partialRow);
|
|
226
|
+
const isPartialRowPlain = partialRowProto === Object.prototype || partialRowProto === null;
|
|
227
|
+
const proto = isPartialRowPlain ? Object.getPrototypeOf(oldRow) : partialRowProto;
|
|
228
|
+
const merged = Object.create(proto);
|
|
229
|
+
Object.assign(merged, oldRow, partialRow);
|
|
230
|
+
return merged;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Warns when a replace demotes a class instance to a plain object, which happens when the
|
|
235
|
+
* replacement was built with a spread instead of being passed as-is.
|
|
236
|
+
* Dev-only, does nothing in production.
|
|
237
|
+
* @param {GridRowModel | undefined} oldRow The row being replaced, if any.
|
|
238
|
+
* @param {GridRowModel} replacement The row provided in a `{ _action: 'replace', row }` update.
|
|
239
|
+
*/
|
|
240
|
+
exports.mergeRowUpdate = mergeRowUpdate;
|
|
241
|
+
const warnIfReplaceLosesPrototype = (oldRow, replacement) => {
|
|
242
|
+
if (process.env.NODE_ENV === 'production' || !oldRow) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const replacementProto = Object.getPrototypeOf(replacement);
|
|
246
|
+
if (replacementProto !== Object.prototype && replacementProto !== null) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const oldRowProto = Object.getPrototypeOf(oldRow);
|
|
250
|
+
if (oldRowProto === Object.prototype || oldRowProto === null) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// The message must stay free of row-specific details: `warnOnce()` caches by message, so
|
|
255
|
+
// interpolating the id would log once per row and grow the cache with every update.
|
|
256
|
+
(0, _warning.warnOnce)(["MUI X Data Grid: A plain object was provided as the `row` of a `_action: 'replace'` update, but the row it replaces is a class instance.", "Building the replacement with a spread (`{ _action: 'replace', row: { ...row } }`) creates a plain object, dropping the prototype chain and the private fields that `_action: 'replace'` exists to preserve.", "Pass the instance itself instead, for example `{ _action: 'replace', row }`.", 'For more detail, see https://mui.com/x/react-data-grid/row-updates/.']);
|
|
257
|
+
};
|
|
258
|
+
exports.warnIfReplaceLosesPrototype = warnIfReplaceLosesPrototype;
|
|
181
259
|
const updateCacheWithNewRows = ({
|
|
182
260
|
previousCache,
|
|
183
261
|
getRowId,
|
|
@@ -191,10 +269,28 @@ const updateCacheWithNewRows = ({
|
|
|
191
269
|
// Remove duplicate updates.
|
|
192
270
|
// A server can batch updates, and send several updates for the same row in one fn call.
|
|
193
271
|
const uniqueUpdates = new Map();
|
|
272
|
+
// Ids whose accumulated update is stored as the row instead of being merged into the
|
|
273
|
+
// existing one. The flag lives outside the row object so that it is never mutated.
|
|
274
|
+
const replaceIds = new Set();
|
|
194
275
|
updates.forEach(update => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
276
|
+
// A replace is provided as a `{ _action: 'replace', row }` envelope: the marker stays
|
|
277
|
+
// on the throwaway envelope and the inner row is used verbatim, so that the object
|
|
278
|
+
// provided by the caller is the one that ends up in the lookup.
|
|
279
|
+
const isReplace = isReplaceUpdate(update);
|
|
280
|
+
const row = isReplace ? getReplaceRow(update) : update;
|
|
281
|
+
const id = getRowIdFromRowModel(row, getRowId, 'A row was provided without id when calling updateRows():');
|
|
282
|
+
if (isReplace) {
|
|
283
|
+
// A replace resets whatever has been accumulated for that id.
|
|
284
|
+
uniqueUpdates.set(id, row);
|
|
285
|
+
replaceIds.add(id);
|
|
286
|
+
} else if (uniqueUpdates.has(id)) {
|
|
287
|
+
const accumulatedUpdate = uniqueUpdates.get(id);
|
|
288
|
+
if (process.env.NODE_ENV !== 'production' && replaceIds.has(id)) {
|
|
289
|
+
(0, _warning.warnOnce)(["MUI X Data Grid: A row was provided with `_action: 'replace'` but it is not the last update for that row in this batch.", 'The remaining updates are merged onto the replacement, so the row keeps its prototype but is neither the same object nor carries its `#private` fields, which a merge cannot copy.', 'Make the replace the last update for that row if `apiRef.current.getRow(id)` must return the object you passed in.', 'For more detail, see https://mui.com/x/react-data-grid/row-updates/.']);
|
|
290
|
+
}
|
|
291
|
+
// The merge keeps the accumulated entry's prototype and the id stays in `replaceIds`,
|
|
292
|
+
// so the result is still applied as a replace.
|
|
293
|
+
uniqueUpdates.set(id, mergeRowUpdate(accumulatedUpdate, update));
|
|
198
294
|
} else {
|
|
199
295
|
uniqueUpdates.set(id, update);
|
|
200
296
|
}
|
|
@@ -246,6 +342,15 @@ const updateCacheWithNewRows = ({
|
|
|
246
342
|
}
|
|
247
343
|
const oldRow = dataRowIdToModelLookup[id];
|
|
248
344
|
|
|
345
|
+
// Action === "replace"
|
|
346
|
+
// The bookkeeping is the same as for "modify" / "insert" below, only the way the row
|
|
347
|
+
// is stored differs: the object is stored as-is so that its prototype chain, private
|
|
348
|
+
// fields (#field) and reference identity are all preserved.
|
|
349
|
+
const isReplace = replaceIds.has(id);
|
|
350
|
+
if (isReplace) {
|
|
351
|
+
warnIfReplaceLosesPrototype(oldRow, partialRow);
|
|
352
|
+
}
|
|
353
|
+
|
|
249
354
|
// Action === "modify"
|
|
250
355
|
if (oldRow) {
|
|
251
356
|
// If the data row has been removed since the last state update,
|
|
@@ -261,23 +366,7 @@ const updateCacheWithNewRows = ({
|
|
|
261
366
|
}
|
|
262
367
|
|
|
263
368
|
// Update the data row lookups.
|
|
264
|
-
|
|
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;
|
|
369
|
+
dataRowIdToModelLookup[id] = isReplace ? partialRow : mergeRowUpdate(oldRow, partialRow);
|
|
281
370
|
return;
|
|
282
371
|
}
|
|
283
372
|
|
|
@@ -319,16 +408,24 @@ const minimalContentHeight = exports.minimalContentHeight = 'var(--DataGrid-over
|
|
|
319
408
|
function computeRowsUpdates(apiRef, updates, getRowId) {
|
|
320
409
|
const nonPinnedRowsUpdates = [];
|
|
321
410
|
updates.forEach(update => {
|
|
322
|
-
const
|
|
411
|
+
const isReplace = isReplaceUpdate(update);
|
|
412
|
+
const row = isReplace ? getReplaceRow(update) : update;
|
|
413
|
+
const id = getRowIdFromRowModel(row, getRowId, 'A row was provided without id when calling updateRows():');
|
|
323
414
|
const rowNode = (0, _gridRowsSelector.gridRowNodeSelector)(apiRef, id);
|
|
324
415
|
if (rowNode?.type === 'pinnedRow') {
|
|
325
416
|
// @ts-ignore because otherwise `release:build` doesn't work
|
|
326
417
|
const pinnedRowsCache = apiRef.current.caches.pinnedRows;
|
|
327
418
|
const prevModel = pinnedRowsCache.idLookup[id];
|
|
328
419
|
if (prevModel) {
|
|
329
|
-
|
|
420
|
+
if (isReplace) {
|
|
421
|
+
warnIfReplaceLosesPrototype(prevModel, row);
|
|
422
|
+
pinnedRowsCache.idLookup[id] = row;
|
|
423
|
+
} else {
|
|
424
|
+
pinnedRowsCache.idLookup[id] = mergeRowUpdate(prevModel, update);
|
|
425
|
+
}
|
|
330
426
|
}
|
|
331
427
|
} else {
|
|
428
|
+
// The envelope is passed through untouched, `updateCacheWithNewRows` unwraps it.
|
|
332
429
|
nonPinnedRowsUpdates.push(update);
|
|
333
430
|
}
|
|
334
431
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import _formatErrorMessage from "@mui/x-internals/formatErrorMessage";
|
|
3
|
+
import { warnOnce } from '@mui/x-internals/warning';
|
|
3
4
|
import { gridRowNodeSelector } from "./gridRowsSelector.mjs";
|
|
4
5
|
export const GRID_ROOT_GROUP_ID = `auto-generated-group-node-root`;
|
|
5
6
|
export const GRID_ID_AUTOGENERATED = Symbol('mui.id_autogenerated');
|
|
@@ -159,6 +160,79 @@ export const getTreeNodeDescendants = (tree, parentId, skipAutoGeneratedRows, di
|
|
|
159
160
|
}
|
|
160
161
|
return validDescendants;
|
|
161
162
|
};
|
|
163
|
+
export const isReplaceUpdate = update =>
|
|
164
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
165
|
+
update._action === 'replace';
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Extracts the replacement row from a `{ _action: 'replace', row }` update.
|
|
169
|
+
* The marker lives on the throwaway envelope, so the row object itself is never touched.
|
|
170
|
+
* @param {GridRowModelReplace} update The update provided to `updateRows()`.
|
|
171
|
+
* @returns {GridRowModel} The object to store as the row, verbatim.
|
|
172
|
+
*/
|
|
173
|
+
export const getReplaceRow = update => {
|
|
174
|
+
const {
|
|
175
|
+
row
|
|
176
|
+
} = update;
|
|
177
|
+
if (row == null) {
|
|
178
|
+
throw new Error(process.env.NODE_ENV !== "production" ? `MUI X Data Grid: A row update with \`_action: 'replace'\` was provided without a \`row\` property.
|
|
179
|
+
Without it, the Data Grid does not know which object to store for that row.
|
|
180
|
+
Provide the replacement object in the \`row\` property, for example \`updateRows([{ _action: 'replace', row }])\`.
|
|
181
|
+
For more detail, see https://mui.com/x/react-data-grid/row-updates/.` : _formatErrorMessage(304));
|
|
182
|
+
}
|
|
183
|
+
return row;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Merges a partial update into the existing row.
|
|
188
|
+
* Prototype-preservation rules:
|
|
189
|
+
* 1. If partialRow is a class instance (non-plain object), use its prototype — the
|
|
190
|
+
* caller is passing in a fully-constructed instance and owns the prototype chain.
|
|
191
|
+
* 2. If partialRow is a plain object (Object.prototype), prefer oldRow's prototype so
|
|
192
|
+
* that a partial-update object does not silently discard the existing row's class.
|
|
193
|
+
* 3. If both are plain objects the result is also a plain object (no-op).
|
|
194
|
+
*
|
|
195
|
+
* Note: private class fields (#field syntax) cannot be preserved through a spread-style
|
|
196
|
+
* merge because the brand check is tied to the original instance. Rows that rely on
|
|
197
|
+
* private fields must either supply a fully-constructed instance as partialRow (rule 1
|
|
198
|
+
* above) or use `_action: 'replace'` rather than a plain-object partial update.
|
|
199
|
+
* @param {GridRowModel} oldRow The row currently stored in the lookup.
|
|
200
|
+
* @param {GridRowModelUpdate} partialRow The update to merge into it.
|
|
201
|
+
* @returns {GridRowModel} The merged row.
|
|
202
|
+
*/
|
|
203
|
+
export const mergeRowUpdate = (oldRow, partialRow) => {
|
|
204
|
+
const partialRowProto = Object.getPrototypeOf(partialRow);
|
|
205
|
+
const isPartialRowPlain = partialRowProto === Object.prototype || partialRowProto === null;
|
|
206
|
+
const proto = isPartialRowPlain ? Object.getPrototypeOf(oldRow) : partialRowProto;
|
|
207
|
+
const merged = Object.create(proto);
|
|
208
|
+
Object.assign(merged, oldRow, partialRow);
|
|
209
|
+
return merged;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Warns when a replace demotes a class instance to a plain object, which happens when the
|
|
214
|
+
* replacement was built with a spread instead of being passed as-is.
|
|
215
|
+
* Dev-only, does nothing in production.
|
|
216
|
+
* @param {GridRowModel | undefined} oldRow The row being replaced, if any.
|
|
217
|
+
* @param {GridRowModel} replacement The row provided in a `{ _action: 'replace', row }` update.
|
|
218
|
+
*/
|
|
219
|
+
export const warnIfReplaceLosesPrototype = (oldRow, replacement) => {
|
|
220
|
+
if (process.env.NODE_ENV === 'production' || !oldRow) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const replacementProto = Object.getPrototypeOf(replacement);
|
|
224
|
+
if (replacementProto !== Object.prototype && replacementProto !== null) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const oldRowProto = Object.getPrototypeOf(oldRow);
|
|
228
|
+
if (oldRowProto === Object.prototype || oldRowProto === null) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// The message must stay free of row-specific details: `warnOnce()` caches by message, so
|
|
233
|
+
// interpolating the id would log once per row and grow the cache with every update.
|
|
234
|
+
warnOnce(["MUI X Data Grid: A plain object was provided as the `row` of a `_action: 'replace'` update, but the row it replaces is a class instance.", "Building the replacement with a spread (`{ _action: 'replace', row: { ...row } }`) creates a plain object, dropping the prototype chain and the private fields that `_action: 'replace'` exists to preserve.", "Pass the instance itself instead, for example `{ _action: 'replace', row }`.", 'For more detail, see https://mui.com/x/react-data-grid/row-updates/.']);
|
|
235
|
+
};
|
|
162
236
|
export const updateCacheWithNewRows = ({
|
|
163
237
|
previousCache,
|
|
164
238
|
getRowId,
|
|
@@ -172,10 +246,28 @@ export const updateCacheWithNewRows = ({
|
|
|
172
246
|
// Remove duplicate updates.
|
|
173
247
|
// A server can batch updates, and send several updates for the same row in one fn call.
|
|
174
248
|
const uniqueUpdates = new Map();
|
|
249
|
+
// Ids whose accumulated update is stored as the row instead of being merged into the
|
|
250
|
+
// existing one. The flag lives outside the row object so that it is never mutated.
|
|
251
|
+
const replaceIds = new Set();
|
|
175
252
|
updates.forEach(update => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
253
|
+
// A replace is provided as a `{ _action: 'replace', row }` envelope: the marker stays
|
|
254
|
+
// on the throwaway envelope and the inner row is used verbatim, so that the object
|
|
255
|
+
// provided by the caller is the one that ends up in the lookup.
|
|
256
|
+
const isReplace = isReplaceUpdate(update);
|
|
257
|
+
const row = isReplace ? getReplaceRow(update) : update;
|
|
258
|
+
const id = getRowIdFromRowModel(row, getRowId, 'A row was provided without id when calling updateRows():');
|
|
259
|
+
if (isReplace) {
|
|
260
|
+
// A replace resets whatever has been accumulated for that id.
|
|
261
|
+
uniqueUpdates.set(id, row);
|
|
262
|
+
replaceIds.add(id);
|
|
263
|
+
} else if (uniqueUpdates.has(id)) {
|
|
264
|
+
const accumulatedUpdate = uniqueUpdates.get(id);
|
|
265
|
+
if (process.env.NODE_ENV !== 'production' && replaceIds.has(id)) {
|
|
266
|
+
warnOnce(["MUI X Data Grid: A row was provided with `_action: 'replace'` but it is not the last update for that row in this batch.", 'The remaining updates are merged onto the replacement, so the row keeps its prototype but is neither the same object nor carries its `#private` fields, which a merge cannot copy.', 'Make the replace the last update for that row if `apiRef.current.getRow(id)` must return the object you passed in.', 'For more detail, see https://mui.com/x/react-data-grid/row-updates/.']);
|
|
267
|
+
}
|
|
268
|
+
// The merge keeps the accumulated entry's prototype and the id stays in `replaceIds`,
|
|
269
|
+
// so the result is still applied as a replace.
|
|
270
|
+
uniqueUpdates.set(id, mergeRowUpdate(accumulatedUpdate, update));
|
|
179
271
|
} else {
|
|
180
272
|
uniqueUpdates.set(id, update);
|
|
181
273
|
}
|
|
@@ -227,6 +319,15 @@ export const updateCacheWithNewRows = ({
|
|
|
227
319
|
}
|
|
228
320
|
const oldRow = dataRowIdToModelLookup[id];
|
|
229
321
|
|
|
322
|
+
// Action === "replace"
|
|
323
|
+
// The bookkeeping is the same as for "modify" / "insert" below, only the way the row
|
|
324
|
+
// is stored differs: the object is stored as-is so that its prototype chain, private
|
|
325
|
+
// fields (#field) and reference identity are all preserved.
|
|
326
|
+
const isReplace = replaceIds.has(id);
|
|
327
|
+
if (isReplace) {
|
|
328
|
+
warnIfReplaceLosesPrototype(oldRow, partialRow);
|
|
329
|
+
}
|
|
330
|
+
|
|
230
331
|
// Action === "modify"
|
|
231
332
|
if (oldRow) {
|
|
232
333
|
// If the data row has been removed since the last state update,
|
|
@@ -242,23 +343,7 @@ export const updateCacheWithNewRows = ({
|
|
|
242
343
|
}
|
|
243
344
|
|
|
244
345
|
// Update the data row lookups.
|
|
245
|
-
|
|
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;
|
|
346
|
+
dataRowIdToModelLookup[id] = isReplace ? partialRow : mergeRowUpdate(oldRow, partialRow);
|
|
262
347
|
return;
|
|
263
348
|
}
|
|
264
349
|
|
|
@@ -299,16 +384,24 @@ export const minimalContentHeight = 'var(--DataGrid-overlayHeight, calc(var(--he
|
|
|
299
384
|
export function computeRowsUpdates(apiRef, updates, getRowId) {
|
|
300
385
|
const nonPinnedRowsUpdates = [];
|
|
301
386
|
updates.forEach(update => {
|
|
302
|
-
const
|
|
387
|
+
const isReplace = isReplaceUpdate(update);
|
|
388
|
+
const row = isReplace ? getReplaceRow(update) : update;
|
|
389
|
+
const id = getRowIdFromRowModel(row, getRowId, 'A row was provided without id when calling updateRows():');
|
|
303
390
|
const rowNode = gridRowNodeSelector(apiRef, id);
|
|
304
391
|
if (rowNode?.type === 'pinnedRow') {
|
|
305
392
|
// @ts-ignore because otherwise `release:build` doesn't work
|
|
306
393
|
const pinnedRowsCache = apiRef.current.caches.pinnedRows;
|
|
307
394
|
const prevModel = pinnedRowsCache.idLookup[id];
|
|
308
395
|
if (prevModel) {
|
|
309
|
-
|
|
396
|
+
if (isReplace) {
|
|
397
|
+
warnIfReplaceLosesPrototype(prevModel, row);
|
|
398
|
+
pinnedRowsCache.idLookup[id] = row;
|
|
399
|
+
} else {
|
|
400
|
+
pinnedRowsCache.idLookup[id] = mergeRowUpdate(prevModel, update);
|
|
401
|
+
}
|
|
310
402
|
}
|
|
311
403
|
} else {
|
|
404
|
+
// The envelope is passed through untouched, `updateCacheWithNewRows` unwraps it.
|
|
312
405
|
nonPinnedRowsUpdates.push(update);
|
|
313
406
|
}
|
|
314
407
|
});
|