[5d6f37a] | 1 | import { RefObject, useEffect, useRef, useLayoutEffect } from 'react';
|
---|
| 2 |
|
---|
| 3 | // ----------------------------------------------------------------------
|
---|
| 4 |
|
---|
| 5 | const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
---|
| 6 |
|
---|
| 7 | // Window Event based useEventListener interface
|
---|
| 8 | export function useEventListener<K extends keyof WindowEventMap>(
|
---|
| 9 | eventName: K,
|
---|
| 10 | handler: (event: WindowEventMap[K]) => void,
|
---|
| 11 | element?: undefined,
|
---|
| 12 | options?: boolean | AddEventListenerOptions
|
---|
| 13 | ): void;
|
---|
| 14 |
|
---|
| 15 | // Element Event based useEventListener interface
|
---|
| 16 | export function useEventListener<
|
---|
| 17 | K extends keyof HTMLElementEventMap,
|
---|
| 18 | T extends HTMLElement = HTMLDivElement,
|
---|
| 19 | >(
|
---|
| 20 | eventName: K,
|
---|
| 21 | handler: (event: HTMLElementEventMap[K]) => void,
|
---|
| 22 | element: RefObject<T>,
|
---|
| 23 | options?: boolean | AddEventListenerOptions
|
---|
| 24 | ): void;
|
---|
| 25 |
|
---|
| 26 | // Document Event based useEventListener interface
|
---|
| 27 | export function useEventListener<K extends keyof DocumentEventMap>(
|
---|
| 28 | eventName: K,
|
---|
| 29 | handler: (event: DocumentEventMap[K]) => void,
|
---|
| 30 | element: RefObject<Document>,
|
---|
| 31 | options?: boolean | AddEventListenerOptions
|
---|
| 32 | ): void;
|
---|
| 33 |
|
---|
| 34 | export function useEventListener<
|
---|
| 35 | KW extends keyof WindowEventMap,
|
---|
| 36 | KH extends keyof HTMLElementEventMap,
|
---|
| 37 | T extends HTMLElement | void = void,
|
---|
| 38 | >(
|
---|
| 39 | eventName: KW | KH,
|
---|
| 40 | handler: (event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event) => void,
|
---|
| 41 | element?: RefObject<T>,
|
---|
| 42 | options?: boolean | AddEventListenerOptions
|
---|
| 43 | ) {
|
---|
| 44 | // Create a ref that stores handler
|
---|
| 45 | const savedHandler = useRef(handler);
|
---|
| 46 |
|
---|
| 47 | useIsomorphicLayoutEffect(() => {
|
---|
| 48 | savedHandler.current = handler;
|
---|
| 49 | }, [handler]);
|
---|
| 50 |
|
---|
| 51 | useEffect(() => {
|
---|
| 52 | // Define the listening target
|
---|
| 53 | const targetElement: T | Window = element?.current || window;
|
---|
| 54 | if (!(targetElement && targetElement.addEventListener)) {
|
---|
| 55 | return;
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | // Create event listener that calls handler function stored in ref
|
---|
| 59 | const eventListener: typeof handler = (event) => savedHandler.current(event);
|
---|
| 60 |
|
---|
| 61 | targetElement.addEventListener(eventName, eventListener, options);
|
---|
| 62 |
|
---|
| 63 | // Remove event listener on cleanup
|
---|
| 64 | // eslint-disable-next-line consistent-return
|
---|
| 65 | return () => {
|
---|
| 66 | targetElement.removeEventListener(eventName, eventListener);
|
---|
| 67 | };
|
---|
| 68 | }, [eventName, element, options]);
|
---|
| 69 | }
|
---|