"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.NavigatorScreen = void 0;
var _dom = require("@wordpress/dom");
var _element = require("@wordpress/element");
var _compose = require("@wordpress/compose");
var _i18n = require("@wordpress/i18n");
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 _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.NavigatorScreen: 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,
    ...otherProps
  } = (0, _context.useContextSystem)(props, 'NavigatorScreen');
  const {
    location,
    match,
    addScreen,
    removeScreen
  } = (0, _element.useContext)(_context2.NavigatorContext);
  const isMatch = match === screenId;
  const wrapperRef = (0, _element.useRef)(null);
  (0, _element.useEffect)(() => {
    const screen = {
      id: screenId,
      path: (0, _escapeHtml.escapeAttribute)(path)
    };
    addScreen(screen);
    return () => removeScreen(screen);
  }, [screenId, path, addScreen, removeScreen]);
  const isRTL = (0, _i18n.isRTL)();
  const {
    isInitial,
    isBack
  } = location;
  const cx = (0, _useCx.useCx)();
  const classes = (0, _element.useMemo)(() => cx(styles.navigatorScreen({
    isInitial,
    isBack,
    isRTL
  }), className), [className, cx, isInitial, isBack, isRTL]);
  const locationRef = (0, _element.useRef)(location);
  (0, _element.useEffect)(() => {
    locationRef.current = location;
  }, [location]);

  // Focus restoration
  const isInitialLocation = location.isInitial && !location.isBack;
  (0, _element.useEffect)(() => {
    // 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 (isInitialLocation || !isMatch || !wrapperRef.current || locationRef.current.hasRestoredFocus || location.skipFocus) {
      return;
    }
    const activeElement = wrapperRef.current.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 (wrapperRef.current.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 (location.isBack && location.focusTargetSelector) {
      elementToFocus = wrapperRef.current.querySelector(location.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(wrapperRef.current);
      elementToFocus = firstTabbable !== null && firstTabbable !== void 0 ? firstTabbable : wrapperRef.current;
    }
    locationRef.current.hasRestoredFocus = true;
    elementToFocus.focus();
  }, [isInitialLocation, isMatch, location.isBack, location.focusTargetSelector, location.skipFocus]);
  const mergedWrapperRef = (0, _compose.useMergeRefs)([forwardedRef, wrapperRef]);
  return isMatch ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_view.View, {
    ref: mergedWrapperRef,
    className: classes,
    ...otherProps,
    children: children
  }) : null;
}

/**
 * The `NavigatorScreen` component represents a single view/screen/panel and
 * should be used in combination with the `NavigatorProvider`, the
 * `NavigatorButton` and the `NavigatorBackButton` components (or the `useNavigator`
 * hook).
 *
 * @example
 * ```jsx
 * import {
 *   __experimentalNavigatorProvider as NavigatorProvider,
 *   __experimentalNavigatorScreen as NavigatorScreen,
 *   __experimentalNavigatorButton as NavigatorButton,
 *   __experimentalNavigatorBackButton as NavigatorBackButton,
 * } from '@wordpress/components';
 *
 * const MyNavigation = () => (
 *   <NavigatorProvider initialPath="/">
 *     <NavigatorScreen path="/">
 *       <p>This is the home screen.</p>
 *        <NavigatorButton path="/child">
 *          Navigate to child screen.
 *       </NavigatorButton>
 *     </NavigatorScreen>
 *
 *     <NavigatorScreen path="/child">
 *       <p>This is the child screen.</p>
 *       <NavigatorBackButton>
 *         Go back
 *       </NavigatorBackButton>
 *     </NavigatorScreen>
 *   </NavigatorProvider>
 * );
 * ```
 */
const NavigatorScreen = exports.NavigatorScreen = (0, _context.contextConnect)(UnconnectedNavigatorScreen, 'NavigatorScreen');
var _default = exports.default = NavigatorScreen;
//# sourceMappingURL=component.js.map