@mui/x-tree-view
Version:
The community edition of the MUI X Tree View components.
342 lines (339 loc) • 13.4 kB
JavaScript
;
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useTreeViewItems = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
var _publishTreeViewEvent = require("../../utils/publishTreeViewEvent");
var _useTreeViewItems = require("./useTreeViewItems.utils");
var _TreeViewItemDepthContext = require("../../TreeViewItemDepthContext");
var _useTreeViewItems2 = require("./useTreeViewItems.selectors");
var _useTreeViewId = require("../../corePlugins/useTreeViewId/useTreeViewId.selectors");
var _useTreeViewId2 = require("../../corePlugins/useTreeViewId/useTreeViewId.utils");
var _jsxRuntime = require("react/jsx-runtime");
const checkId = (id, item, itemMetaLookup) => {
if (id == null) {
throw new Error(['MUI X: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', 'An item was provided without id in the `items` prop:', JSON.stringify(item)].join('\n'));
}
if (itemMetaLookup[id] != null) {
throw new Error(['MUI X: The Tree View component requires all items to have a unique `id` property.', 'Alternatively, you can use the `getItemId` prop to specify a custom id for each item.', `Two items were provided with the same id in the \`items\` prop: "${id}"`].join('\n'));
}
};
const processItemsLookups = ({
disabledItemsFocusable,
items,
isItemDisabled,
getItemLabel,
getItemChildren,
getItemId,
initialDepth = 0,
initialParentId = null,
getChildrenCount,
ignoreChildren = false
}) => {
const itemMetaLookup = {};
const itemModelLookup = {};
const itemOrderedChildrenIdsLookup = {
[_useTreeViewItems.TREE_VIEW_ROOT_PARENT_ID]: []
};
const processItem = (item, depth, parentId) => {
const id = getItemId ? getItemId(item) : item.id;
checkId(id, item, itemMetaLookup);
const label = getItemLabel ? getItemLabel(item) : item.label;
if (label == null) {
throw new Error(['MUI X: The Tree View component requires all items to have a `label` property.', 'Alternatively, you can use the `getItemLabel` prop to specify a custom label for each item.', 'An item was provided without label in the `items` prop:', JSON.stringify(item)].join('\n'));
}
const children = getItemChildren ? getItemChildren(item) : item.children;
itemMetaLookup[id] = {
id,
label,
parentId,
idAttribute: undefined,
expandable: getChildrenCount ? getChildrenCount(item) > 0 : !!children?.length,
disabled: isItemDisabled ? isItemDisabled(item) : false,
depth
};
itemModelLookup[id] = item;
const parentIdWithDefault = parentId ?? _useTreeViewItems.TREE_VIEW_ROOT_PARENT_ID;
if (!itemOrderedChildrenIdsLookup[parentIdWithDefault]) {
itemOrderedChildrenIdsLookup[parentIdWithDefault] = [];
}
itemOrderedChildrenIdsLookup[parentIdWithDefault].push(id);
// if lazy loading is enabled, we don't want to process children passed through the `items` prop
if (!ignoreChildren) {
children?.forEach(child => processItem(child, depth + 1, id));
}
};
items?.forEach(item => processItem(item, initialDepth, initialParentId));
const itemChildrenIndexesLookup = {};
Object.keys(itemOrderedChildrenIdsLookup).forEach(parentId => {
itemChildrenIndexesLookup[parentId] = (0, _useTreeViewItems.buildSiblingIndexes)(itemOrderedChildrenIdsLookup[parentId]);
});
return {
disabledItemsFocusable,
itemMetaLookup,
itemModelLookup,
itemOrderedChildrenIdsLookup,
itemChildrenIndexesLookup
};
};
const useTreeViewItems = ({
instance,
params,
store
}) => {
const getItem = React.useCallback(itemId => (0, _useTreeViewItems2.selectorItemModel)(store.value, itemId), [store]);
const getParentId = React.useCallback(itemId => {
const itemMeta = (0, _useTreeViewItems2.selectorItemMeta)(store.value, itemId);
return itemMeta?.parentId || null;
}, [store]);
const setTreeViewLoading = (0, _useEventCallback.default)(isLoading => {
store.update(prevState => (0, _extends2.default)({}, prevState, {
items: (0, _extends2.default)({}, prevState.items, {
loading: isLoading
})
}));
});
const setTreeViewError = (0, _useEventCallback.default)(error => {
store.update(prevState => (0, _extends2.default)({}, prevState, {
items: (0, _extends2.default)({}, prevState.items, {
error
})
}));
});
const setIsItemDisabled = (0, _useEventCallback.default)(({
itemId,
shouldBeDisabled
}) => {
store.update(prevState => {
if (!prevState.items.itemMetaLookup[itemId]) {
return prevState;
}
const itemMetaLookup = (0, _extends2.default)({}, prevState.items.itemMetaLookup);
itemMetaLookup[itemId] = (0, _extends2.default)({}, itemMetaLookup[itemId], {
disabled: shouldBeDisabled ?? !itemMetaLookup[itemId].disabled
});
return (0, _extends2.default)({}, prevState, {
items: (0, _extends2.default)({}, prevState.items, {
itemMetaLookup
})
});
});
});
const getItemTree = React.useCallback(() => {
const getItemFromItemId = itemId => {
const item = (0, _useTreeViewItems2.selectorItemModel)(store.value, itemId);
const newChildren = (0, _useTreeViewItems2.selectorItemOrderedChildrenIds)(store.value, itemId);
if (newChildren.length > 0) {
item.children = newChildren.map(getItemFromItemId);
} else {
delete item.children;
}
return item;
};
return (0, _useTreeViewItems2.selectorItemOrderedChildrenIds)(store.value, null).map(getItemFromItemId);
}, [store]);
const getItemOrderedChildrenIds = React.useCallback(itemId => (0, _useTreeViewItems2.selectorItemOrderedChildrenIds)(store.value, itemId), [store]);
const getItemDOMElement = itemId => {
const itemMeta = (0, _useTreeViewItems2.selectorItemMeta)(store.value, itemId);
if (itemMeta == null) {
return null;
}
const idAttribute = (0, _useTreeViewId2.generateTreeItemIdAttribute)({
treeId: (0, _useTreeViewId.selectorTreeViewId)(store.value),
itemId,
id: itemMeta.idAttribute
});
return document.getElementById(idAttribute);
};
const areItemUpdatesPreventedRef = React.useRef(false);
const preventItemUpdates = React.useCallback(() => {
areItemUpdatesPreventedRef.current = true;
}, []);
const areItemUpdatesPrevented = React.useCallback(() => areItemUpdatesPreventedRef.current, []);
const addItems = ({
items,
parentId,
depth,
getChildrenCount
}) => {
if (items) {
const newState = processItemsLookups({
disabledItemsFocusable: params.disabledItemsFocusable,
items,
isItemDisabled: params.isItemDisabled,
getItemId: params.getItemId,
getItemLabel: params.getItemLabel,
getItemChildren: params.getItemChildren,
getChildrenCount,
initialDepth: depth,
initialParentId: parentId,
ignoreChildren: true
});
store.update(prevState => {
let newItems;
if (parentId) {
newItems = {
itemModelLookup: (0, _extends2.default)({}, prevState.items.itemModelLookup, newState.itemModelLookup),
itemMetaLookup: (0, _extends2.default)({}, prevState.items.itemMetaLookup, newState.itemMetaLookup),
itemOrderedChildrenIdsLookup: (0, _extends2.default)({}, newState.itemOrderedChildrenIdsLookup, prevState.items.itemOrderedChildrenIdsLookup),
itemChildrenIndexesLookup: (0, _extends2.default)({}, newState.itemChildrenIndexesLookup, prevState.items.itemChildrenIndexesLookup)
};
} else {
newItems = {
itemModelLookup: newState.itemModelLookup,
itemMetaLookup: newState.itemMetaLookup,
itemOrderedChildrenIdsLookup: newState.itemOrderedChildrenIdsLookup,
itemChildrenIndexesLookup: newState.itemChildrenIndexesLookup
};
}
Object.values(prevState.items.itemMetaLookup).forEach(item => {
if (!newItems.itemMetaLookup[item.id]) {
(0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeItem', {
id: item.id
});
}
});
return (0, _extends2.default)({}, prevState, {
items: (0, _extends2.default)({}, prevState.items, newItems)
});
});
}
};
const removeChildren = parentId => {
store.update(prevState => {
if (!parentId) {
return (0, _extends2.default)({}, prevState, {
items: (0, _extends2.default)({}, prevState.items, {
itemMetaLookup: {},
itemOrderedChildrenIdsLookup: {},
itemChildrenIndexesLookup: {}
})
});
}
const newMetaMap = Object.keys(prevState.items.itemMetaLookup).reduce((acc, key) => {
const item = prevState.items.itemMetaLookup[key];
if (item.parentId === parentId) {
(0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeItem', {
id: item.id
});
return acc;
}
return (0, _extends2.default)({}, acc, {
[item.id]: item
});
}, {});
const newItemOrderedChildrenIdsLookup = prevState.items.itemOrderedChildrenIdsLookup;
const newItemChildrenIndexesLookup = prevState.items.itemChildrenIndexesLookup;
delete newItemChildrenIndexesLookup[parentId];
delete newItemOrderedChildrenIdsLookup[parentId];
return (0, _extends2.default)({}, prevState, {
items: (0, _extends2.default)({}, prevState.items, {
itemMetaLookup: newMetaMap,
itemOrderedChildrenIdsLookup: newItemOrderedChildrenIdsLookup,
itemChildrenIndexesLookup: newItemChildrenIndexesLookup
})
});
});
};
React.useEffect(() => {
if (instance.areItemUpdatesPrevented()) {
return;
}
store.update(prevState => {
const newState = processItemsLookups({
disabledItemsFocusable: params.disabledItemsFocusable,
items: params.items,
isItemDisabled: params.isItemDisabled,
getItemId: params.getItemId,
getItemLabel: params.getItemLabel,
getItemChildren: params.getItemChildren
});
Object.values(prevState.items.itemMetaLookup).forEach(item => {
if (!newState.itemMetaLookup[item.id]) {
(0, _publishTreeViewEvent.publishTreeViewEvent)(instance, 'removeItem', {
id: item.id
});
}
});
return (0, _extends2.default)({}, prevState, {
items: (0, _extends2.default)({}, prevState.items, newState)
});
});
}, [instance, store, params.items, params.disabledItemsFocusable, params.isItemDisabled, params.getItemId, params.getItemLabel, params.getItemChildren]);
// Wrap `props.onItemClick` with `useEventCallback` to prevent unneeded context updates.
const handleItemClick = (0, _useEventCallback.default)((event, itemId) => {
if (params.onItemClick) {
params.onItemClick(event, itemId);
}
});
return {
getRootProps: () => ({
style: {
'--TreeView-itemChildrenIndentation': typeof params.itemChildrenIndentation === 'number' ? `${params.itemChildrenIndentation}px` : params.itemChildrenIndentation
}
}),
publicAPI: {
getItem,
getItemDOMElement,
getItemTree,
getItemOrderedChildrenIds,
setIsItemDisabled,
getParentId
},
instance: {
getItemDOMElement,
preventItemUpdates,
areItemUpdatesPrevented,
addItems,
setTreeViewLoading,
setTreeViewError,
removeChildren,
handleItemClick
}
};
};
exports.useTreeViewItems = useTreeViewItems;
useTreeViewItems.getInitialState = params => ({
items: (0, _extends2.default)({}, processItemsLookups({
disabledItemsFocusable: params.disabledItemsFocusable,
items: params.items,
isItemDisabled: params.isItemDisabled,
getItemId: params.getItemId,
getItemLabel: params.getItemLabel,
getItemChildren: params.getItemChildren
}), {
loading: false,
error: null
})
});
useTreeViewItems.applyDefaultValuesToParams = ({
params
}) => (0, _extends2.default)({}, params, {
disabledItemsFocusable: params.disabledItemsFocusable ?? false,
itemChildrenIndentation: params.itemChildrenIndentation ?? '12px'
});
useTreeViewItems.wrapRoot = ({
children
}) => {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeViewItemDepthContext.TreeViewItemDepthContext.Provider, {
value: _useTreeViewItems2.selectorItemDepth,
children: children
});
};
if (process.env.NODE_ENV !== "production") useTreeViewItems.wrapRoot.displayName = "useTreeViewItems.wrapRoot";
useTreeViewItems.params = {
disabledItemsFocusable: true,
items: true,
isItemDisabled: true,
getItemLabel: true,
getItemChildren: true,
getItemId: true,
onItemClick: true,
itemChildrenIndentation: true
};