@mui/x-data-grid
Version:
The Community plan edition of the Data Grid components (MUI X).
165 lines (164 loc) • 6.19 kB
JavaScript
import { GridSignature } from "../../../constants/signature.js";
import { GRID_ROOT_GROUP_ID } from "../rows/gridRowsUtils.js";
import { gridFilteredRowsLookupSelector } from "../filter/gridFilterSelector.js";
import { gridSortedRowIdsSelector } from "../sorting/gridSortingSelector.js";
import { gridRowSelectionManagerSelector } from "./gridRowSelectionSelector.js";
import { gridRowTreeSelector } from "../rows/gridRowsSelector.js";
import { createSelector } from "../../../utils/createSelector.js";
export const ROW_SELECTION_PROPAGATION_DEFAULT = {
parents: true,
descendants: true
};
function getGridRowGroupSelectableDescendants(apiRef, groupId) {
const rowTree = gridRowTreeSelector(apiRef);
const sortedRowIds = gridSortedRowIdsSelector(apiRef);
const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef);
const groupNode = rowTree[groupId];
if (!groupNode || groupNode.type !== 'group') {
return [];
}
const descendants = [];
const startIndex = sortedRowIds.findIndex(id => id === groupId) + 1;
for (let index = startIndex; index < sortedRowIds.length && rowTree[sortedRowIds[index]]?.depth > groupNode.depth; index += 1) {
const id = sortedRowIds[index];
if (filteredRowsLookup[id] !== false && apiRef.current.isRowSelectable(id)) {
descendants.push(id);
}
}
return descendants;
}
// TODO v8: Use `createSelectorV8`
export function getCheckboxPropsSelector(groupId, autoSelectParents) {
return createSelector(gridRowTreeSelector, gridSortedRowIdsSelector, gridFilteredRowsLookupSelector, gridRowSelectionManagerSelector, (rowTree, sortedRowIds, filteredRowsLookup, rowSelectionManager) => {
const groupNode = rowTree[groupId];
if (!groupNode || groupNode.type !== 'group') {
return {
isIndeterminate: false,
isChecked: rowSelectionManager.has(groupId)
};
}
if (rowSelectionManager.has(groupId)) {
return {
isIndeterminate: false,
isChecked: true
};
}
let selectableDescendantsCount = 0;
let selectedDescendantsCount = 0;
const startIndex = sortedRowIds.findIndex(id => id === groupId) + 1;
for (let index = startIndex; index < sortedRowIds.length && rowTree[sortedRowIds[index]]?.depth > groupNode.depth; index += 1) {
const id = sortedRowIds[index];
if (filteredRowsLookup[id] !== false) {
selectableDescendantsCount += 1;
if (rowSelectionManager.has(id)) {
selectedDescendantsCount += 1;
}
}
}
return {
isIndeterminate: selectedDescendantsCount > 0 && (selectedDescendantsCount < selectableDescendantsCount || !rowSelectionManager.has(groupId)),
isChecked: autoSelectParents ? selectedDescendantsCount > 0 : rowSelectionManager.has(groupId)
};
});
}
export function isMultipleRowSelectionEnabled(props) {
if (props.signature === GridSignature.DataGrid) {
// DataGrid Community has multiple row selection enabled only if checkbox selection is enabled.
return props.checkboxSelection && props.disableMultipleRowSelection !== true;
}
return !props.disableMultipleRowSelection;
}
const getRowNodeParents = (tree, id) => {
const parents = [];
let parent = id;
while (parent != null && parent !== GRID_ROOT_GROUP_ID) {
const node = tree[parent];
if (!node) {
return parents;
}
parents.push(parent);
parent = node.parent;
}
return parents;
};
const getFilteredRowNodeSiblings = (tree, filteredRows, id) => {
const node = tree[id];
if (!node) {
return [];
}
const parent = node.parent;
if (parent == null) {
return [];
}
const parentNode = tree[parent];
return parentNode.children.filter(childId => childId !== id && filteredRows[childId] !== false);
};
export const findRowsToSelect = (apiRef, tree, selectedRow, autoSelectDescendants, autoSelectParents, addRow, rowSelectionManager = gridRowSelectionManagerSelector(apiRef)) => {
const filteredRows = gridFilteredRowsLookupSelector(apiRef);
const selectedDescendants = new Set([]);
if (!autoSelectDescendants && !autoSelectParents) {
return;
}
if (autoSelectDescendants) {
const rowNode = tree[selectedRow];
if (rowNode?.type === 'group') {
const descendants = getGridRowGroupSelectableDescendants(apiRef, selectedRow);
descendants.forEach(rowId => {
addRow(rowId);
selectedDescendants.add(rowId);
});
}
}
if (autoSelectParents) {
const checkAllDescendantsSelected = rowId => {
if (!rowSelectionManager.has(rowId) && !selectedDescendants.has(rowId)) {
return false;
}
const node = tree[rowId];
if (!node) {
return false;
}
if (node.type !== 'group') {
return true;
}
return node.children.every(checkAllDescendantsSelected);
};
const traverseParents = rowId => {
const siblings = getFilteredRowNodeSiblings(tree, filteredRows, rowId);
if (siblings.length === 0 || siblings.every(checkAllDescendantsSelected)) {
const rowNode = tree[rowId];
const parent = rowNode?.parent;
if (parent != null && parent !== GRID_ROOT_GROUP_ID && apiRef.current.isRowSelectable(parent)) {
addRow(parent);
selectedDescendants.add(parent);
traverseParents(parent);
}
}
};
traverseParents(selectedRow);
}
};
export const findRowsToDeselect = (apiRef, tree, deselectedRow, autoSelectDescendants, autoSelectParents, removeRow) => {
const rowSelectionManager = gridRowSelectionManagerSelector(apiRef);
if (!autoSelectParents && !autoSelectDescendants) {
return;
}
if (autoSelectParents) {
const allParents = getRowNodeParents(tree, deselectedRow);
allParents.forEach(parent => {
const isSelected = rowSelectionManager.has(parent);
if (isSelected) {
removeRow(parent);
}
});
}
if (autoSelectDescendants) {
const rowNode = tree[deselectedRow];
if (rowNode?.type === 'group') {
const descendants = getGridRowGroupSelectableDescendants(apiRef, deselectedRow);
descendants.forEach(descendant => {
removeRow(descendant);
});
}
}
};