// packages/block-editor/src/components/writing-flow/use-tab-nav.js
import { focus, isFormElement } from "@wordpress/dom";
import { TAB } from "@wordpress/keycodes";
import { useSelect, useDispatch } from "@wordpress/data";
import { useRefEffect, useMergeRefs } from "@wordpress/compose";
import { useRef } from "@wordpress/element";
import { store as blockEditorStore } from "../../store";
import { isInSameBlock, isInsideRootBlock } from "../../utils/dom";
import { unlock } from "../../lock-unlock";
import { jsx } from "react/jsx-runtime";
function useTabNav() {
  const containerRef = (
    /** @type {typeof useRef<HTMLElement>} */
    useRef()
  );
  const focusCaptureBeforeRef = useRef();
  const focusCaptureAfterRef = useRef();
  const {
    hasMultiSelection,
    getSelectedBlockClientId,
    getBlockCount,
    getBlockOrder,
    getLastFocus,
    getSectionRootClientId,
    isZoomOut
  } = unlock(useSelect(blockEditorStore));
  const { setLastFocus } = unlock(useDispatch(blockEditorStore));
  const noCaptureRef = useRef();
  function onFocusCapture(event) {
    const canvasElement = containerRef.current.ownerDocument === event.target.ownerDocument ? containerRef.current : containerRef.current.ownerDocument.defaultView.frameElement;
    if (noCaptureRef.current) {
      noCaptureRef.current = null;
    } else if (hasMultiSelection()) {
      containerRef.current.focus();
    } else if (getSelectedBlockClientId()) {
      if (getLastFocus()?.current) {
        getLastFocus().current.focus();
      } else {
        containerRef.current.querySelector(
          `[data-block="${getSelectedBlockClientId()}"]`
        ).focus();
      }
    } else if (isZoomOut()) {
      const sectionRootClientId = getSectionRootClientId();
      const sectionBlocks = getBlockOrder(sectionRootClientId);
      if (sectionBlocks.length) {
        containerRef.current.querySelector(`[data-block="${sectionBlocks[0]}"]`).focus();
      } else if (sectionRootClientId) {
        containerRef.current.querySelector(`[data-block="${sectionRootClientId}"]`).focus();
      } else {
        canvasElement.focus();
      }
    } else {
      const isBefore = (
        // eslint-disable-next-line no-bitwise
        event.target.compareDocumentPosition(canvasElement) & event.target.DOCUMENT_POSITION_FOLLOWING
      );
      const tabbables = focus.tabbable.find(containerRef.current);
      if (tabbables.length) {
        const next = isBefore ? tabbables[0] : tabbables[tabbables.length - 1];
        next.focus();
      }
    }
  }
  const before = /* @__PURE__ */ jsx(
    "div",
    {
      ref: focusCaptureBeforeRef,
      tabIndex: "0",
      onFocus: onFocusCapture
    }
  );
  const after = /* @__PURE__ */ jsx(
    "div",
    {
      ref: focusCaptureAfterRef,
      tabIndex: "0",
      onFocus: onFocusCapture
    }
  );
  const ref = useRefEffect((node) => {
    function onKeyDown(event) {
      if (event.defaultPrevented) {
        return;
      }
      if (event.keyCode !== TAB) {
        return;
      }
      if (
        // Bails in case the focus capture elements aren’t present. They
        // may be omitted to avoid silent tab stops in preview mode.
        // See: https://github.com/WordPress/gutenberg/pull/59317
        !focusCaptureAfterRef.current || !focusCaptureBeforeRef.current
      ) {
        return;
      }
      const { target, shiftKey: isShift } = event;
      const direction = isShift ? "findPrevious" : "findNext";
      const nextTabbable = focus.tabbable[direction](target);
      const currentBlock = target.closest("[data-block]");
      const isElementPartOfSelectedBlock = currentBlock && nextTabbable && (isInSameBlock(currentBlock, nextTabbable) || isInsideRootBlock(currentBlock, nextTabbable));
      if (isFormElement(nextTabbable) && isElementPartOfSelectedBlock) {
        return;
      }
      const next = isShift ? focusCaptureBeforeRef : focusCaptureAfterRef;
      noCaptureRef.current = true;
      next.current.focus({ preventScroll: true });
    }
    function onFocusOut(event) {
      setLastFocus({ ...getLastFocus(), current: event.target });
      const { ownerDocument: ownerDocument2 } = node;
      if (!event.relatedTarget && event.target.hasAttribute("data-block") && ownerDocument2.activeElement === ownerDocument2.body && getBlockCount() === 0) {
        node.focus();
      }
    }
    function preventScrollOnTab(event) {
      if (event.keyCode !== TAB) {
        return;
      }
      if (event.target?.getAttribute("role") === "region") {
        return;
      }
      if (containerRef.current === event.target) {
        return;
      }
      const isShift = event.shiftKey;
      const direction = isShift ? "findPrevious" : "findNext";
      const target = focus.tabbable[direction](event.target);
      if (target === focusCaptureBeforeRef.current || target === focusCaptureAfterRef.current) {
        event.preventDefault();
        target.focus({ preventScroll: true });
      }
    }
    const { ownerDocument } = node;
    const { defaultView } = ownerDocument;
    defaultView.addEventListener("keydown", preventScrollOnTab);
    node.addEventListener("keydown", onKeyDown);
    node.addEventListener("focusout", onFocusOut);
    return () => {
      defaultView.removeEventListener("keydown", preventScrollOnTab);
      node.removeEventListener("keydown", onKeyDown);
      node.removeEventListener("focusout", onFocusOut);
    };
  }, []);
  const mergedRefs = useMergeRefs([containerRef, ref]);
  return [before, mergedRefs, after];
}
export {
  useTabNav as default
};
//# sourceMappingURL=use-tab-nav.js.map
