{"mappings":"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","sources":["packages/react-aria/src/tooltip/usePreviewTrigger.ts"],"sourcesContent":["/*\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n  KeyboardEvent as AriaKeyboardEvent,\n  DOMAttributes,\n  FocusableElement,\n  RefObject\n} from '@react-types/shared';\nimport {AriaPopoverProps} from '../overlays/usePopover';\nimport {focusWithoutScrolling} from '../utils/focusWithoutScrolling';\nimport {getActiveElement} from '../utils/shadowdom/DOMFunctions';\nimport {getFocusableTreeWalker} from '../focus/FocusScope';\nimport {\n  getInteractionModality,\n  useFocusVisibleListener,\n  useInteractionModality\n} from '../interactions/useFocusVisible';\nimport {getOwnerDocument} from '../utils/domHelpers';\nimport intlMessages from '../../intl/previewtrigger/*.json';\nimport {mergeProps} from '../utils/mergeProps';\nimport {nodeContains} from '../utils/shadowdom/DOMFunctions';\nimport {TooltipTriggerProps, TooltipTriggerState} from 'react-stately/useTooltipTriggerState';\nimport {useEffect, useRef} from 'react';\nimport {useEffectEvent} from '../utils/useEffectEvent';\nimport {useEvent} from '../utils/useEvent';\nimport {useHover} from '../interactions/useHover';\nimport {useId} from '../utils/useId';\nimport {useLocalizedStringFormatter} from '../i18n/useLocalizedStringFormatter';\nimport {useLongPress} from '../interactions/useLongPress';\nimport {useSafeArea} from './useSafeArea';\n\nexport interface AriaPreviewTriggerProps extends Omit<\n  TooltipTriggerProps,\n  'trigger' | 'shouldCloseOnPress'\n> {}\n\nexport interface AriaPreviewTriggerOptions extends AriaPreviewTriggerProps {\n  /** A ref to the trigger element (e.g. a Link). */\n  triggerRef: RefObject<FocusableElement | null>;\n  /** A ref to the popover element. */\n  popoverRef: RefObject<Element | null>;\n}\n\nexport interface PreviewTriggerTriggerAria {\n  /**\n   * Props for the trigger element (e.g. a Link).\n   */\n  triggerProps: DOMAttributes;\n  /**\n   * Props for the popover overlay element.\n   */\n  popoverProps: Omit<AriaPopoverProps, 'triggerRef' | 'popoverRef'> & DOMAttributes;\n}\n\n/**\n * Provides the behavior and accessibility implementation for a preview trigger.\n * A preview trigger displays a popover on hover, focus, or long press. Unlike a\n * tooltip, the popover may contain interactive content.\n */\nexport function usePreviewTrigger(\n  props: AriaPreviewTriggerOptions,\n  state: TooltipTriggerState\n): PreviewTriggerTriggerAria {\n  let {triggerRef, popoverRef, isDisabled} = props;\n  let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/link-preview');\n  let popoverId = useId();\n\n  // Suppresses the next focus from reopening the preview (e.g. when restoring focus on Escape).\n  let ignoreFocus = useRef(false);\n  // When opened via long press, move focus into the popover once it opens so touch screen readers\n  // (e.g. VoiceOver) move their virtual cursor into the preview.\n  let shouldFocusOnOpen = useRef(false);\n  // Whether the pointer is currently within the safe area (the trigger, the popover, or the region\n  // between them). Tracked by useSafeArea below so the preview stays open while the pointer travels\n  // from the link to the popover, even with closeDelay of 0.\n  let pointerInSafeArea = useRef(false);\n\n  let isFocusVisible = useRef(false);\n  useFocusVisibleListener(visible => {\n    isFocusVisible.current = visible;\n  }, []);\n\n  // Cancel a pending close and keep the preview open.\n  let keepOpen = useEffectEvent(() => state.open(true));\n\n  // Close the preview unless something is still keeping it open: the pointer is within the safe\n  // area, or focus is within the trigger or popover. During focus transitions the active element\n  // may briefly be the body; the popover's focusin handler re-opens in that case (focus moving in).\n  let checkClose = useEffectEvent(() => {\n    if (pointerInSafeArea.current) {\n      return;\n    }\n    let active = triggerRef.current ? getActiveElement(getOwnerDocument(triggerRef.current)) : null;\n    if (\n      isFocusVisible.current &&\n      ((triggerRef.current && nodeContains(triggerRef.current, active)) ||\n        (popoverRef.current && nodeContains(popoverRef.current, active)))\n    ) {\n      return;\n    }\n    state.close();\n  });\n\n  useEffect(() => {\n    let popover = popoverRef.current;\n    if (!state.isOpen || !popover || !shouldFocusOnOpen.current) {\n      return;\n    }\n\n    // When opened via long press, move focus to the popover itself so touch screen readers move\n    // their virtual cursor into the preview.\n    shouldFocusOnOpen.current = false;\n    focusWithoutScrolling(popover as FocusableElement);\n  }, [state.isOpen, popoverRef]);\n\n  let onHoverStart = () => {\n    // Match useTooltipTrigger: only treat as hovered when the modality is actually a pointer.\n    if (getInteractionModality() === 'pointer') {\n      pointerInSafeArea.current = true;\n      state.open();\n    }\n  };\n\n  let onHoverEnd = () => {\n    // Before the preview opens, cancel a pending warmup if the pointer leaves the trigger. Once\n    // open, the safe-area polygon (useSafeArea) governs closing as the pointer moves to the popover.\n    if (!state.isOpen) {\n      pointerInSafeArea.current = false;\n      state.close();\n    }\n  };\n\n  let onTriggerFocus = e => {\n    if (ignoreFocus.current) {\n      ignoreFocus.current = false;\n      return;\n    }\n\n    // Prevent browser focusing the link on long press when focus is already in the popover.\n    if (state.isOpen && e.relatedTarget === popoverRef.current) {\n      focusWithoutScrolling(popoverRef.current as FocusableElement);\n      return;\n    }\n\n    if (isFocusVisible.current) {\n      // Open after the warmup delay on keyboard focus, not immediately like a tooltip. This way\n      // tabbing quickly through the page doesn't open previews (and add their tab stops); the\n      // delay ensures the user is actually interested in the link's details.\n      state.open();\n    }\n  };\n\n  useEvent(triggerRef, 'react-aria-focus-scope-restore', e => {\n    e.preventDefault();\n    ignoreFocus.current = true;\n    triggerRef.current?.focus();\n  });\n\n  // Move focus from the link into the preview when the user presses Tab while it is open.\n  // Tabbing back out of the popover is handled by the popover's own FocusScope.\n  let onTriggerKeyDown = (e: AriaKeyboardEvent) => {\n    if (e.key === 'Tab' && !e.shiftKey && state.isOpen && popoverRef.current) {\n      let walker = getFocusableTreeWalker(popoverRef.current, {tabbable: true});\n      let first = walker.nextNode() as FocusableElement | null;\n      if (first) {\n        e.preventDefault();\n        first.focus();\n      }\n    } else if (e.key === 'Escape') {\n      e.preventDefault();\n      state.close(true);\n    }\n  };\n\n  let {hoverProps} = useHover({isDisabled, onHoverStart, onHoverEnd});\n  let focusableProps = {\n    onFocus: onTriggerFocus,\n    onBlur: checkClose,\n    onKeyDown: onTriggerKeyDown\n  };\n\n  // Only describe the long press interaction when the user is actually using touch, otherwise it\n  // is confusing (e.g. a screen reader announcing \"long press\" while navigating with a keyboard).\n  // null is the default before the user has interacted with anything.\n  let modality = useInteractionModality();\n  let shouldLongPress =\n    (modality === 'pointer' || modality === 'virtual' || modality == null) &&\n    typeof window !== 'undefined' &&\n    'ontouchstart' in window;\n\n  // Open the preview on long press on touch devices, since there is no hover. Move focus into the\n  // popover once it opens so touch screen readers (e.g. VoiceOver) move their virtual cursor in.\n  let {longPressProps} = useLongPress({\n    isDisabled,\n    pointerType: 'touch',\n    accessibilityDescription: shouldLongPress\n      ? stringFormatter.format('longPressMessage')\n      : undefined,\n    onLongPress() {\n      shouldFocusOnOpen.current = true;\n      state.open(true);\n    }\n  });\n\n  // Keep the preview open while the pointer is anywhere within the safe area connecting the link\n  // and the popover, so moving the pointer between them (even diagonally) doesn't close it. This\n  // works for any popover placement and even when closeDelay is 0.\n  useSafeArea({\n    triggerRef,\n    overlayRef: popoverRef,\n    isOpen: state.isOpen,\n    isDisabled,\n    onSafeAreaChange: isInSafeArea => {\n      if (isInSafeArea === pointerInSafeArea.current) {\n        return;\n      }\n      pointerInSafeArea.current = isInSafeArea;\n      if (isInSafeArea) {\n        keepOpen();\n      } else {\n        checkClose();\n      }\n    }\n  });\n\n  // oxlint-disable-next-line react/react-compiler\n  let triggerProps = mergeProps(focusableProps, hoverProps, longPressProps);\n  let describedBy = [triggerProps['aria-describedby'], state.isOpen ? popoverId : null]\n    .filter(Boolean)\n    .join(' ');\n\n  return {\n    triggerProps: {\n      ...triggerProps,\n      'aria-haspopup': 'dialog',\n      'aria-expanded': state.isOpen,\n      'aria-controls': state.isOpen ? popoverId : undefined,\n      'aria-describedby': describedBy || undefined,\n      style: {\n        WebkitTouchCallout: 'none',\n        // @ts-ignore\n        WebkitUserDrag: 'none'\n      }\n    },\n    popoverProps: {\n      id: popoverId,\n      onFocusWithin: keepOpen,\n      onBlurWithin: checkClose\n    }\n  };\n}\n"],"names":[],"version":3,"file":"usePreviewTrigger.cjs.map"}