UNPKG

expo-router

Version:

Expo Router is a file-based router for React Native and web applications.

362 lines (360 loc) • 17.5 kB
'use client'; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "BaseNavigationContainer", { enumerable: true, get: function() { return BaseNavigationContainer; } }); function _jsxruntime() { const data = require("react/jsx-runtime"); _jsxruntime = function() { return data; }; return data; } function _react() { const data = /*#__PURE__*/ _interop_require_wildcard(require("react")); _react = function() { return data; }; return data; } const _findFocusedRoute = require("../../fork/findFocusedRoute"); const _BrowserHistorySync = require("../../global-state/BrowserHistorySync"); const _RoutingQueueDrainer = require("../../global-state/RoutingQueueDrainer"); const _browserHistoryAdapter = require("../../global-state/browserHistoryAdapter"); const _getRouteInfoFromState = require("../../global-state/getRouteInfoFromState"); const _removalPrevention = require("../../global-state/removalPrevention"); const _routeInfoContext = require("../../global-state/routeInfoContext"); const _routerConfigContext = require("../../global-state/routerConfigContext"); const _routerRegistry = require("../../global-state/routerRegistry"); const _routingQueueContext = require("../../global-state/routingQueueContext"); const _useNavigationTreeReducer = require("../../global-state/useNavigationTreeReducer"); const _useNavigationTreeReportEvents = require("../../global-state/useNavigationTreeReportEvents"); const _useLatestCallback = /*#__PURE__*/ _interop_require_default(require("../../utils/useLatestCallback")); const _routers = require("../routers"); const _CanDismissContext = require("./CanDismissContext"); const _CanGoBackContext = require("./CanGoBackContext"); const _EnsureSingleNavigator = require("./EnsureSingleNavigator"); const _NavigationBuilderContext = require("./NavigationBuilderContext"); const _NavigationContainerRefContext = require("./NavigationContainerRefContext"); const _NavigationStateContext = require("./NavigationStateContext"); const _RootNavigationStateContext = require("./RootNavigationStateContext"); const _checkDuplicateRouteNames = require("./checkDuplicateRouteNames"); const _checkSerializable = require("./checkSerializable"); const _createNavigationContainerRef = require("./createNavigationContainerRef"); const _ThemeProvider = require("./theming/ThemeProvider"); const _useChildListeners = require("./useChildListeners"); const _useClientLayoutEffect = require("./useClientLayoutEffect"); const _useEventEmitter = require("./useEventEmitter"); const _useOptionsGetters = require("./useOptionsGetters"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interop_require_wildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = { __proto__: null }; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const serializableWarnings = []; const duplicateNameWarnings = []; function BaseNavigationContainer(props) { const { ref, initialState, UNSTABLE_routeNode, theme, children } = props; const parent = (0, _react().use)(_NavigationStateContext.NavigationStateContext); const inheritedRouteInfo = (0, _react().use)(_routeInfoContext.RouteInfoContext); const routerConfig = (0, _react().use)(_routerConfigContext.RouterConfigContext); const routingQueue = (0, _react().use)(_routingQueueContext.RoutingQueueApiContext); const isNavigationPending = (0, _react().use)(_routingQueueContext.NavigationPendingContext); const routesWithRemovalPrevented = (0, _react().use)(_removalPrevention.GlobalRoutesWithRemovalPreventedContext); if (!parent.isDefault) { throw new Error("Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If you need to render an isolated navigation tree inside a screen, install '@react-navigation/native' and use its NavigationContainer instead."); } if (routingQueue === undefined || routesWithRemovalPrevented === undefined) { throw new Error('The navigation container requires the shared routing state provided by `ExpoRoot`. Render the navigation container inside `ExpoRoot`.'); } const emitter = (0, _useEventEmitter.useEventEmitter)(); const [registry, setRegistry] = _react().useState(()=>new Map()); // TODO(@ubax): consider moving this state to ExpoRoot. const { state, isWaitingForLayouts, report, consumeReportEvents, resetNavigator, handleAction, processIntent } = (0, _useNavigationTreeReducer.useNavigationTreeReducer)({ initialState, routeNode: UNSTABLE_routeNode, registry, routesWithRemovalPrevented, linking: routerConfig?.linking, redirects: routerConfig?.redirects }); const [browserHistory] = _react().useState(_browserHistoryAdapter.createBrowserHistoryAdapter); (0, _useNavigationTreeReportEvents.useNavigationTreeReportEvents)(report, consumeReportEvents, browserHistory); const registrySetters = _react().useMemo(()=>({ register (stateKey, entry) { setRegistry((previous)=>{ if (previous.get(stateKey) === entry) { return previous; } return new Map(previous).set(stateKey, entry); }); }, unregister (stateKey, entry) { setRegistry((previous)=>{ if (previous.get(stateKey) !== entry) { return previous; } const next = new Map(previous); next.delete(stateKey); return next; }); } }), []); const { listeners, addListener } = (0, _useChildListeners.useChildListeners)(); const dispatch = (0, _useLatestCallback.default)((action)=>{ if (listeners.focus[0] == null) { console.error(_createNavigationContainerRef.NOT_INITIALIZED_ERROR); } else { listeners.focus[0]((navigation)=>navigation.dispatch(action)); } }); const dispatchSync = (0, _useLatestCallback.default)((action)=>{ // TODO(@ubax): Throw if this is called from a `removePrevented` callback. // TODO(@ubax): Review urgent dispatches interleaved with pending navigation transitions. React // rebases the queued actions, but intermediate state can reflect only the urgent action. handleAction(action); }); const canGoBack = (0, _useLatestCallback.default)(()=>{ if (listeners.focus[0] == null) { return false; } const { result, handled } = listeners.focus[0]((navigation)=>navigation.canGoBack()); if (handled) { return result; } else { return false; } }); const getRootState = (0, _useLatestCallback.default)(()=>state); // TODO(@ubax): Back router.canGoBack() with this value (ENG-28350). const focusedCanGoBack = (0, _CanGoBackContext.getFocusedCanGoBack)(state); const canDismiss = (0, _CanDismissContext.getCanDismiss)(state); const getCurrentRoute = (0, _useLatestCallback.default)(()=>{ const state = getRootState(); if (state == null) { return undefined; } const route = (0, _findFocusedRoute.findFocusedRoute)(state); return route; }); const { addOptionsGetter, getCurrentOptions } = (0, _useOptionsGetters.useOptionsGetters)({}); const navigation = _react().useMemo(()=>({ ...Object.keys(_routers.CommonActions).reduce((acc, name)=>{ acc[name] = (...args)=>// @ts-expect-error: this is ok dispatch(_routers.CommonActions[name](...args)); return acc; }, {}), ...emitter.create('root'), dispatch, dispatchSync, isFocused: ()=>true, canGoBack, getParent: ()=>undefined, getState: getRootState, getRootState, getCurrentRoute, getCurrentOptions, // Kept for compatibility. There is no ready state to report. isReady: ()=>true, setOptions: ()=>{ throw new Error('Cannot call setOptions outside a screen'); } }), [ canGoBack, dispatch, dispatchSync, emitter, getCurrentOptions, getCurrentRoute, getRootState ]); _react().useImperativeHandle(ref, ()=>navigation, [ navigation ]); const builderContext = _react().useMemo(()=>({ addListener, handleAction, resetNavigator }), [ addListener, handleAction, resetNavigator ]); const context = _react().useMemo(()=>({ state, addOptionsGetter }), [ state, addOptionsGetter ]); const nextRouteInfo = _react().useMemo(()=>UNSTABLE_routeNode ? (0, _getRouteInfoFromState.getRouteInfoFromState)(state) : inheritedRouteInfo, [ state, UNSTABLE_routeNode, inheritedRouteInfo ]); const [routeInfo, setRouteInfo] = _react().useState(nextRouteInfo); // React retries this component before rendering its children, preserving context identity when // the derived route info is unchanged. https://react.dev/reference/react/useState#storing-information-from-previous-renders if (!(0, _getRouteInfoFromState.areUrlObjectsEqual)(routeInfo, nextRouteInfo)) { setRouteInfo(nextRouteInfo); } _react().useEffect(()=>{ const hydratedState = getRootState(); if (process.env.NODE_ENV !== 'production') { if (hydratedState !== undefined) { const serializableResult = (0, _checkSerializable.checkSerializable)(hydratedState); if (!serializableResult.serializable) { const { location, reason } = serializableResult; let path = ''; let pointer = hydratedState; let params = false; for(let i = 0; i < location.length; i++){ const curr = location[i]; const prev = location[i - 1]; pointer = pointer[curr]; if (!params && curr === 'state') { continue; } else if (!params && curr === 'routes') { if (path) { path += ' > '; } } else if (!params && typeof curr === 'number' && prev === 'routes') { path += pointer?.name; } else if (!params) { path += ` > ${curr}`; params = true; } else { if (typeof curr === 'number' || /^[0-9]+$/.test(curr)) { path += `[${curr}]`; } else if (/^[a-z$_]+$/i.test(curr)) { path += `.${curr}`; } else { path += `[${JSON.stringify(curr)}]`; } } } const message = `Non-serializable values were found in the navigation state. Check:\n\n${path} (${reason})\n\nThis can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. Pass only serializable values in route params.`; if (!serializableWarnings.includes(message)) { serializableWarnings.push(message); console.warn(message); } } const duplicateRouteNamesResult = (0, _checkDuplicateRouteNames.checkDuplicateRouteNames)(hydratedState); if (duplicateRouteNamesResult.length) { const message = `Found screens with the same name nested inside one another. Check:\n${duplicateRouteNamesResult.map((locations)=>`\n${locations.join(', ')}`)}\n\nThis can cause confusing behavior during navigation. Consider using unique names for each screen instead.`; if (!duplicateNameWarnings.includes(message)) { duplicateNameWarnings.push(message); console.warn(message); } } } } }, [ getRootState, state ]); (0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{ emitter.emit({ type: 'state', data: { state } }); }, [ emitter, state ]); return /*#__PURE__*/ (0, _jsxruntime().jsx)(_NavigationContainerRefContext.NavigationContainerRefContext.Provider, { value: navigation, children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_NavigationBuilderContext.NavigationBuilderContext.Provider, { value: builderContext, children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_NavigationStateContext.NavigationStateContext.Provider, { value: context, children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_routeInfoContext.RouteInfoContext.Provider, { value: routeInfo, children: /*#__PURE__*/ (0, _jsxruntime().jsxs)(_RootNavigationStateContext.RootNavigationStateContext.Provider, { value: state, children: [ /*#__PURE__*/ (0, _jsxruntime().jsx)(_CanGoBackContext.CanGoBackContext, { value: focusedCanGoBack, children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_CanDismissContext.CanDismissContext, { value: canDismiss, children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_routerRegistry.RouterRegistrySettersContext.Provider, { value: registrySetters, children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_EnsureSingleNavigator.EnsureSingleNavigator, { children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_routingQueueContext.NavigationPendingContext, { value: isNavigationPending || isWaitingForLayouts, children: /*#__PURE__*/ (0, _jsxruntime().jsx)(_ThemeProvider.ThemeProvider, { value: theme, children: children }) }) }) }) }) }), /*#__PURE__*/ (0, _jsxruntime().jsx)(_routingQueueContext.ImperativeRoutingQueueBridge, { enqueue: routingQueue.enqueue, setTransitionMode: routingQueue.setTransitionMode }), /*#__PURE__*/ (0, _jsxruntime().jsx)(_RoutingQueueDrainer.RoutingQueueDrainer, { processIntent: processIntent }), /*#__PURE__*/ (0, _jsxruntime().jsx)(_BrowserHistorySync.BrowserHistorySync, { adapter: browserHistory }) ] }) }) }) }) }); } //# sourceMappingURL=BaseNavigationContainer.js.map