UNPKG

rsuite

Version:

A suite of react components

166 lines 5.8 kB
'use client'; import isNil from 'lodash/isNil'; import { useCallback, useEffect, useRef, useState } from 'react'; import { KEY_VALUES } from "../../internals/constants/index.js"; import { useEventCallback, useCustom } from "../../internals/hooks/index.js"; import { onMenuKeyDown } from "../../internals/Picker/index.js"; import { useItemDataKeys, useRegisterTreeMethods } from "../../internals/Tree/TreeProvider.js"; import { isSearching, focusNextItem, getFocusableItems, getActiveItem, focusPreviousItem, focusFirstItem, focusLastItem, focusCurrentItem, focusTreeNode, handleLeftArrow, handleRightArrow } from "../utils/index.js"; import useTreeNodeRefs from "./useTreeNodeRefs.js"; /** * Custom hook that manages the focus behavior of a tree component. */ function useFocusTree(props) { const { filteredData, searchKeyword, flattenedNodes, expandItemValues, disabledItemValues, onExpand, onFocused } = props; const { rtl } = useCustom(); const { valueKey, childrenKey } = useItemDataKeys(); const { treeNodesRefs, saveTreeNodeRef } = useTreeNodeRefs(); const treeViewRef = useRef(null); const [focusItemValue, setFocusItemValue] = useState(null); const register = useRegisterTreeMethods(); const flattenedNodesRef = useRef(flattenedNodes); const getFocusProps = value => { const options = { disabledItemValues, valueKey, childrenKey, expandItemValues }; const focusableItems = getFocusableItems(filteredData, options, isSearching(searchKeyword)); return { focusItemValue: value || focusItemValue, valueKey, focusableItems, treeNodesRefs }; }; const handleFocusItem = useEventCallback(key => { const focusProps = getFocusProps(); let focusedValue = null; if (key === KEY_VALUES.DOWN) { focusedValue = focusNextItem(focusProps); } else if (key === KEY_VALUES.UP) { focusedValue = focusPreviousItem(focusProps); } if (focusedValue) { setFocusItemValue(focusedValue); onFocused === null || onFocused === void 0 || onFocused(focusedValue); } }); const handleLeftArrowEvent = useEventCallback(() => { if (isNil(focusItemValue)) { return; } const focusItem = getActiveItem(focusItemValue, flattenedNodes, valueKey); const expand = expandItemValues.includes(focusItem === null || focusItem === void 0 ? void 0 : focusItem[valueKey]); const onFocusItem = () => { var _focusItem$parent, _focusItem$parent2; const focusedValue = focusItem === null || focusItem === void 0 || (_focusItem$parent = focusItem.parent) === null || _focusItem$parent === void 0 ? void 0 : _focusItem$parent[valueKey]; setFocusItemValue(focusedValue); onFocused === null || onFocused === void 0 || onFocused(focusedValue); focusTreeNode(focusItem === null || focusItem === void 0 || (_focusItem$parent2 = focusItem.parent) === null || _focusItem$parent2 === void 0 ? void 0 : _focusItem$parent2.refKey, treeNodesRefs); }; handleLeftArrow({ focusItem, expand, onExpand, childrenKey, onFocusItem }); }); const handleRightArrowEvent = useEventCallback(() => { if (isNil(focusItemValue)) { return; } const focusItem = getActiveItem(focusItemValue, flattenedNodes, valueKey); const expand = expandItemValues.includes(focusItem === null || focusItem === void 0 ? void 0 : focusItem[valueKey]); const onFocusItem = () => handleFocusItem(KEY_VALUES.DOWN); handleRightArrow({ focusItem, expand, childrenKey, onExpand, onFocusItem }); }); const handleHomeKey = useEventCallback(() => { const focusProps = getFocusProps(); const focusedValue = focusFirstItem(focusProps); if (focusedValue) { setFocusItemValue(focusedValue); onFocused === null || onFocused === void 0 || onFocused(focusedValue); } }); const handleEndKey = useEventCallback(() => { const focusProps = getFocusProps(); const focusedValue = focusLastItem(focusProps); if (focusedValue) { setFocusItemValue(focusedValue); onFocused === null || onFocused === void 0 || onFocused(focusedValue); } }); const onTreeKeydown = useEventCallback(event => { onMenuKeyDown(event, { down: () => handleFocusItem(KEY_VALUES.DOWN), up: () => handleFocusItem(KEY_VALUES.UP), left: rtl ? handleRightArrowEvent : handleLeftArrowEvent, right: rtl ? handleLeftArrowEvent : handleRightArrowEvent, home: handleHomeKey, end: handleEndKey }); }); const focusTreeFirstNode = useEventCallback(() => { handleFocusItem(KEY_VALUES.DOWN); }); const focusTreeActiveNode = useCallback(() => { const refKey = focusCurrentItem({ container: treeViewRef.current }); if (refKey) { var _flattenedNodesRef$cu; const node = (_flattenedNodesRef$cu = flattenedNodesRef.current) === null || _flattenedNodesRef$cu === void 0 ? void 0 : _flattenedNodesRef$cu[refKey]; if (node) { setFocusItemValue(node[valueKey]); onFocused === null || onFocused === void 0 || onFocused(node[valueKey]); } } }, [onFocused, valueKey]); useEffect(() => { const unregister = register === null || register === void 0 ? void 0 : register({ focusTreeFirstNode, focusTreeActiveNode }); return () => { unregister === null || unregister === void 0 || unregister(); }; }, []); useEffect(() => { flattenedNodesRef.current = flattenedNodes; }, [flattenedNodes]); return { treeViewRef, focusTreeFirstNode, focusItemValue, treeNodesRefs, saveTreeNodeRef, setFocusItemValue, onTreeKeydown }; } export default useFocusTree;