diff --git a/packages/expo-router/CHANGELOG.md b/packages/expo-router/CHANGELOG.md index dcae6486df0a7..4f8e10e41029a 100644 --- a/packages/expo-router/CHANGELOG.md +++ b/packages/expo-router/CHANGELOG.md @@ -28,6 +28,7 @@ - Cancel ExpoRouter SplashScreen during test teardown ([#27620](https://github.com/expo/expo/pull/27620) by [@marklawlor](https://github.com/marklawlor)) - Export `toHaveRouterState` and other matcher types from `expo-router/testing-library` ([#27646](https://github.com/expo/expo/pull/27646) by [@marklawlor](https://github.com/marklawlor)) - Fix missing types from typed routes ([#27412](https://github.com/expo/expo/pull/27412) by [@marklawlor](https://github.com/marklawlor)) +- Fork NavigationContainer on web to use custom linking context ([#27712](https://github.com/expo/expo/pull/27712) by [@marklawlor](https://github.com/marklawlor)) ### 💡 Others diff --git a/packages/expo-router/build/fork/NavigationContainer.d.ts b/packages/expo-router/build/fork/NavigationContainer.d.ts index 8e94d015d7923..dc797e94aa957 100644 --- a/packages/expo-router/build/fork/NavigationContainer.d.ts +++ b/packages/expo-router/build/fork/NavigationContainer.d.ts @@ -1,3 +1,26 @@ -import { NavigationContainer } from '@react-navigation/native'; +import { NavigationContainerProps, NavigationContainerRef } from '@react-navigation/core'; +import { DocumentTitleOptions, LinkingOptions, Theme } from '@react-navigation/native'; +import * as React from 'react'; +declare global { + var REACT_NAVIGATION_DEVTOOLS: WeakMap, { + readonly linking: LinkingOptions; + }>; +} +type Props = NavigationContainerProps & { + theme?: Theme; + linking?: LinkingOptions; + fallback?: React.ReactNode; + documentTitle?: DocumentTitleOptions; + onReady?: () => void; +}; +declare const NavigationContainer: (props: NavigationContainerProps & { + theme?: Theme | undefined; + linking?: LinkingOptions | undefined; + fallback?: React.ReactNode; + documentTitle?: DocumentTitleOptions | undefined; + onReady?: (() => void) | undefined; +} & { + ref?: React.Ref> | undefined; +}) => React.ReactElement; export default NavigationContainer; //# sourceMappingURL=NavigationContainer.d.ts.map \ No newline at end of file diff --git a/packages/expo-router/build/fork/NavigationContainer.d.ts.map b/packages/expo-router/build/fork/NavigationContainer.d.ts.map index 6967de5e569bf..b3212d482c178 100644 --- a/packages/expo-router/build/fork/NavigationContainer.d.ts.map +++ b/packages/expo-router/build/fork/NavigationContainer.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"NavigationContainer.d.ts","sourceRoot":"","sources":["../../src/fork/NavigationContainer.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,eAAe,mBAAmB,CAAC"} \ No newline at end of file +{"version":3,"file":"NavigationContainer.d.ts","sourceRoot":"","sources":["../../src/fork/NavigationContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,wBAAwB,EACxB,sBAAsB,EAGvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAGL,oBAAoB,EACpB,cAAc,EAEd,KAAK,EACN,MAAM,0BAA0B,CAAC;AAIlC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,yBAAyB,EAAE,OAAO,CACpC,sBAAsB,CAAC,GAAG,CAAC,EAC3B;QAAE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,CAAA;KAAE,CAC1C,CAAC;CACH;AAID,KAAK,KAAK,CAAC,SAAS,SAAS,MAAM,IAAI,wBAAwB,GAAG;IAChE,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAuGF,QAAA,MAAM,mBAAmB;;;eA1GZ,MAAM,SAAS;;qBAEV,IAAI;;;MA8GjB,MAAM,YAAY,CAAC;AAExB,eAAe,mBAAmB,CAAC"} \ No newline at end of file diff --git a/packages/expo-router/build/fork/NavigationContainer.js b/packages/expo-router/build/fork/NavigationContainer.js index d334b70cc347f..4508416b19aed 100644 --- a/packages/expo-router/build/fork/NavigationContainer.js +++ b/packages/expo-router/build/fork/NavigationContainer.js @@ -1,6 +1,111 @@ "use strict"; +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 (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __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 }); -// We only need to fork on native to support any prefixes. +// Forked from React Navigation in order to use a custom `useLinking` function. +// https://github.com/react-navigation/react-navigation/blob/6.x/packages/native/src/NavigationContainer.tsx +const core_1 = require("@react-navigation/core"); const native_1 = require("@react-navigation/native"); -exports.default = native_1.NavigationContainer; +const useBackButton_1 = __importDefault(require("@react-navigation/native/src/useBackButton")); +const useDocumentTitle_1 = __importDefault(require("@react-navigation/native/src/useDocumentTitle")); +const useThenable_1 = __importDefault(require("@react-navigation/native/src/useThenable")); +const React = __importStar(require("react")); +const useLinking_1 = __importDefault(require("./useLinking")); +global.REACT_NAVIGATION_DEVTOOLS = new WeakMap(); +/** + * Container component which holds the navigation state designed for React Native apps. + * This should be rendered at the root wrapping the whole app. + * + * @param props.initialState Initial state object for the navigation tree. When deep link handling is enabled, this will override deep links when specified. Make sure that you don't specify an `initialState` when there's a deep link (`Linking.getInitialURL()`). + * @param props.onReady Callback which is called after the navigation tree mounts. + * @param props.onStateChange Callback which is called with the latest navigation state when it changes. + * @param props.theme Theme object for the navigators. + * @param props.linking Options for deep linking. Deep link handling is enabled when this prop is provided, unless `linking.enabled` is `false`. + * @param props.fallback Fallback component to render until we have finished getting initial state when linking is enabled. Defaults to `null`. + * @param props.documentTitle Options to configure the document title on Web. Updating document title is handled by default unless `documentTitle.enabled` is `false`. + * @param props.children Child elements to render the content. + * @param props.ref Ref object which refers to the navigation object containing helper methods. + */ +function NavigationContainerInner({ theme = native_1.DefaultTheme, linking, fallback = null, documentTitle, onReady, ...rest }, ref) { + const isLinkingEnabled = linking ? linking.enabled !== false : false; + if (linking?.config) { + (0, core_1.validatePathConfig)(linking.config); + } + const refContainer = React.useRef(null); + (0, useBackButton_1.default)(refContainer); + (0, useDocumentTitle_1.default)(refContainer, documentTitle); + const { getInitialState } = (0, useLinking_1.default)(refContainer, { + independent: rest.independent, + enabled: isLinkingEnabled, + prefixes: [], + ...linking, + }); + // Add additional linking related info to the ref + // This will be used by the devtools + React.useEffect(() => { + if (refContainer.current) { + REACT_NAVIGATION_DEVTOOLS.set(refContainer.current, { + get linking() { + return { + ...linking, + enabled: isLinkingEnabled, + prefixes: linking?.prefixes ?? [], + getStateFromPath: linking?.getStateFromPath ?? core_1.getStateFromPath, + getPathFromState: linking?.getPathFromState ?? core_1.getPathFromState, + getActionFromState: linking?.getActionFromState ?? core_1.getActionFromState, + }; + }, + }); + } + }); + const [isResolved, initialState] = (0, useThenable_1.default)(getInitialState); + React.useImperativeHandle(ref, () => refContainer.current); + const linkingContext = React.useMemo(() => ({ options: linking }), [linking]); + const isReady = rest.initialState != null || !isLinkingEnabled || isResolved; + const onReadyRef = React.useRef(onReady); + React.useEffect(() => { + onReadyRef.current = onReady; + }); + React.useEffect(() => { + if (isReady) { + onReadyRef.current?.(); + } + }, [isReady]); + if (!isReady) { + // This is temporary until we have Suspense for data-fetching + // Then the fallback will be handled by a parent `Suspense` component + return fallback; + } + return ( + + + + ); +} +const NavigationContainer = React.forwardRef(NavigationContainerInner); +exports.default = NavigationContainer; //# sourceMappingURL=NavigationContainer.js.map \ No newline at end of file diff --git a/packages/expo-router/build/fork/NavigationContainer.js.map b/packages/expo-router/build/fork/NavigationContainer.js.map index d71087a29b129..d5cb8554c5203 100644 --- a/packages/expo-router/build/fork/NavigationContainer.js.map +++ b/packages/expo-router/build/fork/NavigationContainer.js.map @@ -1 +1 @@ -{"version":3,"file":"NavigationContainer.js","sourceRoot":"","sources":["../../src/fork/NavigationContainer.tsx"],"names":[],"mappings":";;AAAA,0DAA0D;AAC1D,qDAA+D;AAE/D,kBAAe,4BAAmB,CAAC","sourcesContent":["// We only need to fork on native to support any prefixes.\nimport { NavigationContainer } from '@react-navigation/native';\n\nexport default NavigationContainer;\n"]} \ No newline at end of file +{"version":3,"file":"NavigationContainer.js","sourceRoot":"","sources":["../../src/fork/NavigationContainer.tsx"],"names":[],"mappings":"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","sourcesContent":["// Forked from React Navigation in order to use a custom `useLinking` function.\n// https://github.com/react-navigation/react-navigation/blob/6.x/packages/native/src/NavigationContainer.tsx\nimport {\n BaseNavigationContainer,\n getActionFromState,\n getPathFromState,\n getStateFromPath,\n NavigationContainerProps,\n NavigationContainerRef,\n ParamListBase,\n validatePathConfig,\n} from '@react-navigation/core';\nimport {\n DefaultTheme,\n ThemeProvider,\n DocumentTitleOptions,\n LinkingOptions,\n LinkingContext,\n Theme,\n} from '@react-navigation/native';\nimport useBackButton from '@react-navigation/native/src/useBackButton';\nimport useDocumentTitle from '@react-navigation/native/src/useDocumentTitle';\nimport useThenable from '@react-navigation/native/src/useThenable';\nimport * as React from 'react';\n\nimport useLinking from './useLinking';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var REACT_NAVIGATION_DEVTOOLS: WeakMap<\n NavigationContainerRef,\n { readonly linking: LinkingOptions }\n >;\n}\n\nglobal.REACT_NAVIGATION_DEVTOOLS = new WeakMap();\n\ntype Props = NavigationContainerProps & {\n theme?: Theme;\n linking?: LinkingOptions;\n fallback?: React.ReactNode;\n documentTitle?: DocumentTitleOptions;\n onReady?: () => void;\n};\n\n/**\n * Container component which holds the navigation state designed for React Native apps.\n * This should be rendered at the root wrapping the whole app.\n *\n * @param props.initialState Initial state object for the navigation tree. When deep link handling is enabled, this will override deep links when specified. Make sure that you don't specify an `initialState` when there's a deep link (`Linking.getInitialURL()`).\n * @param props.onReady Callback which is called after the navigation tree mounts.\n * @param props.onStateChange Callback which is called with the latest navigation state when it changes.\n * @param props.theme Theme object for the navigators.\n * @param props.linking Options for deep linking. Deep link handling is enabled when this prop is provided, unless `linking.enabled` is `false`.\n * @param props.fallback Fallback component to render until we have finished getting initial state when linking is enabled. Defaults to `null`.\n * @param props.documentTitle Options to configure the document title on Web. Updating document title is handled by default unless `documentTitle.enabled` is `false`.\n * @param props.children Child elements to render the content.\n * @param props.ref Ref object which refers to the navigation object containing helper methods.\n */\nfunction NavigationContainerInner(\n {\n theme = DefaultTheme,\n linking,\n fallback = null,\n documentTitle,\n onReady,\n ...rest\n }: Props,\n ref?: React.Ref | null>\n) {\n const isLinkingEnabled = linking ? linking.enabled !== false : false;\n\n if (linking?.config) {\n validatePathConfig(linking.config);\n }\n\n const refContainer = React.useRef>(null);\n\n useBackButton(refContainer);\n useDocumentTitle(refContainer, documentTitle);\n\n const { getInitialState } = useLinking(refContainer, {\n independent: rest.independent,\n enabled: isLinkingEnabled,\n prefixes: [],\n ...linking,\n });\n\n // Add additional linking related info to the ref\n // This will be used by the devtools\n React.useEffect(() => {\n if (refContainer.current) {\n REACT_NAVIGATION_DEVTOOLS.set(refContainer.current, {\n get linking() {\n return {\n ...linking,\n enabled: isLinkingEnabled,\n prefixes: linking?.prefixes ?? [],\n getStateFromPath: linking?.getStateFromPath ?? getStateFromPath,\n getPathFromState: linking?.getPathFromState ?? getPathFromState,\n getActionFromState: linking?.getActionFromState ?? getActionFromState,\n };\n },\n });\n }\n });\n\n const [isResolved, initialState] = useThenable(getInitialState);\n\n React.useImperativeHandle(ref, () => refContainer.current);\n\n const linkingContext = React.useMemo(() => ({ options: linking }), [linking]);\n\n const isReady = rest.initialState != null || !isLinkingEnabled || isResolved;\n\n const onReadyRef = React.useRef(onReady);\n\n React.useEffect(() => {\n onReadyRef.current = onReady;\n });\n\n React.useEffect(() => {\n if (isReady) {\n onReadyRef.current?.();\n }\n }, [isReady]);\n\n if (!isReady) {\n // This is temporary until we have Suspense for data-fetching\n // Then the fallback will be handled by a parent `Suspense` component\n return fallback as React.ReactElement;\n }\n\n return (\n \n \n \n \n \n );\n}\n\nconst NavigationContainer = React.forwardRef(NavigationContainerInner) as <\n RootParamList extends object = ReactNavigation.RootParamList,\n>(\n props: Props & {\n ref?: React.Ref>;\n }\n) => React.ReactElement;\n\nexport default NavigationContainer;\n"]} \ No newline at end of file diff --git a/packages/expo-router/src/fork/NavigationContainer.tsx b/packages/expo-router/src/fork/NavigationContainer.tsx index df9943806f8e2..4502275bbe79b 100644 --- a/packages/expo-router/src/fork/NavigationContainer.tsx +++ b/packages/expo-router/src/fork/NavigationContainer.tsx @@ -1,4 +1,155 @@ -// We only need to fork on native to support any prefixes. -import { NavigationContainer } from '@react-navigation/native'; +// Forked from React Navigation in order to use a custom `useLinking` function. +// https://github.com/react-navigation/react-navigation/blob/6.x/packages/native/src/NavigationContainer.tsx +import { + BaseNavigationContainer, + getActionFromState, + getPathFromState, + getStateFromPath, + NavigationContainerProps, + NavigationContainerRef, + ParamListBase, + validatePathConfig, +} from '@react-navigation/core'; +import { + DefaultTheme, + ThemeProvider, + DocumentTitleOptions, + LinkingOptions, + LinkingContext, + Theme, +} from '@react-navigation/native'; +import useBackButton from '@react-navigation/native/src/useBackButton'; +import useDocumentTitle from '@react-navigation/native/src/useDocumentTitle'; +import useThenable from '@react-navigation/native/src/useThenable'; +import * as React from 'react'; + +import useLinking from './useLinking'; + +declare global { + // eslint-disable-next-line no-var + var REACT_NAVIGATION_DEVTOOLS: WeakMap< + NavigationContainerRef, + { readonly linking: LinkingOptions } + >; +} + +global.REACT_NAVIGATION_DEVTOOLS = new WeakMap(); + +type Props = NavigationContainerProps & { + theme?: Theme; + linking?: LinkingOptions; + fallback?: React.ReactNode; + documentTitle?: DocumentTitleOptions; + onReady?: () => void; +}; + +/** + * Container component which holds the navigation state designed for React Native apps. + * This should be rendered at the root wrapping the whole app. + * + * @param props.initialState Initial state object for the navigation tree. When deep link handling is enabled, this will override deep links when specified. Make sure that you don't specify an `initialState` when there's a deep link (`Linking.getInitialURL()`). + * @param props.onReady Callback which is called after the navigation tree mounts. + * @param props.onStateChange Callback which is called with the latest navigation state when it changes. + * @param props.theme Theme object for the navigators. + * @param props.linking Options for deep linking. Deep link handling is enabled when this prop is provided, unless `linking.enabled` is `false`. + * @param props.fallback Fallback component to render until we have finished getting initial state when linking is enabled. Defaults to `null`. + * @param props.documentTitle Options to configure the document title on Web. Updating document title is handled by default unless `documentTitle.enabled` is `false`. + * @param props.children Child elements to render the content. + * @param props.ref Ref object which refers to the navigation object containing helper methods. + */ +function NavigationContainerInner( + { + theme = DefaultTheme, + linking, + fallback = null, + documentTitle, + onReady, + ...rest + }: Props, + ref?: React.Ref | null> +) { + const isLinkingEnabled = linking ? linking.enabled !== false : false; + + if (linking?.config) { + validatePathConfig(linking.config); + } + + const refContainer = React.useRef>(null); + + useBackButton(refContainer); + useDocumentTitle(refContainer, documentTitle); + + const { getInitialState } = useLinking(refContainer, { + independent: rest.independent, + enabled: isLinkingEnabled, + prefixes: [], + ...linking, + }); + + // Add additional linking related info to the ref + // This will be used by the devtools + React.useEffect(() => { + if (refContainer.current) { + REACT_NAVIGATION_DEVTOOLS.set(refContainer.current, { + get linking() { + return { + ...linking, + enabled: isLinkingEnabled, + prefixes: linking?.prefixes ?? [], + getStateFromPath: linking?.getStateFromPath ?? getStateFromPath, + getPathFromState: linking?.getPathFromState ?? getPathFromState, + getActionFromState: linking?.getActionFromState ?? getActionFromState, + }; + }, + }); + } + }); + + const [isResolved, initialState] = useThenable(getInitialState); + + React.useImperativeHandle(ref, () => refContainer.current); + + const linkingContext = React.useMemo(() => ({ options: linking }), [linking]); + + const isReady = rest.initialState != null || !isLinkingEnabled || isResolved; + + const onReadyRef = React.useRef(onReady); + + React.useEffect(() => { + onReadyRef.current = onReady; + }); + + React.useEffect(() => { + if (isReady) { + onReadyRef.current?.(); + } + }, [isReady]); + + if (!isReady) { + // This is temporary until we have Suspense for data-fetching + // Then the fallback will be handled by a parent `Suspense` component + return fallback as React.ReactElement; + } + + return ( + + + + + + ); +} + +const NavigationContainer = React.forwardRef(NavigationContainerInner) as < + RootParamList extends object = ReactNavigation.RootParamList, +>( + props: Props & { + ref?: React.Ref>; + } +) => React.ReactElement; export default NavigationContainer;