Skip to content

Instantly share code, notes, and snippets.

@zGrav
Created June 17, 2020 09:10
Show Gist options
  • Save zGrav/883a4ff3613580da6beb204d3e0f1a4b to your computer and use it in GitHub Desktop.
Save zGrav/883a4ff3613580da6beb204d3e0f1a4b to your computer and use it in GitHub Desktop.
useful event stuff
useEffect(() => {
if (!isSidebarOpen) {
removeAllListeners(document.body, "click");
} else {
addListener(document.body, "click", (event: MouseEvent) =>
handleBodyClick(event, "sidebar", setIsSidebarOpen)
);
}
if (localStorage) {
localStorage.setItem("sidebar-open", isSidebarOpen.toString());
}
}, [isSidebarOpen]);
const eventHandlers = {};
export const addListener = (
node: HTMLElement | Node,
event: string,
handler,
capture: boolean = false
) => {
// checks if specific event is stored in our obj
// otherwise create it
if (!(event in eventHandlers)) {
eventHandlers[event] = [];
}
// update eventHandlers
// and in here we track the events
// and their nodes.
// we cannot use the node itself as Object keys,
// as they'd get coerced into a string
eventHandlers[event].push({
node,
handler,
capture
});
node.addEventListener(event, handler, capture);
return true;
};
export const removeAllListeners = (
targetNode: HTMLElement | Node,
event: string
) => {
// if we don't have this event stored, we can skip
if (!(event in eventHandlers)) {
return false;
}
// remove listeners from the matching nodes
eventHandlers[event]
.filter(({ node }) => node === targetNode)
.forEach(({ node, handler, capture }) =>
node.removeEventListener(event, handler, capture)
);
// update eventHandlers
eventHandlers[event] = eventHandlers[event].filter(
({ node }) => node !== targetNode
);
return true;
};
// handles outside of elements clicks (closes sidebar/dropdowns)
export const handleBodyClick = (
event: MouseEvent,
type: string,
action: (visibility: boolean) => void
) => {
if (!event) {
return false;
}
// since it's event-based and all...
event.preventDefault();
// these id's can also include buttons
// so be careful:)
const playerProfileId = "player-profile-";
const questsId = "quests-";
const sidebarId = "sidebar";
// gets objects on which event listeners will be invoked
const paths = event.composedPath();
// let's trickle down the array
const found = paths.filter(path => {
// this is actually a HTMLElement so map it as so
const p = path as HTMLElement;
// if we got one of the HTMLElement
// with a certain id we return true
// since we are filtering, falses get dropped.
if (p.id && typeof p.id === "string") {
if (
p.id.indexOf(playerProfileId) > -1 ||
p.id.indexOf(questsId) > -1 ||
p.id.indexOf(sidebarId) > -1
) {
return true;
}
}
return false;
});
// if we found no reference to our IDs
// (aka clicked outside of it or it's children)
// we trigger the hide action
if (found.length === 0) {
if (type === "player" || type === "quest" || type === "sidebar") {
action(false);
}
}
return true;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment