@mui/x-tree-view
Version:
The community edition of the MUI X Tree View components.
231 lines (219 loc) • 8.96 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TreeViewItemsPlugin = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _id = require("../id");
var _selectors = require("./selectors");
var _utils = require("./utils");
class TreeViewItemsPlugin {
// We can't type `store`, otherwise we get the following TS error:
// 'items' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
constructor(store) {
this.store = store;
}
/**
* Determines if the items state should be rebuilt based on the new and previous parameters.
*/
static shouldRebuildItemsState = (newParameters, previousParameters) => {
return ['items', 'isItemDisabled', 'isItemSelectionDisabled', 'getItemId', 'getItemLabel', 'getItemChildren'].some(key => {
const typedKey = key;
return newParameters[typedKey] !== previousParameters[typedKey];
});
};
/**
* Builds the state properties derived from the `items` prop.
*/
static buildItemsStateIfNeeded = parameters => {
const itemMetaLookup = {};
const itemModelLookup = {};
const itemOrderedChildrenIdsLookup = {};
const itemChildrenIndexesLookup = {};
function processSiblings(items, parentId, depth) {
const parentIdWithDefault = parentId ?? _utils.TREE_VIEW_ROOT_PARENT_ID;
const {
metaLookup,
modelLookup,
orderedChildrenIds,
childrenIndexes,
itemsChildren
} = (0, _utils.buildItemsLookups)({
storeParameters: parameters,
items,
parentId,
depth,
isItemExpandable: (item, children) => !!children && children.length > 0,
otherItemsMetaLookup: itemMetaLookup
});
Object.assign(itemMetaLookup, metaLookup);
Object.assign(itemModelLookup, modelLookup);
itemOrderedChildrenIdsLookup[parentIdWithDefault] = orderedChildrenIds;
itemChildrenIndexesLookup[parentIdWithDefault] = childrenIndexes;
for (const item of itemsChildren) {
processSiblings(item.children || [], item.id, depth + 1);
}
}
processSiblings(parameters.items, null, 0);
return {
itemMetaLookup,
itemModelLookup,
itemOrderedChildrenIdsLookup,
itemChildrenIndexesLookup
};
};
/**
* Get the item with the given id.
* When used in the Simple Tree View, it returns an object with the `id` and `label` properties.
* @param {TreeViewItemId} itemId The id of the item to retrieve.
* @returns {R} The item with the given id.
*/
getItem = itemId => _selectors.itemsSelectors.itemModel(this.store.state, itemId);
/**
* Get all the items in the same format as provided by `props.items`.
* @returns {R[]} The items in the tree.
*/
getItemTree = () => {
const getItemFromItemId = itemId => {
const item = _selectors.itemsSelectors.itemModel(this.store.state, itemId);
const itemToMutate = (0, _extends2.default)({}, item);
const newChildren = _selectors.itemsSelectors.itemOrderedChildrenIds(this.store.state, itemId);
if (newChildren.length > 0) {
itemToMutate.children = newChildren.map(getItemFromItemId);
} else {
delete itemToMutate.children;
}
return itemToMutate;
};
return _selectors.itemsSelectors.itemOrderedChildrenIds(this.store.state, null).map(getItemFromItemId);
};
/**
* Get the ids of a given item's children.
* Those ids are returned in the order they should be rendered.
* To get the root items, pass `null` as the `itemId`.
* @param {TreeViewItemId | null} itemId The id of the item to get the children of.
* @returns {TreeViewItemId[]} The ids of the item's children.
*/
getItemOrderedChildrenIds = itemId => _selectors.itemsSelectors.itemOrderedChildrenIds(this.store.state, itemId);
/** * Get the id of the parent item.
* @param {TreeViewItemId} itemId The id of the item to whose parentId we want to retrieve.
* @returns {TreeViewItemId | null} The id of the parent item.
*/
getParentId = itemId => {
const itemMeta = _selectors.itemsSelectors.itemMeta(this.store.state, itemId);
return itemMeta?.parentId || null;
};
/**
* Toggle the disabled state of the item with the given id.
* @param {object} parameters The params of the method.
* @param {TreeViewItemId } parameters.itemId The id of the item to get the children of.
* @param {boolean } parameters.shouldBeDisabled true if the item should be disabled.
*/
setIsItemDisabled = ({
itemId,
shouldBeDisabled
}) => {
if (!this.store.state.itemMetaLookup[itemId]) {
return;
}
const itemMetaLookup = (0, _extends2.default)({}, this.store.state.itemMetaLookup);
itemMetaLookup[itemId] = (0, _extends2.default)({}, itemMetaLookup[itemId], {
disabled: shouldBeDisabled ?? !itemMetaLookup[itemId].disabled
});
this.store.set('itemMetaLookup', itemMetaLookup);
};
buildPublicAPI = () => {
return {
getItem: this.getItem,
getItemDOMElement: this.getItemDOMElement,
getItemOrderedChildrenIds: this.getItemOrderedChildrenIds,
getItemTree: this.getItemTree,
getParentId: this.getParentId,
setIsItemDisabled: this.setIsItemDisabled
};
};
/**
* Get the DOM element of the item with the given id.
* @param {TreeViewItemId} itemId The id of the item to get the DOM element of.
* @returns {HTMLElement | null} The DOM element of the item with the given id.
*/
getItemDOMElement = itemId => {
const itemMeta = _selectors.itemsSelectors.itemMeta(this.store.state, itemId);
if (itemMeta == null) {
return null;
}
const idAttribute = _id.idSelectors.treeItemIdAttribute(this.store.state, itemId, itemMeta.idAttribute);
return document.getElementById(idAttribute);
};
/**
* Add an array of items to the tree.
* @param {SetItemChildrenParameters<R>} args The items to add to the tree and information about their ancestors.
*/
setItemChildren = ({
items,
parentId,
getChildrenCount
}) => {
const parentIdWithDefault = parentId ?? _utils.TREE_VIEW_ROOT_PARENT_ID;
const parentDepth = parentId == null ? -1 : _selectors.itemsSelectors.itemDepth(this.store.state, parentId);
const {
metaLookup,
modelLookup,
orderedChildrenIds,
childrenIndexes
} = (0, _utils.buildItemsLookups)({
storeParameters: this.store.parameters,
items,
parentId,
depth: parentDepth + 1,
isItemExpandable: getChildrenCount ? item => getChildrenCount(item) !== 0 : () => false,
otherItemsMetaLookup: _selectors.itemsSelectors.itemMetaLookup(this.store.state)
});
this.store.update({
itemModelLookup: (0, _extends2.default)({}, this.store.state.itemModelLookup, modelLookup),
itemMetaLookup: (0, _extends2.default)({}, this.store.state.itemMetaLookup, metaLookup),
itemOrderedChildrenIdsLookup: (0, _extends2.default)({}, this.store.state.itemOrderedChildrenIdsLookup, {
[parentIdWithDefault]: orderedChildrenIds
}),
itemChildrenIndexesLookup: (0, _extends2.default)({}, this.store.state.itemChildrenIndexesLookup, {
[parentIdWithDefault]: childrenIndexes
})
});
};
/**
* Remove the children of an item.
* @param {TreeViewItemId | null} parentId The id of the item to remove the children of.
*/
removeChildren = parentId => {
const itemMetaLookup = this.store.state.itemMetaLookup;
const newMetaMap = Object.keys(itemMetaLookup).reduce((acc, key) => {
const item = itemMetaLookup[key];
if (item.parentId === parentId) {
return acc;
}
return (0, _extends2.default)({}, acc, {
[item.id]: item
});
}, {});
const newItemOrderedChildrenIdsLookup = (0, _extends2.default)({}, this.store.state.itemOrderedChildrenIdsLookup);
const newItemChildrenIndexesLookup = (0, _extends2.default)({}, this.store.state.itemChildrenIndexesLookup);
const cleanId = parentId ?? _utils.TREE_VIEW_ROOT_PARENT_ID;
delete newItemChildrenIndexesLookup[cleanId];
delete newItemOrderedChildrenIdsLookup[cleanId];
this.store.update({
itemMetaLookup: newMetaMap,
itemOrderedChildrenIdsLookup: newItemOrderedChildrenIdsLookup,
itemChildrenIndexesLookup: newItemChildrenIndexesLookup
});
};
/**
* Callback fired when the `content` slot of a given Tree Item is clicked.
* @param {React.MouseEvent} event The DOM event that triggered the change.
* @param {TreeViewItemId} itemId The id of the item being clicked.
*/
handleItemClick = (event, itemId) => {
this.store.parameters.onItemClick?.(event, itemId);
};
}
exports.TreeViewItemsPlugin = TreeViewItemsPlugin;