UNPKG

one

Version:

One is a new React Framework that makes Vite serve both native and web.

105 lines (91 loc) 3.59 kB
import * as Linking from 'expo-linking' import { Platform } from 'react-native' import { adjustPathname } from '../fork/extractPathFromURL' import { getPathFromState } from '../fork/getPathFromState' import { getStateFromPath } from '../fork/getStateFromPath' // @ts-expect-error const isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo // A custom getInitialURL is used on native to ensure the app always starts at // the root path if it's launched from something other than a deep link. // This helps keep the native functionality working like the web functionality. // For example, if you had a root navigator where the first screen was `/settings` and the second was `/index` // then `/index` would be used on web and `/settings` would be used on native. export function getInitialURL(): Promise<string | null> | string { if (process.env.NODE_ENV === 'test') { return Linking.getInitialURL() ?? getRootURL() } if (Platform.OS === 'web') { if (typeof window === 'undefined') { return '' } if (window.location?.href) { return window.location.href } } return Promise.race<string>([ (async () => { const url = await Linking.getInitialURL() // NOTE: This could probably be wrapped with the development boundary // since Expo Go is mostly just used in development. // Expo Go is weird and requires the root path to be `/--/` if (url && isExpoGo) { const parsed = Linking.parse(url) // If the URL is defined (default in Expo Go dev apps) and the URL has no path: // `exp://192.168.87.39:19000/` then use the default `exp://192.168.87.39:19000/--/` if ( parsed.path === null || ['', '/'].includes( adjustPathname({ hostname: parsed.hostname, pathname: parsed.path, }) ) ) { return getRootURL() } } // The path will be nullish in bare apps when the app is launched from the home screen. // TODO: define some policy around notifications. return url ?? getRootURL() })(), new Promise<string>((resolve) => // Timeout in 150ms if `getInitialState` doesn't resolve // Workaround for https://github.com/facebook/react-native/issues/25675 setTimeout(() => resolve(getRootURL()), 150) ), ]) } let _rootURL: string | undefined export function getRootURL(): string { if (_rootURL === undefined) { _rootURL = Linking.createURL('/') } return _rootURL } export function addEventListener(listener: (url: string) => void) { let callback: (({ url }: { url: string }) => void) | undefined if (isExpoGo) { // This extra work is only done in the Expo Go app. callback = ({ url }: { url: string }) => { const parsed = Linking.parse(url) // If the URL is defined (default in Expo Go dev apps) and the URL has no path: // `exp://192.168.87.39:19000/` then use the default `exp://192.168.87.39:19000/--/` if ( parsed.path === null || ['', '/'].includes(adjustPathname({ hostname: parsed.hostname, pathname: parsed.path })) ) { listener(getRootURL()) } else { listener(url) } } } else { callback = ({ url }: { url: string }) => listener(url) } const subscription = Linking.addEventListener('url', callback) return () => { // https://github.com/facebook/react-native/commit/6d1aca806cee86ad76de771ed3a1cc62982ebcd7 subscription?.remove?.() } } export { getStateFromPath, getPathFromState }