UNPKG

@lekseek/ui

Version:

Vue 3 components library

85 lines (71 loc) 2.31 kB
import { Directive } from 'vue'; const HANDLERS_PROPERTY = '__v-click-outside'; const HAS_WINDOWS = typeof window !== 'undefined'; const HAS_NAVIGATOR = typeof navigator !== 'undefined'; const IS_TOUCH = HAS_WINDOWS && ('ontouchstart' in window || (HAS_NAVIGATOR && (navigator as any).msMaxTouchPoints > 0)); const EVENTS = IS_TOUCH ? ['touchstart'] : ['click']; const processDirectiveArguments = (bindingValue: any) => { const isFunction = typeof bindingValue === 'function'; if (!isFunction && typeof bindingValue !== 'object') { throw new Error( 'v-click-outside: Binding value must be a function or an object', ); } return { handler: isFunction ? bindingValue : bindingValue.handler, middleware: bindingValue.middleware || ((item: any) => item), events: bindingValue.events || EVENTS, isActive: !(bindingValue.isActive === false), }; }; const onEvent = ({ el, event, handler, middleware }: any) => { const path = event.path || (event.composedPath && event.composedPath()); const isClickOutside = path ? path.indexOf(el) < 0 : !el.contains(event.target); if (!isClickOutside) { return; } if (middleware(event)) { handler(event); } }; const beforeMount = (el: any, { value }: any) => { const { events, handler, middleware, isActive } = processDirectiveArguments(value); if (!isActive) { return; } el[HANDLERS_PROPERTY] = events.map((eventName: any) => ({ event: eventName, handler: (event: any) => onEvent({ event, el, handler, middleware }), })); el[HANDLERS_PROPERTY].forEach(({ event, handler }: any) => setTimeout(() => { if (!el[HANDLERS_PROPERTY]) { return; } document.documentElement.addEventListener(event, handler, false); }, 0), ); }; const unmounted = (el: any) => { const handlers = el[HANDLERS_PROPERTY] || []; handlers.forEach(({ event, handler }: any) => document.documentElement.removeEventListener(event, handler, false), ); delete el[HANDLERS_PROPERTY]; }; const updated = (el: any, { value, oldValue }: any) => { if (JSON.stringify(value) === JSON.stringify(oldValue)) { return; } unmounted(el); beforeMount(el, { value }); }; const directive: Directive = { beforeMount, updated, unmounted, }; export default directive;