{"version":3,"file":"SelectContentImpl.cjs","sources":["../../src/Select/SelectContentImpl.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type {\n  ComponentPublicInstance,\n  Ref,\n} from 'vue'\nimport type { PopperContentProps } from '@/Popper'\nimport type { PointerDownOutsideEvent } from '@/DismissableLayer'\nimport {\n  createContext,\n  useFocusGuards,\n  useForwardProps,\n  useHideOthers,\n  useTypeahead,\n} from '@/shared'\nimport { useBodyScrollLock } from '@/shared/useBodyScrollLock'\nimport type { AcceptableValue } from '@/shared/types'\nimport { valueComparator } from './utils'\nimport { useCollection } from '@/Collection'\n\nexport interface SelectContentContext {\n  content?: Ref<HTMLElement | undefined>\n  viewport?: Ref<HTMLElement | undefined>\n  onViewportChange: (node: HTMLElement | undefined) => void\n  itemRefCallback: (\n    node: HTMLElement | undefined,\n    value: AcceptableValue,\n    disabled: boolean\n  ) => void\n  selectedItem?: Ref<HTMLElement | undefined>\n  onItemLeave?: () => void\n  itemTextRefCallback: (\n    node: HTMLElement | undefined,\n    value: AcceptableValue,\n    disabled: boolean\n  ) => void\n  focusSelectedItem?: () => void\n  selectedItemText?: Ref<HTMLElement | undefined>\n  position?: 'item-aligned' | 'popper'\n  isPositioned?: Ref<boolean>\n  searchRef?: Ref<string>\n}\n\nexport const SelectContentDefaultContextValue: SelectContentContext = {\n  onViewportChange: () => {},\n  itemTextRefCallback: () => {},\n  itemRefCallback: () => {},\n}\n\nexport type SelectContentImplEmits = {\n  closeAutoFocus: [event: Event]\n  /**\n   * Event handler called when the escape key is down.\n   * Can be prevented.\n   */\n  escapeKeyDown: [event: KeyboardEvent]\n  /**\n   * Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`.\n   * Can be prevented.\n   */\n  pointerDownOutside: [event: PointerDownOutsideEvent]\n}\n\nexport interface SelectContentImplProps extends PopperContentProps {\n  /**\n   *  The positioning mode to use\n   *\n   *  `item-aligned (default)` - behaves similarly to a native MacOS menu by positioning content relative to the active item. <br>\n   *  `popper` - positions content in the same way as our other primitives, for example `Popover` or `DropdownMenu`.\n   */\n  position?: 'item-aligned' | 'popper'\n  /**\n   * The document.body will be lock, and scrolling will be disabled.\n   *\n   * @defaultValue true\n   */\n  bodyLock?: boolean\n}\n\nexport const [injectSelectContentContext, provideSelectContentContext]\n  = createContext<SelectContentContext>('SelectContent')\n</script>\n\n<script setup lang=\"ts\">\nimport {\n  computed,\n  ref,\n  watch,\n  watchEffect,\n} from 'vue'\nimport { unrefElement } from '@vueuse/core'\nimport { injectSelectRootContext } from './SelectRoot.vue'\nimport SelectItemAlignedPosition from './SelectItemAlignedPosition.vue'\nimport SelectPopperPosition from './SelectPopperPosition.vue'\nimport { FocusScope } from '@/FocusScope'\nimport { DismissableLayer } from '@/DismissableLayer'\nimport { focusFirst } from '@/Menu/utils'\n\nconst props = withDefaults(defineProps<SelectContentImplProps>(), {\n  align: 'start',\n  position: 'item-aligned',\n  bodyLock: true,\n})\nconst emits = defineEmits<SelectContentImplEmits>()\n\nconst rootContext = injectSelectRootContext()\n\nuseFocusGuards()\nuseBodyScrollLock(props.bodyLock)\nconst { CollectionSlot, getItems } = useCollection()\n\nconst content = ref<HTMLElement>()\nuseHideOthers(content)\n\nconst { search, handleTypeaheadSearch } = useTypeahead()\n\nconst viewport = ref<HTMLElement>()\nconst selectedItem = ref<HTMLElement>()\nconst selectedItemText = ref<HTMLElement>()\nconst isPositioned = ref(false)\nconst firstValidItemFoundRef = ref(false)\nconst firstSelectedItemInArrayFoundRef = ref(false)\n\nfunction focusSelectedItem() {\n  if (selectedItem.value && content.value)\n    focusFirst([selectedItem.value, content.value])\n}\n\nwatch(isPositioned, () => {\n  focusSelectedItem()\n})\n\n// prevent selecting items on `pointerup` in some cases after opening from `pointerdown`\n// and close on `pointerup` outside.\nconst { onOpenChange, triggerPointerDownPosRef } = rootContext\nwatchEffect((cleanupFn) => {\n  if (!content.value)\n    return\n  let pointerMoveDelta = { x: 0, y: 0 }\n\n  const handlePointerMove = (event: PointerEvent) => {\n    pointerMoveDelta = {\n      x: Math.abs(\n        Math.round(event.pageX) - (triggerPointerDownPosRef.value?.x ?? 0),\n      ),\n      y: Math.abs(\n        Math.round(event.pageY) - (triggerPointerDownPosRef.value?.y ?? 0),\n      ),\n    }\n  }\n  const handlePointerUp = (event: PointerEvent) => {\n    // Prevent options from being untappable on touch devices\n    // https://github.com/unovue/reka-ui/issues/804\n    if (event.pointerType === 'touch')\n      return\n\n    // If the pointer hasn't moved by a certain threshold then we prevent selecting item on `pointerup`.\n    if (pointerMoveDelta.x <= 10 && pointerMoveDelta.y <= 10) {\n      event.preventDefault()\n    }\n    else {\n      // otherwise, if the event was outside the content, close.\n      if (!content.value?.contains(event.target as HTMLElement))\n        onOpenChange(false)\n    }\n    document.removeEventListener('pointermove', handlePointerMove)\n    triggerPointerDownPosRef.value = null\n  }\n\n  if (triggerPointerDownPosRef.value !== null) {\n    document.addEventListener('pointermove', handlePointerMove)\n    document.addEventListener('pointerup', handlePointerUp, {\n      capture: true,\n      once: true,\n    })\n  }\n\n  cleanupFn(() => {\n    document.removeEventListener('pointermove', handlePointerMove)\n    document.removeEventListener('pointerup', handlePointerUp, {\n      capture: true,\n    })\n  })\n})\n\nfunction handleKeyDown(event: KeyboardEvent) {\n  const isModifierKey = event.ctrlKey || event.altKey || event.metaKey\n\n  // select should not be navigated using tab key so we prevent it\n  if (event.key === 'Tab')\n    event.preventDefault()\n\n  if (!isModifierKey && event.key.length === 1)\n    handleTypeaheadSearch(event.key, getItems())\n\n  if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) {\n    const collectionItems = getItems().map(i => i.ref)\n    let candidateNodes = [...collectionItems]\n\n    if (['ArrowUp', 'End'].includes(event.key))\n      candidateNodes = candidateNodes.slice().reverse()\n\n    if (['ArrowUp', 'ArrowDown'].includes(event.key)) {\n      const currentElement = event.target as HTMLElement\n      const currentIndex = candidateNodes.indexOf(currentElement)\n      candidateNodes = candidateNodes.slice(currentIndex + 1)\n    }\n    setTimeout(() => focusFirst(candidateNodes))\n    event.preventDefault()\n  }\n}\n\nconst pickedProps = computed(() => {\n  if (props.position === 'popper')\n    return props\n  else return {}\n})\n\nconst forwardedProps = useForwardProps(pickedProps.value)\n\nprovideSelectContentContext({\n  content,\n  viewport,\n  onViewportChange: (node) => {\n    viewport.value = node\n  },\n  itemRefCallback: (node, value, disabled) => {\n    const isFirstValidItem = !firstValidItemFoundRef.value && !disabled\n    const isSelectedItem = valueComparator(rootContext.modelValue.value, value, rootContext.by)\n\n    if (rootContext.multiple.value) {\n      if (firstSelectedItemInArrayFoundRef.value) {\n        return\n      }\n      if (isSelectedItem || isFirstValidItem) {\n        selectedItem.value = node\n\n        // make sure to keep the first item highlighted when `multiple`\n        if (isSelectedItem) {\n          firstSelectedItemInArrayFoundRef.value = true\n        }\n      }\n    }\n    else {\n      if (isSelectedItem || isFirstValidItem) {\n        selectedItem.value = node\n      }\n    }\n\n    if (isFirstValidItem) {\n      firstValidItemFoundRef.value = true\n    }\n  },\n  selectedItem,\n  selectedItemText,\n  onItemLeave: () => {\n    content.value?.focus()\n  },\n  itemTextRefCallback: (node, value, disabled) => {\n    const isFirstValidItem = !firstValidItemFoundRef.value && !disabled\n    const isSelectedItem = valueComparator(rootContext.modelValue.value, value, rootContext.by)\n\n    if (isSelectedItem || isFirstValidItem)\n      selectedItemText.value = node\n  },\n  focusSelectedItem,\n  position: props.position,\n  isPositioned,\n  searchRef: search,\n})\n</script>\n\n<template>\n  <CollectionSlot>\n    <FocusScope\n      as-child\n      @mount-auto-focus.prevent\n      @unmount-auto-focus=\"\n        (event) => {\n          emits('closeAutoFocus', event);\n          if (event.defaultPrevented) return;\n          rootContext.triggerElement.value?.focus({ preventScroll: true });\n          event.preventDefault();\n        }\n      \"\n    >\n      <DismissableLayer\n        as-child\n        disable-outside-pointer-events\n        @focus-outside.prevent\n        @dismiss=\"rootContext.onOpenChange(false)\"\n        @escape-key-down=\"emits('escapeKeyDown', $event)\"\n        @pointer-down-outside=\"emits('pointerDownOutside', $event)\"\n      >\n        <component\n          :is=\"\n            position === 'popper'\n              ? SelectPopperPosition\n              : SelectItemAlignedPosition\n          \"\n          v-bind=\"{ ...$attrs, ...forwardedProps }\"\n          :id=\"rootContext.contentId\"\n          :ref=\"\n            (vnode: ComponentPublicInstance) => {\n              content = unrefElement(vnode) as HTMLElement\n              return undefined\n            }\n          \"\n          role=\"listbox\"\n          :data-state=\"rootContext.open.value ? 'open' : 'closed'\"\n          :dir=\"rootContext.dir.value\"\n          :style=\"{\n            // flex layout so we can place the scroll buttons properly\n            display: 'flex',\n            flexDirection: 'column',\n            // reset the outline by default as the content MAY get focused\n            outline: 'none',\n          }\"\n          @contextmenu.prevent\n          @placed=\"isPositioned = true\"\n          @keydown=\"(handleKeyDown as any)\"\n        >\n          <slot />\n        </component>\n      </DismissableLayer>\n    </FocusScope>\n  </CollectionSlot>\n</template>\n"],"names":["createContext","injectSelectRootContext","useFocusGuards","useBodyScrollLock","useCollection","ref","useHideOthers","useTypeahead","focusFirst","watch","watchEffect","computed","useForwardProps","valueComparator"],"mappings":"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"}