81 lines
2.9 KiB
JavaScript
81 lines
2.9 KiB
JavaScript
import * as React from 'react';
|
|
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
|
|
import { isHTMLElement } from '@fluentui/react-utilities';
|
|
export function useOptionWalker(options) {
|
|
const { matchOption } = options;
|
|
const { targetDocument } = useFluent();
|
|
const treeWalkerRef = React.useRef(null);
|
|
const listboxRef = React.useRef(null);
|
|
const optionFilter = React.useCallback((node)=>{
|
|
if (isHTMLElement(node) && matchOption(node)) {
|
|
return NodeFilter.FILTER_ACCEPT;
|
|
}
|
|
return NodeFilter.FILTER_SKIP;
|
|
}, [
|
|
matchOption
|
|
]);
|
|
const setListbox = React.useCallback((el)=>{
|
|
if (el && targetDocument) {
|
|
listboxRef.current = el;
|
|
treeWalkerRef.current = targetDocument.createTreeWalker(el, NodeFilter.SHOW_ELEMENT, optionFilter);
|
|
} else {
|
|
listboxRef.current = null;
|
|
}
|
|
}, [
|
|
targetDocument,
|
|
optionFilter
|
|
]);
|
|
const optionWalker = React.useMemo(()=>({
|
|
first: ()=>{
|
|
if (!treeWalkerRef.current || !listboxRef.current) {
|
|
return null;
|
|
}
|
|
treeWalkerRef.current.currentNode = listboxRef.current;
|
|
return treeWalkerRef.current.firstChild();
|
|
},
|
|
last: ()=>{
|
|
if (!treeWalkerRef.current || !listboxRef.current) {
|
|
return null;
|
|
}
|
|
treeWalkerRef.current.currentNode = listboxRef.current;
|
|
return treeWalkerRef.current.lastChild();
|
|
},
|
|
next: ()=>{
|
|
if (!treeWalkerRef.current) {
|
|
return null;
|
|
}
|
|
return treeWalkerRef.current.nextNode();
|
|
},
|
|
prev: ()=>{
|
|
if (!treeWalkerRef.current) {
|
|
return null;
|
|
}
|
|
return treeWalkerRef.current.previousNode();
|
|
},
|
|
find: (predicate, startFrom)=>{
|
|
if (!treeWalkerRef.current || !listboxRef.current) {
|
|
return null;
|
|
}
|
|
const start = startFrom ? targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.getElementById(startFrom) : null;
|
|
treeWalkerRef.current.currentNode = start !== null && start !== void 0 ? start : listboxRef.current;
|
|
let cur = treeWalkerRef.current.currentNode;
|
|
while(cur && !predicate(cur.id)){
|
|
cur = treeWalkerRef.current.nextNode();
|
|
}
|
|
return cur;
|
|
},
|
|
setCurrent: (el)=>{
|
|
if (!treeWalkerRef.current) {
|
|
return;
|
|
}
|
|
treeWalkerRef.current.currentNode = el;
|
|
}
|
|
}), [
|
|
targetDocument
|
|
]);
|
|
return {
|
|
optionWalker,
|
|
listboxCallbackRef: setListbox
|
|
};
|
|
}
|