{"version":3,"file":"MenuContentImpl.cjs","sources":["../../src/Menu/MenuContentImpl.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Ref } from 'vue'\nimport type {\n  GraceIntent,\n  Side,\n} from './utils'\nimport type { FocusScopeProps } from '@/FocusScope'\nimport type { RovingFocusGroupEmits } from '@/RovingFocus'\nimport type {\n  DismissableLayerEmits,\n  DismissableLayerProps,\n} from '@/DismissableLayer'\nimport type { PopperContentProps } from '@/Popper'\n\nimport {\n  createContext,\n  getActiveElement,\n  useArrowNavigation,\n  useFocusGuards,\n  useForwardExpose,\n  useTypeahead,\n} from '@/shared'\nimport { useBodyScrollLock } from '@/shared/useBodyScrollLock'\n\nexport interface MenuContentContext {\n  onItemEnter: (event: PointerEvent) => boolean\n  onItemLeave: (event: PointerEvent) => void\n  onTriggerLeave: (event: PointerEvent) => boolean\n  searchRef: Ref<string>\n  pointerGraceTimerRef: Ref<number>\n  onPointerGraceIntentChange: (intent: GraceIntent | null) => void\n}\n\nexport const [injectMenuContentContext, provideMenuContentContext]\n  = createContext<MenuContentContext>('MenuContent')\n\nexport interface MenuContentImplPrivateProps {\n  /**\n   * When `true`, hover/focus/click interactions will be disabled on elements outside\n   * the `DismissableLayer`. Users will need to click twice on outside elements to\n   * interact with them: once to close the `DismissableLayer`, and again to trigger the element.\n   */\n  disableOutsidePointerEvents?: DismissableLayerProps['disableOutsidePointerEvents']\n  /**\n   * Whether scrolling outside the `MenuContent` should be prevented\n   * @defaultValue false\n   */\n  disableOutsideScroll?: boolean\n\n  /**\n   * Whether focus should be trapped within the `MenuContent`\n   * @defaultValue also\n   */\n  trapFocus?: FocusScopeProps['trapped']\n}\n\nexport type MenuContentImplEmits = DismissableLayerEmits & Omit<RovingFocusGroupEmits, 'update:currentTabStopId'> & {\n  openAutoFocus: [event: Event]\n  /**\n   * Event handler called when auto-focusing on close.\n   * Can be prevented.\n   */\n  closeAutoFocus: [event: Event]\n}\n\ntype MenuContentImplPrivateEmits = MenuContentImplEmits & {\n  /**\n   * Handler called when the `DismissableLayer` should be dismissed\n   */\n  dismiss: []\n}\n\nexport interface MenuContentImplProps\n  extends MenuContentImplPrivateProps,\n  Omit<PopperContentProps, 'dir'> {\n  /**\n   * When `true`, keyboard navigation will loop from last item to first, and vice versa.\n   * @defaultValue false\n   */\n  loop?: boolean\n}\n\nexport interface MenuRootContentTypeProps\n  extends Omit<MenuContentImplProps, 'disableOutsidePointerEvents' | 'disableOutsideScroll' | 'trapFocus'> {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n  onUnmounted,\n  ref,\n  toRefs,\n  watch,\n} from 'vue'\nimport { injectMenuContext, injectMenuRootContext } from './MenuRoot.vue'\nimport {\n  FIRST_LAST_KEYS,\n  LAST_KEYS,\n  focusFirst,\n  getOpenState,\n  isMouseEvent,\n  isPointerInGraceArea,\n} from './utils'\nimport { FocusScope } from '@/FocusScope'\nimport { DismissableLayer } from '@/DismissableLayer'\nimport {\n  PopperContent,\n  PopperContentPropsDefaultValue,\n} from '@/Popper'\nimport { RovingFocusGroup } from '@/RovingFocus'\n\nconst props = withDefaults(defineProps<MenuContentImplProps>(), {\n  ...PopperContentPropsDefaultValue,\n})\nconst emits = defineEmits<MenuContentImplPrivateEmits>()\nconst menuContext = injectMenuContext()\nconst rootContext = injectMenuRootContext()\n\nconst { trapFocus, disableOutsidePointerEvents, loop } = toRefs(props)\n\nuseFocusGuards()\nuseBodyScrollLock(disableOutsidePointerEvents.value)\n\nconst searchRef = ref('')\nconst timerRef = ref(0)\nconst pointerGraceTimerRef = ref(0)\nconst pointerGraceIntentRef = ref<GraceIntent | null>(null)\nconst pointerDirRef = ref<Side>('right')\nconst lastPointerXRef = ref(0)\nconst currentItemId = ref<string | null>(null)\n\nconst rovingFocusGroupRef = ref<InstanceType<typeof RovingFocusGroup>>()\nconst { forwardRef, currentElement: contentElement } = useForwardExpose()\nconst { handleTypeaheadSearch } = useTypeahead()\n\nwatch(contentElement, (el) => {\n  menuContext!.onContentChange(el)\n})\n\nonUnmounted(() => {\n  window.clearTimeout(timerRef.value)\n})\n\nfunction isPointerMovingToSubmenu(event: PointerEvent) {\n  const isMovingTowards\n    = pointerDirRef.value === pointerGraceIntentRef.value?.side\n\n  return (\n    isMovingTowards\n    && isPointerInGraceArea(event, pointerGraceIntentRef.value?.area)\n  )\n}\n\nasync function handleMountAutoFocus(event: Event) {\n  emits('openAutoFocus', event)\n  if (event.defaultPrevented)\n    return\n  // when opening, explicitly focus the content area only and leave\n  // `onEntryFocus` in  control of focusing first item\n  event.preventDefault()\n  contentElement.value?.focus({\n    preventScroll: true,\n  })\n}\n\nfunction handleKeyDown(event: KeyboardEvent) {\n  if (event.defaultPrevented)\n    return\n  // submenu key events bubble through portals. We only care about keys in this menu.\n  const target = event.target as HTMLElement\n  const isKeyDownInside\n    = target.closest('[data-reka-menu-content]') === event.currentTarget\n  const isModifierKey = event.ctrlKey || event.altKey || event.metaKey\n  const isCharacterKey = event.key.length === 1\n\n  const el = useArrowNavigation(\n    event,\n    getActiveElement() as HTMLElement,\n    contentElement.value,\n    {\n      loop: loop.value,\n      arrowKeyOptions: 'vertical',\n      dir: rootContext?.dir.value,\n      focus: true,\n      attributeName: '[data-reka-collection-item]:not([data-disabled])',\n    },\n  )\n  if (el)\n    return el?.focus()\n\n  // prevent \"Space\" taken account into handleTypeahead\n  if (event.code === 'Space')\n    return\n\n  const collectionItems = rovingFocusGroupRef.value?.getItems() ?? []\n\n  if (isKeyDownInside) {\n    // menus should not be navigated using tab key so we prevent it\n    if (event.key === 'Tab')\n      event.preventDefault()\n    if (!isModifierKey && isCharacterKey)\n      handleTypeaheadSearch(event.key, collectionItems)\n  }\n\n  // focus first/last item based on key pressed\n  if (event.target !== contentElement.value)\n    return\n  if (!FIRST_LAST_KEYS.includes(event.key))\n    return\n  event.preventDefault()\n  const candidateNodes = [...collectionItems.map(item => item.ref)]\n  if (LAST_KEYS.includes(event.key))\n    candidateNodes.reverse()\n  focusFirst(candidateNodes)\n}\n\nfunction handleBlur(event: FocusEvent) {\n  // clear search buffer when leaving the menu\n  // @ts-expect-error the provided currentTarget and target should be HTMLElement\n  if (!event?.currentTarget?.contains?.(event.target)) {\n    window.clearTimeout(timerRef.value)\n    searchRef.value = ''\n  }\n}\n\nfunction handlePointerMove(event: PointerEvent) {\n  if (!isMouseEvent(event))\n    return\n  const target = event.target as HTMLElement\n  const pointerXHasChanged = lastPointerXRef.value !== event.clientX\n\n  // We don't use `event.movementX` for this check because Safari will\n  // always return `0` on a pointer event.\n  if (\n    (event?.currentTarget as HTMLElement)?.contains(target)\n    && pointerXHasChanged\n  ) {\n    const newDir = event.clientX > lastPointerXRef.value ? 'right' : 'left'\n    pointerDirRef.value = newDir\n    lastPointerXRef.value = event.clientX\n  }\n}\n\nprovideMenuContentContext({\n  onItemEnter: (event) => {\n    // event.preventDefault() we can't prevent pointerMove event\n    if (isPointerMovingToSubmenu(event))\n      return true\n    else\n      return false\n  },\n  onItemLeave: (event) => {\n    if (isPointerMovingToSubmenu(event))\n      return\n    contentElement.value?.focus()\n    currentItemId.value = null\n  },\n  onTriggerLeave: (event) => {\n    // event.preventDefault() we can't prevent pointerLeave event\n    if (isPointerMovingToSubmenu(event))\n      return true\n    else\n      return false\n  },\n  searchRef,\n  pointerGraceTimerRef,\n  onPointerGraceIntentChange: (intent) => {\n    pointerGraceIntentRef.value = intent\n  },\n})\n</script>\n\n<template>\n  <FocusScope\n    as-child\n    :trapped=\"trapFocus\"\n    @mount-auto-focus=\"handleMountAutoFocus\"\n    @unmount-auto-focus=\"emits('closeAutoFocus', $event)\"\n  >\n    <DismissableLayer\n      as-child\n      :disable-outside-pointer-events=\"disableOutsidePointerEvents\"\n      @escape-key-down=\"emits('escapeKeyDown', $event)\"\n      @pointer-down-outside=\"emits('pointerDownOutside', $event)\"\n      @focus-outside=\"emits('focusOutside', $event)\"\n      @interact-outside=\"emits('interactOutside', $event)\"\n      @dismiss=\"emits('dismiss')\"\n    >\n      <RovingFocusGroup\n        ref=\"rovingFocusGroupRef\"\n        v-model:current-tab-stop-id=\"currentItemId\"\n        as-child\n        orientation=\"vertical\"\n        :dir=\"rootContext.dir.value\"\n        :loop=\"loop\"\n        @entry-focus=\"(event) => {\n          emits('entryFocus', event)\n          // only focus first item when using keyboard\n          if (!rootContext.isUsingKeyboardRef.value) event.preventDefault();\n        }\"\n      >\n        <PopperContent\n          :ref=\"forwardRef\"\n          role=\"menu\"\n          :as=\"as\"\n          :as-child=\"asChild\"\n          aria-orientation=\"vertical\"\n          data-reka-menu-content\n          :data-state=\"getOpenState(menuContext.open.value)\"\n          :dir=\"rootContext.dir.value\"\n          :side=\"side\"\n          :side-offset=\"sideOffset\"\n          :align=\"align\"\n          :align-offset=\"alignOffset\"\n          :avoid-collisions=\"avoidCollisions\"\n          :collision-boundary=\"collisionBoundary\"\n          :collision-padding=\"collisionPadding\"\n          :arrow-padding=\"arrowPadding\"\n          :prioritize-position=\"prioritizePosition\"\n          :position-strategy=\"positionStrategy\"\n          :update-position-strategy=\"updatePositionStrategy\"\n          :sticky=\"sticky\"\n          :hide-when-detached=\"hideWhenDetached\"\n          :reference=\"reference\"\n          @keydown=\"handleKeyDown\"\n          @blur=\"handleBlur\"\n          @pointermove=\"handlePointerMove\"\n        >\n          <slot />\n        </PopperContent>\n      </RovingFocusGroup>\n    </DismissableLayer>\n  </FocusScope>\n</template>\n"],"names":["createContext","injectMenuContext","injectMenuRootContext","toRefs","useFocusGuards","useBodyScrollLock","ref","useForwardExpose","useTypeahead","watch","onUnmounted","isPointerInGraceArea","useArrowNavigation","getActiveElement","FIRST_LAST_KEYS","LAST_KEYS","focusFirst","isMouseEvent"],"mappings":"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"}