Repository: adobe/react-spectrum
File: packages/@react-aria/overlays/src/ariaHideOutside.ts (TypeScript)

Code before:
interface AriaHideOutsideOptions {
  root?: Element,
  useInert?: boolean
}

// Keeps a ref count of all hidden elements. Added to when hiding an element, and
// subtracted from when showing it again. When it reaches zero, aria-hidden is removed.
let refCountMap = new WeakMap<Element, number>();
interface ObserverWrapper {
  visibleNodes: Set<Element>,
  hiddenNodes: Set<Element>,
  observe: () => void,
  disconnect: () => void
}
let observerStack: Array<ObserverWrapper> = [];

/**
 * Hides all elements in the DOM outside the given targets from screen readers using aria-hidden,
 * and returns a function to revert these changes. In addition, changes to the DOM are watched
 * and new elements outside the targets are automatically hidden.
 * @param targets - The elements that should remain visible.
 * @param root - Nothing will be hidden above this element.
 * @returns - A function to restore all hidden elements.
 */
export function ariaHideOutside(targets: Element[], options?: AriaHideOutsideOptions | Element) {
  let opts = options instanceof Element ? {root: options} : options;
  let root = opts?.root ?? document.body;
  let useInert = opts?.useInert && supportsInert;
  let visibleNodes = new Set<Element>(targets);
  let hiddenNodes = new Set<Element>();

  let getHidden = (element: Element) => {
    return useInert && element instanceof HTMLElement ? element.inert : element.getAttribute('aria-hidden') === 'true';
  };

  let setHidden = (element: Element, hidden: boolean) => {
    if (useInert && element instanceof HTMLElement) {
      element.inert = hidden;
    } else if (hidden) {
      element.setAttribute('aria-hidden', 'true');
    } else {
      element.removeAttribute('aria-hidden');
    }
  };

  let walk = (root: Element) => {
    // Keep live announcer and top layer elements (e.g. toasts) visible.
    for (let element of root.querySelectorAll('[data-live-announcer], [data-react-aria-top-layer]')) {
      visibleNodes.add(element);
    }


Review comment (suggestion):
i'm ok if you decide to forgo this change
```suggestion
  let windowObj = getOwnerWindow(targets?.[0]);
  let opts = options instanceof windowObj.Element ? {root: options} : options;
```

Code after:
const supportsInert = typeof HTMLElement !== 'undefined' && 'inert' in HTMLElement.prototype;

interface AriaHideOutsideOptions {
  root?: Element,
  shouldUseInert?: boolean
}

// Keeps a ref count of all hidden elements. Added to when hiding an element, and
// subtracted from when showing it again. When it reaches zero, aria-hidden is removed.
let refCountMap = new WeakMap<Element, number>();
interface ObserverWrapper {
  visibleNodes: Set<Element>,
  hiddenNodes: Set<Element>,
  observe: () => void,
  disconnect: () => void
}
let observerStack: Array<ObserverWrapper> = [];

/**
 * Hides all elements in the DOM outside the given targets from screen readers using aria-hidden,
 * and returns a function to revert these changes. In addition, changes to the DOM are watched
 * and new elements outside the targets are automatically hidden.
 * @param targets - The elements that should remain visible.
 * @param root - Nothing will be hidden above this element.
 * @returns - A function to restore all hidden elements.
 */
export function ariaHideOutside(targets: Element[], options?: AriaHideOutsideOptions | Element) {
  let windowObj = getOwnerWindow(targets?.[0]);
  let opts = options instanceof windowObj.Element ? {root: options} : options;
  let root = opts?.root ?? document.body;
  let shouldUseInert = opts?.shouldUseInert && supportsInert;
  let visibleNodes = new Set<Element>(targets);
  let hiddenNodes = new Set<Element>();

  let getHidden = (element: Element) => {
    return shouldUseInert && element instanceof windowObj.HTMLElement ? element.inert : element.getAttribute('aria-hidden') === 'true';
  };

  let setHidden = (element: Element, hidden: boolean) => {
    if (shouldUseInert && element instanceof windowObj.HTMLElement) {
      element.inert = hidden;
    } else if (hidden) {
      element.setAttribute('aria-hidden', 'true');
    } else {
      element.removeAttribute('aria-hidden');
    }
  };

  let walk = (root: Element) => {
    // Keep live announcer and top layer elements (e.g. toasts) visible.
    for (let element of root.querySelectorAll('[data-live-announcer], [data-react-aria-top-layer]')) {