Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React from "react";
- export default function useClickOutside(onClickOutside, exempt = []) {
- const container = React.useRef(null);
- const mouseDownTargetIsOutside = React.useRef(false);
- React.useEffect(() => {
- /* if the click event doesnt start outside of the element then we want to ignore it */
- /* imagine if someone clicked while swiping the cursor, if it started inside, then they probably */
- /* wouldn't expect mouseup to fire like it was outside */
- function onMouseDown(event) {
- /* If the target is inside, then don't fire click outside handler */
- if (container.current && container.current.contains(event.target)) {
- mouseDownTargetIsOutside.current = false;
- return;
- }
- mouseDownTargetIsOutside.current = true;
- }
- function onMouseUp(event) {
- /* If both targets weren't outside then we can bail early */
- const mouseUpTargetIsOutside =
- !container.current || !container.current.contains(event.target);
- if (!mouseDownTargetIsOutside.current || !mouseUpTargetIsOutside) {
- return;
- }
- /* exempt is an array of strings (css selectors) or html elements */
- /* Here we figure out if the target matches either, or is nested inside an exempt element */
- const targetIsExempt = exempt.some(selectorOrElement => {
- if (typeof selectorOrElement === "string") {
- return Boolean(event.target.closest(selectorOrElement));
- } else if (
- selectorOrElement instanceof HTMLElement ||
- selectorOrElement.current instanceof HTMLElement
- ) {
- const element = selectorOrElement.current || selectorOrElement;
- return event.target === element || element.contains(event.target);
- }
- return false;
- });
- if (targetIsExempt) {
- return;
- }
- onClickOutside(event, container);
- }
- window.addEventListener("mousedown", onMouseDown, true);
- window.addEventListener("mouseup", onMouseUp, true);
- return () => {
- window.removeEventListener("mousedown", onMouseDown, true);
- window.removeEventListener("mouseup", onMouseUp, true);
- };
- });
- return container;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement