ivyforms
/
frontend
/
src
/
views
/
_components
/
table
/
composables
/
useContextMenuClickOutside.ts
useContextMenuClickOutside.ts in The Innovative Form Builder – IvyForms 1.1.1, at frontend/src/views/_components/table/composables/useContextMenuClickOutside.ts
| 1 | import { onBeforeUnmount, onMounted, type Ref } from 'vue' |
| 2 | |
| 3 | export interface UseContextMenuClickOutsideOptions { |
| 4 | selector?: string |
| 5 | ignore?: Ref<unknown>[] |
| 6 | } |
| 7 | |
| 8 | const DEFAULT_SELECTOR = '.ivyforms-context-menu, .ivyforms-popper-context-menu' |
| 9 | |
| 10 | function resolveElement(value: unknown): HTMLElement | null { |
| 11 | if (!value) return null |
| 12 | if (value instanceof HTMLElement) return value |
| 13 | if (typeof value === 'object' && value !== null && '$el' in value) { |
| 14 | const el = (value as { $el: unknown }).$el |
| 15 | return el instanceof HTMLElement ? el : null |
| 16 | } |
| 17 | return null |
| 18 | } |
| 19 | |
| 20 | export function useContextMenuClickOutside( |
| 21 | close: () => void, |
| 22 | options: UseContextMenuClickOutsideOptions = {}, |
| 23 | ) { |
| 24 | const { selector = DEFAULT_SELECTOR, ignore = [] } = options |
| 25 | |
| 26 | const handler = (event: MouseEvent) => { |
| 27 | const target = event.target |
| 28 | if (!(target instanceof Node)) return |
| 29 | |
| 30 | const menus = document.querySelectorAll(selector) |
| 31 | for (const menu of menus) { |
| 32 | if (menu.contains(target)) return |
| 33 | } |
| 34 | |
| 35 | for (const ref of ignore) { |
| 36 | const el = resolveElement(ref.value) |
| 37 | if (el?.contains(target)) return |
| 38 | } |
| 39 | |
| 40 | close() |
| 41 | } |
| 42 | |
| 43 | onMounted(() => { |
| 44 | document.addEventListener('mousedown', handler) |
| 45 | }) |
| 46 | |
| 47 | onBeforeUnmount(() => { |
| 48 | document.removeEventListener('mousedown', handler) |
| 49 | }) |
| 50 | } |
| 51 |