UIKit/lib/hooks/useEventListener.ts

80 lines
2.6 KiB
TypeScript
Raw Normal View History

2023-06-06 10:02:17 +00:00
import { useEffect, useRef, RefObject, useLayoutEffect } from "react";
// https://usehooks-ts.com/react-hook/use-event-listener
// MediaQueryList Event based useEventListener interface
2023-06-06 11:22:22 +00:00
export function useEventListener<K extends keyof MediaQueryListEventMap>(
2023-06-06 10:02:17 +00:00
eventName: K,
handler: (event: MediaQueryListEventMap[K]) => void,
element: RefObject<MediaQueryList>,
options?: boolean | AddEventListenerOptions,
): void;
// Window Event based useEventListener interface
2023-06-06 11:22:22 +00:00
export function useEventListener<K extends keyof WindowEventMap>(
2023-06-06 10:02:17 +00:00
eventName: K,
handler: (event: WindowEventMap[K]) => void,
element?: undefined,
options?: boolean | AddEventListenerOptions,
): void;
// Element Event based useEventListener interface
2023-06-06 11:22:22 +00:00
export function useEventListener<
2023-06-06 10:02:17 +00:00
K extends keyof HTMLElementEventMap,
T extends HTMLElement = HTMLDivElement,
>(
eventName: K,
handler: (event: HTMLElementEventMap[K]) => void,
element: RefObject<T>,
options?: boolean | AddEventListenerOptions,
): void;
// Document Event based useEventListener interface
2023-06-06 11:22:22 +00:00
export function useEventListener<K extends keyof DocumentEventMap>(
2023-06-06 10:02:17 +00:00
eventName: K,
handler: (event: DocumentEventMap[K]) => void,
element: RefObject<Document>,
options?: boolean | AddEventListenerOptions,
): void;
2023-06-06 11:22:22 +00:00
export function useEventListener<
2023-06-06 10:02:17 +00:00
KW extends keyof WindowEventMap,
KH extends keyof HTMLElementEventMap,
KM extends keyof MediaQueryListEventMap,
T extends HTMLElement | MediaQueryList | void = void,
>(
eventName: KW | KH | KM,
handler: (
event:
| WindowEventMap[KW]
| HTMLElementEventMap[KH]
| MediaQueryListEventMap[KM]
| Event,
) => void,
element?: RefObject<T>,
options?: boolean | AddEventListenerOptions,
) {
// Create a ref that stores handler
const savedHandler = useRef(handler);
useLayoutEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
// Define the listening target
const targetElement: T | Window = element?.current ?? window;
if (!(targetElement && targetElement.addEventListener)) return;
2023-06-06 11:22:22 +00:00
// Create event listener that calls handler export function stored in ref
2023-06-06 10:02:17 +00:00
const listener: typeof handler = event => savedHandler.current(event);
targetElement.addEventListener(eventName, listener, options);
// Remove event listener on cleanup
return () => {
targetElement.removeEventListener(eventName, listener, options);
};
}, [eventName, element, options]);
2023-06-06 11:22:22 +00:00
}