{"version":3,"file":"focus-scope.mjs","sources":["../src/focus-scope/utils.ts","../src/focus-scope/FocusScope.ts"],"sourcesContent":["/* -------------------------------------------------------------------------------------------------\n * Utils\n * ----------------------------------------------------------------------------------------------- */\n\ntype FocusableTarget = HTMLElement | { focus: () => void }\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nexport function focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n  const previouslyFocusedElement = document.activeElement\n  for (const candidate of candidates) {\n    focus(candidate, { select })\n    if (document.activeElement !== previouslyFocusedElement)\n      return\n  }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nexport function getTabbableEdges(container: HTMLElement) {\n  const candidates = getTabbableCandidates(container)\n  const first = findVisible(candidates, container)\n  const last = findVisible(candidates.reverse(), container)\n  return [first, last] as const\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nexport function getTabbableCandidates(container: HTMLElement) {\n  const nodes: HTMLElement[] = []\n  const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n    acceptNode(node: HTMLInputElement) {\n      const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden'\n      if (node.disabled || node.hidden || isHiddenInput)\n        return NodeFilter.FILTER_SKIP\n      // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n      // runtime's understanding of tabbability, so this automatically accounts\n      // for any kind of element that could be tabbed to.\n      return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP\n    },\n  })\n  while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement)\n  // we do not take into account the order of nodes with positive `tabIndex` as it\n  // hinders accessibility to have tab order different from visual order.\n  return nodes\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n  for (const element of elements) {\n    // we stop checking if it's hidden at the `container` level (excluding)\n    if (!isHidden(element, { upTo: container }))\n      return element\n  }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n  if (getComputedStyle(node).visibility === 'hidden')\n    return true\n\n  while (node) {\n    // we stop at `upTo` (excluding it)\n    if (upTo !== undefined && node === upTo)\n      return false\n\n    if (getComputedStyle(node).display === 'none')\n      return true\n\n    node = node.parentElement as HTMLElement\n  }\n\n  return false\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n  return element instanceof HTMLInputElement && 'select' in element\n}\n\nexport function focus(element?: FocusableTarget | null, { select = false } = {}) {\n  // only focus if that element is focusable\n  if (!element || !element.focus)\n    return\n\n  const previouslyFocusedElement = document.activeElement\n  // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n  element.focus({ preventScroll: true })\n  // only select if its not the same element, it supports selection and we need to select\n  if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n    element.select()\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * ----------------------------------------------------------------------------------------------- */\n\ninterface FocusScopeAPI { paused: boolean, pause: () => void, resume: () => void }\nexport const focusScopesStack = createFocusScopesStack()\n\nfunction createFocusScopesStack() {\n  /** A stack of focus scopes, with the active one at the top */\n  let stack: FocusScopeAPI[] = []\n\n  return {\n    add(focusScope: FocusScopeAPI) {\n      // pause the currently active focus scope (at the top of the stack)\n      const activeFocusScope = stack[0]\n\n      if (focusScope !== activeFocusScope) {\n        activeFocusScope?.pause()\n      }\n\n      // remove in case it already exists (because we'll re-add it at the top of the stack)\n      stack = arrayRemove(stack, focusScope)\n      stack.unshift(focusScope)\n    },\n\n    remove(focusScope: FocusScopeAPI) {\n      stack = arrayRemove(stack, focusScope)\n      stack[0]?.resume()\n    },\n  }\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n  const updatedArray = [...array]\n  const index = updatedArray.indexOf(item)\n\n  if (index !== -1) {\n    updatedArray.splice(index, 1)\n  }\n\n  return updatedArray\n}\n\nexport function removeLinks(items: HTMLElement[]) {\n  return items.filter(item => item.tagName !== 'A')\n}\n","import { isClient } from '@vueuse/core'\nimport { nextTick, onWatcherCleanup, type Ref, shallowRef, watch, watchEffect } from 'vue'\nimport { type EmitsToHookProps, mergePrimitiveAttrs, type PrimitiveDefaultProps, type RadixPrimitiveReturns } from '../shared/index.ts'\nimport { focus, focusFirst, focusScopesStack, getTabbableCandidates, getTabbableEdges, removeLinks } from './utils.ts'\n\nexport interface FocusScopeProps {\n  /**\n   * When `true`, tabbing from last item will focus first tabbable\n   * and shift+tab from first item will focus last tababble.\n   * @defaultValue false\n   */\n  loop?: boolean\n\n  /**\n   * When `true`, focus cannot escape the focus scope via keyboard,\n   * pointer, or a programmatic focus.\n   * @defaultValue false\n   */\n  trapped?: boolean\n}\n\nexport const DEFAULT_FOCUS_SCOPE_PROPS = {\n  loop: undefined,\n  trapped: false,\n} satisfies PrimitiveDefaultProps<FocusScopeProps, 'trapped'>\n\nexport type FocusScopeEmits = {\n  /**\n   * Event handler called when auto-focusing on mount.\n   * Can be prevented.\n   */\n  mountAutoFocus: [event: Event]\n\n  /**\n   * Event handler called when auto-focusing on unmount.\n   * Can be prevented.\n   */\n  unmountAutoFocus: [event: Event]\n}\n\nexport const AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount'\nexport const EVENT_OPTIONS = { bubbles: false, cancelable: true }\nexport const AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount'\n\nexport interface UseFocusScopeProps extends EmitsToHookProps<FocusScopeEmits> {\n  el?: Ref<HTMLElement | undefined>\n  loop?: boolean\n  trapped?: () => boolean\n}\n\nexport function useFocusScope(props: UseFocusScopeProps): RadixPrimitiveReturns {\n  const { trapped = () => false } = props\n\n  const el = props.el || shallowRef<HTMLElement>()\n  const setElRef = props.el ? undefined : (value: HTMLElement | undefined) => el.value = value\n\n  let lastFocusedElementRef: HTMLElement | null | undefined\n\n  const focusScope = {\n    paused: false,\n    pause() {\n      this.paused = true\n    },\n    resume() {\n      this.paused = false\n    },\n  }\n\n  // Takes care of trapping focus if focus is moved outside programmatically for example\n  if (isClient) {\n    function handleFocusIn(event: FocusEvent) {\n      if (focusScope.paused || !el.value)\n        return\n\n      const target = event.target as HTMLElement | null\n\n      if (el.value.contains(target)) {\n        lastFocusedElementRef = target\n      }\n      else {\n        focus(lastFocusedElementRef, { select: true })\n      }\n    }\n\n    function handleFocusOut(event: FocusEvent) {\n      if (focusScope.paused || !el.value)\n        return\n      const relatedTarget = event.relatedTarget as HTMLElement | null\n\n      // A `focusout` event with a `null` `relatedTarget` will happen in at least two cases:\n      //\n      // 1. When the user switches app/tabs/windows/the browser itself loses focus.\n      // 2. In Google Chrome, when the focused element is removed from the DOM.\n      //\n      // We let the browser do its thing here because:\n      //\n      // 1. The browser already keeps a memory of what's focused for when the page gets refocused.\n      // 2. In Google Chrome, if we try to focus the deleted focused element (as per below), it\n      //    throws the CPU to 100%, so we avoid doing anything for this reason here too.\n      if (relatedTarget === null)\n        return\n\n      // If the focus has moved to an actual legitimate element (`relatedTarget !== null`)\n      // that is outside the container, we move focus to the last valid focused element inside.\n      if (!el.value.contains(relatedTarget)) {\n        focus(lastFocusedElementRef, { select: true })\n      }\n    }\n\n    // When the focused element gets removed from the DOM, browsers move focus\n    // back to the document.body. In this case, we move focus to the container\n    // to keep focus trapped correctly.\n    // -- related: https://github.com/radix-vue/radix-vue/issues/518\n    // Radix Vue tentative solution:\n    // instead of leaning on document.activeElement, we use lastFocusedElementRef.value to check\n    // if the element still exist inside the container,\n    // if not then we focus to the container\n    function handleMutations() {\n      const isLastFocusedElementExist = el.value?.contains(lastFocusedElementRef as HTMLElement)\n      if (!isLastFocusedElementExist) {\n        focus(el.value)\n      }\n    }\n\n    watchEffect(() => {\n      if (!trapped())\n        return\n\n      document.addEventListener('focusin', handleFocusIn)\n      document.addEventListener('focusout', handleFocusOut)\n      const mutationObserver = new MutationObserver(handleMutations)\n\n      if (el.value)\n        mutationObserver.observe(el.value, { childList: true, subtree: true })\n\n      onWatcherCleanup(() => {\n        document.removeEventListener('focusin', handleFocusIn)\n        document.removeEventListener('focusout', handleFocusOut)\n        mutationObserver.disconnect()\n      })\n    })\n\n    watch(el, async (container, _, onCleanup) => {\n      if (!container)\n        return\n      focusScopesStack.add(focusScope)\n\n      await nextTick()\n      const onMountAutoFocus = props.onMountAutoFocus\n      const onUnmountAutoFocus = props.onUnmountAutoFocus\n\n      const previouslyFocusedElement = document.activeElement as HTMLElement | null\n      const hasFocusedCandidate = container.contains(previouslyFocusedElement)\n\n      if (!hasFocusedCandidate) {\n        const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS)\n        if (onMountAutoFocus)\n          container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus)\n        container.dispatchEvent(mountEvent)\n        if (!mountEvent.defaultPrevented) {\n          focusFirst(removeLinks(getTabbableCandidates(container)), { select: true })\n          if (document.activeElement === previouslyFocusedElement) {\n            focus(container)\n          }\n        }\n      }\n\n      onCleanup(() => {\n        if (onMountAutoFocus)\n          container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus)\n\n        // We hit a react bug (fixed in v17) with focusing in unmount.\n        // We need to delay the focus a little to get around it for now.\n        // See: https://github.com/facebook/react/issues/17894\n        const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS)\n        if (onUnmountAutoFocus)\n          container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus)\n        container.dispatchEvent(unmountEvent)\n\n        setTimeout(() => {\n          if (!unmountEvent.defaultPrevented) {\n            focus(previouslyFocusedElement ?? document.body, { select: true })\n          }\n\n          // we need to remove the listener after we `dispatchEvent`\n          if (onUnmountAutoFocus)\n            container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus)\n\n          focusScopesStack.remove(focusScope)\n        }, 0)\n      })\n    })\n  }\n\n  // Takes care of looping focus (when tabbing whilst at the edges)\n  function onKeydown(event: KeyboardEvent) {\n    if (!props.loop && !trapped())\n      return\n    if (focusScope.paused)\n      return\n\n    const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey\n    const focusedElement = document.activeElement as HTMLElement | null\n\n    if (!isTabKey || !focusedElement)\n      return\n\n    const container = event.currentTarget as HTMLElement\n    const [first, last] = getTabbableEdges(container)\n    const hasTabbableElementsInside = first && last\n\n    // we can only wrap focus if we have tabbable edges\n    if (!hasTabbableElementsInside) {\n      if (focusedElement === container)\n        event.preventDefault()\n    }\n    else {\n      if (!event.shiftKey && focusedElement === last) {\n        event.preventDefault()\n\n        if (props.loop) {\n          focus(first, { select: true })\n        }\n      }\n      else if (event.shiftKey && focusedElement === first) {\n        event.preventDefault()\n\n        if (props.loop) {\n          focus(last, { select: true })\n        }\n      }\n    }\n  }\n\n  return {\n    attrs(extraAttrs) {\n      const attrs = {\n        elRef: setElRef,\n        tabindex: -1,\n        onKeydown,\n      }\n\n      if (extraAttrs && extraAttrs.length > 0) {\n        mergePrimitiveAttrs(attrs, extraAttrs)\n      }\n\n      return attrs\n    },\n  }\n}\n"],"names":[],"mappings":"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"}