UNPKG

@mui/x-tree-view

Version:

The community edition of the MUI X Tree View components.

223 lines (221 loc) 8.42 kB
'use client'; import _extends from "@babel/runtime/helpers/esm/extends"; import * as React from 'react'; import { useStableCallback } from '@base-ui/utils/useStableCallback'; import { buildItemsLookups, buildItemsState, TREE_VIEW_ROOT_PARENT_ID } from "./useTreeViewItems.utils.js"; import { TreeViewItemDepthContext } from "../../TreeViewItemDepthContext/index.js"; import { itemsSelectors } from "./useTreeViewItems.selectors.js"; import { idSelectors } from "../../corePlugins/useTreeViewId/index.js"; import { generateTreeItemIdAttribute } from "../../corePlugins/useTreeViewId/useTreeViewId.utils.js"; import { jsx as _jsx } from "react/jsx-runtime"; const defaultIsItemSelectionDisabled = item => item.disableSelection === true; export const useTreeViewItems = ({ instance, params, store }) => { const itemsConfig = React.useMemo(() => ({ isItemDisabled: params.isItemDisabled, isItemSelectionDisabled: params.isItemSelectionDisabled, getItemLabel: params.getItemLabel, getItemChildren: params.getItemChildren, getItemId: params.getItemId }), [params.isItemDisabled, params.isItemSelectionDisabled, params.getItemLabel, params.getItemChildren, params.getItemId]); const getItem = React.useCallback(itemId => itemsSelectors.itemModel(store.state, itemId), [store]); const getParentId = React.useCallback(itemId => { const itemMeta = itemsSelectors.itemMeta(store.state, itemId); return itemMeta?.parentId || null; }, [store]); const setIsItemDisabled = useStableCallback(({ itemId, shouldBeDisabled }) => { if (!store.state.items.itemMetaLookup[itemId]) { return; } const itemMetaLookup = _extends({}, store.state.items.itemMetaLookup); itemMetaLookup[itemId] = _extends({}, itemMetaLookup[itemId], { disabled: shouldBeDisabled ?? !itemMetaLookup[itemId].disabled }); store.set('items', _extends({}, store.state.items, { itemMetaLookup })); }); const getItemTree = React.useCallback(() => { const getItemFromItemId = itemId => { const item = itemsSelectors.itemModel(store.state, itemId); const itemToMutate = _extends({}, item); const newChildren = itemsSelectors.itemOrderedChildrenIds(store.state, itemId); if (newChildren.length > 0) { itemToMutate.children = newChildren.map(getItemFromItemId); } else { delete itemToMutate.children; } return itemToMutate; }; return itemsSelectors.itemOrderedChildrenIds(store.state, null).map(getItemFromItemId); }, [store]); const getItemOrderedChildrenIds = React.useCallback(itemId => itemsSelectors.itemOrderedChildrenIds(store.state, itemId), [store]); const getItemDOMElement = itemId => { const itemMeta = itemsSelectors.itemMeta(store.state, itemId); if (itemMeta == null) { return null; } const idAttribute = generateTreeItemIdAttribute({ treeId: idSelectors.treeId(store.state), 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 setItemChildren = ({ items, parentId, getChildrenCount }) => { const parentIdWithDefault = parentId ?? TREE_VIEW_ROOT_PARENT_ID; const parentDepth = parentId == null ? -1 : itemsSelectors.itemDepth(store.state, parentId); const { metaLookup, modelLookup, orderedChildrenIds, childrenIndexes } = buildItemsLookups({ config: itemsConfig, items, parentId, depth: parentDepth + 1, isItemExpandable: getChildrenCount ? item => getChildrenCount(item) > 0 : () => false, otherItemsMetaLookup: itemsSelectors.itemMetaLookup(store.state) }); const lookups = { itemModelLookup: _extends({}, store.state.items.itemModelLookup, modelLookup), itemMetaLookup: _extends({}, store.state.items.itemMetaLookup, metaLookup), itemOrderedChildrenIdsLookup: _extends({}, store.state.items.itemOrderedChildrenIdsLookup, { [parentIdWithDefault]: orderedChildrenIds }), itemChildrenIndexesLookup: _extends({}, store.state.items.itemChildrenIndexesLookup, { [parentIdWithDefault]: childrenIndexes }) }; store.set('items', _extends({}, store.state.items, lookups)); }; const removeChildren = useStableCallback(parentId => { const newMetaMap = Object.keys(store.state.items.itemMetaLookup).reduce((acc, key) => { const item = store.state.items.itemMetaLookup[key]; if (item.parentId === parentId) { return acc; } return _extends({}, acc, { [item.id]: item }); }, {}); const newItemOrderedChildrenIdsLookup = _extends({}, store.state.items.itemOrderedChildrenIdsLookup); const newItemChildrenIndexesLookup = _extends({}, store.state.items.itemChildrenIndexesLookup); const cleanId = parentId ?? TREE_VIEW_ROOT_PARENT_ID; delete newItemChildrenIndexesLookup[cleanId]; delete newItemOrderedChildrenIdsLookup[cleanId]; store.set('items', _extends({}, store.state.items, { itemMetaLookup: newMetaMap, itemOrderedChildrenIdsLookup: newItemOrderedChildrenIdsLookup, itemChildrenIndexesLookup: newItemChildrenIndexesLookup })); }); const addExpandableItems = useStableCallback(items => { const newItemMetaLookup = _extends({}, store.state.items.itemMetaLookup); for (const itemId of items) { newItemMetaLookup[itemId] = _extends({}, newItemMetaLookup[itemId], { expandable: true }); } store.set('items', _extends({}, store.state.items, { itemMetaLookup: newItemMetaLookup })); }); React.useEffect(() => { if (instance.areItemUpdatesPrevented()) { return; } const newState = buildItemsState({ disabledItemsFocusable: params.disabledItemsFocusable, items: params.items, config: itemsConfig }); store.set('items', _extends({}, store.state.items, newState)); }, [instance, store, params.items, params.disabledItemsFocusable, itemsConfig]); // Wrap `props.onItemClick` with `useStableCallback` to prevent unneeded context updates. const handleItemClick = useStableCallback((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, setItemChildren, removeChildren, addExpandableItems, handleItemClick } }; }; useTreeViewItems.getInitialState = params => ({ items: buildItemsState({ items: params.items, disabledItemsFocusable: params.disabledItemsFocusable, config: { isItemDisabled: params.isItemDisabled, isItemSelectionDisabled: params.isItemSelectionDisabled, getItemId: params.getItemId, getItemLabel: params.getItemLabel, getItemChildren: params.getItemChildren } }) }); useTreeViewItems.applyDefaultValuesToParams = ({ params }) => _extends({}, params, { disabledItemsFocusable: params.disabledItemsFocusable ?? false, itemChildrenIndentation: params.itemChildrenIndentation ?? '12px', isItemSelectionDisabled: params.isItemSelectionDisabled ?? defaultIsItemSelectionDisabled }); useTreeViewItems.wrapRoot = ({ children }) => { return /*#__PURE__*/_jsx(TreeViewItemDepthContext.Provider, { value: itemsSelectors.itemDepth, children: children }); }; if (process.env.NODE_ENV !== "production") useTreeViewItems.wrapRoot.displayName = "useTreeViewItems.wrapRoot"; useTreeViewItems.params = { disabledItemsFocusable: true, items: true, isItemDisabled: true, isItemSelectionDisabled: true, getItemLabel: true, getItemChildren: true, getItemId: true, onItemClick: true, itemChildrenIndentation: true };