"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