UNPKG

@wordpress/block-editor

Version:
173 lines (171 loc) 6.87 kB
"use strict"; 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