UNPKG

@mui/x-data-grid

Version:

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

291 lines (278 loc) 12.2 kB
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; import _extends from "@babel/runtime/helpers/esm/extends"; import { gridPinnedRowsSelector } from './gridRowsSelector'; import { gridDensityFactorSelector } from '../density/densitySelector'; export var GRID_ROOT_GROUP_ID = "auto-generated-group-node-root"; export var GRID_ID_AUTOGENERATED = Symbol('mui.id_autogenerated'); export var buildRootGroup = function buildRootGroup() { return { type: 'group', id: GRID_ROOT_GROUP_ID, depth: -1, groupingField: null, groupingKey: null, isAutoGenerated: true, children: [], childrenFromPath: {}, childrenExpanded: true, parent: null }; }; /** * A helper function to check if the id provided is valid. * @param {GridRowId} id Id as [[GridRowId]]. * @param {GridRowModel | Partial<GridRowModel>} row Row as [[GridRowModel]]. * @param {string} detailErrorMessage A custom error message to display for invalid IDs */ export function checkGridRowIdIsValid(id, row) { var detailErrorMessage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'A row was provided without id in the rows prop:'; if (id == null) { throw new Error(['MUI: The data grid component requires all rows to have a unique `id` property.', 'Alternatively, you can use the `getRowId` prop to specify a custom id for each row.', detailErrorMessage, JSON.stringify(row)].join('\n')); } } export var getRowIdFromRowModel = function getRowIdFromRowModel(rowModel, getRowId, detailErrorMessage) { var id = getRowId ? getRowId(rowModel) : rowModel.id; checkGridRowIdIsValid(id, rowModel, detailErrorMessage); return id; }; export var createRowsInternalCache = function createRowsInternalCache(_ref) { var rows = _ref.rows, getRowId = _ref.getRowId, loading = _ref.loading, rowCount = _ref.rowCount; var updates = { type: 'full', rows: [] }; var dataRowIdToModelLookup = {}; var dataRowIdToIdLookup = {}; for (var i = 0; i < rows.length; i += 1) { var model = rows[i]; var _id = getRowIdFromRowModel(model, getRowId); dataRowIdToModelLookup[_id] = model; dataRowIdToIdLookup[_id] = _id; updates.rows.push(_id); } return { rowsBeforePartialUpdates: rows, loadingPropBeforePartialUpdates: loading, rowCountPropBeforePartialUpdates: rowCount, updates: updates, dataRowIdToIdLookup: dataRowIdToIdLookup, dataRowIdToModelLookup: dataRowIdToModelLookup }; }; export var getTopLevelRowCount = function getTopLevelRowCount(_ref2) { var tree = _ref2.tree, _ref2$rowCountProp = _ref2.rowCountProp, rowCountProp = _ref2$rowCountProp === void 0 ? 0 : _ref2$rowCountProp; var rootGroupNode = tree[GRID_ROOT_GROUP_ID]; return Math.max(rowCountProp, rootGroupNode.children.length + (rootGroupNode.footerId == null ? 0 : 1)); }; export var getRowsStateFromCache = function getRowsStateFromCache(_ref3) { var apiRef = _ref3.apiRef, _ref3$rowCountProp = _ref3.rowCountProp, rowCountProp = _ref3$rowCountProp === void 0 ? 0 : _ref3$rowCountProp, loadingProp = _ref3.loadingProp, previousTree = _ref3.previousTree, previousTreeDepths = _ref3.previousTreeDepths; var cache = apiRef.current.caches.rows; // 1. Apply the "rowTreeCreation" family processing. var _apiRef$current$apply = apiRef.current.applyStrategyProcessor('rowTreeCreation', { previousTree: previousTree, previousTreeDepths: previousTreeDepths, updates: cache.updates, dataRowIdToIdLookup: cache.dataRowIdToIdLookup, dataRowIdToModelLookup: cache.dataRowIdToModelLookup }), unProcessedTree = _apiRef$current$apply.tree, unProcessedTreeDepths = _apiRef$current$apply.treeDepths, unProcessedDataRowIds = _apiRef$current$apply.dataRowIds, groupingName = _apiRef$current$apply.groupingName; // 2. Apply the "hydrateRows" pipe-processing. var groupingParamsWithHydrateRows = apiRef.current.unstable_applyPipeProcessors('hydrateRows', { tree: unProcessedTree, treeDepths: unProcessedTreeDepths, dataRowIdToIdLookup: cache.dataRowIdToIdLookup, dataRowIds: unProcessedDataRowIds, dataRowIdToModelLookup: cache.dataRowIdToModelLookup }); // 3. Reset the cache updates apiRef.current.caches.rows.updates = { type: 'partial', actions: { insert: [], modify: [], remove: [] }, idToActionLookup: {} }; return _extends({}, groupingParamsWithHydrateRows, { totalRowCount: Math.max(rowCountProp, groupingParamsWithHydrateRows.dataRowIds.length), totalTopLevelRowCount: getTopLevelRowCount({ tree: groupingParamsWithHydrateRows.tree, rowCountProp: rowCountProp }), groupingName: groupingName, loading: loadingProp }); }; export var isAutoGeneratedRow = function isAutoGeneratedRow(rowNode) { return rowNode.type === 'skeletonRow' || rowNode.type === 'footer' || rowNode.type === 'group' && rowNode.isAutoGenerated || rowNode.type === 'pinnedRow' && rowNode.isAutoGenerated; }; export var getTreeNodeDescendants = function getTreeNodeDescendants(tree, parentId, skipAutoGeneratedRows) { var node = tree[parentId]; if (node.type !== 'group') { return []; } var validDescendants = []; for (var i = 0; i < node.children.length; i += 1) { var child = node.children[i]; if (!skipAutoGeneratedRows || !isAutoGeneratedRow(tree[child])) { validDescendants.push(child); } validDescendants.push.apply(validDescendants, _toConsumableArray(getTreeNodeDescendants(tree, child, skipAutoGeneratedRows))); } if (!skipAutoGeneratedRows && node.footerId != null) { validDescendants.push(node.footerId); } return validDescendants; }; export var updateCacheWithNewRows = function updateCacheWithNewRows(_ref4) { var _previousCache$update, _previousCache$update2, _previousCache$update3; var previousCache = _ref4.previousCache, getRowId = _ref4.getRowId, updates = _ref4.updates; if (previousCache.updates.type === 'full') { throw new Error('MUI: Unable to prepare a partial update if a full update is not applied yet'); } // Remove duplicate updates. // A server can batch updates, and send several updates for the same row in one fn call. var uniqueUpdates = new Map(); updates.forEach(function (update) { var id = getRowIdFromRowModel(update, getRowId, 'A row was provided without id when calling updateRows():'); if (uniqueUpdates.has(id)) { uniqueUpdates.set(id, _extends({}, uniqueUpdates.get(id), update)); } else { uniqueUpdates.set(id, update); } }); var partialUpdates = { type: 'partial', actions: { insert: _toConsumableArray((_previousCache$update = previousCache.updates.actions.insert) != null ? _previousCache$update : []), modify: _toConsumableArray((_previousCache$update2 = previousCache.updates.actions.modify) != null ? _previousCache$update2 : []), remove: _toConsumableArray((_previousCache$update3 = previousCache.updates.actions.remove) != null ? _previousCache$update3 : []) }, idToActionLookup: _extends({}, previousCache.updates.idToActionLookup) }; var dataRowIdToModelLookup = _extends({}, previousCache.dataRowIdToModelLookup); var dataRowIdToIdLookup = _extends({}, previousCache.dataRowIdToIdLookup); var alreadyAppliedActionsToRemove = { insert: {}, modify: {}, remove: {} }; // Depending on the action already applied to the data row, // We might want drop the already-applied-update. // For instance: // - if you delete then insert, then you don't want to apply the deletion in the tree. // - if you insert, then modify, then you just want to apply the insertion in the tree. uniqueUpdates.forEach(function (partialRow, id) { var actionAlreadyAppliedToRow = partialUpdates.idToActionLookup[id]; // Action === "delete" // eslint-disable-next-line no-underscore-dangle if (partialRow._action === 'delete') { // If the data row has been removed since the last state update, // Then do nothing. if (actionAlreadyAppliedToRow === 'remove' || !dataRowIdToModelLookup[id]) { return; } // If the data row has been inserted / modified since the last state update, // Then drop this "insert" / "modify" update. if (actionAlreadyAppliedToRow != null) { alreadyAppliedActionsToRemove[actionAlreadyAppliedToRow][id] = true; } // Remove the data row from the lookups and add it to the "delete" update. partialUpdates.actions.remove.push(id); delete dataRowIdToModelLookup[id]; delete dataRowIdToIdLookup[id]; return; } var oldRow = dataRowIdToModelLookup[id]; // Action === "modify" if (oldRow) { // If the data row has been removed since the last state update, // Then drop this "remove" update and add it to the "modify" update instead. if (actionAlreadyAppliedToRow === 'remove') { alreadyAppliedActionsToRemove.remove[id] = true; partialUpdates.actions.modify.push(id); } // If the date has not been inserted / modified since the last state update, // Then add it to the "modify" update (if it has been inserted it should just remain "inserted"). else if (actionAlreadyAppliedToRow == null) { partialUpdates.actions.modify.push(id); } // Update the data row lookups. dataRowIdToModelLookup[id] = _extends({}, oldRow, partialRow); return; } // Action === "insert" // If the data row has been removed since the last state update, // Then drop the "remove" update and add it to the "insert" update instead. if (actionAlreadyAppliedToRow === 'remove') { alreadyAppliedActionsToRemove.remove[id] = true; partialUpdates.actions.insert.push(id); } // If the data row has not been inserted since the last state update, // Then add it to the "insert" update. // `actionAlreadyAppliedToRow` can't be equal to "modify", otherwise we would have an `oldRow` above. else if (actionAlreadyAppliedToRow == null) { partialUpdates.actions.insert.push(id); } // Update the data row lookups. dataRowIdToModelLookup[id] = partialRow; dataRowIdToIdLookup[id] = id; }); var actionTypeWithActionsToRemove = Object.keys(alreadyAppliedActionsToRemove); var _loop = function _loop() { var actionType = actionTypeWithActionsToRemove[i]; var idsToRemove = alreadyAppliedActionsToRemove[actionType]; if (Object.keys(idsToRemove).length > 0) { partialUpdates.actions[actionType] = partialUpdates.actions[actionType].filter(function (id) { return !idsToRemove[id]; }); } }; for (var i = 0; i < actionTypeWithActionsToRemove.length; i += 1) { _loop(); } return { dataRowIdToModelLookup: dataRowIdToModelLookup, dataRowIdToIdLookup: dataRowIdToIdLookup, updates: partialUpdates, rowsBeforePartialUpdates: previousCache.rowsBeforePartialUpdates, loadingPropBeforePartialUpdates: previousCache.loadingPropBeforePartialUpdates, rowCountPropBeforePartialUpdates: previousCache.rowCountPropBeforePartialUpdates }; }; export function calculatePinnedRowsHeight(apiRef) { var _pinnedRows$top, _pinnedRows$bottom; var pinnedRows = gridPinnedRowsSelector(apiRef); var topPinnedRowsHeight = (pinnedRows == null || (_pinnedRows$top = pinnedRows.top) == null ? void 0 : _pinnedRows$top.reduce(function (acc, value) { acc += apiRef.current.unstable_getRowHeight(value.id); return acc; }, 0)) || 0; var bottomPinnedRowsHeight = (pinnedRows == null || (_pinnedRows$bottom = pinnedRows.bottom) == null ? void 0 : _pinnedRows$bottom.reduce(function (acc, value) { acc += apiRef.current.unstable_getRowHeight(value.id); return acc; }, 0)) || 0; return { top: topPinnedRowsHeight, bottom: bottomPinnedRowsHeight }; } export function getMinimalContentHeight(apiRef, rowHeight) { var densityFactor = gridDensityFactorSelector(apiRef); return "var(--DataGrid-overlayHeight, ".concat(2 * Math.floor(rowHeight * densityFactor), "px)"); }