import { nextTypeAheadElement } from '../utils/nextTypeAheadElement'; import { treeDataTypes } from '../utils/tokens'; import { useRovingTabIndex } from './useRovingTabIndexes'; import * as React from 'react'; import { useHTMLElementWalkerRef } from './useHTMLElementWalkerRef'; import { useMergedRefs } from '@fluentui/react-utilities'; /** * @internal */ export function useTreeNavigation() { 'use no memo'; const { rove, initialize: initializeRovingTabIndex } = useRovingTabIndex(); const { walkerRef, rootRef: walkerRootRef } = useHTMLElementWalkerRef(); const rootRefCallback = React.useCallback((root)=>{ if (root && walkerRef.current) { initializeRovingTabIndex(walkerRef.current); } }, [ walkerRef, initializeRovingTabIndex ]); const getNextElement = (data)=>{ if (!walkerRef.current) { return null; } switch(data.type){ case treeDataTypes.Click: return data.target; case treeDataTypes.TypeAhead: walkerRef.current.currentElement = data.target; return nextTypeAheadElement(walkerRef.current, data.event.key); case treeDataTypes.ArrowLeft: walkerRef.current.currentElement = data.target; return walkerRef.current.parentElement(); case treeDataTypes.ArrowRight: walkerRef.current.currentElement = data.target; return walkerRef.current.firstChild(); case treeDataTypes.End: walkerRef.current.currentElement = walkerRef.current.root; return lastChildRecursive(walkerRef.current); case treeDataTypes.Home: walkerRef.current.currentElement = walkerRef.current.root; return walkerRef.current.firstChild(); case treeDataTypes.ArrowDown: walkerRef.current.currentElement = data.target; return walkerRef.current.nextElement(); case treeDataTypes.ArrowUp: walkerRef.current.currentElement = data.target; return walkerRef.current.previousElement(); } }; function navigate(data, focusOptions) { const nextElement = getNextElement(data); if (nextElement) { rove(nextElement, focusOptions); } } return { navigate, treeRef: useMergedRefs(walkerRootRef, rootRefCallback) }; } function lastChildRecursive(walker) { let lastElement = null; let nextElement = null; while(nextElement = walker.lastChild()){ lastElement = nextElement; } return lastElement; }