Skip to content

Instantly share code, notes, and snippets.

@vpellegrino
Last active May 4, 2023 14:50
Show Gist options
  • Save vpellegrino/47090aa09d2a2959f59c6040c50c7642 to your computer and use it in GitHub Desktop.
Save vpellegrino/47090aa09d2a2959f59c6040c50c7642 to your computer and use it in GitHub Desktop.
Collection of useful React Hooks to be used by a React component
import { RefObject, useCallback, useEffect, useRef, useState } from "react";
export function useContextMenuHandler(): {
contextMenuRef: RefObject<HTMLDivElement>;
contextMenuXPos: string;
contextMenuYPos: string;
contextMenuVisibility: boolean;
setContextMenuVisibility: (value: ((prevState: boolean) => boolean) | boolean) => void;
} {
const wrapperRef = useRef<HTMLDivElement>(null);
const [xPos, setXPos] = useState("0px");
const [yPos, setYPos] = useState("0px");
const [contextMenuVisible, setContextMenuVisible] = useState(false);
const hideContextMenu = useCallback(() => {
contextMenuVisible && setContextMenuVisible(false);
}, [contextMenuVisible]);
const showContextMenu = useCallback(
(event: MouseEvent) => {
if (wrapperRef.current && wrapperRef.current === event.target) {
event.preventDefault();
setXPos(`${event.pageX}px`);
setYPos(`${event.pageY}px`);
setContextMenuVisible(true);
}
},
[setXPos, setYPos]
);
useEffect(() => {
document.addEventListener("click", hideContextMenu);
document.addEventListener("contextmenu", hideContextMenu);
document.addEventListener("contextmenu", showContextMenu);
return () => {
document.removeEventListener("click", hideContextMenu);
document.removeEventListener("contextmenu", hideContextMenu);
document.removeEventListener("contextmenu", showContextMenu);
};
});
return {
contextMenuRef: wrapperRef,
contextMenuXPos: xPos,
contextMenuYPos: yPos,
contextMenuVisibility: contextMenuVisible,
setContextMenuVisibility: setContextMenuVisible,
};
}
export function useDragEvents(): {
setResizerElement: (element: HTMLDivElement) => void;
dragItHorizontally: (x: number) => void;
} {
let resizerElement: HTMLDivElement;
let mouseDownEvent: MouseEvent;
const initMouseDownEvent = (element: HTMLDivElement) => {
mouseDownEvent = new MouseEvent("mousedown", {
clientX: element.getBoundingClientRect().left,
clientY: element.getBoundingClientRect().top,
bubbles: true,
cancelable: true,
});
};
const moveHorizontallyBy = (x: number) => {
resizerElement.dispatchEvent(
new MouseEvent("mousemove", {
clientX: resizerElement.getBoundingClientRect().left + x,
clientY: resizerElement.getBoundingClientRect().top,
bubbles: true,
cancelable: true,
})
);
};
const mouseUpEvent = new MouseEvent("mouseup", {
bubbles: true,
cancelable: true,
});
const setResizerElement = (element: HTMLDivElement) => {
resizerElement = element;
initMouseDownEvent(resizerElement);
};
const dragItHorizontally = (x: number) => {
resizerElement.dispatchEvent(mouseDownEvent);
moveHorizontallyBy(x);
resizerElement.dispatchEvent(mouseUpEvent);
};
return {
setResizerElement,
dragItHorizontally,
};
}
import { useEffect, useRef } from "react";
import * as React from "react";
export function useOutsideClickEventHandler(callback: () => void): [React.RefObject<HTMLDivElement>] {
const wrapperRef = useRef<HTMLDivElement>(null);
useEffect(() => {
function handleClickOutside(event: Event) {
if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) {
callback();
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
console.log("removing event listener");
document.removeEventListener("mousedown", handleClickOutside);
};
}, [callback]);
return { wrapperRef };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment