skillbox/client/src/directives/click-outside.ts

47 lines
1.4 KiB
TypeScript

// taken from https://stackoverflow.com/questions/36170425/detect-click-outside-element
import { DirectiveBinding, VNode } from 'vue';
declare global {
interface HTMLElement {
clickOutsideEvent: (event: Event) => void;
}
}
/*
todo:
there is a special interaction with nested elements where the parent has a @click event:
the parent triggers the event, something happens, but the click event bubbles to the child element.
If the event is then used to open some kind of sidebar or modal that has the `click-outside` propert, t
he bubbled event will be outside of it, thereby closing it.
example:
<div
class="sidebar"
v-if="showSidebar"
v-click-outside="showSidebar=false"
>
...
</div>
<a class="sidebar-toggle" @click="showSidebar=true">
<span>Hello</span>
</a>
FIX:
In this example, setting the event on the a-tag as `@click.stop` will solve the problem
*/
export default {
unmounted(el: HTMLElement) {
document.body.removeEventListener('click', el.clickOutsideEvent);
},
created: (el: HTMLElement, binding: DirectiveBinding) => {
el.clickOutsideEvent = (event: Event) => {
if (!(el === event.target || el.contains(event.target as Node))) {
const eventHandler = binding.value;
eventHandler(event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent);
},
};