{"version":3,"file":"SelectItemAlignedPosition.cjs","sources":["../../src/Select/SelectItemAlignedPosition.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Ref } from 'vue'\nimport type { PrimitiveProps } from '@/Primitive'\nimport { clamp, createContext, useForwardExpose } from '@/shared'\nimport { useCollection } from '@/Collection'\nimport { useResizeObserver } from '@vueuse/core'\n\ninterface SelectItemAlignedPositionContext {\n  contentWrapper?: Ref<HTMLElement | undefined>\n  shouldExpandOnScrollRef?: Ref<boolean>\n  onScrollButtonChange: (node: HTMLElement | undefined) => void\n}\n\nexport interface SelectItemAlignedPositionProps extends PrimitiveProps {}\n\nexport const [injectSelectItemAlignedPositionContext, provideSelectItemAlignedPositionContext]\n  = createContext<SelectItemAlignedPositionContext>('SelectItemAlignedPosition')\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, ref } from 'vue'\nimport { injectSelectRootContext } from './SelectRoot.vue'\nimport { injectSelectContentContext } from './SelectContentImpl.vue'\nimport { CONTENT_MARGIN } from './utils'\nimport { Primitive } from '@/Primitive'\n\ndefineOptions({\n  inheritAttrs: false,\n})\n\nconst props = defineProps<SelectItemAlignedPositionProps>()\nconst emits = defineEmits<{\n  placed: []\n}>()\n\nconst { getItems } = useCollection()\nconst rootContext = injectSelectRootContext()\nconst contentContext = injectSelectContentContext()\n\nconst shouldExpandOnScrollRef = ref(false)\nconst shouldRepositionRef = ref(true)\n\nconst contentWrapperElement = ref<HTMLElement>()\nconst { forwardRef, currentElement: contentElement } = useForwardExpose()\n\nconst { viewport, selectedItem, selectedItemText, focusSelectedItem }\n  = contentContext!\n\nfunction position() {\n  if (\n    rootContext.triggerElement.value\n    && rootContext.valueElement.value\n    && contentWrapperElement.value\n    && contentElement.value\n    && viewport?.value\n    && selectedItem?.value\n    && selectedItemText?.value\n  ) {\n    const triggerRect = rootContext.triggerElement.value.getBoundingClientRect()\n\n    // -----------------------------------------------------------------------------------------\n    //  Horizontal positioning\n    // -----------------------------------------------------------------------------------------\n    const contentRect = contentElement.value.getBoundingClientRect()\n    const valueNodeRect = rootContext.valueElement.value.getBoundingClientRect()\n    const itemTextRect = selectedItemText.value.getBoundingClientRect()\n\n    if (rootContext.dir.value !== 'rtl') {\n      const itemTextOffset = itemTextRect.left - contentRect.left\n      const left = valueNodeRect.left - itemTextOffset\n      const leftDelta = triggerRect.left - left\n      const minContentWidth = triggerRect.width + leftDelta\n      const contentWidth = Math.max(minContentWidth, contentRect.width)\n      const rightEdge = window.innerWidth - CONTENT_MARGIN\n      const clampedLeft = clamp(left, CONTENT_MARGIN, Math.max(CONTENT_MARGIN, rightEdge - contentWidth))\n\n      contentWrapperElement.value.style.minWidth = `${minContentWidth}px`\n      contentWrapperElement.value.style.left = `${clampedLeft}px`\n    }\n    else {\n      const itemTextOffset = contentRect.right - itemTextRect.right\n      const right = window.innerWidth - valueNodeRect.right - itemTextOffset\n      const rightDelta = window.innerWidth - triggerRect.right - right\n      const minContentWidth = triggerRect.width + rightDelta\n      const contentWidth = Math.max(minContentWidth, contentRect.width)\n      const leftEdge = window.innerWidth - CONTENT_MARGIN\n      const clampedRight = clamp(\n        right,\n        CONTENT_MARGIN,\n        Math.max(CONTENT_MARGIN, leftEdge - contentWidth),\n      )\n\n      contentWrapperElement.value.style.minWidth = `${minContentWidth}px`\n      contentWrapperElement.value.style.right = `${clampedRight}px`\n    }\n\n    // -----------------------------------------------------------------------------------------\n    // Vertical positioning\n    // -----------------------------------------------------------------------------------------\n    const items = getItems().map(i => i.ref)\n    const availableHeight = window.innerHeight - CONTENT_MARGIN * 2\n    const itemsHeight = viewport.value.scrollHeight\n\n    const contentStyles = window.getComputedStyle(contentElement.value)\n    const contentBorderTopWidth = Number.parseInt(\n      contentStyles.borderTopWidth,\n      10,\n    )\n    const contentPaddingTop = Number.parseInt(contentStyles.paddingTop, 10)\n    const contentBorderBottomWidth = Number.parseInt(\n      contentStyles.borderBottomWidth,\n      10,\n    )\n    const contentPaddingBottom = Number.parseInt(\n      contentStyles.paddingBottom,\n      10,\n    )\n\n    const fullContentHeight = contentBorderTopWidth + contentPaddingTop + itemsHeight + contentPaddingBottom + contentBorderBottomWidth\n    const minContentHeight = Math.min(\n      selectedItem.value.offsetHeight * 5,\n      fullContentHeight,\n    )\n\n    const viewportStyles = window.getComputedStyle(viewport.value)\n    const viewportPaddingTop = Number.parseInt(viewportStyles.paddingTop, 10)\n    const viewportPaddingBottom = Number.parseInt(\n      viewportStyles.paddingBottom,\n      10,\n    )\n\n    const topEdgeToTriggerMiddle\n      = triggerRect.top + triggerRect.height / 2 - CONTENT_MARGIN\n    const triggerMiddleToBottomEdge = availableHeight - topEdgeToTriggerMiddle\n\n    const selectedItemHalfHeight = selectedItem.value.offsetHeight / 2\n    const itemOffsetMiddle\n      = selectedItem.value.offsetTop + selectedItemHalfHeight\n    const contentTopToItemMiddle\n      = contentBorderTopWidth + contentPaddingTop + itemOffsetMiddle\n    const itemMiddleToContentBottom\n      = fullContentHeight - contentTopToItemMiddle\n\n    const willAlignWithoutTopOverflow\n      = contentTopToItemMiddle <= topEdgeToTriggerMiddle\n\n    if (willAlignWithoutTopOverflow) {\n      const isLastItem = selectedItem.value === items[items.length - 1]\n      contentWrapperElement.value.style.bottom = `${0}px`\n      const viewportOffsetBottom\n        = contentElement.value.clientHeight\n        - viewport.value.offsetTop\n        - viewport.value.offsetHeight\n      const clampedTriggerMiddleToBottomEdge = Math.max(\n        triggerMiddleToBottomEdge,\n        selectedItemHalfHeight\n        // viewport might have padding bottom, include it to avoid a scrollable viewport\n        + (isLastItem ? viewportPaddingBottom : 0)\n        + viewportOffsetBottom\n        + contentBorderBottomWidth,\n      )\n      const height = contentTopToItemMiddle + clampedTriggerMiddleToBottomEdge\n      contentWrapperElement.value.style.height = `${height}px`\n    }\n    else {\n      const isFirstItem = selectedItem.value === items[0]\n      contentWrapperElement.value.style.top = `${0}px`\n      const clampedTopEdgeToTriggerMiddle = Math.max(\n        topEdgeToTriggerMiddle,\n        contentBorderTopWidth\n        + viewport.value.offsetTop\n        // viewport might have padding top, include it to avoid a scrollable viewport\n        + (isFirstItem ? viewportPaddingTop : 0)\n        + selectedItemHalfHeight,\n      )\n      const height = clampedTopEdgeToTriggerMiddle + itemMiddleToContentBottom\n      contentWrapperElement.value.style.height = `${height}px`\n      viewport.value.scrollTop\n        = contentTopToItemMiddle\n        - topEdgeToTriggerMiddle\n        + viewport.value.offsetTop\n    }\n\n    contentWrapperElement.value.style.margin = `${CONTENT_MARGIN}px 0`\n    contentWrapperElement.value.style.minHeight = `${minContentHeight}px`\n    contentWrapperElement.value.style.maxHeight = `${availableHeight}px`\n    // -----------------------------------------------------------------------------------------\n\n    emits('placed')\n\n    // we don't want the initial scroll position adjustment to trigger \"expand on scroll\"\n    // so we explicitly turn it on only after they've registered.\n    requestAnimationFrame(() => (shouldExpandOnScrollRef.value = true))\n  }\n}\n\n// copy z-index from content to wrapper\nconst contentZIndex = ref('')\n\nonMounted(async () => {\n  await nextTick()\n  position()\n  if (contentElement.value)\n    contentZIndex.value = window.getComputedStyle(contentElement.value).zIndex\n})\n\n// When the viewport becomes scrollable at the top, the scroll up button will mount.\n// Because it is part of the normal flow, it will push down the viewport, thus throwing our\n// trigger => selectedItem alignment off by the amount the viewport was pushed down.\n// We wait for this to happen and then re-run the positining logic one more time to account for it.\nfunction handleScrollButtonChange(node: HTMLElement | undefined) {\n  if (node && shouldRepositionRef.value === true) {\n    position()\n    focusSelectedItem?.()\n    shouldRepositionRef.value = false\n  }\n}\n\n// Resize and position when trigger element changes\nuseResizeObserver(rootContext.triggerElement, () => {\n  position()\n})\n\nprovideSelectItemAlignedPositionContext({\n  contentWrapper: contentWrapperElement,\n  shouldExpandOnScrollRef,\n  onScrollButtonChange: handleScrollButtonChange,\n})\n</script>\n\n<template>\n  <div\n    ref=\"contentWrapperElement\"\n    :style=\"{\n      display: 'flex',\n      flexDirection: 'column',\n      position: 'fixed',\n      zIndex: contentZIndex,\n    }\"\n  >\n    <Primitive\n      :ref=\"forwardRef\"\n      :style=\"{\n        // When we get the height of the content, it includes borders. If we were to set\n        // the height without having `boxSizing: 'border-box'` it would be too big.\n        boxSizing: 'border-box',\n        // We need to ensure the content doesn't get taller than the wrapper\n        maxHeight: '100%',\n      }\"\n      v-bind=\"{ ...$attrs, ...props }\"\n    >\n      <slot />\n    </Primitive>\n  </div>\n</template>\n"],"names":["createContext","useCollection","injectSelectRootContext","injectSelectContentContext","ref","useForwardExpose","CONTENT_MARGIN","clamp","onMounted","nextTick","useResizeObserver"],"mappings":"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"}