@mui/x-tree-view
Version:
The community edition of the MUI X Tree View components.
108 lines (107 loc) • 3.47 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import useEventCallback from '@mui/utils/useEventCallback';
import { useInstanceEventHandler } from "../../hooks/useInstanceEventHandler.js";
import { selectorDefaultFocusableItemId, selectorFocusedItemId } from "./useTreeViewFocus.selectors.js";
import { selectorIsItemExpanded } from "../useTreeViewExpansion/useTreeViewExpansion.selectors.js";
import { selectorItemMeta } from "../useTreeViewItems/useTreeViewItems.selectors.js";
export const useTreeViewFocus = ({
instance,
params,
store
}) => {
const setFocusedItemId = useEventCallback(itemId => {
store.update(prevState => {
const focusedItemId = selectorFocusedItemId(prevState);
if (focusedItemId === itemId) {
return prevState;
}
return _extends({}, prevState, {
focus: _extends({}, prevState.focus, {
focusedItemId: itemId
})
});
});
});
const isItemVisible = itemId => {
const itemMeta = selectorItemMeta(store.value, itemId);
return itemMeta && (itemMeta.parentId == null || selectorIsItemExpanded(store.value, itemMeta.parentId));
};
const innerFocusItem = (event, itemId) => {
const itemElement = instance.getItemDOMElement(itemId);
if (itemElement) {
itemElement.focus();
}
setFocusedItemId(itemId);
if (params.onItemFocus) {
params.onItemFocus(event, itemId);
}
};
const focusItem = useEventCallback((event, itemId) => {
// If we receive an itemId, and it is visible, the focus will be set to it
if (isItemVisible(itemId)) {
innerFocusItem(event, itemId);
}
});
const removeFocusedItem = useEventCallback(() => {
const focusedItemId = selectorFocusedItemId(store.value);
if (focusedItemId == null) {
return;
}
const itemMeta = selectorItemMeta(store.value, focusedItemId);
if (itemMeta) {
const itemElement = instance.getItemDOMElement(focusedItemId);
if (itemElement) {
itemElement.blur();
}
}
setFocusedItemId(null);
});
useInstanceEventHandler(instance, 'removeItem', ({
id
}) => {
const focusedItemId = selectorFocusedItemId(store.value);
const defaultFocusableItemId = selectorDefaultFocusableItemId(store.value);
if (focusedItemId === id && defaultFocusableItemId != null) {
innerFocusItem(null, defaultFocusableItemId);
}
});
const createRootHandleFocus = otherHandlers => event => {
otherHandlers.onFocus?.(event);
if (event.defaultMuiPrevented) {
return;
}
// if the event bubbled (which is React specific) we don't want to steal focus
const defaultFocusableItemId = selectorDefaultFocusableItemId(store.value);
if (event.target === event.currentTarget && defaultFocusableItemId != null) {
innerFocusItem(event, defaultFocusableItemId);
}
};
const createRootHandleBlur = otherHandlers => event => {
otherHandlers.onBlur?.(event);
if (event.defaultMuiPrevented) {
return;
}
setFocusedItemId(null);
};
return {
getRootProps: otherHandlers => ({
onFocus: createRootHandleFocus(otherHandlers),
onBlur: createRootHandleBlur(otherHandlers)
}),
publicAPI: {
focusItem
},
instance: {
focusItem,
removeFocusedItem
}
};
};
useTreeViewFocus.getInitialState = () => ({
focus: {
focusedItemId: null
}
});
useTreeViewFocus.params = {
onItemFocus: true
};