{"mappings":"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","sources":["packages/react-aria/src/toast/useToastRegion.ts"],"sourcesContent":["/*\n * Copyright 2025 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 {AriaLabelingProps, DOMAttributes, FocusableElement, RefObject} from '@react-types/shared';\nimport {focusWithoutScrolling} from '../utils/focusWithoutScrolling';\nimport {getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport {getInteractionModality} from '../interactions/useFocusVisible';\nimport intlMessages from '../../intl/toast/*.json';\nimport {mergeProps} from '../utils/mergeProps';\nimport {ToastState} from 'react-stately/useToastState';\nimport {useCallback, useEffect, useRef} from 'react';\n// @ts-ignore\nimport {useFocusWithin} from '../interactions/useFocusWithin';\nimport {useHover} from '../interactions/useHover';\nimport {useLandmark} from '../landmark/useLandmark';\nimport {useLayoutEffect} from '../utils/useLayoutEffect';\nimport {useLocalizedStringFormatter} from '../i18n/useLocalizedStringFormatter';\n\nexport interface AriaToastRegionProps extends AriaLabelingProps {\n  /**\n   * An accessibility label for the toast region.\n   * @default \"Notifications\"\n   */\n  'aria-label'?: string\n}\n\nexport interface ToastRegionAria {\n  /** Props for the landmark region element. */\n  regionProps: DOMAttributes\n}\n\n/**\n * Provides the behavior and accessibility implementation for a toast region containing one or more toasts.\n * Toasts display brief, temporary notifications of actions, errors, or other events in an application.\n */\nexport function useToastRegion<T>(props: AriaToastRegionProps, state: ToastState<T>, ref: RefObject<HTMLElement | null>): ToastRegionAria {\n  let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/toast');\n  let {landmarkProps} = useLandmark({\n    role: 'region',\n    'aria-label': props['aria-label'] || stringFormatter.format('notifications', {count: state.visibleToasts.length})\n  }, ref);\n\n  let isHovered = useRef(false);\n  let isFocused = useRef(false);\n  let updateTimers = useCallback(() => {\n    if (isHovered.current || isFocused.current) {\n      state.pauseAll();\n    } else {\n      state.resumeAll();\n    }\n  }, [state]);\n\n  let {hoverProps} = useHover({\n    onHoverStart: () => {\n      isHovered.current = true;\n      updateTimers();\n    },\n    onHoverEnd: () => {\n      isHovered.current = false;\n      updateTimers();\n    }\n  });\n\n  // Manage focus within the toast region.\n  // If a focused containing toast is removed, move focus to the next toast, or the previous toast if there is no next toast.\n  let toasts = useRef<FocusableElement[]>([]);\n  let prevVisibleToasts = useRef(state.visibleToasts);\n  let focusedToast = useRef<number | null>(null);\n  useLayoutEffect(() => {\n    // If no toast has focus, then don't do anything.\n    if (focusedToast.current === -1 || state.visibleToasts.length === 0 || !ref.current) {\n      toasts.current = [];\n      prevVisibleToasts.current = state.visibleToasts;\n      return;\n    }\n    toasts.current = [...ref.current.querySelectorAll('[role=\"alertdialog\"]')] as FocusableElement[];\n    // If the visible toasts haven't changed, we don't need to do anything.\n    if (prevVisibleToasts.current.length === state.visibleToasts.length\n      && state.visibleToasts.every((t, i) => t.key === prevVisibleToasts.current[i].key)) {\n      prevVisibleToasts.current = state.visibleToasts;\n      return;\n    }\n    // Get a list of all toasts by index and add info if they are removed.\n    let allToasts = prevVisibleToasts.current\n      .map((t, i) => ({\n        ...t,\n        i,\n        isRemoved: !state.visibleToasts.some(t2 => t.key === t2.key)\n      }));\n\n    let removedFocusedToastIndex = allToasts.findIndex(t => t.i === focusedToast.current && t.isRemoved);\n\n    // If the focused toast was removed, focus the next or previous toast.\n    if (removedFocusedToastIndex > -1) {\n      // In pointer modality, move focus out of the toast region.\n      // Otherwise auto-dismiss timers will appear \"stuck\".\n      if (getInteractionModality() === 'pointer' && lastFocused.current?.isConnected) {\n        focusWithoutScrolling(lastFocused.current);\n      } else {\n        let i = 0;\n        let nextToast;\n        let prevToast;\n        while (i <= removedFocusedToastIndex) {\n          if (!allToasts[i].isRemoved) {\n            prevToast = Math.max(0, i - 1);\n          }\n          i++;\n        }\n        while (i < allToasts.length) {\n          if (!allToasts[i].isRemoved) {\n            nextToast = i - 1;\n            break;\n          }\n          i++;\n        }\n\n        // in the case where it's one toast at a time, both will be undefined, but we know the index must be 0\n        if (prevToast === undefined && nextToast === undefined) {\n          prevToast = 0;\n        }\n\n        // prioritize going to newer toasts\n        if (prevToast >= 0 && prevToast < toasts.current.length) {\n          focusWithoutScrolling(toasts.current[prevToast]);\n        } else if (nextToast >= 0 && nextToast < toasts.current.length) {\n          focusWithoutScrolling(toasts.current[nextToast]);\n        }\n      }\n    }\n\n    prevVisibleToasts.current = state.visibleToasts;\n  }, [state.visibleToasts, ref]);\n\n  let lastFocused = useRef<FocusableElement | null>(null);\n  let {focusWithinProps} = useFocusWithin({\n    onFocusWithin: (e) => {\n      isFocused.current = true;\n      lastFocused.current = e.relatedTarget as FocusableElement;\n      updateTimers();\n    },\n    onBlurWithin: () => {\n      isFocused.current = false;\n      lastFocused.current = null;\n      updateTimers();\n    }\n  });\n\n  // When the number of visible toasts becomes 0 or the region unmounts,\n  // restore focus to the last element that had focus before the user moved focus\n  // into the region. FocusScope restore focus doesn't update whenever the focus\n  // moves in, it only happens once, so we correct it.\n  // Because we're in a hook, we can't control if the user unmounts or not.\n  useEffect(() => {\n    if (state.visibleToasts.length === 0 && lastFocused.current?.isConnected) {\n      if (getInteractionModality() === 'pointer') {\n        focusWithoutScrolling(lastFocused.current);\n      } else {\n        lastFocused.current.focus();\n      }\n      lastFocused.current = null;\n    }\n  }, [ref, state.visibleToasts.length]);\n\n  useEffect(() => {\n    return () => {\n      if (lastFocused.current?.isConnected) {\n        if (getInteractionModality() === 'pointer') {\n          focusWithoutScrolling(lastFocused.current);\n        } else {\n          lastFocused.current.focus();\n        }\n        lastFocused.current = null;\n      }\n    };\n  }, [ref]);\n\n  return {\n    regionProps: mergeProps(landmarkProps, hoverProps, focusWithinProps, {\n      tabIndex: -1,\n      // Mark the toast region as a \"top layer\", so that it:\n      //   - is not aria-hidden when opening an overlay\n      //   - allows focus even outside a containing focus scope\n      //   - doesn’t dismiss overlays when clicking on it, even though it is outside\n      // @ts-ignore\n      'data-react-aria-top-layer': true,\n      // listen to focus events separate from focuswithin because that will only fire once\n      // and we need to follow all focus changes\n      onFocus: (e) => {\n        let target = (getEventTarget(e) as Element).closest('[role=\"alertdialog\"]');\n        focusedToast.current = toasts.current.findIndex(t => t === target);\n      },\n      onBlur: () => {\n        focusedToast.current = -1;\n      }\n    })\n  };\n}\n"],"names":[],"version":3,"file":"useToastRegion.cjs.map"}