From 92b7b04e141eb04c4d3cde92d601527532f72c2f Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 25 Nov 2022 12:08:34 +0000 Subject: [PATCH] Refactor clickoutside util to use a single event listener rather than many, and add support for ignoring certain classes --- packages/bbui/src/Actions/click_outside.js | 60 +++++++++++++++++----- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/packages/bbui/src/Actions/click_outside.js b/packages/bbui/src/Actions/click_outside.js index 2be29f7b79..8995df14f3 100644 --- a/packages/bbui/src/Actions/click_outside.js +++ b/packages/bbui/src/Actions/click_outside.js @@ -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) - return { - update(newCallbackFunction) { - callbackFunction = newCallbackFunction - }, - destroy() { - document.body.removeEventListener("click", onClick, 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: newCallback => updateHandler(id, element, newCallback), + destroy: () => removeHandler(id), } }