Files
headlessui/packages/@headlessui-react/src/hooks/use-document-event.ts
T
Robin Malfait b2c4023731 Improve outside click on Safari iOS (#1712)
* ensure outside click works on Safari in iOS

When tapping on an element that is not clickable (like a div), then the
`click` and `mousedown` events will not reach the
`window.addEventListener('click')` listeners.

The only event that does that could be interesting for us is the
`pointerdown` event. The issue with this one is that we then run into
the big issue we ran in a few months ago where clicks on a scrollbar
*also* fired while a click doesn't.

This issue was not an issue in React land, the
`window.addEventListener('click')` was fired even when tapping on a
`div`. This was very very confusing, but we think this is because of the
syntethic event system, where the event listener is added to the root of
your application (E.g.: #app) and React manually bubbles the events.
Because this is done manually, it *does* reach the window as well.

The confusing part is, how does React convert a `pointerdown` event to a
`mousedown` and `click`. There is no code for that in their codebase?

Turns out they don't, and turns out the events **do** bubble, but up
until the `document`, not the `window`. But since they are manually
bubbling events it all makes sense.

So the solution? Let's switch from `window` to `document`...

* update Dialog example to use DialogPanel

* update changelog
2022-07-26 11:40:21 +02:00

21 lines
584 B
TypeScript

import { useEffect } from 'react'
import { useLatestValue } from './use-latest-value'
export function useDocumentEvent<TType extends keyof DocumentEventMap>(
type: TType,
listener: (ev: DocumentEventMap[TType]) => any,
options?: boolean | AddEventListenerOptions
) {
let listenerRef = useLatestValue(listener)
useEffect(() => {
function handler(event: DocumentEventMap[TType]) {
listenerRef.current(event)
}
document.addEventListener(type, handler, options)
return () => document.removeEventListener(type, handler, options)
}, [type, options])
}