UNPKG

@wordpress/block-editor

Version:
123 lines (93 loc) 3.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useFocusFirstElement = useFocusFirstElement; var _element = require("@wordpress/element"); var _dom = require("@wordpress/dom"); var _data = require("@wordpress/data"); var _dom2 = require("../../../utils/dom"); var _store = require("../../../store"); /** * WordPress dependencies */ /** * Internal dependencies */ /** @typedef {import('@wordpress/element').RefObject} RefObject */ /** * Returns the initial position if the block needs to be focussed, `undefined` * otherwise. The initial position is either 0 (start) or -1 (end). * * @param {string} clientId Block client ID. * * @return {number} The initial position, either 0 (start) or -1 (end). */ function useInitialPosition(clientId) { return (0, _data.useSelect)(select => { const { getSelectedBlocksInitialCaretPosition, __unstableGetEditorMode, isBlockSelected } = select(_store.store); if (!isBlockSelected(clientId)) { return; } if (__unstableGetEditorMode() !== 'edit') { return; } // If there's no initial position, return 0 to focus the start. return getSelectedBlocksInitialCaretPosition(); }, [clientId]); } /** * Transitions focus to the block or inner tabbable when the block becomes * selected and an initial position is set. * * @param {string} clientId Block client ID. * * @return {RefObject} React ref with the block element. */ function useFocusFirstElement(clientId) { const ref = (0, _element.useRef)(); const initialPosition = useInitialPosition(clientId); const { isBlockSelected, isMultiSelecting } = (0, _data.useSelect)(_store.store); (0, _element.useEffect)(() => { // Check if the block is still selected at the time this effect runs. if (!isBlockSelected(clientId) || isMultiSelecting()) { return; } if (initialPosition === undefined || initialPosition === null) { return; } if (!ref.current) { return; } const { ownerDocument } = ref.current; // Do not focus the block if it already contains the active element. if ((0, _dom2.isInsideRootBlock)(ref.current, ownerDocument.activeElement)) { return; } // Find all tabbables within node. const textInputs = _dom.focus.tabbable.find(ref.current).filter(node => (0, _dom.isTextField)(node)); // If reversed (e.g. merge via backspace), use the last in the set of // tabbables. const isReverse = -1 === initialPosition; const target = textInputs[isReverse ? textInputs.length - 1 : 0] || ref.current; if (!(0, _dom2.isInsideRootBlock)(ref.current, target)) { ref.current.focus(); return; } // Check to see if element is focussable before a generic caret insert. if (!ref.current.getAttribute('contenteditable')) { const focusElement = _dom.focus.tabbable.findNext(ref.current); // Make sure focusElement is valid, contained in the same block, and a form field. if (focusElement && (0, _dom2.isInsideRootBlock)(ref.current, focusElement) && (0, _dom.isFormElement)(focusElement)) { focusElement.focus(); return; } } (0, _dom.placeCaretAtHorizontalEdge)(target, isReverse); }, [initialPosition, clientId]); return ref; } //# sourceMappingURL=use-focus-first-element.js.map