Files
headlessui/packages/@headlessui-react/src/hooks/use-tree-walker.ts
T
Robin Malfait d950146bcc add use tree walker hook (#316)
* add useTreeWalker hooks

We got a PR to fix the createTreeWalker so that it also works in IE11.
We don't actively support IE11, so if things work (with polyfills) then
it's good but I don't want to maintain IE11 specific code.

That said, I wanted to abstract the createTreeWalker code to a nice
little hook. The fix for IE is also pretty small, it uses a function
instead of an object and it has a last argument that is deprecated, but
has no obvious effect for our use cases.

Since the incoming PR was based on the `main` branch (where we only had
1 reference to createTreeWalker), I wanted to make sure that we got all
the references on the latest `develop` branch.

Closes: #295
Co-authored-by: Simon VDB <simonvdbroeck@gmail.com>

* use useTreeWalker hook

Co-authored-by: Simon VDB <simonvdbroeck@gmail.com>
2021-04-09 12:29:32 +02:00

43 lines
1.1 KiB
TypeScript

import { useRef, useEffect } from 'react'
import { useIsoMorphicEffect } from './use-iso-morphic-effect'
type AcceptNode = (
node: HTMLElement
) =>
| typeof NodeFilter.FILTER_ACCEPT
| typeof NodeFilter.FILTER_SKIP
| typeof NodeFilter.FILTER_REJECT
export function useTreeWalker({
container,
accept,
walk,
enabled = true,
}: {
container: HTMLElement | null
accept: AcceptNode
walk(node: HTMLElement): void
enabled?: boolean
}) {
let acceptRef = useRef(accept)
let walkRef = useRef(walk)
useEffect(() => {
acceptRef.current = accept
walkRef.current = walk
}, [accept, walk])
useIsoMorphicEffect(() => {
if (!container) return
if (!enabled) return
let accept = acceptRef.current
let walk = walkRef.current
let acceptNode = Object.assign((node: HTMLElement) => accept(node), { acceptNode: accept })
let walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, acceptNode, false)
while (walker.nextNode()) walk(walker.currentNode as HTMLElement)
}, [container, enabled, acceptRef, walkRef])
}