@mui/x-tree-view
Version:
The community edition of the MUI X Tree View components.
239 lines (236 loc) • 10.2 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.useTreeViewSelection = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _useAssertModelConsistency = require("@mui/x-internals/useAssertModelConsistency");
var _useIsoLayoutEffect = require("@base-ui-components/utils/useIsoLayoutEffect");
var _tree = require("../../utils/tree");
var _useTreeViewSelection = require("./useTreeViewSelection.utils");
var _useTreeViewSelection2 = require("./useTreeViewSelection.selectors");
var _useTreeViewSelection3 = require("./useTreeViewSelection.itemPlugin");
const useTreeViewSelection = ({
store,
params
}) => {
(0, _useAssertModelConsistency.useAssertModelConsistency)({
componentName: 'Tree View',
propName: 'selectedItems',
controlled: params.selectedItems,
defaultValue: params.defaultSelectedItems
});
const lastSelectedItem = React.useRef(null);
const lastSelectedRange = React.useRef({});
const setSelectedItems = (event, newModel, additionalItemsToPropagate) => {
const oldModel = _useTreeViewSelection2.selectionSelectors.selectedItemsRaw(store.state);
let cleanModel;
const isMultiSelectEnabled = _useTreeViewSelection2.selectionSelectors.isMultiSelectEnabled(store.state);
if (isMultiSelectEnabled && (params.selectionPropagation.descendants || params.selectionPropagation.parents)) {
cleanModel = (0, _useTreeViewSelection.propagateSelection)({
store,
selectionPropagation: params.selectionPropagation,
newModel: newModel,
oldModel: oldModel,
additionalItemsToPropagate
});
} else {
cleanModel = newModel;
}
if (params.onItemSelectionToggle) {
if (isMultiSelectEnabled) {
const changes = (0, _useTreeViewSelection.getAddedAndRemovedItems)({
store,
newModel: cleanModel,
oldModel: oldModel
});
if (params.onItemSelectionToggle) {
changes.added.forEach(itemId => {
params.onItemSelectionToggle(event, itemId, true);
});
changes.removed.forEach(itemId => {
params.onItemSelectionToggle(event, itemId, false);
});
}
} else if (params.onItemSelectionToggle && cleanModel !== oldModel) {
if (oldModel != null) {
params.onItemSelectionToggle(event, oldModel, false);
}
if (cleanModel != null) {
params.onItemSelectionToggle(event, cleanModel, true);
}
}
}
if (params.selectedItems === undefined) {
store.set('selection', (0, _extends2.default)({}, store.state.selection, {
selectedItems: cleanModel
}));
}
params.onSelectedItemsChange?.(event, cleanModel);
};
const setItemSelection = ({
itemId,
event = null,
keepExistingSelection = false,
shouldBeSelected
}) => {
if (!_useTreeViewSelection2.selectionSelectors.enabled(store.state)) {
return;
}
let newSelected;
const isMultiSelectEnabled = _useTreeViewSelection2.selectionSelectors.isMultiSelectEnabled(store.state);
if (keepExistingSelection) {
const oldSelected = _useTreeViewSelection2.selectionSelectors.selectedItems(store.state);
const isSelectedBefore = _useTreeViewSelection2.selectionSelectors.isItemSelected(store.state, itemId);
if (isSelectedBefore && (shouldBeSelected === false || shouldBeSelected == null)) {
newSelected = oldSelected.filter(id => id !== itemId);
} else if (!isSelectedBefore && (shouldBeSelected === true || shouldBeSelected == null)) {
newSelected = [itemId].concat(oldSelected);
} else {
newSelected = oldSelected;
}
} else {
// eslint-disable-next-line no-lonely-if
if (shouldBeSelected === false || shouldBeSelected == null && _useTreeViewSelection2.selectionSelectors.isItemSelected(store.state, itemId)) {
newSelected = isMultiSelectEnabled ? [] : null;
} else {
newSelected = isMultiSelectEnabled ? [itemId] : itemId;
}
}
setSelectedItems(event, newSelected,
// If shouldBeSelected === selectionSelectors.isItemSelected(store, itemId), we still want to propagate the select.
// This is useful when the element is in an indeterminate state.
[itemId]);
lastSelectedItem.current = itemId;
lastSelectedRange.current = {};
};
const selectRange = (event, [start, end]) => {
const isMultiSelectEnabled = _useTreeViewSelection2.selectionSelectors.isMultiSelectEnabled(store.state);
if (!isMultiSelectEnabled) {
return;
}
let newSelectedItems = _useTreeViewSelection2.selectionSelectors.selectedItems(store.state).slice();
// If the last selection was a range selection,
// remove the items that were part of the last range from the model
if (Object.keys(lastSelectedRange.current).length > 0) {
newSelectedItems = newSelectedItems.filter(id => !lastSelectedRange.current[id]);
}
// Add to the model the items that are part of the new range and not already part of the model.
const selectedItemsLookup = (0, _useTreeViewSelection.getLookupFromArray)(newSelectedItems);
const range = (0, _tree.getNonDisabledItemsInRange)(store.state, start, end);
const itemsToAddToModel = range.filter(id => !selectedItemsLookup[id]);
newSelectedItems = newSelectedItems.concat(itemsToAddToModel);
setSelectedItems(event, newSelectedItems);
lastSelectedRange.current = (0, _useTreeViewSelection.getLookupFromArray)(range);
};
const expandSelectionRange = (event, itemId) => {
if (lastSelectedItem.current != null) {
const [start, end] = (0, _tree.findOrderInTremauxTree)(store.state, itemId, lastSelectedItem.current);
selectRange(event, [start, end]);
}
};
const selectRangeFromStartToItem = (event, itemId) => {
selectRange(event, [(0, _tree.getFirstNavigableItem)(store.state), itemId]);
};
const selectRangeFromItemToEnd = (event, itemId) => {
selectRange(event, [itemId, (0, _tree.getLastNavigableItem)(store.state)]);
};
const selectAllNavigableItems = event => {
const isMultiSelectEnabled = _useTreeViewSelection2.selectionSelectors.isMultiSelectEnabled(store.state);
if (!isMultiSelectEnabled) {
return;
}
const navigableItems = (0, _tree.getAllNavigableItems)(store.state);
setSelectedItems(event, navigableItems);
lastSelectedRange.current = (0, _useTreeViewSelection.getLookupFromArray)(navigableItems);
};
const selectItemFromArrowNavigation = (event, currentItem, nextItem) => {
const isMultiSelectEnabled = _useTreeViewSelection2.selectionSelectors.isMultiSelectEnabled(store.state);
if (!isMultiSelectEnabled) {
return;
}
let newSelectedItems = _useTreeViewSelection2.selectionSelectors.selectedItems(store.state).slice();
if (Object.keys(lastSelectedRange.current).length === 0) {
newSelectedItems.push(nextItem);
lastSelectedRange.current = {
[currentItem]: true,
[nextItem]: true
};
} else {
if (!lastSelectedRange.current[currentItem]) {
lastSelectedRange.current = {};
}
if (lastSelectedRange.current[nextItem]) {
newSelectedItems = newSelectedItems.filter(id => id !== currentItem);
delete lastSelectedRange.current[currentItem];
} else {
newSelectedItems.push(nextItem);
lastSelectedRange.current[nextItem] = true;
}
}
setSelectedItems(event, newSelectedItems);
};
(0, _useIsoLayoutEffect.useIsoLayoutEffect)(() => {
store.set('selection', {
selectedItems: params.selectedItems === undefined ? store.state.selection.selectedItems : params.selectedItems,
isEnabled: !params.disableSelection,
isMultiSelectEnabled: params.multiSelect,
isCheckboxSelectionEnabled: params.checkboxSelection,
selectionPropagation: {
descendants: params.selectionPropagation.descendants,
parents: params.selectionPropagation.parents
}
});
}, [store, params.selectedItems, params.multiSelect, params.checkboxSelection, params.disableSelection, params.selectionPropagation.descendants, params.selectionPropagation.parents]);
return {
getRootProps: () => ({
'aria-multiselectable': params.multiSelect
}),
publicAPI: {
setItemSelection
},
instance: {
setItemSelection,
selectAllNavigableItems,
expandSelectionRange,
selectRangeFromStartToItem,
selectRangeFromItemToEnd,
selectItemFromArrowNavigation
}
};
};
exports.useTreeViewSelection = useTreeViewSelection;
useTreeViewSelection.itemPlugin = _useTreeViewSelection3.useTreeViewSelectionItemPlugin;
const DEFAULT_SELECTED_ITEMS = [];
const EMPTY_SELECTION_PROPAGATION = {};
useTreeViewSelection.applyDefaultValuesToParams = ({
params
}) => (0, _extends2.default)({}, params, {
disableSelection: params.disableSelection ?? false,
multiSelect: params.multiSelect ?? false,
checkboxSelection: params.checkboxSelection ?? false,
defaultSelectedItems: params.defaultSelectedItems ?? (params.multiSelect ? DEFAULT_SELECTED_ITEMS : null),
selectionPropagation: params.selectionPropagation ?? EMPTY_SELECTION_PROPAGATION
});
useTreeViewSelection.getInitialState = params => ({
selection: {
selectedItems: params.selectedItems === undefined ? params.defaultSelectedItems : params.selectedItems,
isEnabled: !params.disableSelection,
isMultiSelectEnabled: params.multiSelect,
isCheckboxSelectionEnabled: params.checkboxSelection,
selectionPropagation: params.selectionPropagation
}
});
useTreeViewSelection.params = {
disableSelection: true,
multiSelect: true,
checkboxSelection: true,
defaultSelectedItems: true,
selectedItems: true,
onSelectedItemsChange: true,
onItemSelectionToggle: true,
selectionPropagation: true
};