Refactor clickoutside util to use a single event listener rather than many, and add support for ignoring certain classes

This commit is contained in:
Andrew Kingston 2022-11-25 12:08:34 +00:00
parent abedb5d9eb
commit 92b7b04e14
1 changed files with 48 additions and 12 deletions

View File

@ -1,18 +1,54 @@
export default function clickOutside(element, callbackFunction) {
function onClick(event) {
if (!element.contains(event.target)) {
callbackFunction?.(event)
const ignoredClasses = [".flatpickr-calendar"]
let clickHandlers = []
/**
* Handle a body click event
*/
const handleClick = event => {
// Ignore click if needed
for (let className of ignoredClasses) {
if (event.target.closest(className)) {
console.log("ignore")
return
}
}
document.body.addEventListener("click", onClick, true)
// Process handlers
clickHandlers.forEach(handler => {
if (!handler.element.contains(event.target)) {
handler.callback?.(event)
}
})
}
document.documentElement.addEventListener("click", handleClick, true)
/**
* Adds or updates a click handler
*/
const updateHandler = (id, element, callback) => {
let existingHandler = clickHandlers.find(x => x.id === id)
if (!existingHandler) {
clickHandlers.push({ id, element, callback })
} else {
existingHandler.callback = callback
}
}
/**
* Removes a click handler
*/
const removeHandler = id => {
clickHandlers = clickHandlers.filter(x => x.id !== id)
}
/**
* Svelte action to apply a click outside handler for a certain element
*/
export default (element, callback) => {
const id = Math.random()
updateHandler(id, element, callback)
return {
update(newCallbackFunction) {
callbackFunction = newCallbackFunction
},
destroy() {
document.body.removeEventListener("click", onClick, true)
},
update: newCallback => updateHandler(id, element, newCallback),
destroy: () => removeHandler(id),
}
}