@wordpress/block-editor
Version:
173 lines (171 loc) • 6.87 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// packages/block-editor/src/components/writing-flow/use-tab-nav.js
var use_tab_nav_exports = {};
__export(use_tab_nav_exports, {
default: () => useTabNav
});
module.exports = __toCommonJS(use_tab_nav_exports);
var import_dom = require("@wordpress/dom");
var import_keycodes = require("@wordpress/keycodes");
var import_data = require("@wordpress/data");
var import_compose = require("@wordpress/compose");
var import_element = require("@wordpress/element");
var import_store = require("../../store");
var import_dom2 = require("../../utils/dom");
var import_lock_unlock = require("../../lock-unlock");
var import_jsx_runtime = require("react/jsx-runtime");
function useTabNav() {
const containerRef = (
/** @type {typeof useRef<HTMLElement>} */
(0, import_element.useRef)()
);
const focusCaptureBeforeRef = (0, import_element.useRef)();
const focusCaptureAfterRef = (0, import_element.useRef)();
const {
hasMultiSelection,
getSelectedBlockClientId,
getBlockCount,
getBlockOrder,
getLastFocus,
getSectionRootClientId,
isZoomOut
} = (0, import_lock_unlock.unlock)((0, import_data.useSelect)(import_store.store));
const { setLastFocus } = (0, import_lock_unlock.unlock)((0, import_data.useDispatch)(import_store.store));
const noCaptureRef = (0, import_element.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 = import_dom.focus.tabbable.find(containerRef.current);
if (tabbables.length) {
const next = isBefore ? tabbables[0] : tabbables[tabbables.length - 1];
next.focus();
}
}
}
const before = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div",
{
ref: focusCaptureBeforeRef,
tabIndex: "0",
onFocus: onFocusCapture
}
);
const after = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div",
{
ref: focusCaptureAfterRef,
tabIndex: "0",
onFocus: onFocusCapture
}
);
const ref = (0, import_compose.useRefEffect)((node) => {
function onKeyDown(event) {
if (event.defaultPrevented) {
return;
}
if (event.keyCode !== import_keycodes.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 = import_dom.focus.tabbable[direction](target);
const currentBlock = target.closest("[data-block]");
const isElementPartOfSelectedBlock = currentBlock && nextTabbable && ((0, import_dom2.isInSameBlock)(currentBlock, nextTabbable) || (0, import_dom2.isInsideRootBlock)(currentBlock, nextTabbable));
if ((0, import_dom.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 !== import_keycodes.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 = import_dom.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 = (0, import_compose.useMergeRefs)([containerRef, ref]);
return [before, mergedRefs, after];
}
//# sourceMappingURL=use-tab-nav.js.map