vuestic-ui
Version:
Vue 3 UI Framework
1 lines • 6.2 kB
Source Map (JSON)
{"version":3,"file":"useDropdownNavigation.mjs","sources":["../../../../../../src/components/va-dropdown/hooks/useDropdownNavigation.ts"],"sourcesContent":["import { Ref, computed, toRef, ComputedRef } from 'vue'\nimport { useDebounceFn, useEvent, useNumericProp } from '../../../composables'\n\nconst isTyping = (e: Event) => {\n const target = e.target as HTMLElement\n if (!(target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')) { return false }\n if (target.attributes.getNamedItem('readonly')) { return false }\n return true\n}\n\nconst isReadonlyArray = (arr: any): arr is readonly any[] => {\n return Array.isArray(arr)\n}\n\nexport type Trigger = 'click' | 'hover' | 'right-click' | 'dblclick' | 'space' | 'enter' | 'arrow-down' | 'arrow-up' | 'none'\n\nexport const useNavigation = (\n isOpen: Ref<boolean>,\n anchorRef: Ref<HTMLElement | undefined>,\n contentRef: Ref<HTMLElement | undefined>,\n props: {\n trigger: Trigger | readonly Trigger[],\n disabled: boolean,\n closeOnAnchorClick: boolean,\n closeOnContentClick: boolean,\n isContentHoverable: boolean,\n cursor: any,\n hoverOverTimeout: number | string,\n hoverOutTimeout: number | string,\n },\n) => {\n const normalizeTriggerName = (t: string) => {\n t = t.replace(/-/g, '').toLowerCase()\n\n if (t === 'space') { return ' ' }\n if (t === 'rightclick') { return 'contextmenu' }\n\n return t\n }\n\n const normalizedTriggers = computed(() => {\n if (isReadonlyArray(props.trigger)) {\n return props.trigger.map((t) => normalizeTriggerName(t))\n }\n\n // TODO: Include keyboard navigation for mouse events\n return [normalizeTriggerName(props.trigger)]\n })\n\n // Keyboard\n useEvent('keydown', (e) => {\n if (props.disabled) { return }\n\n if (e.key === 'Escape' && isOpen.value) {\n isOpen.value = false\n e.preventDefault()\n }\n\n if (isTyping(e)) { return }\n\n if (normalizedTriggers.value.includes(normalizeTriggerName(e.key))) {\n isOpen.value = !isOpen.value\n e.preventDefault()\n }\n }, anchorRef)\n\n useEvent('keydown', (e) => {\n if (props.disabled) { return }\n\n if (e.key === 'Escape' && isOpen.value) {\n isOpen.value = false\n e.preventDefault()\n }\n }, contentRef)\n\n // Click\n useEvent(['click', 'contextmenu', 'dblclick'], (e) => {\n if (props.disabled) { return }\n\n if (isTyping(e)) { return }\n\n if (normalizedTriggers.value.includes(normalizeTriggerName(e.type))) {\n e.preventDefault()\n\n if (isOpen.value && props.closeOnAnchorClick) {\n isOpen.value = false\n\n if (props.cursor) {\n // When cursor we need to re-open the dropdown, similar to context menu\n setTimeout(() => {\n isOpen.value = true\n }, 16)\n }\n } else {\n isOpen.value = true\n }\n }\n }, anchorRef)\n\n useEvent(['click', 'contextmenu', 'dblclick'], (e) => {\n if (props.closeOnContentClick) {\n isOpen.value = false\n }\n }, contentRef)\n\n // Hover\n const { debounced: debounceHover, cancel: cancelHoverDebounce } = useDebounceFn(useNumericProp('hoverOverTimeout') as ComputedRef<number>)\n const { debounced: debounceUnHover, cancel: cancelUnHoverDebounce } = useDebounceFn(useNumericProp('hoverOutTimeout') as ComputedRef<number>)\n\n const onMouseHover = (e: Event) => {\n if (props.disabled) { return }\n\n if (!normalizedTriggers.value.includes('hover')) { return }\n\n if (e.type === 'mouseleave') {\n cancelHoverDebounce()\n\n if (!props.isContentHoverable) {\n isOpen.value = false\n return\n }\n\n debounceUnHover(() => {\n isOpen.value = false\n })\n } else {\n cancelUnHoverDebounce()\n debounceHover(() => {\n isOpen.value = true\n })\n }\n }\n\n useEvent(['mouseleave', 'mouseenter'], onMouseHover, anchorRef)\n useEvent(['mouseleave', 'mouseenter'], onMouseHover, contentRef)\n}\n"],"names":[],"mappings":"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"}