263 lines
10 KiB
JavaScript
263 lines
10 KiB
JavaScript
"use strict";
|
|
'use client';
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || (function () {
|
|
var ownKeys = function(o) {
|
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
var ar = [];
|
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
return ar;
|
|
};
|
|
return ownKeys(o);
|
|
};
|
|
return function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
})();
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.store = void 0;
|
|
exports.useStore = useStore;
|
|
exports.useRouteInfo = useRouteInfo;
|
|
const native_1 = require("@react-navigation/native");
|
|
const expo_constants_1 = __importDefault(require("expo-constants"));
|
|
const react_1 = require("react");
|
|
const react_native_1 = require("react-native");
|
|
const extractPathFromURL_1 = require("../fork/extractPathFromURL");
|
|
const getStateFromPath_forks_1 = require("../fork/getStateFromPath-forks");
|
|
const getLinkingConfig_1 = require("../getLinkingConfig");
|
|
const getReactNavigationConfig_1 = require("../getReactNavigationConfig");
|
|
const getRoutes_1 = require("../getRoutes");
|
|
const routeInfo_1 = require("./routeInfo");
|
|
const href_1 = require("../link/href");
|
|
const useScreens_1 = require("../useScreens");
|
|
const PreviewRouteContext_1 = require("../link/preview/PreviewRouteContext");
|
|
const url_1 = require("../utils/url");
|
|
const SplashScreen = __importStar(require("../views/Splash"));
|
|
const storeRef = {
|
|
current: {},
|
|
};
|
|
const routeInfoCache = new WeakMap();
|
|
const routeInfoValuesCache = new Map();
|
|
let splashScreenAnimationFrame;
|
|
let hasAttemptedToHideSplash = false;
|
|
exports.store = {
|
|
shouldShowTutorial() {
|
|
return !storeRef.current.routeNode && process.env.NODE_ENV === 'development';
|
|
},
|
|
get state() {
|
|
return storeRef.current.state;
|
|
},
|
|
get navigationRef() {
|
|
return storeRef.current.navigationRef;
|
|
},
|
|
get routeNode() {
|
|
return storeRef.current.routeNode;
|
|
},
|
|
getRouteInfo() {
|
|
return storeRef.current.routeInfo || routeInfo_1.defaultRouteInfo;
|
|
},
|
|
get redirects() {
|
|
return storeRef.current.redirects || [];
|
|
},
|
|
get rootComponent() {
|
|
return storeRef.current.rootComponent;
|
|
},
|
|
getStateForHref(href, options) {
|
|
href = (0, href_1.resolveHref)(href);
|
|
href = (0, href_1.resolveHrefStringWithSegments)(href, exports.store.getRouteInfo(), options);
|
|
return this.linking?.getStateFromPath(href, this.linking.config);
|
|
},
|
|
get linking() {
|
|
return storeRef.current.linking;
|
|
},
|
|
setFocusedState(state) {
|
|
const routeInfo = getCachedRouteInfo(state);
|
|
storeRef.current.routeInfo = routeInfo;
|
|
},
|
|
onReady() {
|
|
if (!hasAttemptedToHideSplash) {
|
|
hasAttemptedToHideSplash = true;
|
|
// NOTE(EvanBacon): `navigationRef.isReady` is sometimes not true when state is called initially.
|
|
splashScreenAnimationFrame = requestAnimationFrame(() => {
|
|
SplashScreen._internal_maybeHideAsync?.();
|
|
});
|
|
}
|
|
},
|
|
onStateChange(newState) {
|
|
if (!newState) {
|
|
return;
|
|
}
|
|
if (process.env.NODE_ENV === 'development') {
|
|
let isStale = false;
|
|
let state = newState;
|
|
while (!isStale && state) {
|
|
isStale = state.stale;
|
|
state =
|
|
state.routes?.['index' in state && typeof state.index === 'number'
|
|
? state.index
|
|
: state.routes.length - 1]?.state;
|
|
}
|
|
if (isStale) {
|
|
// This should never happen, as onStateChange should provide a full state. However, adding this check to catch any undocumented behavior.
|
|
console.error('Detected stale state in onStateChange. This is likely a bug in Expo Router.');
|
|
}
|
|
}
|
|
storeRef.current.state = newState;
|
|
storeRef.current.routeInfo = getCachedRouteInfo(newState);
|
|
for (const callback of routeInfoSubscribers) {
|
|
callback();
|
|
}
|
|
},
|
|
assertIsReady() {
|
|
if (!storeRef.current.navigationRef.isReady()) {
|
|
throw new Error('Attempted to navigate before mounting the Root Layout component. Ensure the Root Layout component is rendering a Slot, or other navigator on the first render.');
|
|
}
|
|
},
|
|
};
|
|
function useStore(context, linkingConfigOptions, serverUrl) {
|
|
const navigationRef = (0, native_1.useNavigationContainerRef)();
|
|
const config = expo_constants_1.default.expoConfig?.extra?.router;
|
|
let linking;
|
|
let rootComponent = react_1.Fragment;
|
|
let initialState;
|
|
const routeNode = (0, getRoutes_1.getRoutes)(context, {
|
|
...config,
|
|
skipGenerated: true,
|
|
ignoreEntryPoints: true,
|
|
platform: react_native_1.Platform.OS,
|
|
preserveRedirectAndRewrites: true,
|
|
});
|
|
const redirects = [config?.redirects, config?.rewrites]
|
|
.filter(Boolean)
|
|
.flat()
|
|
.map((route) => {
|
|
return [
|
|
(0, getStateFromPath_forks_1.routePatternToRegex)((0, getReactNavigationConfig_1.parseRouteSegments)(route.source)),
|
|
route,
|
|
(0, url_1.shouldLinkExternally)(route.destination),
|
|
];
|
|
});
|
|
if (routeNode) {
|
|
// We have routes, so get the linking config and the root component
|
|
linking = (0, getLinkingConfig_1.getLinkingConfig)(routeNode, context, () => exports.store.getRouteInfo(), {
|
|
metaOnly: linkingConfigOptions.metaOnly,
|
|
serverUrl,
|
|
redirects,
|
|
skipGenerated: config?.skipGenerated ?? false,
|
|
sitemap: config?.sitemap ?? true,
|
|
notFound: config?.notFound ?? true,
|
|
});
|
|
rootComponent = (0, useScreens_1.getQualifiedRouteComponent)(routeNode);
|
|
// By default React Navigation is async and does not render anything in the first pass as it waits for `getInitialURL`
|
|
// This will cause static rendering to fail, which once performs a single pass.
|
|
// If the initialURL is a string, we can prefetch the state and routeInfo, skipping React Navigation's async behavior.
|
|
const initialURL = linking?.getInitialURL?.();
|
|
if (typeof initialURL === 'string') {
|
|
let initialPath = (0, extractPathFromURL_1.extractExpoPathFromURL)(linking.prefixes, initialURL);
|
|
// It does not matter if the path starts with a `/` or not, but this keeps the behavior consistent
|
|
if (!initialPath.startsWith('/'))
|
|
initialPath = '/' + initialPath;
|
|
initialState = linking.getStateFromPath(initialPath, linking.config);
|
|
const initialRouteInfo = (0, routeInfo_1.getRouteInfoFromState)(initialState);
|
|
routeInfoCache.set(initialState, initialRouteInfo);
|
|
routeInfoValuesCache.set(JSON.stringify(initialRouteInfo), initialRouteInfo);
|
|
}
|
|
}
|
|
else {
|
|
// Only error in production, in development we will show the onboarding screen
|
|
if (process.env.NODE_ENV === 'production') {
|
|
throw new Error('No routes found');
|
|
}
|
|
// In development, we will show the onboarding screen
|
|
rootComponent = react_1.Fragment;
|
|
}
|
|
if (react_native_1.Platform.OS === 'android' && storeRef.current.state && storeRef.current.context === context) {
|
|
initialState = storeRef.current.state;
|
|
}
|
|
storeRef.current = {
|
|
navigationRef,
|
|
routeNode,
|
|
config,
|
|
rootComponent,
|
|
linking,
|
|
redirects,
|
|
state: initialState,
|
|
context,
|
|
};
|
|
if (initialState) {
|
|
storeRef.current.routeInfo = getCachedRouteInfo(initialState);
|
|
}
|
|
(0, react_1.useEffect)(() => {
|
|
return () => {
|
|
// listener();
|
|
if (splashScreenAnimationFrame) {
|
|
cancelAnimationFrame(splashScreenAnimationFrame);
|
|
splashScreenAnimationFrame = undefined;
|
|
}
|
|
};
|
|
});
|
|
return exports.store;
|
|
}
|
|
const routeInfoSubscribers = new Set();
|
|
const routeInfoSubscribe = (callback) => {
|
|
routeInfoSubscribers.add(callback);
|
|
return () => {
|
|
routeInfoSubscribers.delete(callback);
|
|
};
|
|
};
|
|
function useRouteInfo() {
|
|
const routeInfo = (0, react_1.useSyncExternalStore)(routeInfoSubscribe, exports.store.getRouteInfo, exports.store.getRouteInfo);
|
|
const { isPreview, segments, params, pathname } = (0, PreviewRouteContext_1.usePreviewInfo)();
|
|
if (isPreview) {
|
|
return {
|
|
pathname: pathname ?? '',
|
|
segments: segments ?? [],
|
|
unstable_globalHref: '',
|
|
params: params ?? {},
|
|
searchParams: new URLSearchParams(),
|
|
pathnameWithParams: pathname ?? '',
|
|
isIndex: false,
|
|
};
|
|
}
|
|
return routeInfo;
|
|
}
|
|
function getCachedRouteInfo(state) {
|
|
let routeInfo = routeInfoCache.get(state);
|
|
if (!routeInfo) {
|
|
routeInfo = (0, routeInfo_1.getRouteInfoFromState)(state);
|
|
const routeInfoString = JSON.stringify(routeInfo);
|
|
// Using cached values to avoid re-renders, to increase the chance that the object reference is the same
|
|
const cachedRouteInfo = routeInfoValuesCache.get(routeInfoString);
|
|
if (cachedRouteInfo) {
|
|
routeInfo = cachedRouteInfo;
|
|
}
|
|
else {
|
|
routeInfoValuesCache.set(routeInfoString, routeInfo);
|
|
}
|
|
routeInfoCache.set(state, routeInfo);
|
|
}
|
|
return routeInfo;
|
|
}
|
|
//# sourceMappingURL=router-store.js.map
|