diff --git a/lib/src/hooks/useBodyScrollLock.tsx b/lib/src/hooks/useBodyScrollLock.tsx new file mode 100644 index 0000000..b6062e2 --- /dev/null +++ b/lib/src/hooks/useBodyScrollLock.tsx @@ -0,0 +1,13 @@ +import { useLayoutEffect } from "react"; + +const useLockBodyScroll = (value: boolean): void => { + useLayoutEffect((): (() => void) => { + value + ? (document.body.style.overflow = "hidden") + : (document.body.style.overflow = "auto"); + + return () => (document.body.style.overflow = "auto"); + }, []); +}; + +export { useLockBodyScroll }; diff --git a/lib/src/hooks/useClickOutside.tsx b/lib/src/hooks/useClickOutside.tsx new file mode 100644 index 0000000..13ecebd --- /dev/null +++ b/lib/src/hooks/useClickOutside.tsx @@ -0,0 +1,33 @@ +import { RefObject, useEffect } from "react"; + +type AnyEvent = MouseEvent | TouchEvent; + +function useClickOutside( + ref: RefObject, + handler: (event: AnyEvent) => void +): void { + useEffect(() => { + const listener = (event: AnyEvent) => { + const el = ref?.current; + + // Do nothing if clicking ref's element or descendent elements + if (!el || el.contains(event.target as Node)) { + return; + } + + handler(event); + }; + + document.addEventListener(`mousedown`, listener); + document.addEventListener(`touchstart`, listener); + + return () => { + document.removeEventListener(`mousedown`, listener); + document.removeEventListener(`touchstart`, listener); + }; + + // Reload only if ref or handler changes + }, [ref, handler]); +} + +export { useClickOutside };