UNPKG

reka-ui

Version:

Vue port for Radix UI Primitives.

1 lines 8.08 kB
{"version":3,"file":"MenuSubTrigger.cjs","sources":["../../src/Menu/MenuSubTrigger.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { MenuItemImplProps } from './MenuItemImpl.vue'\nimport type { Side } from './utils'\n\nexport interface MenuSubTriggerProps extends MenuItemImplProps {}\n</script>\n\n<script setup lang=\"ts\">\nimport { type ComponentPublicInstance, nextTick, onUnmounted, ref } from 'vue'\nimport MenuItemImpl from './MenuItemImpl.vue'\nimport { injectMenuContext, injectMenuRootContext } from './MenuRoot.vue'\nimport { injectMenuSubContext } from './MenuSub.vue'\nimport { injectMenuContentContext } from './MenuContentImpl.vue'\nimport { useId } from '@/shared'\nimport { SUB_OPEN_KEYS, getOpenState, isMouseEvent } from './utils'\nimport MenuAnchor from './MenuAnchor.vue'\n\nconst props = defineProps<MenuSubTriggerProps>()\n\nconst menuContext = injectMenuContext()\nconst rootContext = injectMenuRootContext()\nconst subContext = injectMenuSubContext()\nconst contentContext = injectMenuContentContext()\n\nconst openTimerRef = ref<number | null>(null)\n\nsubContext.triggerId ||= useId(undefined, 'reka-menu-sub-trigger')\n\nfunction clearOpenTimer() {\n if (openTimerRef.value)\n window.clearTimeout(openTimerRef.value)\n openTimerRef.value = null\n}\n\nonUnmounted(() => {\n clearOpenTimer()\n})\n\nfunction handlePointerMove(event: PointerEvent) {\n if (!isMouseEvent(event))\n return\n const defaultPrevented = contentContext.onItemEnter(event)\n if (defaultPrevented)\n return\n\n if (!props.disabled && !menuContext.open.value && !openTimerRef.value) {\n contentContext.onPointerGraceIntentChange(null)\n openTimerRef.value = window.setTimeout(() => {\n menuContext.onOpenChange(true)\n clearOpenTimer()\n }, 100)\n }\n}\n\nasync function handlePointerLeave(event: PointerEvent) {\n if (!isMouseEvent(event))\n return\n clearOpenTimer()\n\n const contentRect = menuContext.content.value?.getBoundingClientRect()\n if (contentRect?.width) {\n // TODO (Radix UI): make sure to update this when we change positioning logic\n // https://github.com/radix-ui/primitives/blob/main/packages/react/menu/src/Menu.tsx#L1088\n const side = menuContext.content.value?.dataset.side as Side\n\n const rightSide = side === 'right'\n const bleed = rightSide ? -5 : +5\n const contentNearEdge = contentRect[rightSide ? 'left' : 'right']\n const contentFarEdge = contentRect[rightSide ? 'right' : 'left']\n\n contentContext.onPointerGraceIntentChange({\n area: [\n // Apply a bleed on clientX to ensure that our exit point is\n // consistently within polygon bounds\n { x: event.clientX + bleed, y: event.clientY },\n { x: contentNearEdge, y: contentRect.top },\n { x: contentFarEdge, y: contentRect.top },\n { x: contentFarEdge, y: contentRect.bottom },\n { x: contentNearEdge, y: contentRect.bottom },\n ],\n side,\n })\n\n window.clearTimeout(contentContext.pointerGraceTimerRef.value)\n contentContext.pointerGraceTimerRef.value = window.setTimeout(\n () => contentContext.onPointerGraceIntentChange(null),\n 300,\n )\n }\n else {\n const defaultPrevented = contentContext.onTriggerLeave(event)\n if (defaultPrevented)\n return\n\n // There's 100ms where the user may leave an item before the submenu was opened.\n contentContext.onPointerGraceIntentChange(null)\n }\n}\n\nasync function handleKeyDown(event: KeyboardEvent) {\n const isTypingAhead = contentContext.searchRef.value !== ''\n if (props.disabled || (isTypingAhead && event.key === ' '))\n return\n if (SUB_OPEN_KEYS[rootContext.dir.value].includes(event.key)) {\n menuContext.onOpenChange(true)\n\n await nextTick()\n // The trigger may hold focus if opened via pointer interaction\n // so we ensure content is given focus again when switching to keyboard.\n menuContext.content.value?.focus()\n // prevent window from scrolling\n event.preventDefault()\n }\n}\n</script>\n\n<template>\n <MenuAnchor as-child>\n <MenuItemImpl\n v-bind=\"props\"\n :id=\"subContext.triggerId\"\n :ref=\"\n (vnode: ComponentPublicInstance) => {\n // @ts-ignore\n subContext?.onTriggerChange(vnode?.$el);\n return undefined\n }\n \"\n aria-haspopup=\"menu\"\n :aria-expanded=\"menuContext.open.value\"\n :aria-controls=\"subContext.contentId\"\n :data-state=\"getOpenState(menuContext.open.value)\"\n @click=\"\n async (event) => {\n if (props.disabled || event.defaultPrevented) return;\n /**\n * We manually focus because iOS Safari doesn't always focus on click (e.g. buttons)\n * and we rely heavily on `onFocusOutside` for submenus to close when switching\n * between separate submenus.\n */\n event.currentTarget.focus();\n if (!menuContext.open.value) menuContext.onOpenChange(true);\n }\n \"\n @pointermove=\"handlePointerMove\"\n @pointerleave=\"handlePointerLeave\"\n @keydown=\"handleKeyDown\"\n >\n <slot />\n </MenuItemImpl>\n </MenuAnchor>\n</template>\n"],"names":["injectMenuContext","injectMenuRootContext","injectMenuSubContext","injectMenuContentContext","ref","useId","onUnmounted","isMouseEvent","SUB_OPEN_KEYS","nextTick"],"mappings":"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"}