@mui/x-data-grid-premium
Version:
The Premium plan edition of the MUI X Data Grid Components.
442 lines (439 loc) • 17.4 kB
JavaScript
;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useGridPivotingExportState = exports.useGridPivoting = exports.pivotingStateInitializer = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _xDataGridPro = require("@mui/x-data-grid-pro");
var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
var _useOnMount = _interopRequireDefault(require("@mui/utils/useOnMount"));
var _internals = require("@mui/x-data-grid-pro/internals");
var _pivotPanel = require("../../../components/pivotPanel");
var _gridPivotingSelectors = require("./gridPivotingSelectors");
var _utils = require("./utils");
var _gridAggregationUtils = require("../aggregation/gridAggregationUtils");
var _sidebar = require("../sidebar");
var _jsxRuntime = require("react/jsx-runtime");
const emptyPivotModel = {
rows: [],
columns: [],
values: []
};
const pivotingStateInitializer = (state, props, apiRef) => {
apiRef.current.caches.pivoting = {
exportedStateRef: {
current: null
},
nonPivotDataRef: {
current: undefined
}
};
if (props.disablePivoting) {
return (0, _extends2.default)({}, state, {
pivoting: {
active: false,
model: emptyPivotModel
}
});
}
const initialColumns = (0, _utils.getInitialColumns)(props.columns ?? [], props.getPivotDerivedColumns, apiRef.current.getLocaleText);
const open = props.pivotPanelOpen ?? props.initialState?.pivoting?.panelOpen ?? false;
const sidebarStateUpdate = open ? {
open,
value: _sidebar.GridSidebarValue.Pivot
} : {};
return (0, _extends2.default)({}, state, {
pivoting: {
active: props.pivotActive ?? props.initialState?.pivoting?.enabled ?? false,
model: props.pivotModel ?? props.initialState?.pivoting?.model ?? emptyPivotModel,
initialColumns
},
sidebar: (0, _extends2.default)({}, state.sidebar, sidebarStateUpdate)
});
};
exports.pivotingStateInitializer = pivotingStateInitializer;
const useGridPivoting = (apiRef, props, originalColumnsProp, originalRowsProp) => {
const isPivotActive = (0, _internals.useGridSelector)(apiRef, _gridPivotingSelectors.gridPivotActiveSelector);
const isLoading = props.loading ?? (0, _xDataGridPro.gridRowsLoadingSelector)(apiRef);
const {
exportedStateRef,
nonPivotDataRef
} = apiRef.current.caches.pivoting;
const isPivotingAvailable = !props.disablePivoting;
apiRef.current.registerControlState({
stateId: 'pivotModel',
propModel: props.pivotModel,
propOnChange: props.onPivotModelChange,
stateSelector: _gridPivotingSelectors.gridPivotModelSelector,
changeEvent: 'pivotModelChange'
});
apiRef.current.registerControlState({
stateId: 'pivotMode',
propModel: props.pivotActive,
propOnChange: props.onPivotActiveChange,
stateSelector: _gridPivotingSelectors.gridPivotActiveSelector,
changeEvent: 'pivotModeChange'
});
apiRef.current.registerControlState({
stateId: 'pivotPanelOpen',
propModel: props.pivotPanelOpen,
propOnChange: props.onPivotPanelOpenChange,
stateSelector: _gridPivotingSelectors.gridPivotPanelOpenSelector,
changeEvent: 'pivotPanelOpenChange'
});
const getInitialData = React.useCallback(() => {
if (!exportedStateRef.current) {
exportedStateRef.current = apiRef.current.exportState();
}
let rows = [];
if (!props.dataSource) {
const rowIds = (0, _xDataGridPro.gridDataRowIdsSelector)(apiRef);
const rowsLookup = (0, _xDataGridPro.gridRowsLookupSelector)(apiRef);
rows = rowIds.map(id => rowsLookup[id]);
}
const initialColumns = (0, _utils.getInitialColumns)(originalColumnsProp, props.getPivotDerivedColumns, apiRef.current.getLocaleText);
return {
rows,
columns: initialColumns,
originalRowsProp
};
}, [apiRef, props.getPivotDerivedColumns, originalColumnsProp, originalRowsProp, exportedStateRef, props.dataSource]);
const computePivotingState = React.useCallback(({
active,
model: pivotModel
}) => {
if (active && pivotModel) {
const {
rows,
columns
} = nonPivotDataRef.current || {
rows: [],
columns: new Map()
};
let propsOverrides = (0, _utils.getPivotForcedProps)(pivotModel, columns, props.groupingColDef);
// without data source, add more props overrides based on the data
if (!isLoading && !props.dataSource) {
propsOverrides = (0, _extends2.default)({}, propsOverrides, (0, _utils.createPivotPropsFromRows)({
rows,
columns,
pivotModel,
pivotingColDef: props.pivotingColDef,
apiRef
}));
}
return {
initialColumns: columns,
propsOverrides
};
}
return {};
}, [apiRef, isLoading, props.dataSource, props.pivotingColDef, props.groupingColDef, nonPivotDataRef]);
(0, _useOnMount.default)(() => {
if (!isPivotingAvailable || !isPivotActive) {
return undefined;
}
nonPivotDataRef.current = getInitialData();
apiRef.current.setState(state => {
const {
initialColumns,
propsOverrides
} = computePivotingState(state.pivoting);
const pivotingState = (0, _extends2.default)({}, state.pivoting, {
initialColumns: initialColumns || state.pivoting.initialColumns,
propsOverrides: (0, _extends2.default)({}, state.pivoting.propsOverrides, propsOverrides)
});
return (0, _extends2.default)({}, state, {
pivoting: pivotingState
});
});
return undefined;
});
(0, _useEnhancedEffect.default)(() => {
if (!isPivotingAvailable || !isPivotActive) {
if (nonPivotDataRef.current) {
// Prevent rows from being resynced from the original rows prop
apiRef.current.caches.rows.rowsBeforePartialUpdates = nonPivotDataRef.current.originalRowsProp;
apiRef.current.setRows(nonPivotDataRef.current.rows);
nonPivotDataRef.current = undefined;
}
if (exportedStateRef.current) {
apiRef.current.restoreState(exportedStateRef.current);
exportedStateRef.current = null;
}
}
}, [isPivotActive, apiRef, isPivotingAvailable, nonPivotDataRef, exportedStateRef]);
const setPivotModel = React.useCallback(callback => {
if (!isPivotingAvailable) {
return;
}
apiRef.current.setState(state => {
const newPivotModel = typeof callback === 'function' ? callback(state.pivoting?.model) : callback;
if (state.pivoting?.model === newPivotModel) {
return state;
}
const {
initialColumns,
propsOverrides
} = computePivotingState((0, _extends2.default)({}, state.pivoting, {
model: newPivotModel
}));
const newPivotingState = (0, _extends2.default)({}, state.pivoting, {
initialColumns: initialColumns || state.pivoting.initialColumns,
propsOverrides: (0, _extends2.default)({}, state.pivoting.propsOverrides, propsOverrides),
model: newPivotModel
});
return (0, _extends2.default)({}, state, {
pivoting: newPivotingState
});
});
}, [apiRef, computePivotingState, isPivotingAvailable]);
const updatePivotModel = React.useCallback(({
field,
targetSection,
originSection,
targetField,
targetFieldPosition
}) => {
if (field === targetField) {
return;
}
apiRef.current.setPivotModel(prev => {
const newModel = (0, _extends2.default)({}, prev);
const isSameSection = targetSection === originSection;
const hidden = originSection === null ? false : prev[originSection].find(item => item.field === field)?.hidden ?? false;
if (targetSection) {
const newSectionArray = [...prev[targetSection]];
let toIndex = newSectionArray.length;
if (targetField) {
const fromIndex = newSectionArray.findIndex(item => item.field === field);
if (fromIndex > -1) {
newSectionArray.splice(fromIndex, 1);
}
toIndex = newSectionArray.findIndex(item => item.field === targetField);
if (targetFieldPosition === 'bottom') {
toIndex += 1;
}
}
if (targetSection === 'values') {
const initialColumns = (0, _internals.gridPivotInitialColumnsSelector)(apiRef);
const aggFunc = isSameSection ? prev.values.find(item => item.field === field)?.aggFunc : (0, _gridAggregationUtils.getAvailableAggregationFunctions)({
aggregationFunctions: props.aggregationFunctions,
colDef: initialColumns.get(field),
isDataSource: !!props.dataSource
})[0];
newSectionArray.splice(toIndex, 0, {
field,
aggFunc,
hidden
});
newModel.values = newSectionArray;
} else if (targetSection === 'columns') {
const sort = isSameSection ? prev.columns.find(item => item.field === field)?.sort : undefined;
newSectionArray.splice(toIndex, 0, {
field,
sort,
hidden
});
newModel.columns = newSectionArray;
} else if (targetSection === 'rows') {
newSectionArray.splice(toIndex, 0, {
field,
hidden
});
newModel.rows = newSectionArray;
}
}
if (!isSameSection && originSection) {
newModel[originSection] = prev[originSection].filter(f => f.field !== field);
}
return newModel;
});
}, [apiRef, props.aggregationFunctions, props.dataSource]);
const setPivotActive = React.useCallback(callback => {
if (!isPivotingAvailable) {
return;
}
apiRef.current.setState(state => {
const newPivotMode = typeof callback === 'function' ? callback(state.pivoting?.active) : callback;
if (state.pivoting?.active === newPivotMode) {
return state;
}
if (newPivotMode) {
nonPivotDataRef.current = getInitialData();
}
const {
initialColumns,
propsOverrides
} = computePivotingState((0, _extends2.default)({}, state.pivoting, {
active: newPivotMode
}));
const newPivotingState = (0, _extends2.default)({}, state.pivoting, {
initialColumns: initialColumns || state.pivoting.initialColumns,
propsOverrides: (0, _extends2.default)({}, state.pivoting.propsOverrides, propsOverrides),
active: newPivotMode
});
const newState = (0, _extends2.default)({}, state, {
pivoting: newPivotingState
});
return newState;
});
apiRef.current.selectRows([], false, true);
}, [apiRef, computePivotingState, getInitialData, isPivotingAvailable, nonPivotDataRef]);
const setPivotPanelOpen = React.useCallback(callback => {
if (!isPivotingAvailable) {
return;
}
const panelOpen = (0, _gridPivotingSelectors.gridPivotPanelOpenSelector)(apiRef);
const newPanelOpen = typeof callback === 'function' ? callback(panelOpen) : callback;
if (panelOpen === newPanelOpen) {
return;
}
if (newPanelOpen) {
apiRef.current.showSidebar(_sidebar.GridSidebarValue.Pivot);
} else {
apiRef.current.hideSidebar();
}
}, [apiRef, isPivotingAvailable]);
const addColumnMenuButton = React.useCallback(menuItems => {
if (isPivotingAvailable) {
return [...menuItems, 'columnMenuManagePanelItem'];
}
return menuItems;
}, [isPivotingAvailable]);
(0, _internals.useGridRegisterPipeProcessor)(apiRef, 'columnMenu', addColumnMenuButton);
const updateNonPivotColumns = React.useCallback((columns, keepPreviousColumns = true) => {
if (!nonPivotDataRef.current || !isPivotingAvailable) {
return;
}
if (keepPreviousColumns) {
(0, _utils.getInitialColumns)(columns, props.getPivotDerivedColumns, apiRef.current.getLocaleText).forEach(col => {
nonPivotDataRef.current.columns.set(col.field, col);
});
} else {
nonPivotDataRef.current.columns = (0, _utils.getInitialColumns)(columns, props.getPivotDerivedColumns, apiRef.current.getLocaleText);
}
apiRef.current.setState(state => {
const {
propsOverrides
} = computePivotingState(state.pivoting);
return (0, _extends2.default)({}, state, {
pivoting: (0, _extends2.default)({}, state.pivoting, {
initialColumns: nonPivotDataRef.current?.columns,
propsOverrides: (0, _extends2.default)({}, state.pivoting.propsOverrides, propsOverrides)
})
});
});
}, [isPivotingAvailable, apiRef, props.getPivotDerivedColumns, computePivotingState, nonPivotDataRef]);
const updateNonPivotRows = React.useCallback((rows, keepPreviousRows = true) => {
if (!nonPivotDataRef.current || props.dataSource || !isPivotingAvailable || !rows || rows.length === 0) {
return;
}
if (keepPreviousRows) {
const rowsMap = new Map();
nonPivotDataRef.current.rows.forEach(row => {
rowsMap.set((0, _xDataGridPro.gridRowIdSelector)(apiRef, row), row);
});
rows.forEach(row => {
const rowId = (0, _xDataGridPro.gridRowIdSelector)(apiRef, row);
// eslint-disable-next-line no-underscore-dangle
if (row._action === 'delete') {
rowsMap.delete(rowId);
} else {
rowsMap.set(rowId, row);
}
});
nonPivotDataRef.current.rows = Array.from(rowsMap.values());
} else {
nonPivotDataRef.current.rows = rows;
}
apiRef.current.setState(state => {
const {
initialColumns,
propsOverrides
} = computePivotingState(state.pivoting);
return (0, _extends2.default)({}, state, {
pivoting: (0, _extends2.default)({}, state.pivoting, {
initialColumns: initialColumns || state.pivoting.initialColumns,
propsOverrides: (0, _extends2.default)({}, state.pivoting.propsOverrides, propsOverrides)
})
});
});
}, [apiRef, computePivotingState, isPivotingAvailable, nonPivotDataRef, props.dataSource]);
const addPivotingPanel = React.useCallback((initialValue, value) => {
if (isPivotingAvailable && value === _sidebar.GridSidebarValue.Pivot) {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_pivotPanel.GridPivotPanel, {});
}
return initialValue;
}, [isPivotingAvailable]);
const addGetRowsParams = React.useCallback(params => {
if (!isPivotingAvailable || !isPivotActive) {
return params;
}
const pivotModel = (0, _gridPivotingSelectors.gridPivotModelSelector)(apiRef);
const visibleColumns = pivotModel.columns.filter(column => !column.hidden);
const visibleRows = pivotModel.rows.filter(row => !row.hidden);
const visibleValues = pivotModel.values.filter(value => !value.hidden);
return (0, _extends2.default)({}, params, {
pivotModel: {
columns: visibleColumns,
rows: visibleRows,
values: visibleValues
}
});
}, [apiRef, isPivotingAvailable, isPivotActive]);
(0, _internals.useGridRegisterPipeProcessor)(apiRef, 'sidebar', addPivotingPanel);
(0, _internals.useGridRegisterPipeProcessor)(apiRef, 'getRowsParams', addGetRowsParams);
(0, _internals.useGridApiMethod)(apiRef, {
setPivotModel,
setPivotActive,
setPivotPanelOpen
}, 'public');
(0, _internals.useGridApiMethod)(apiRef, {
updatePivotModel,
updateNonPivotColumns,
updateNonPivotRows
}, 'private');
(0, _useEnhancedEffect.default)(() => {
apiRef.current.updateNonPivotColumns(originalColumnsProp, false);
}, [originalColumnsProp, apiRef]);
(0, _useEnhancedEffect.default)(() => {
apiRef.current.updateNonPivotRows(originalRowsProp, false);
if (nonPivotDataRef.current) {
nonPivotDataRef.current.originalRowsProp = originalRowsProp;
}
}, [originalRowsProp, apiRef, nonPivotDataRef]);
(0, _useEnhancedEffect.default)(() => {
if (props.pivotModel !== undefined) {
apiRef.current.setPivotModel(props.pivotModel);
}
}, [apiRef, props.pivotModel]);
(0, _useEnhancedEffect.default)(() => {
if (props.pivotActive !== undefined) {
apiRef.current.setPivotActive(props.pivotActive);
}
}, [apiRef, props.pivotActive]);
(0, _useEnhancedEffect.default)(() => {
if (props.pivotPanelOpen !== undefined) {
apiRef.current.setPivotPanelOpen(props.pivotPanelOpen);
}
}, [apiRef, props.pivotPanelOpen]);
};
exports.useGridPivoting = useGridPivoting;
const useGridPivotingExportState = apiRef => {
const stateExportPreProcessing = React.useCallback(state => {
const isPivotActive = (0, _gridPivotingSelectors.gridPivotActiveSelector)(apiRef);
if (!isPivotActive) {
return state;
}
// To-do: implement context.exportOnlyDirtyModels
const newState = (0, _extends2.default)({}, state, apiRef.current.caches.pivoting.exportedStateRef.current, {
sorting: state.sorting
});
return newState;
}, [apiRef]);
(0, _internals.useGridRegisterPipeProcessor)(apiRef, 'exportState', stateExportPreProcessing);
};
exports.useGridPivotingExportState = useGridPivotingExportState;