@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
291 lines (278 loc) • 12.2 kB
JavaScript
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)");
}