UNPKG

@mui/x-data-grid

Version:

The community edition of the data grid component (MUI X).

303 lines (270 loc) 11.7 kB
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; import _extends from "@babel/runtime/helpers/esm/extends"; import * as React from 'react'; import { GridFeatureModeConstant } from '../../../models/gridFeatureMode'; import { isEnterKey } from '../../../utils/keyboardUtils'; import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; import { useGridApiMethod } from '../../utils/useGridApiMethod'; import { useGridLogger } from '../../utils/useGridLogger'; import { gridColumnLookupSelector } from '../columns/gridColumnsSelector'; import { gridSortedRowEntriesSelector, gridSortedRowIdsSelector, gridSortModelSelector } from './gridSortingSelector'; import { gridRowIdsSelector, gridRowTreeSelector } from '../rows'; import { useFirstRender } from '../../utils/useFirstRender'; import { useGridRegisterStrategyProcessor, GRID_DEFAULT_STRATEGY } from '../../core/strategyProcessing'; import { buildAggregatedSortingApplier, mergeStateWithSortModel, getNextGridSortDirection, sanitizeSortModel } from './gridSortingUtils'; import { useGridRegisterPipeProcessor } from '../../core/pipeProcessing'; export var sortingStateInitializer = function sortingStateInitializer(state, props) { var _ref, _props$sortModel, _props$initialState, _props$initialState$s; var sortModel = (_ref = (_props$sortModel = props.sortModel) != null ? _props$sortModel : (_props$initialState = props.initialState) == null ? void 0 : (_props$initialState$s = _props$initialState.sorting) == null ? void 0 : _props$initialState$s.sortModel) != null ? _ref : []; return _extends({}, state, { sorting: { sortModel: sanitizeSortModel(sortModel, props.disableMultipleColumnsSorting), sortedRows: [] } }); }; /** * @requires useGridRows (event) * @requires useGridColumns (event) */ export var useGridSorting = function useGridSorting(apiRef, props) { var _props$initialState3, _props$initialState3$; var logger = useGridLogger(apiRef, 'useGridSorting'); apiRef.current.unstable_registerControlState({ stateId: 'sortModel', propModel: props.sortModel, propOnChange: props.onSortModelChange, stateSelector: gridSortModelSelector, changeEvent: 'sortModelChange' }); var upsertSortModel = React.useCallback(function (field, sortItem) { var sortModel = gridSortModelSelector(apiRef); var existingIdx = sortModel.findIndex(function (c) { return c.field === field; }); var newSortModel = _toConsumableArray(sortModel); if (existingIdx > -1) { if (!sortItem) { newSortModel.splice(existingIdx, 1); } else { newSortModel.splice(existingIdx, 1, sortItem); } } else { newSortModel = [].concat(_toConsumableArray(sortModel), [sortItem]); } return newSortModel; }, [apiRef]); var createSortItem = React.useCallback(function (col, directionOverride) { var _col$sortingOrder2; var sortModel = gridSortModelSelector(apiRef); var existing = sortModel.find(function (c) { return c.field === col.field; }); if (existing) { var _col$sortingOrder; var nextSort = directionOverride === undefined ? getNextGridSortDirection((_col$sortingOrder = col.sortingOrder) != null ? _col$sortingOrder : props.sortingOrder, existing.sort) : directionOverride; return nextSort == null ? undefined : _extends({}, existing, { sort: nextSort }); } return { field: col.field, sort: directionOverride === undefined ? getNextGridSortDirection((_col$sortingOrder2 = col.sortingOrder) != null ? _col$sortingOrder2 : props.sortingOrder) : directionOverride }; }, [apiRef, props.sortingOrder]); /** * API METHODS */ var applySorting = React.useCallback(function () { apiRef.current.setState(function (state) { if (props.sortingMode === GridFeatureModeConstant.server) { logger.debug('Skipping sorting rows as sortingMode = server'); return _extends({}, state, { sorting: _extends({}, state.sorting, { sortedRows: gridRowIdsSelector(state, apiRef.current.instanceId) }) }); } var sortModel = gridSortModelSelector(state, apiRef.current.instanceId); var sortRowList = buildAggregatedSortingApplier(sortModel, apiRef); var sortedRows = apiRef.current.unstable_applyStrategyProcessor('sorting', { sortRowList: sortRowList }); return _extends({}, state, { sorting: _extends({}, state.sorting, { sortedRows: sortedRows }) }); }); apiRef.current.publishEvent('sortedRowsSet'); apiRef.current.forceUpdate(); }, [apiRef, logger, props.sortingMode]); var setSortModel = React.useCallback(function (model) { var currentModel = gridSortModelSelector(apiRef); if (currentModel !== model) { logger.debug("Setting sort model"); apiRef.current.setState(mergeStateWithSortModel(model, props.disableMultipleColumnsSorting)); apiRef.current.forceUpdate(); apiRef.current.applySorting(); } }, [apiRef, logger, props.disableMultipleColumnsSorting]); var sortColumn = React.useCallback(function (column, direction, allowMultipleSorting) { if (!column.sortable) { return; } var sortItem = createSortItem(column, direction); var sortModel; if (!allowMultipleSorting || props.disableMultipleColumnsSorting) { sortModel = !sortItem ? [] : [sortItem]; } else { sortModel = upsertSortModel(column.field, sortItem); } apiRef.current.setSortModel(sortModel); }, [apiRef, upsertSortModel, createSortItem, props.disableMultipleColumnsSorting]); var getSortModel = React.useCallback(function () { return gridSortModelSelector(apiRef); }, [apiRef]); var getSortedRows = React.useCallback(function () { var sortedRows = gridSortedRowEntriesSelector(apiRef); return sortedRows.map(function (row) { return row.model; }); }, [apiRef]); var getSortedRowIds = React.useCallback(function () { return gridSortedRowIdsSelector(apiRef); }, [apiRef]); var getRowIndex = React.useCallback(function (id) { return apiRef.current.getSortedRowIds().indexOf(id); }, [apiRef]); var getRowIdFromRowIndex = React.useCallback(function (index) { return apiRef.current.getSortedRowIds()[index]; }, [apiRef]); var sortApi = { getSortModel: getSortModel, getSortedRows: getSortedRows, getSortedRowIds: getSortedRowIds, getRowIndex: getRowIndex, getRowIdFromRowIndex: getRowIdFromRowIndex, setSortModel: setSortModel, sortColumn: sortColumn, applySorting: applySorting }; useGridApiMethod(apiRef, sortApi, 'GridSortApi'); /** * PRE-PROCESSING */ var stateExportPreProcessing = React.useCallback(function (prevState, context) { var _props$initialState2, _props$initialState2$; var sortModelToExport = gridSortModelSelector(apiRef); var shouldExportSortModel = // Always export if the `exportOnlyDirtyModels` property is activated !context.exportOnlyDirtyModels || // Always export if the model is controlled props.sortModel != null || // Always export if the model has been initialized ((_props$initialState2 = props.initialState) == null ? void 0 : (_props$initialState2$ = _props$initialState2.sorting) == null ? void 0 : _props$initialState2$.sortModel) != null || // Export if the model is not empty sortModelToExport.length > 0; if (!shouldExportSortModel) { return prevState; } return _extends({}, prevState, { sorting: { sortModel: sortModelToExport } }); }, [apiRef, props.sortModel, (_props$initialState3 = props.initialState) == null ? void 0 : (_props$initialState3$ = _props$initialState3.sorting) == null ? void 0 : _props$initialState3$.sortModel]); var stateRestorePreProcessing = React.useCallback(function (params, context) { var _context$stateToResto; var sortModel = (_context$stateToResto = context.stateToRestore.sorting) == null ? void 0 : _context$stateToResto.sortModel; if (sortModel == null) { return params; } apiRef.current.setState(mergeStateWithSortModel(sortModel, props.disableMultipleColumnsSorting)); return _extends({}, params, { callbacks: [].concat(_toConsumableArray(params.callbacks), [apiRef.current.applySorting]) }); }, [apiRef, props.disableMultipleColumnsSorting]); var flatSortingMethod = React.useCallback(function (params) { var rowTree = gridRowTreeSelector(apiRef); if (!params.sortRowList) { var bodyRowIds = []; var _footerRowIds = []; gridRowIdsSelector(apiRef).forEach(function (rowId) { if (rowTree[rowId].isPinned) { return; } if (rowTree[rowId].position === 'footer') { _footerRowIds.push(rowId); } else { bodyRowIds.push(rowId); } }); return [].concat(bodyRowIds, _footerRowIds); } var bodyRows = []; var footerRowIds = []; Object.values(rowTree).forEach(function (rowNode) { if (rowNode.isPinned) { return; } if (rowNode.position === 'footer') { footerRowIds.push(rowNode.id); } else { bodyRows.push(rowNode); } }); return [].concat(_toConsumableArray(params.sortRowList(bodyRows)), footerRowIds); }, [apiRef]); useGridRegisterPipeProcessor(apiRef, 'exportState', stateExportPreProcessing); useGridRegisterPipeProcessor(apiRef, 'restoreState', stateRestorePreProcessing); useGridRegisterStrategyProcessor(apiRef, GRID_DEFAULT_STRATEGY, 'sorting', flatSortingMethod); /** * EVENTS */ var handleColumnHeaderClick = React.useCallback(function (_ref2, event) { var colDef = _ref2.colDef; var allowMultipleSorting = event.shiftKey || event.metaKey || event.ctrlKey; sortColumn(colDef, undefined, allowMultipleSorting); }, [sortColumn]); var handleColumnHeaderKeyDown = React.useCallback(function (_ref3, event) { var colDef = _ref3.colDef; // Ctrl + Enter opens the column menu if (isEnterKey(event.key) && !event.ctrlKey && !event.metaKey) { sortColumn(colDef, undefined, event.shiftKey); } }, [sortColumn]); var handleColumnsChange = React.useCallback(function () { // When the columns change we check that the sorted columns are still part of the dataset var sortModel = gridSortModelSelector(apiRef); var latestColumns = gridColumnLookupSelector(apiRef); if (sortModel.length > 0) { var newModel = sortModel.filter(function (sortItem) { return latestColumns[sortItem.field]; }); if (newModel.length < sortModel.length) { apiRef.current.setSortModel(newModel); } } }, [apiRef]); var handleStrategyProcessorChange = React.useCallback(function (methodName) { if (methodName === 'sorting') { apiRef.current.applySorting(); } }, [apiRef]); useGridApiEventHandler(apiRef, 'columnHeaderClick', handleColumnHeaderClick); useGridApiEventHandler(apiRef, 'columnHeaderKeyDown', handleColumnHeaderKeyDown); useGridApiEventHandler(apiRef, 'rowsSet', apiRef.current.applySorting); useGridApiEventHandler(apiRef, 'columnsChange', handleColumnsChange); useGridApiEventHandler(apiRef, 'activeStrategyProcessorChange', handleStrategyProcessorChange); /** * 1ST RENDER */ useFirstRender(function () { apiRef.current.applySorting(); }); /** * EFFECTS */ React.useEffect(function () { if (props.sortModel !== undefined) { apiRef.current.setSortModel(props.sortModel); } }, [apiRef, props.sortModel]); };