UNPKG

@wordpress/components

Version:
136 lines (126 loc) 5.71 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.NavigatorScreen = void 0; var _dom = require("@wordpress/dom"); var _element = require("@wordpress/element"); var _compose = require("@wordpress/compose"); var _escapeHtml = require("@wordpress/escape-html"); var _warning = _interopRequireDefault(require("@wordpress/warning")); var _context = require("../../context"); var _useCx = require("../../utils/hooks/use-cx"); var _view = require("../../view"); var _context2 = require("../context"); var styles = _interopRequireWildcard(require("../styles")); var _useScreenAnimatePresence = require("./use-screen-animate-presence"); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ function UnconnectedNavigatorScreen(props, forwardedRef) { if (!/^\//.test(props.path)) { globalThis.SCRIPT_DEBUG === true ? (0, _warning.default)('wp.components.Navigator.Screen: the `path` should follow a URL-like scheme; it should start with and be separated by the `/` character.') : void 0; } const screenId = (0, _element.useId)(); const { children, className, path, onAnimationEnd: onAnimationEndProp, ...otherProps } = (0, _context.useContextSystem)(props, 'Navigator.Screen'); const { location, match, addScreen, removeScreen } = (0, _element.useContext)(_context2.NavigatorContext); const { isInitial, isBack, focusTargetSelector, skipFocus } = location; const isMatch = match === screenId; const wrapperRef = (0, _element.useRef)(null); const skipAnimationAndFocusRestoration = !!isInitial && !isBack; // Register / unregister screen with the navigator context. (0, _element.useEffect)(() => { const screen = { id: screenId, path: (0, _escapeHtml.escapeAttribute)(path) }; addScreen(screen); return () => removeScreen(screen); }, [screenId, path, addScreen, removeScreen]); // Animation. const { animationStyles, shouldRenderScreen, screenProps } = (0, _useScreenAnimatePresence.useScreenAnimatePresence)({ isMatch, isBack, onAnimationEnd: onAnimationEndProp, skipAnimation: skipAnimationAndFocusRestoration }); const cx = (0, _useCx.useCx)(); const classes = (0, _element.useMemo)(() => cx(styles.navigatorScreen, animationStyles, className), [className, cx, animationStyles]); // Focus restoration const locationRef = (0, _element.useRef)(location); (0, _element.useEffect)(() => { locationRef.current = location; }, [location]); (0, _element.useEffect)(() => { const wrapperEl = wrapperRef.current; // Only attempt to restore focus: // - if the current location is not the initial one (to avoid moving focus on page load) // - when the screen becomes visible // - if the wrapper ref has been assigned // - if focus hasn't already been restored for the current location // - if the `skipFocus` option is not set to `true`. This is useful when we trigger the navigation outside of NavigatorScreen. if (skipAnimationAndFocusRestoration || !isMatch || !wrapperEl || locationRef.current.hasRestoredFocus || skipFocus) { return; } const activeElement = wrapperEl.ownerDocument.activeElement; // If an element is already focused within the wrapper do not focus the // element. This prevents inputs or buttons from losing focus unnecessarily. if (wrapperEl.contains(activeElement)) { return; } let elementToFocus = null; // When navigating back, if a selector is provided, use it to look for the // target element (assumed to be a node inside the current NavigatorScreen) if (isBack && focusTargetSelector) { elementToFocus = wrapperEl.querySelector(focusTargetSelector); } // If the previous query didn't run or find any element to focus, fallback // to the first tabbable element in the screen (or the screen itself). if (!elementToFocus) { const [firstTabbable] = _dom.focus.tabbable.find(wrapperEl); elementToFocus = firstTabbable !== null && firstTabbable !== void 0 ? firstTabbable : wrapperEl; } locationRef.current.hasRestoredFocus = true; elementToFocus.focus(); }, [skipAnimationAndFocusRestoration, isMatch, isBack, focusTargetSelector, skipFocus]); const mergedWrapperRef = (0, _compose.useMergeRefs)([forwardedRef, wrapperRef]); return shouldRenderScreen ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_view.View, { ref: mergedWrapperRef, className: classes, ...screenProps, ...otherProps, children: children }) : null; } const NavigatorScreen = exports.NavigatorScreen = (0, _context.contextConnect)(UnconnectedNavigatorScreen, 'Navigator.Screen'); //# sourceMappingURL=component.js.map