diff --git a/404.html b/404.html index 729721a7ba..c97b0b311c 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ -Page Not Found | React Navigation
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

\ No newline at end of file +Page Not Found | React Navigation
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

\ No newline at end of file diff --git a/assets/js/8c4738b1.6f7dc34c.js b/assets/js/8c4738b1.6f7dc34c.js new file mode 100644 index 0000000000..7802ec9942 --- /dev/null +++ b/assets/js/8c4738b1.6f7dc34c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkreact_navigation_website_next=self.webpackChunkreact_navigation_website_next||[]).push([["95935"],{24906:function(e,n,t){t.r(n),t.d(n,{metadata:()=>i,contentTitle:()=>d,default:()=>g,assets:()=>h,toc:()=>p,frontMatter:()=>l});var i=JSON.parse('{"id":"configuring-links","title":"Configuring links","description":"In this guide, we will configure React Navigation to handle external links. This is necessary if you want to:","source":"@site/versioned_docs/version-7.x/configuring-links.md","sourceDirName":".","slug":"/configuring-links","permalink":"/docs/configuring-links","draft":false,"unlisted":false,"editUrl":"https://github.com/react-navigation/react-navigation.github.io/edit/main/versioned_docs/version-7.x/configuring-links.md","tags":[],"version":"7.x","frontMatter":{"id":"configuring-links","title":"Configuring links","sidebar_label":"Configuring links"},"sidebar":"docs","previous":{"title":"Deep linking","permalink":"/docs/deep-linking"},"next":{"title":"Web support","permalink":"/docs/web-support"}}'),a=t("85893"),s=t("50065"),r=t("47902"),o=t("5525"),c=t("41665");let l={id:"configuring-links",title:"Configuring links",sidebar_label:"Configuring links"},d=void 0,h={},p=[{value:"Prefixes",id:"prefixes",level:2},{value:"Multiple subdomains\u200B",id:"multiple-subdomains",level:3},{value:"Filtering certain paths",id:"filtering-certain-paths",level:2},{value:"Apps under subpaths",id:"apps-under-subpaths",level:2},{value:"Mapping path to route names",id:"mapping-path-to-route-names",level:2},{value:"How does automatic path generation work?",id:"how-does-automatic-path-generation-work",level:3},{value:"Passing params",id:"passing-params",level:2},{value:"Marking params as optional",id:"marking-params-as-optional",level:2},{value:"Handling unmatched routes or 404",id:"handling-unmatched-routes-or-404",level:2},{value:"Rendering an initial route",id:"rendering-an-initial-route",level:2},{value:"Matching exact paths",id:"matching-exact-paths",level:2},{value:"Omitting a screen from path",id:"omitting-a-screen-from-path",level:2},{value:"Serializing and parsing params",id:"serializing-and-parsing-params",level:2},{value:"Matching regular expressions",id:"matching-regular-expressions",level:2},{value:"Advanced cases",id:"advanced-cases",level:2},{value:"Playground",id:"playground",level:2}];function u(e){let n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components},{Details:t}=n;return!t&&x("Details",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.p,{children:"In this guide, we will configure React Navigation to handle external links. This is necessary if you want to:"}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsx)(n.li,{children:"Handle deep links in React Native apps on Android and iOS"}),"\n",(0,a.jsx)(n.li,{children:"Enable URL integration in browser when using on web"}),"\n",(0,a.jsxs)(n.li,{children:["Use ",(0,a.jsx)(n.a,{href:"/docs/link",children:(0,a.jsx)(n.code,{children:""})})," or ",(0,a.jsx)(n.a,{href:"/docs/use-link-to",children:(0,a.jsx)(n.code,{children:"useLinkTo"})})," to navigate using paths."]}),"\n"]}),"\n",(0,a.jsxs)(n.p,{children:["Make sure that you have ",(0,a.jsx)(n.a,{href:"/docs/deep-linking",children:"configured deep links"})," in your app before proceeding. If you have an Android or iOS app, remember to specify the ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkingprefixes",children:(0,a.jsx)(n.code,{children:"prefixes"})})," option."]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsxs)(o.Z,{value:"static",label:"Static",default:!0,children:[(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.a,{href:"/docs/static-configuration#createstaticnavigation",children:(0,a.jsx)(n.code,{children:"Navigation"})})," component accepts a ",(0,a.jsx)(n.a,{href:"/docs/static-configuration#differences-in-the-linking-prop",children:(0,a.jsx)(n.code,{children:"linking"})})," prop that makes it easier to handle incoming links:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"import { createStaticNavigation } from '@react-navigation/native';\n\n// highlight-start\nconst linking = {\n enabled: 'auto' /* Automatically generate paths for all screens */,\n prefixes: [\n /* your linking prefixes */\n ],\n};\n// highlight-end\n\nfunction App() {\n return (\n Loading...}\n />\n );\n}\n\nconst Navigation = createStaticNavigation(RootStack);\n"})})]}),(0,a.jsxs)(o.Z,{value:"dynamic",label:"Dynamic",children:[(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"NavigationContainer"})," accepts a ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linking",children:(0,a.jsx)(n.code,{children:"linking"})})," prop that makes it easier to handle incoming links. The 2 of the most important properties you can specify in the ",(0,a.jsx)(n.code,{children:"linking"})," prop are ",(0,a.jsx)(n.code,{children:"prefixes"})," and ",(0,a.jsx)(n.code,{children:"config"}),":"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"import { NavigationContainer } from '@react-navigation/native';\n\n// highlight-start\nconst linking = {\n prefixes: [\n /* your linking prefixes */\n ],\n config: {\n /* configuration for matching screens with paths */\n },\n};\n// highlight-end\n\nfunction App() {\n return (\n Loading...}\n >\n {/* content */}\n \n );\n}\n"})})]})]}),"\n",(0,a.jsxs)(n.p,{children:["When you specify the ",(0,a.jsx)(n.code,{children:"linking"})," prop, React Navigation will handle incoming links automatically. On Android and iOS, it'll use React Native's ",(0,a.jsxs)(n.a,{href:"https://reactnative.dev/docs/linking",children:[(0,a.jsx)(n.code,{children:"Linking"})," module"]})," to handle incoming links, both when the app was opened with the link, and when new links are received when the app is open. On the Web, it'll use the ",(0,a.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/History_API",children:"History API"})," to sync the URL with the browser."]}),"\n",(0,a.jsx)(n.admonition,{type:"warning",children:(0,a.jsxs)(n.p,{children:["Currently there seems to be bug (",(0,a.jsx)(n.a,{href:"https://github.com/facebook/react-native/issues/25675",children:"facebook/react-native#25675"}),") which results in it never resolving on Android. We add a timeout to avoid getting stuck forever, but it means that the link might not be handled in some cases."]})}),"\n",(0,a.jsxs)(n.p,{children:["You can also pass a ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#fallback",children:(0,a.jsx)(n.code,{children:"fallback"})})," prop that controls what's displayed when React Navigation is trying to resolve the initial deep link URL."]}),"\n",(0,a.jsx)(n.h2,{id:"prefixes",children:"Prefixes"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"prefixes"})," option can be used to specify custom schemes (e.g. ",(0,a.jsx)(n.code,{children:"mychat://"}),") as well as host & domain names (e.g. ",(0,a.jsx)(n.code,{children:"https://mychat.com"}),") if you have configured ",(0,a.jsx)(n.a,{href:"https://developer.apple.com/ios/universal-links/",children:"Universal Links"})," or ",(0,a.jsx)(n.a,{href:"https://developer.android.com/training/app-links",children:"Android App Links"}),"."]}),"\n",(0,a.jsx)(n.p,{children:"For example:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com'],\n};\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Note that the ",(0,a.jsx)(n.code,{children:"prefixes"})," option is not supported on Web. The host & domain names will be automatically determined from the Website URL in the browser. If your app runs only on Web, then you can omit this option from the config."]}),"\n",(0,a.jsx)(n.h3,{id:"multiple-subdomains",children:"Multiple subdomains\u200B"}),"\n",(0,a.jsxs)(n.p,{children:["To match all subdomains of an associated domain, you can specify a wildcard by prefixing ",(0,a.jsx)(n.code,{children:"*"}),". before the beginning of a specific domain. Note that an entry for ",(0,a.jsx)(n.code,{children:"*.mychat.com"})," does not match ",(0,a.jsx)(n.code,{children:"mychat.com"})," because of the period after the asterisk. To enable matching for both ",(0,a.jsx)(n.code,{children:"*.mychat.com"})," and ",(0,a.jsx)(n.code,{children:"mychat.com"}),", you need to provide a separate prefix entry for each."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com', 'https://*.mychat.com'],\n};\n"})}),"\n",(0,a.jsx)(n.h2,{id:"filtering-certain-paths",children:"Filtering certain paths"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes we may not want to handle all incoming links. For example, we may want to filter out links meant for authentication (e.g. ",(0,a.jsx)(n.code,{children:"expo-auth-session"}),") or other purposes instead of navigating to a specific screen."]}),"\n",(0,a.jsxs)(n.p,{children:["To achieve this, you can use the ",(0,a.jsx)(n.code,{children:"filter"})," option:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com'],\n // highlight-next-line\n filter: (url) => !url.includes('+expo-auth-session'),\n};\n"})}),"\n",(0,a.jsx)(n.p,{children:"This is not supported on Web as we always need to handle the URL of the page."}),"\n",(0,a.jsx)(n.h2,{id:"apps-under-subpaths",children:"Apps under subpaths"}),"\n",(0,a.jsxs)(n.p,{children:["If your app is hosted under a subpath, you can specify the subpath at the top-level of the ",(0,a.jsx)(n.code,{children:"config"}),". For example, if your app is hosted at ",(0,a.jsx)(n.code,{children:"https://mychat.com/app"}),", you can specify the ",(0,a.jsx)(n.code,{children:"path"})," as ",(0,a.jsx)(n.code,{children:"app"}),":"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com'],\n config: {\n // highlight-next-line\n path: 'app',\n\n // ...\n },\n};\n"})}),"\n",(0,a.jsxs)(n.p,{children:["It's not possible to specify params here since this doesn't belong to a screen, e.g. ",(0,a.jsx)(n.code,{children:"app/:id"})," won't work."]}),"\n",(0,a.jsx)(n.h2,{id:"mapping-path-to-route-names",children:"Mapping path to route names"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsxs)(o.Z,{value:"static",label:"Static",default:!0,children:[(0,a.jsxs)(n.p,{children:["If you specify ",(0,a.jsx)(n.code,{children:"enabled: 'auto'"})," in the ",(0,a.jsx)(n.code,{children:"linking"})," prop, React Navigation will automatically generate paths for all screens. For example, if you have a ",(0,a.jsx)(n.code,{children:"Profile"})," screen in the navigator, it'll automatically generate a path for it as ",(0,a.jsx)(n.code,{children:"profile"}),"."]}),(0,a.jsxs)(n.p,{children:["If you wish to handle the configuration manually, or want to override the generated path for a specific screen, you can specify ",(0,a.jsx)(n.code,{children:"linking"})," property next to the screen in the navigator to map a path to a screen. For example:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Profile: {\n screen: ProfileScreen,\n // highlight-start\n linking: {\n path: 'user',\n },\n // highlight-end\n },\n Chat: {\n screen: ChatScreen,\n // highlight-start\n linking: {\n path: 'feed/:sort',\n },\n // highlight-end\n },\n },\n});\n"})}),(0,a.jsx)(n.p,{children:"In this example:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Chat"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/feed"})," with the param ",(0,a.jsx)(n.code,{children:"sort"})," (e.g. ",(0,a.jsx)(n.code,{children:"/feed/latest"})," - the ",(0,a.jsx)(n.code,{children:"Chat"})," screen will receive a param ",(0,a.jsx)(n.code,{children:"sort"})," with the value ",(0,a.jsx)(n.code,{children:"latest"}),")."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Profile"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/user"}),"."]}),"\n"]}),(0,a.jsxs)(n.p,{children:["Similarly, when you have a nested navigator, you can specify the ",(0,a.jsx)(n.code,{children:"linking"})," property for the screens in the navigator to handle the path for the nested screens:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Home: {\n screen: HomeScreen,\n // highlight-start\n linking: {\n path: 'home',\n },\n // highlight-end\n },\n Settings: {\n screen: SettingsScreen,\n // highlight-start\n linking: {\n path: 'settings',\n },\n // highlight-end\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n HomeTabs: {\n screen: HomeTabs,\n },\n Profile: {\n screen: ProfileScreen,\n // highlight-start\n linking: {\n path: 'user',\n },\n // highlight-end\n },\n Chat: {\n screen: ChatScreen,\n // highlight-start\n linking: {\n path: 'feed/:sort',\n },\n // highlight-end\n },\n },\n});\n"})}),(0,a.jsx)(n.p,{children:"In the above example, the following path formats are handled:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/home"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Home"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/settings"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Settings"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/user"})," navigates to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/feed/:sort"})," navigates to the ",(0,a.jsx)(n.code,{children:"Chat"})," screen with the param ",(0,a.jsx)(n.code,{children:"sort"})]}),"\n"]}),(0,a.jsx)(n.h3,{id:"how-does-automatic-path-generation-work",children:"How does automatic path generation work?"}),(0,a.jsxs)(n.p,{children:["When using automatic path generation with ",(0,a.jsx)(n.code,{children:"enabled: 'auto'"}),", the following rules are applied:"]}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:["Screens with an explicit ",(0,a.jsx)(n.code,{children:"linking"})," property are not used for path generation and will be added as-is."]}),"\n",(0,a.jsxs)(n.li,{children:["Screen names will be converted from ",(0,a.jsx)(n.code,{children:"PascalCase"})," to ",(0,a.jsx)(n.code,{children:"kebab-case"})," to use as the path (e.g. ",(0,a.jsx)(n.code,{children:"NewsFeed"})," -> ",(0,a.jsx)(n.code,{children:"news-feed"}),")."]}),"\n",(0,a.jsxs)(n.li,{children:["Unless a screen has explicit empty path (",(0,a.jsx)(n.code,{children:"path: ''"}),") to use for the homepage, the first leaf screen encountered will be used as the homepage."]}),"\n",(0,a.jsxs)(n.li,{children:["Path generation only handles leaf screens, i.e. no path is generated for screens containing nested navigators. It's still possible to specify a path for them with an explicit ",(0,a.jsx)(n.code,{children:"linking"})," property."]}),"\n"]}),(0,a.jsx)(n.p,{children:"Let's say we have the following navigation structure:"}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Home: {\n screen: HomeScreen,\n },\n Settings: {\n screen: SettingsScreen,\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n HomeTabs: {\n screen: HomeTabs,\n },\n Profile: {\n screen: ProfileScreen,\n },\n Chat: {\n screen: ChatScreen,\n },\n },\n});\n"})}),(0,a.jsx)(n.p,{children:"With automatic path generation, the following paths will be generated:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Home"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/settings"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Settings"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/profile"})," navigates to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/chat"})," navigates to the ",(0,a.jsx)(n.code,{children:"Chat"})," screen"]}),"\n"]}),(0,a.jsxs)(n.p,{children:["If the URL contains a query string, it'll be passed as params to the screen. For example, the URL ",(0,a.jsx)(n.code,{children:"/profile?user=jane"})," will pass the ",(0,a.jsx)(n.code,{children:"user"})," param to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]})]}),(0,a.jsxs)(o.Z,{value:"dynamic",label:"Dynamic",children:[(0,a.jsxs)(n.p,{children:["If you specify a ",(0,a.jsx)(n.code,{children:"linking"})," option, by default React Navigation will use the path segments as the route name when parsing the URL. However, directly translating path segments to route names may not be the expected behavior."]}),(0,a.jsxs)(n.p,{children:["You can specify the ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkingconfig",children:(0,a.jsx)(n.code,{children:"config"})})," option in ",(0,a.jsx)(n.code,{children:"linking"})," to control how the deep link is parsed to suit your needs. The config should specify the mapping between route names and path patterns:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: 'feed/:sort',\n Profile: 'user',\n },\n};\n"})}),(0,a.jsx)(n.p,{children:"In this example:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Chat"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/feed"})," with the param ",(0,a.jsx)(n.code,{children:"sort"})," (e.g. ",(0,a.jsx)(n.code,{children:"/feed/latest"})," - the ",(0,a.jsx)(n.code,{children:"Chat"})," screen will receive a param ",(0,a.jsx)(n.code,{children:"sort"})," with the value ",(0,a.jsx)(n.code,{children:"latest"}),")."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Profile"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/user"}),"."]}),"\n"]}),(0,a.jsxs)(n.p,{children:["The config option can then be passed in the ",(0,a.jsx)(n.code,{children:"linking"})," prop to the container:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"import { NavigationContainer } from '@react-navigation/native';\n\nconst config = {\n screens: {\n Chat: 'feed/:sort',\n Profile: 'user',\n },\n};\n\nconst linking = {\n prefixes: ['https://mychat.com', 'mychat://'],\n config,\n};\n\nfunction App() {\n return (\n Loading...}>\n {/* content */}\n \n );\n}\n"})}),(0,a.jsxs)(n.p,{children:["The config object must match the navigation structure for your app. For example, the above configuration is if you have ",(0,a.jsx)(n.code,{children:"Chat"})," and ",(0,a.jsx)(n.code,{children:"Profile"})," screens in the navigator at the root:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:'function App() {\n return (\n \n \n \n \n );\n}\n'})}),(0,a.jsxs)(n.p,{children:["If your ",(0,a.jsx)(n.code,{children:"Chat"})," screen is inside a nested navigator, we'd need to account for that. For example, consider the following structure where your ",(0,a.jsx)(n.code,{children:"Profile"})," screen is at the root, but the ",(0,a.jsx)(n.code,{children:"Chat"})," screen is nested inside ",(0,a.jsx)(n.code,{children:"Home"}),":"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:'function App() {\n return (\n \n \n \n \n );\n}\n\nfunction HomeScreen() {\n return (\n \n \n \n );\n}\n'})}),(0,a.jsx)(n.p,{children:"For the above structure, our configuration will look like this:"}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n screens: {\n Chat: 'feed/:sort',\n },\n },\n Profile: 'user',\n },\n};\n"})}),(0,a.jsx)(n.p,{children:"Similarly, any nesting needs to be reflected in the configuration."})]})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"How it works"}),(0,a.jsxs)(n.p,{children:["The linking works by translating the URL to a valid ",(0,a.jsx)(n.a,{href:"/docs/navigation-state",children:"navigation state"})," and vice versa using the configuration provided. For example, the path ",(0,a.jsx)(n.code,{children:"/rooms/chat?user=jane"})," may be translated to a state object like this:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'rooms',\n state: {\n routes: [\n {\n name: 'chat',\n params: { user: 'jane' },\n },\n ],\n },\n },\n ],\n};\n"})}),(0,a.jsxs)(n.p,{children:["For example, you might want to parse the path ",(0,a.jsx)(n.code,{children:"/feed/latest"})," to something like:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Chat',\n params: {\n sort: 'latest',\n },\n },\n ];\n}\n"})}),(0,a.jsxs)(n.p,{children:["See ",(0,a.jsx)(n.a,{href:"/docs/navigation-state",children:"Navigation State reference"})," for more details on how the state object is structured."]})]}),"\n",(0,a.jsx)(n.h2,{id:"passing-params",children:"Passing params"}),"\n",(0,a.jsxs)(n.p,{children:["A common use case is to pass params to a screen to pass some data. For example, you may want the ",(0,a.jsx)(n.code,{children:"Profile"})," screen to have an ",(0,a.jsx)(n.code,{children:"id"})," param to know which user's profile it is. It's possible to pass params to a screen through a URL when handling deep links."]}),"\n",(0,a.jsxs)(n.p,{children:["By default, query params are parsed to get the params for a screen. For example, with the above example, the URL ",(0,a.jsx)(n.code,{children:"/user?id=jane"})," will pass the ",(0,a.jsx)(n.code,{children:"id"})," param to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]}),"\n",(0,a.jsxs)(n.p,{children:["You can also customize how the params are parsed from the URL. Let's say you want the URL to look like ",(0,a.jsx)(n.code,{children:"/user/jane"})," where the ",(0,a.jsx)(n.code,{children:"id"})," param is ",(0,a.jsx)(n.code,{children:"jane"})," instead of having the ",(0,a.jsx)(n.code,{children:"id"})," in query params. You can do this by specifying ",(0,a.jsx)(n.code,{children:"user/:id"})," for the ",(0,a.jsx)(n.code,{children:"path"}),". ",(0,a.jsxs)(n.strong,{children:["When the path segment starts with ",(0,a.jsx)(n.code,{children:":"}),", it'll be treated as a param"]}),". For example, the URL ",(0,a.jsx)(n.code,{children:"/user/jane"})," would resolve to ",(0,a.jsx)(n.code,{children:"Profile"})," screen with the string ",(0,a.jsx)(n.code,{children:"jane"})," as a value of the ",(0,a.jsx)(n.code,{children:"id"})," param and will be available in ",(0,a.jsx)(n.code,{children:"route.params.id"})," in ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]}),"\n",(0,a.jsxs)(n.p,{children:["By default, all params are treated as strings. You can also customize how to parse them by specifying a function in the ",(0,a.jsx)(n.code,{children:"parse"})," property to parse the param, and a function in the ",(0,a.jsx)(n.code,{children:"stringify"})," property to convert it back to a string."]}),"\n",(0,a.jsxs)(n.p,{children:["If you wanted to resolve ",(0,a.jsx)(n.code,{children:"/user/@jane/settings"})," to result in the params ",(0,a.jsx)(n.code,{children:"{ id: 'jane' section: 'settings' }"}),", you could make ",(0,a.jsx)(n.code,{children:"Profile"}),"'s config to look like this:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Profile: {\n screen: ProfileScreen,\n // highlight-start\n linking: {\n path: 'user/:id/:section',\n parse: {\n id: (id) => id.replace(/^@/, ''),\n },\n stringify: {\n id: (id) => `@${id}`,\n },\n },\n // highlight-end\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Profile: {\n // highlight-start\n path: 'user/:id/:section',\n parse: {\n id: (id) => id.replace(/^@/, ''),\n },\n stringify: {\n id: (id) => `@${id}`,\n },\n // highlight-end\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/user/@jane/settings"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Profile',\n params: { id: 'jane', section: 'settings' },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsx)(n.h2,{id:"marking-params-as-optional",children:"Marking params as optional"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes a param may or may not be present in the URL depending on certain conditions. For example, in the above scenario, you may not always have the section parameter in the URL, i.e. both ",(0,a.jsx)(n.code,{children:"/user/jane/settings"})," and ",(0,a.jsx)(n.code,{children:"/user/jane"})," should go to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen, but the ",(0,a.jsx)(n.code,{children:"section"})," param (with the value ",(0,a.jsx)(n.code,{children:"settings"})," in this case) may or may not be present."]}),"\n",(0,a.jsxs)(n.p,{children:["In this case, you would need to mark the ",(0,a.jsx)(n.code,{children:"section"})," param as optional. You can do it by adding the ",(0,a.jsx)(n.code,{children:"?"})," suffix after the param name:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Profile: {\n screen: ProfileScreen,\n linking: {\n // highlight-next-line\n path: 'user/:id/:section?',\n parse: {\n id: (id) => `user-${id}`,\n },\n stringify: {\n id: (id) => id.replace(/^user-/, ''),\n },\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Profile: {\n // highlight-next-line\n path: 'user/:id/:section?',\n parse: {\n id: (id) => `user-${id}`,\n },\n stringify: {\n id: (id) => id.replace(/^user-/, ''),\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/user/jane"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Profile',\n params: { id: 'user-jane' },\n },\n ],\n};\n"})}),(0,a.jsxs)(n.p,{children:["If the URL contains a ",(0,a.jsx)(n.code,{children:"section"})," param (e.g. ",(0,a.jsx)(n.code,{children:"/user/jane/settings"}),"), this will result in the following with the same config:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Profile',\n params: { id: 'user-jane', section: 'settings' },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsx)(n.h2,{id:"handling-unmatched-routes-or-404",children:"Handling unmatched routes or 404"}),"\n",(0,a.jsx)(n.p,{children:"If your app is opened with an invalid URL, most of the times you'd want to show an error page with some information. On the web, this is commonly known as 404 - or page not found error."}),"\n",(0,a.jsxs)(n.p,{children:["To handle this, you'll need to define a catch-all route that will be rendered if no other routes match the path. You can do it by specifying ",(0,a.jsx)(n.code,{children:"*"})," for the path matching pattern:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Feed: {\n screen: FeedScreen,\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n Settings: {\n screen: SettingsScreen,\n linking: {\n path: 'settings',\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: HomeTabs,\n },\n NotFound: {\n screen: NotFoundScreen,\n linking: {\n // highlight-next-line\n path: '*',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n initialRouteName: 'Feed',\n screens: {\n Profile: 'users/:id',\n Settings: 'settings',\n },\n },\n NotFound: {\n // highlight-start\n path: '*',\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["Here, we have defined a route named ",(0,a.jsx)(n.code,{children:"NotFound"})," and set it to match ",(0,a.jsx)(n.code,{children:"*"})," aka everything. If the path didn't match ",(0,a.jsx)(n.code,{children:"user/:id"})," or ",(0,a.jsx)(n.code,{children:"settings"}),", it'll be matched by this route."]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, a path like ",(0,a.jsx)(n.code,{children:"/library"})," or ",(0,a.jsx)(n.code,{children:"/settings/notification"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [{ name: 'NotFound' }],\n};\n"})})]}),"\n",(0,a.jsxs)(n.p,{children:["You can even go more specific, for example, say if you want to show a different screen for invalid paths under ",(0,a.jsx)(n.code,{children:"/settings"}),", you can specify such a pattern under ",(0,a.jsx)(n.code,{children:"Settings"}),":"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const SettingsStack = createStackNavigator({\n screens: {\n UserSettings: {\n screen: UserSettingsScreen,\n linking: {\n path: 'user-settings',\n },\n },\n InvalidSettings: {\n screen: InvalidSettingsScreen,\n linking: {\n // highlight-next-line\n path: '*',\n },\n },\n },\n});\n\nconst HomeTabs = createBottomTabNavigator({\n screens: {\n Feed: {\n screen: FeedScreen,\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n Settings: {\n screen: SettingsStack,\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: HomeTabs,\n },\n NotFound: {\n screen: NotFoundScreen,\n linking: {\n path: '*',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n initialRouteName: 'Feed',\n screens: {\n Profile: 'users/:id',\n Settings: {\n path: 'settings',\n screens: {\n InvalidSettings: '*',\n },\n },\n },\n },\n NotFound: '*',\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/settings/notification"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Home',\n state: {\n index: 1,\n routes: [\n { name: 'Feed' },\n {\n name: 'Settings',\n state: {\n routes: [\n { name: 'InvalidSettings', path: '/settings/notification' },\n ],\n },\n },\n ],\n },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"route"})," passed to the ",(0,a.jsx)(n.code,{children:"NotFound"})," screen will contain a ",(0,a.jsx)(n.code,{children:"path"})," property which corresponds to the path that opened the page. If you need, you can use this property to customize what's shown in this screen, e.g. load the page in a ",(0,a.jsx)(n.code,{children:"WebView"}),":"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"function NotFoundScreen({ route }) {\n if (route.path) {\n return ;\n }\n\n return This screen doesn't exist!;\n}\n"})}),"\n",(0,a.jsxs)(n.p,{children:["When doing server rendering, you'd also want to return correct status code for 404 errors. See ",(0,a.jsx)(n.a,{href:"/docs/server-rendering#handling-404-or-other-status-codes",children:"server rendering docs"})," for a guide on how to handle it."]}),"\n",(0,a.jsx)(n.h2,{id:"rendering-an-initial-route",children:"Rendering an initial route"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes you want to ensure that a certain screen will always be present as the first screen in the navigator's state. You can use the ",(0,a.jsx)(n.code,{children:"initialRouteName"})," property to specify the screen to use for the initial screen."]}),"\n",(0,a.jsxs)(n.p,{children:["In the above example, if you want the ",(0,a.jsx)(n.code,{children:"Feed"})," screen to be the initial route in the navigator under ",(0,a.jsx)(n.code,{children:"Home"}),", your config will look like this:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Feed: {\n screen: FeedScreen,\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n Settings: {\n screen: SettingsScreen,\n linking: {\n path: 'settings',\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: HomeTabs,\n linking: {\n // highlight-next-line\n initialRouteName: 'Feed',\n },\n },\n NotFound: {\n screen: NotFoundScreen,\n linking: {\n path: '*',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n // highlight-next-line\n initialRouteName: 'Feed',\n screens: {\n Profile: 'users/:id',\n Settings: 'settings',\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/users/42"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Home',\n state: {\n index: 1,\n routes: [\n { name: 'Feed' },\n {\n name: 'Profile',\n params: { id: '42' },\n },\n ],\n },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsx)(n.admonition,{type:"warning",children:(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"initialRouteName"})," will add the screen to React Navigation's state only. If your app is running on the Web, the browser's history will not contain this screen as the user has never visited it. So, if the user presses the browser's back button, it'll not go back to this screen."]})}),"\n",(0,a.jsxs)(n.p,{children:["Another thing to keep in mind is that it's not possible to pass params to the initial screen through the URL. So make sure that your initial route doesn't need any params or specify ",(0,a.jsx)(n.code,{children:"initialParams"})," in the screen configuration to pass the required params."]}),"\n",(0,a.jsxs)(n.p,{children:["In this case, any params in the URL are only passed to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen which matches the path pattern ",(0,a.jsx)(n.code,{children:"users/:id"}),", and the ",(0,a.jsx)(n.code,{children:"Feed"})," screen doesn't receive any params. If you want to have the same params in the ",(0,a.jsx)(n.code,{children:"Feed"})," screen, you can specify a ",(0,a.jsxs)(n.a,{href:"/docs/navigation-container#linkinggetstatefrompath",children:["custom ",(0,a.jsx)(n.code,{children:"getStateFromPath"})," function"]})," and copy those params."]}),"\n",(0,a.jsxs)(n.p,{children:["Similarly, if you want to access params of a parent screen from a child screen, you can use ",(0,a.jsx)(n.a,{href:"https://react.dev/reference/react/useContext",children:"React Context"})," to expose them."]}),"\n",(0,a.jsx)(n.h2,{id:"matching-exact-paths",children:"Matching exact paths"}),"\n",(0,a.jsx)(n.p,{children:"By default, paths defined for each screen are matched against the URL relative to their parent screen's path. Consider the following config:"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const ProfileTabs = createBottomTabNavigator({\n screens: {\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileTabs,\n linking: {\n path: 'feed',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: 'feed',\n screens: {\n Profile: 'users/:id',\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["Here, you have a ",(0,a.jsx)(n.code,{children:"path"})," property defined for the ",(0,a.jsx)(n.code,{children:"Home"})," screen, as well as the child ",(0,a.jsx)(n.code,{children:"Profile"})," screen. The profile screen specifies the path ",(0,a.jsx)(n.code,{children:"users/:id"}),", but since it's nested inside a screen with the path ",(0,a.jsx)(n.code,{children:"feed"}),", it'll try to match the pattern ",(0,a.jsx)(n.code,{children:"feed/users/:id"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:["This will result in the URL ",(0,a.jsx)(n.code,{children:"/feed"})," navigating to ",(0,a.jsx)(n.code,{children:"Home"})," screen, and ",(0,a.jsx)(n.code,{children:"/feed/users/cal"})," navigating to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]}),"\n",(0,a.jsxs)(n.p,{children:["In this case, it makes more sense to navigate to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen using a URL like ",(0,a.jsx)(n.code,{children:"/users/cal"}),", rather than ",(0,a.jsx)(n.code,{children:"/feed/users/cal"}),". To achieve this, you can override the relative matching behavior to ",(0,a.jsx)(n.code,{children:"exact"})," matching:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const ProfileTabs = createBottomTabNavigator({\n screens: {\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n // highlight-next-line\n exact: true,\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileTabs,\n linking: {\n path: 'feed',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: 'feed',\n screens: {\n Profile: {\n path: 'users/:id',\n // highlight-next-line\n exact: true,\n },\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["With ",(0,a.jsx)(n.code,{children:"exact"})," property set to ",(0,a.jsx)(n.code,{children:"true"}),", ",(0,a.jsx)(n.code,{children:"Profile"})," will ignore the parent screen's ",(0,a.jsx)(n.code,{children:"path"})," config and you'll be able to navigate to ",(0,a.jsx)(n.code,{children:"Profile"})," using a URL like ",(0,a.jsx)(n.code,{children:"users/cal"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"omitting-a-screen-from-path",children:"Omitting a screen from path"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes, you may not want to have the route name of a screen in the path. For example, let's say you have a ",(0,a.jsx)(n.code,{children:"Home"})," screen and the following config. When the page is opened in the browser you'll get ",(0,a.jsx)(n.code,{children:"/home"})," as the URL:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileScreen,\n linking: {\n path: 'home',\n },\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: 'home',\n },\n Profile: 'users/:id',\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["But it'll be nicer if the URL was just ",(0,a.jsx)(n.code,{children:"/"})," when visiting the home screen."]}),"\n",(0,a.jsx)(n.p,{children:"You can specify an empty string as path or not specify a path at all, and React Navigation won't add the screen to the path (think of it like adding empty string to the path, which doesn't change anything):"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileScreen,\n linking: {\n path: '',\n },\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: '',\n },\n Profile: 'users/:id',\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.h2,{id:"serializing-and-parsing-params",children:"Serializing and parsing params"}),"\n",(0,a.jsx)(n.p,{children:"Since URLs are strings, any params you have for routes are also converted to strings when constructing the path."}),"\n",(0,a.jsxs)(n.p,{children:["For example, say you have the URL ",(0,a.jsx)(n.code,{children:"/chat/1589842744264"})," with the following config:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Chat: {\n screen: ChatScreen,\n linking: {\n path: 'chat/:date',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: 'chat/:date',\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.p,{children:"When handling the URL, your params will look like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yml",children:"{ date: '1589842744264' }\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Here, the ",(0,a.jsx)(n.code,{children:"date"})," param was parsed as a string because React Navigation doesn't know that it's supposed to be a timestamp, and hence number. You can customize it by providing a custom function to use for parsing:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Chat: {\n screen: ChatScreen,\n linking: {\n path: 'chat/:date',\n parse: {\n date: Number,\n },\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: {\n path: 'chat/:date',\n parse: {\n date: Number,\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.p,{children:"You can also provide a your own function to serialize the params. For example, let's say that you want to use a DD-MM-YYYY format in the path instead of a timestamp:"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Chat: {\n screen: ChatScreen,\n linking: {\n path: 'chat/:date',\n parse: {\n date: (date) => new Date(date).getTime(),\n },\n stringify: {\n date: (date) => {\n const d = new Date(date);\n\n return d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate();\n },\n },\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: {\n path: 'chat/:date',\n parse: {\n date: (date) => new Date(date).getTime(),\n },\n stringify: {\n date: (date) => {\n const d = new Date(date);\n\n return d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate();\n },\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.p,{children:"Depending on your requirements, you can use this functionality to parse and stringify more complex data."}),"\n",(0,a.jsx)(n.h2,{id:"matching-regular-expressions",children:"Matching regular expressions"}),"\n",(0,a.jsxs)(n.p,{children:["If you need more complex matching logic, you can use regular expressions to match the path. For example, if you want to use the pattern ",(0,a.jsx)(n.code,{children:"@username"})," to match a user's profile, you can use a regular expression to match the path."]}),"\n",(0,a.jsxs)(n.p,{children:["Regular expressions can be specified between parentheses ",(0,a.jsx)(n.code,{children:"("})," and ",(0,a.jsx)(n.code,{children:")"})," in the after a param name. For example:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Profile: {\n screen: ProfileScreen,\n linking: {\n path: ':username(@[A-Za-z0-9_]+)',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Profile: ':username(@[A-Za-z0-9_]+)',\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["This will only match the path if it starts with ",(0,a.jsx)(n.code,{children:"@"})," followed by alphanumeric characters or underscores. For example, the URL ",(0,a.jsx)(n.code,{children:"/@jane"})," will match the ",(0,a.jsx)(n.code,{children:"Profile"})," screen, but ",(0,a.jsx)(n.code,{children:"/jane"})," won't."]}),"\n",(0,a.jsxs)(n.p,{children:["Regular expressions are intended to only match path segments, not the entire path. So, avoid using ",(0,a.jsx)(n.code,{children:"/"}),", ",(0,a.jsx)(n.code,{children:"^"}),", ",(0,a.jsx)(n.code,{children:"$"}),", etc. in the regular expressions."]}),"\n",(0,a.jsx)(n.admonition,{type:"warning",children:(0,a.jsx)(n.p,{children:"Regular expressions are an advanced feature. They cannot be validated to warn you about potential issues, so it's up to you to ensure that the regular expression is correct."})}),"\n",(0,a.jsx)(n.h2,{id:"advanced-cases",children:"Advanced cases"}),"\n",(0,a.jsxs)(n.p,{children:["For some advanced cases, specifying the mapping may not be sufficient. To handle such cases, you can specify a custom function to parse the URL into a state object (",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkinggetstatefrompath",children:(0,a.jsx)(n.code,{children:"getStateFromPath"})}),"), and a custom function to serialize the state object into an URL (",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkinggetpathfromstate",children:(0,a.jsx)(n.code,{children:"getPathFromState"})}),")."]}),"\n",(0,a.jsx)(n.p,{children:"Example:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['https://mychat.com', 'mychat://'],\n getStateFromPath: (path, options) => {\n // Return a state object here\n // You can also reuse the default logic by importing `getStateFromPath` from `@react-navigation/native`\n },\n getPathFromState(state, config) {\n // Return a path string here\n // You can also reuse the default logic by importing `getPathFromState` from `@react-navigation/native`\n },\n\n // ...\n};\n"})}),"\n",(0,a.jsx)(n.h2,{id:"playground",children:"Playground"}),"\n","\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.p,{children:"Playground is not available for static config."})}),(0,a.jsxs)(o.Z,{value:"dynamic",label:"Dynamic",children:[(0,a.jsx)(n.p,{children:"You can play around with customizing the config and path below, and see how the path is parsed."}),(0,a.jsx)(c.Z,{})]})]})]})}function g(e={}){let{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(u,{...e})}):u(e)}function x(e,n){throw Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},5525:function(e,n,t){t.d(n,{Z:()=>r});var i=t("85893");t("67294");var a=t("67026");let s="tabItem_Ymn6";function r(e){let{children:n,hidden:t,className:r}=e;return(0,i.jsx)("div",{role:"tabpanel",className:(0,a.Z)(s,r),hidden:t,children:n})}},47902:function(e,n,t){t.d(n,{Z:()=>F});var i=t("85893"),a=t("67294"),s=t("67026"),r=t("69599"),o=t("16550"),c=t("32000"),l=t("4520"),d=t("38341"),h=t("76009");function p(e){let{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}function u(e){var n,t;return null!==(t=null===(n=a.Children.toArray(e).filter(e=>"\n"!==e).map(e=>{if(!e||(0,a.isValidElement)(e)&&p(e))return e;throw Error("Docusaurus error: Bad child <".concat("string"==typeof e.type?e.type:e.type.name,'>: all children of the component should be , and every should have a unique "value" prop.'))}))||void 0===n?void 0:n.filter(Boolean))&&void 0!==t?t:[]}function g(e){return u(e).map(e=>{let{props:{value:n,label:t,attributes:i,default:a}}=e;return{value:n,label:t,attributes:i,default:a}})}function x(e){let n=(0,d.lx)(e,(e,n)=>e.value===n.value);if(n.length>0)throw Error('Docusaurus error: Duplicate values "'.concat(n.map(e=>e.value).join(", "),'" found in . Every value needs to be unique.'))}function m(e){let{values:n,children:t}=e;return(0,a.useMemo)(()=>{let e=null!=n?n:g(t);return x(e),e},[n,t])}function j(e){let{value:n,tabValues:t}=e;return t.some(e=>e.value===n)}function f(e){var n;let{defaultValue:t,tabValues:i}=e;if(0===i.length)throw Error("Docusaurus error: the component requires at least one children component");if(t){if(!j({value:t,tabValues:i}))throw Error('Docusaurus error: The has a defaultValue "'.concat(t,'" but none of its children has the corresponding value. Available values are: ').concat(i.map(e=>e.value).join(", "),". If you intend to show no default tab, use defaultValue={null} instead."));return t}let a=null!==(n=i.find(e=>e.default))&&void 0!==n?n:i[0];if(!a)throw Error("Unexpected error: 0 tabValues");return a.value}function v(e){return e?"docusaurus.tab.".concat(e):null}function y(e){let{queryString:n=!1,groupId:t}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!t)throw Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=t?t:null}function b(e){let{queryString:n=!1,groupId:t}=e,i=(0,o.k6)(),s=y({queryString:n,groupId:t}),r=(0,l._X)(s);return[r,(0,a.useCallback)(e=>{if(!s)return;let n=new URLSearchParams(i.location.search);n.set(s,e),i.replace({...i.location,search:n.toString()})},[s,i])]}function k(e){let{groupId:n}=e,t=v(n),[i,s]=(0,h.Nk)(t);return[i,(0,a.useCallback)(e=>{if(!!t)s.set(e)},[t,s])]}function w(e){let{defaultValue:n,queryString:t=!1,groupId:i}=e,s=m(e),[r,o]=(0,a.useState)(()=>f({defaultValue:n,tabValues:s})),[l,d]=b({queryString:t,groupId:i}),[h,p]=k({groupId:i}),u=(()=>{let e=null!=l?l:h;return j({value:e,tabValues:s})?e:null})();return(0,c.Z)(()=>{u&&o(u)},[u]),{selectedValue:r,selectValue:(0,a.useCallback)(e=>{if(!j({value:e,tabValues:s}))throw Error("Can't select invalid tab value=".concat(e));o(e),d(e),p(e)},[d,p,s]),tabValues:s}}var S=t("7227");let N="tabList__CuJ",R="tabItem_LNqP";function P(e){let{className:n,block:t,selectedValue:a,selectValue:o,tabValues:c}=e,l=[],{blockElementScrollPositionUntilNextRender:d}=(0,r.o5)(),h=e=>{let n=e.currentTarget,t=c[l.indexOf(n)].value;t!==a&&(d(n),o(t))},p=e=>{var n,t;let i=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{let t=l.indexOf(e.currentTarget)+1;i=null!==(n=l[t])&&void 0!==n?n:l[0];break}case"ArrowLeft":{let n=l.indexOf(e.currentTarget)-1;i=null!==(t=l[n])&&void 0!==t?t:l[l.length-1]}}null==i||i.focus()};return(0,i.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.Z)("tabs",{"tabs--block":t},n),children:c.map(e=>{let{value:n,label:t,attributes:r}=e;return(0,i.jsx)("li",{role:"tab",tabIndex:a===n?0:-1,"aria-selected":a===n,ref:e=>l.push(e),onKeyDown:p,onClick:h,...r,className:(0,s.Z)("tabs__item",R,null==r?void 0:r.className,{"tabs__item--active":a===n}),children:null!=t?t:n},n)})})}function T(e){let{lazy:n,children:t,selectedValue:r}=e,o=(Array.isArray(t)?t:[t]).filter(Boolean);if(n){let e=o.find(e=>e.props.value===r);return e?(0,a.cloneElement)(e,{className:(0,s.Z)("margin-top--md",e.props.className)}):null}return(0,i.jsx)("div",{className:"margin-top--md",children:o.map((e,n)=>(0,a.cloneElement)(e,{key:n,hidden:e.props.value!==r}))})}function C(e){let n=w(e);return(0,i.jsxs)("div",{className:(0,s.Z)("tabs-container",N),children:[(0,i.jsx)(P,{...n,...e}),(0,i.jsx)(T,{...n,...e})]})}function F(e){let n=(0,S.Z)();return(0,i.jsx)(C,{...e,children:u(e.children)},String(n))}},41665:function(__unused_webpack_module,__webpack_exports__,__webpack_require__){__webpack_require__.d(__webpack_exports__,{Z:function(){return LinkingTester}});var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(85893),_docusaurus_theme_common__WEBPACK_IMPORTED_MODULE_6__=__webpack_require__(84239),_react_navigation_core__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(49640),prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__(83229),react__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__(67294),react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4__=__webpack_require__(40460),react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4___default=__webpack_require__.n(react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4__),_RouteMap__WEBPACK_IMPORTED_MODULE_5__=__webpack_require__(58002);let parse=value=>eval("(function() { return ".concat(value,"; }())"));function Code(e){let{code:n,theme:t,language:i}=e;return(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.y$,{code:n,theme:t,language:i,children:e=>{let{className:n,style:t,tokens:i,getLineProps:a,getTokenProps:s}=e;return(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("pre",{className:n,style:{...t,...styles.json},children:i.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div",{...a({line:e,key:n}),children:e.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span",{...s({token:e,key:n})}))}))})}})}function LinkingTester(){let e,n;let{colorMode:t}=(0,_docusaurus_theme_common__WEBPACK_IMPORTED_MODULE_6__.I)(),i="dark"===t?prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.np.dracula:prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.np.github,[a,s]=react__WEBPACK_IMPORTED_MODULE_3__.useState("{\n screens: {\n Home: {\n initialRouteName: 'Feed',\n screens: {\n Profile: {\n path: 'user/:id',\n parse: {\n id: id => id.replace(/^@/, ''),\n },\n screens: {\n Settings: 'edit',\n },\n },\n },\n },\n NoMatch: '*',\n }\n}"),[r,o]=react__WEBPACK_IMPORTED_MODULE_3__.useState("/user/@vergil/edit"),[c,l]=react__WEBPACK_IMPORTED_MODULE_3__.useState(()=>parse(a)),[d,h]=react__WEBPACK_IMPORTED_MODULE_3__.useState("chart");try{e=(0,_react_navigation_core__WEBPACK_IMPORTED_MODULE_1__.cT)(r.replace(/(^\w+:|^)\/\//,""),c),n=(0,_react_navigation_core__WEBPACK_IMPORTED_MODULE_1__.ft)(e,c)}catch(e){}return(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,{children:[(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input",{type:"text",value:r,placeholder:"Type a path, e.g. /user/@vergil/edit",onChange:e=>o(e.target.value),style:{...styles.code,...styles.input}}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4___default(),{value:a,placeholder:"Type linking config",onValueChange:e=>{s(e);try{let n=parse(e);l(n)}catch(e){}},highlight:e=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.y$,{code:e,theme:i,language:"jsx",children:e=>{let{tokens:n,getLineProps:t,getTokenProps:i}=e;return n.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div",{...t({line:e,key:n}),children:e.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span",{...i({token:e,key:n})}))}))}}),padding:16,style:{...styles.code,...styles.editor}}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div",{style:styles.preview,children:[(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div",{style:styles.toggles,children:[(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button",{type:"button",style:styles.button,onClick:()=>h("chart"),children:"Chart"}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button",{type:"button",style:styles.button,onClick:()=>h("state"),children:"State"}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button",{type:"button",style:styles.button,onClick:()=>h("action"),children:"Action"})]}),"state"===d?(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Code,{theme:i,code:JSON.stringify(e,null,2)||"",language:"json"}):"action"===d?(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Code,{theme:i,code:JSON.stringify(n,null,2)||"",language:"json"}):"chart"===d?e?(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_RouteMap__WEBPACK_IMPORTED_MODULE_5__.Z,{routes:e.routes}):(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p",{style:styles.error,children:"Failed to parse the path. Make sure that the path matches the patterns specified in the config."}):null]})]})}let styles={code:{display:"block",fontFamily:"var(--ifm-font-family-monospace)",fontSize:"var(--ifm-code-font-size)",borderRadius:"var(--ifm-pre-border-radius)",margin:"var(--ifm-spacing-vertical) 0"},input:{display:"block",width:"100%",padding:"var(--ifm-pre-padding)",backgroundColor:"transparent",color:"inherit",border:"1px solid var(--ifm-contents-border-color)"},editor:{border:"1px solid var(--ifm-contents-border-color)"},preview:{position:"relative",border:"1px solid var(--ifm-contents-border-color)",borderRadius:"var(--ifm-pre-border-radius)",minHeight:70},json:{margin:0,fontFamily:"var(--ifm-font-family-monospace)",fontSize:"var(--ifm-code-font-size)",borderRadius:"var(--ifm-pre-border-radius)",padding:"var(--ifm-pre-padding)",minHeight:70},toggles:{position:"absolute",flexDirection:"row",right:0,top:0,borderBottom:"1px solid var(--ifm-contents-border-color)"},button:{border:0,borderLeft:"1px solid var(--ifm-contents-border-color)",borderRadius:0,cursor:"pointer",display:"inline-flex",fontSize:12,margin:0,padding:"4px 8px",color:"inherit",background:"none",MozAppearance:"none",WebkitAppearance:"none"},error:{margin:24,color:"#A12027"}}},58002:function(e,n,t){t.d(n,{Z:function(){return o}});var i=t(85893);t(67294);let a="#3F51B5",s="#009688",r="#E91E63";function o(e){let{routes:n,root:t=!0}=e;return(0,i.jsx)("div",{style:{...c.container,...t?{overflowX:"auto",padding:"calc(var(--ifm-pre-padding) / 2)"}:null},children:n.map((e,n)=>(0,i.jsxs)("div",{style:c.item,children:[(0,i.jsxs)("div",{style:c.route,children:[(0,i.jsxs)("div",{style:c.name,children:[e.name,t?null:0===n?(0,i.jsx)("div",{style:c.connectLeft}):(0,i.jsx)("div",{style:c.connectUpLeft})]}),e.params?(0,i.jsxs)("div",{style:c.paramsContainer,children:[(0,i.jsx)("table",{style:c.params,children:(0,i.jsx)("tbody",{children:Object.entries(e.params).map(e=>{let[n,t]=e;return(0,i.jsxs)("tr",{style:c.row,children:[(0,i.jsx)("td",{style:c.key,children:n}),(0,i.jsx)("td",{style:c.colon,children:":"}),(0,i.jsx)("td",{style:c.value,children:JSON.stringify(t)})]},n)})})}),(0,i.jsx)("div",{style:c.connectUp})]}):null]}),e.state?(0,i.jsx)(o,{routes:e.state.routes,root:!1}):null]},e.name))})}let c={container:{display:"flex",flexDirection:"column"},item:{display:"flex",flexDirection:"row",alignItems:"flex-start"},route:{minWidth:160},name:{backgroundColor:a,color:"white",fontSize:"var(--ifm-code-font-size)",margin:"calc(var(--ifm-pre-padding) / 2)",padding:"calc(var(--ifm-pre-padding) / 2) var(--ifm-pre-padding)",borderRadius:4,position:"relative",textAlign:"center"},paramsContainer:{position:"relative"},params:{backgroundColor:"rgba(3, 169, 244, 0.08)",border:"1px solid ".concat(a),fontFamily:"var(--ifm-font-family-monospace)",fontSize:"var(--ifm-code-font-size)",margin:"var(--ifm-pre-padding) calc(var(--ifm-pre-padding) / 2)",borderRadius:4,padding:3,width:"auto",overflow:"visible"},row:{border:0,background:"none"},key:{color:s,border:0,padding:"4px 6px",textAlign:"right"},value:{color:r,padding:"4px 6px",border:0},colon:{color:"inherit",opacity:.3,border:0,padding:0},connectLeft:{position:"absolute",width:16,height:1,backgroundColor:a,right:"100%",top:"50%"},connectUpLeft:{position:"absolute",width:9,height:52,border:"1px solid ".concat(a),borderRadius:"0 0 0 3px",borderRight:0,borderTop:0,right:"100%",bottom:"50%"},connectUp:{position:"absolute",width:1,height:16,backgroundColor:a,right:"50%",bottom:"100%"}}}}]); \ No newline at end of file diff --git a/assets/js/8c4738b1.e7f53e24.js b/assets/js/8c4738b1.e7f53e24.js deleted file mode 100644 index 53d8313069..0000000000 --- a/assets/js/8c4738b1.e7f53e24.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkreact_navigation_website_next=self.webpackChunkreact_navigation_website_next||[]).push([["95935"],{24906:function(e,n,t){t.r(n),t.d(n,{metadata:()=>i,contentTitle:()=>d,default:()=>g,assets:()=>h,toc:()=>p,frontMatter:()=>l});var i=JSON.parse('{"id":"configuring-links","title":"Configuring links","description":"In this guide, we will configure React Navigation to handle external links. This is necessary if you want to:","source":"@site/versioned_docs/version-7.x/configuring-links.md","sourceDirName":".","slug":"/configuring-links","permalink":"/docs/configuring-links","draft":false,"unlisted":false,"editUrl":"https://github.com/react-navigation/react-navigation.github.io/edit/main/versioned_docs/version-7.x/configuring-links.md","tags":[],"version":"7.x","frontMatter":{"id":"configuring-links","title":"Configuring links","sidebar_label":"Configuring links"},"sidebar":"docs","previous":{"title":"Deep linking","permalink":"/docs/deep-linking"},"next":{"title":"Web support","permalink":"/docs/web-support"}}'),a=t("85893"),s=t("50065"),r=t("47902"),o=t("5525"),c=t("41665");let l={id:"configuring-links",title:"Configuring links",sidebar_label:"Configuring links"},d=void 0,h={},p=[{value:"Prefixes",id:"prefixes",level:2},{value:"Multiple subdomains\u200B",id:"multiple-subdomains",level:3},{value:"Filtering certain paths",id:"filtering-certain-paths",level:2},{value:"Apps under subpaths",id:"apps-under-subpaths",level:2},{value:"Mapping path to route names",id:"mapping-path-to-route-names",level:2},{value:"How does automatic path generation work?",id:"how-does-automatic-path-generation-work",level:3},{value:"Passing params",id:"passing-params",level:2},{value:"Marking params as optional",id:"marking-params-as-optional",level:2},{value:"Handling unmatched routes or 404",id:"handling-unmatched-routes-or-404",level:2},{value:"Rendering an initial route",id:"rendering-an-initial-route",level:2},{value:"Matching exact paths",id:"matching-exact-paths",level:2},{value:"Omitting a screen from path",id:"omitting-a-screen-from-path",level:2},{value:"Serializing and parsing params",id:"serializing-and-parsing-params",level:2},{value:"Advanced cases",id:"advanced-cases",level:2},{value:"Playground",id:"playground",level:2}];function u(e){let n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components},{Details:t}=n;return!t&&x("Details",!0),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.p,{children:"In this guide, we will configure React Navigation to handle external links. This is necessary if you want to:"}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsx)(n.li,{children:"Handle deep links in React Native apps on Android and iOS"}),"\n",(0,a.jsx)(n.li,{children:"Enable URL integration in browser when using on web"}),"\n",(0,a.jsxs)(n.li,{children:["Use ",(0,a.jsx)(n.a,{href:"/docs/link",children:(0,a.jsx)(n.code,{children:""})})," or ",(0,a.jsx)(n.a,{href:"/docs/use-link-to",children:(0,a.jsx)(n.code,{children:"useLinkTo"})})," to navigate using paths."]}),"\n"]}),"\n",(0,a.jsxs)(n.p,{children:["Make sure that you have ",(0,a.jsx)(n.a,{href:"/docs/deep-linking",children:"configured deep links"})," in your app before proceeding. If you have an Android or iOS app, remember to specify the ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkingprefixes",children:(0,a.jsx)(n.code,{children:"prefixes"})})," option."]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsxs)(o.Z,{value:"static",label:"Static",default:!0,children:[(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.a,{href:"/docs/static-configuration#createstaticnavigation",children:(0,a.jsx)(n.code,{children:"Navigation"})})," component accepts a ",(0,a.jsx)(n.a,{href:"/docs/static-configuration#differences-in-the-linking-prop",children:(0,a.jsx)(n.code,{children:"linking"})})," prop that makes it easier to handle incoming links:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"import { createStaticNavigation } from '@react-navigation/native';\n\n// highlight-start\nconst linking = {\n enabled: 'auto' /* Automatically generate paths for all screens */,\n prefixes: [\n /* your linking prefixes */\n ],\n};\n// highlight-end\n\nfunction App() {\n return (\n Loading...}\n />\n );\n}\n\nconst Navigation = createStaticNavigation(RootStack);\n"})})]}),(0,a.jsxs)(o.Z,{value:"dynamic",label:"Dynamic",children:[(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"NavigationContainer"})," accepts a ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linking",children:(0,a.jsx)(n.code,{children:"linking"})})," prop that makes it easier to handle incoming links. The 2 of the most important properties you can specify in the ",(0,a.jsx)(n.code,{children:"linking"})," prop are ",(0,a.jsx)(n.code,{children:"prefixes"})," and ",(0,a.jsx)(n.code,{children:"config"}),":"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"import { NavigationContainer } from '@react-navigation/native';\n\n// highlight-start\nconst linking = {\n prefixes: [\n /* your linking prefixes */\n ],\n config: {\n /* configuration for matching screens with paths */\n },\n};\n// highlight-end\n\nfunction App() {\n return (\n Loading...}\n >\n {/* content */}\n \n );\n}\n"})})]})]}),"\n",(0,a.jsxs)(n.p,{children:["When you specify the ",(0,a.jsx)(n.code,{children:"linking"})," prop, React Navigation will handle incoming links automatically. On Android and iOS, it'll use React Native's ",(0,a.jsxs)(n.a,{href:"https://reactnative.dev/docs/linking",children:[(0,a.jsx)(n.code,{children:"Linking"})," module"]})," to handle incoming links, both when the app was opened with the link, and when new links are received when the app is open. On the Web, it'll use the ",(0,a.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/History_API",children:"History API"})," to sync the URL with the browser."]}),"\n",(0,a.jsx)(n.admonition,{type:"warning",children:(0,a.jsxs)(n.p,{children:["Currently there seems to be bug (",(0,a.jsx)(n.a,{href:"https://github.com/facebook/react-native/issues/25675",children:"facebook/react-native#25675"}),") which results in it never resolving on Android. We add a timeout to avoid getting stuck forever, but it means that the link might not be handled in some cases."]})}),"\n",(0,a.jsxs)(n.p,{children:["You can also pass a ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#fallback",children:(0,a.jsx)(n.code,{children:"fallback"})})," prop that controls what's displayed when React Navigation is trying to resolve the initial deep link URL."]}),"\n",(0,a.jsx)(n.h2,{id:"prefixes",children:"Prefixes"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"prefixes"})," option can be used to specify custom schemes (e.g. ",(0,a.jsx)(n.code,{children:"mychat://"}),") as well as host & domain names (e.g. ",(0,a.jsx)(n.code,{children:"https://mychat.com"}),") if you have configured ",(0,a.jsx)(n.a,{href:"https://developer.apple.com/ios/universal-links/",children:"Universal Links"})," or ",(0,a.jsx)(n.a,{href:"https://developer.android.com/training/app-links",children:"Android App Links"}),"."]}),"\n",(0,a.jsx)(n.p,{children:"For example:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com'],\n};\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Note that the ",(0,a.jsx)(n.code,{children:"prefixes"})," option is not supported on Web. The host & domain names will be automatically determined from the Website URL in the browser. If your app runs only on Web, then you can omit this option from the config."]}),"\n",(0,a.jsx)(n.h3,{id:"multiple-subdomains",children:"Multiple subdomains\u200B"}),"\n",(0,a.jsxs)(n.p,{children:["To match all subdomains of an associated domain, you can specify a wildcard by prefixing ",(0,a.jsx)(n.code,{children:"*"}),". before the beginning of a specific domain. Note that an entry for ",(0,a.jsx)(n.code,{children:"*.mychat.com"})," does not match ",(0,a.jsx)(n.code,{children:"mychat.com"})," because of the period after the asterisk. To enable matching for both ",(0,a.jsx)(n.code,{children:"*.mychat.com"})," and ",(0,a.jsx)(n.code,{children:"mychat.com"}),", you need to provide a separate prefix entry for each."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com', 'https://*.mychat.com'],\n};\n"})}),"\n",(0,a.jsx)(n.h2,{id:"filtering-certain-paths",children:"Filtering certain paths"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes we may not want to handle all incoming links. For example, we may want to filter out links meant for authentication (e.g. ",(0,a.jsx)(n.code,{children:"expo-auth-session"}),") or other purposes instead of navigating to a specific screen."]}),"\n",(0,a.jsxs)(n.p,{children:["To achieve this, you can use the ",(0,a.jsx)(n.code,{children:"filter"})," option:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com'],\n // highlight-next-line\n filter: (url) => !url.includes('+expo-auth-session'),\n};\n"})}),"\n",(0,a.jsx)(n.p,{children:"This is not supported on Web as we always need to handle the URL of the page."}),"\n",(0,a.jsx)(n.h2,{id:"apps-under-subpaths",children:"Apps under subpaths"}),"\n",(0,a.jsxs)(n.p,{children:["If your app is hosted under a subpath, you can specify the subpath at the top-level of the ",(0,a.jsx)(n.code,{children:"config"}),". For example, if your app is hosted at ",(0,a.jsx)(n.code,{children:"https://mychat.com/app"}),", you can specify the ",(0,a.jsx)(n.code,{children:"path"})," as ",(0,a.jsx)(n.code,{children:"app"}),":"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['mychat://', 'https://mychat.com'],\n config: {\n // highlight-next-line\n path: 'app',\n\n // ...\n },\n};\n"})}),"\n",(0,a.jsxs)(n.p,{children:["It's not possible to specify params here since this doesn't belong to a screen, e.g. ",(0,a.jsx)(n.code,{children:"app/:id"})," won't work."]}),"\n",(0,a.jsx)(n.h2,{id:"mapping-path-to-route-names",children:"Mapping path to route names"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsxs)(o.Z,{value:"static",label:"Static",default:!0,children:[(0,a.jsxs)(n.p,{children:["If you specify ",(0,a.jsx)(n.code,{children:"enabled: 'auto'"})," in the ",(0,a.jsx)(n.code,{children:"linking"})," prop, React Navigation will automatically generate paths for all screens. For example, if you have a ",(0,a.jsx)(n.code,{children:"Profile"})," screen in the navigator, it'll automatically generate a path for it as ",(0,a.jsx)(n.code,{children:"profile"}),"."]}),(0,a.jsxs)(n.p,{children:["If you wish to handle the configuration manually, or want to override the generated path for a specific screen, you can specify ",(0,a.jsx)(n.code,{children:"linking"})," property next to the screen in the navigator to map a path to a screen. For example:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Profile: {\n screen: ProfileScreen,\n // highlight-start\n linking: {\n path: 'user',\n },\n // highlight-end\n },\n Chat: {\n screen: ChatScreen,\n // highlight-start\n linking: {\n path: 'feed/:sort',\n },\n // highlight-end\n },\n },\n});\n"})}),(0,a.jsx)(n.p,{children:"In this example:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Chat"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/feed"})," with the param ",(0,a.jsx)(n.code,{children:"sort"})," (e.g. ",(0,a.jsx)(n.code,{children:"/feed/latest"})," - the ",(0,a.jsx)(n.code,{children:"Chat"})," screen will receive a param ",(0,a.jsx)(n.code,{children:"sort"})," with the value ",(0,a.jsx)(n.code,{children:"latest"}),")."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Profile"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/user"}),"."]}),"\n"]}),(0,a.jsxs)(n.p,{children:["Similarly, when you have a nested navigator, you can specify the ",(0,a.jsx)(n.code,{children:"linking"})," property for the screens in the navigator to handle the path for the nested screens:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Home: {\n screen: HomeScreen,\n // highlight-start\n linking: {\n path: 'home',\n },\n // highlight-end\n },\n Settings: {\n screen: SettingsScreen,\n // highlight-start\n linking: {\n path: 'settings',\n },\n // highlight-end\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n HomeTabs: {\n screen: HomeTabs,\n },\n Profile: {\n screen: ProfileScreen,\n // highlight-start\n linking: {\n path: 'user',\n },\n // highlight-end\n },\n Chat: {\n screen: ChatScreen,\n // highlight-start\n linking: {\n path: 'feed/:sort',\n },\n // highlight-end\n },\n },\n});\n"})}),(0,a.jsx)(n.p,{children:"In the above example, the following path formats are handled:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/home"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Home"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/settings"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Settings"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/user"})," navigates to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/feed/:sort"})," navigates to the ",(0,a.jsx)(n.code,{children:"Chat"})," screen with the param ",(0,a.jsx)(n.code,{children:"sort"})]}),"\n"]}),(0,a.jsx)(n.h3,{id:"how-does-automatic-path-generation-work",children:"How does automatic path generation work?"}),(0,a.jsxs)(n.p,{children:["When using automatic path generation with ",(0,a.jsx)(n.code,{children:"enabled: 'auto'"}),", the following rules are applied:"]}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:["Screens with an explicit ",(0,a.jsx)(n.code,{children:"linking"})," property are not used for path generation and will be added as-is."]}),"\n",(0,a.jsxs)(n.li,{children:["Screen names will be converted from ",(0,a.jsx)(n.code,{children:"PascalCase"})," to ",(0,a.jsx)(n.code,{children:"kebab-case"})," to use as the path (e.g. ",(0,a.jsx)(n.code,{children:"NewsFeed"})," -> ",(0,a.jsx)(n.code,{children:"news-feed"}),")."]}),"\n",(0,a.jsxs)(n.li,{children:["Unless a screen has explicit empty path (",(0,a.jsx)(n.code,{children:"path: ''"}),") to use for the homepage, the first leaf screen encountered will be used as the homepage."]}),"\n",(0,a.jsxs)(n.li,{children:["Path generation only handles leaf screens, i.e. no path is generated for screens containing nested navigators. It's still possible to specify a path for them with an explicit ",(0,a.jsx)(n.code,{children:"linking"})," property."]}),"\n"]}),(0,a.jsx)(n.p,{children:"Let's say we have the following navigation structure:"}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Home: {\n screen: HomeScreen,\n },\n Settings: {\n screen: SettingsScreen,\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n HomeTabs: {\n screen: HomeTabs,\n },\n Profile: {\n screen: ProfileScreen,\n },\n Chat: {\n screen: ChatScreen,\n },\n },\n});\n"})}),(0,a.jsx)(n.p,{children:"With automatic path generation, the following paths will be generated:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Home"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/settings"})," navigates to the ",(0,a.jsx)(n.code,{children:"HomeTabs"})," -> ",(0,a.jsx)(n.code,{children:"Settings"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/profile"})," navigates to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"/chat"})," navigates to the ",(0,a.jsx)(n.code,{children:"Chat"})," screen"]}),"\n"]}),(0,a.jsxs)(n.p,{children:["If the URL contains a query string, it'll be passed as params to the screen. For example, the URL ",(0,a.jsx)(n.code,{children:"/profile?user=jane"})," will pass the ",(0,a.jsx)(n.code,{children:"user"})," param to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]})]}),(0,a.jsxs)(o.Z,{value:"dynamic",label:"Dynamic",children:[(0,a.jsxs)(n.p,{children:["If you specify a ",(0,a.jsx)(n.code,{children:"linking"})," option, by default React Navigation will use the path segments as the route name when parsing the URL. However, directly translating path segments to route names may not be the expected behavior."]}),(0,a.jsxs)(n.p,{children:["You can specify the ",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkingconfig",children:(0,a.jsx)(n.code,{children:"config"})})," option in ",(0,a.jsx)(n.code,{children:"linking"})," to control how the deep link is parsed to suit your needs. The config should specify the mapping between route names and path patterns:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: 'feed/:sort',\n Profile: 'user',\n },\n};\n"})}),(0,a.jsx)(n.p,{children:"In this example:"}),(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Chat"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/feed"})," with the param ",(0,a.jsx)(n.code,{children:"sort"})," (e.g. ",(0,a.jsx)(n.code,{children:"/feed/latest"})," - the ",(0,a.jsx)(n.code,{children:"Chat"})," screen will receive a param ",(0,a.jsx)(n.code,{children:"sort"})," with the value ",(0,a.jsx)(n.code,{children:"latest"}),")."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"Profile"})," screen that handles the URL ",(0,a.jsx)(n.code,{children:"/user"}),"."]}),"\n"]}),(0,a.jsxs)(n.p,{children:["The config option can then be passed in the ",(0,a.jsx)(n.code,{children:"linking"})," prop to the container:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"import { NavigationContainer } from '@react-navigation/native';\n\nconst config = {\n screens: {\n Chat: 'feed/:sort',\n Profile: 'user',\n },\n};\n\nconst linking = {\n prefixes: ['https://mychat.com', 'mychat://'],\n config,\n};\n\nfunction App() {\n return (\n Loading...}>\n {/* content */}\n \n );\n}\n"})}),(0,a.jsxs)(n.p,{children:["The config object must match the navigation structure for your app. For example, the above configuration is if you have ",(0,a.jsx)(n.code,{children:"Chat"})," and ",(0,a.jsx)(n.code,{children:"Profile"})," screens in the navigator at the root:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:'function App() {\n return (\n \n \n \n \n );\n}\n'})}),(0,a.jsxs)(n.p,{children:["If your ",(0,a.jsx)(n.code,{children:"Chat"})," screen is inside a nested navigator, we'd need to account for that. For example, consider the following structure where your ",(0,a.jsx)(n.code,{children:"Profile"})," screen is at the root, but the ",(0,a.jsx)(n.code,{children:"Chat"})," screen is nested inside ",(0,a.jsx)(n.code,{children:"Home"}),":"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:'function App() {\n return (\n \n \n \n \n );\n}\n\nfunction HomeScreen() {\n return (\n \n \n \n );\n}\n'})}),(0,a.jsx)(n.p,{children:"For the above structure, our configuration will look like this:"}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n screens: {\n Chat: 'feed/:sort',\n },\n },\n Profile: 'user',\n },\n};\n"})}),(0,a.jsx)(n.p,{children:"Similarly, any nesting needs to be reflected in the configuration."})]})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"How it works"}),(0,a.jsxs)(n.p,{children:["The linking works by translating the URL to a valid ",(0,a.jsx)(n.a,{href:"/docs/navigation-state",children:"navigation state"})," and vice versa using the configuration provided. For example, the path ",(0,a.jsx)(n.code,{children:"/rooms/chat?user=jane"})," may be translated to a state object like this:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'rooms',\n state: {\n routes: [\n {\n name: 'chat',\n params: { user: 'jane' },\n },\n ],\n },\n },\n ],\n};\n"})}),(0,a.jsxs)(n.p,{children:["For example, you might want to parse the path ",(0,a.jsx)(n.code,{children:"/feed/latest"})," to something like:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Chat',\n params: {\n sort: 'latest',\n },\n },\n ];\n}\n"})}),(0,a.jsxs)(n.p,{children:["See ",(0,a.jsx)(n.a,{href:"/docs/navigation-state",children:"Navigation State reference"})," for more details on how the state object is structured."]})]}),"\n",(0,a.jsx)(n.h2,{id:"passing-params",children:"Passing params"}),"\n",(0,a.jsxs)(n.p,{children:["A common use case is to pass params to a screen to pass some data. For example, you may want the ",(0,a.jsx)(n.code,{children:"Profile"})," screen to have an ",(0,a.jsx)(n.code,{children:"id"})," param to know which user's profile it is. It's possible to pass params to a screen through a URL when handling deep links."]}),"\n",(0,a.jsxs)(n.p,{children:["By default, query params are parsed to get the params for a screen. For example, with the above example, the URL ",(0,a.jsx)(n.code,{children:"/user?id=jane"})," will pass the ",(0,a.jsx)(n.code,{children:"id"})," param to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]}),"\n",(0,a.jsxs)(n.p,{children:["You can also customize how the params are parsed from the URL. Let's say you want the URL to look like ",(0,a.jsx)(n.code,{children:"/user/jane"})," where the ",(0,a.jsx)(n.code,{children:"id"})," param is ",(0,a.jsx)(n.code,{children:"jane"})," instead of having the ",(0,a.jsx)(n.code,{children:"id"})," in query params. You can do this by specifying ",(0,a.jsx)(n.code,{children:"user/:id"})," for the ",(0,a.jsx)(n.code,{children:"path"}),". ",(0,a.jsxs)(n.strong,{children:["When the path segment starts with ",(0,a.jsx)(n.code,{children:":"}),", it'll be treated as a param"]}),". For example, the URL ",(0,a.jsx)(n.code,{children:"/user/jane"})," would resolve to ",(0,a.jsx)(n.code,{children:"Profile"})," screen with the string ",(0,a.jsx)(n.code,{children:"jane"})," as a value of the ",(0,a.jsx)(n.code,{children:"id"})," param and will be available in ",(0,a.jsx)(n.code,{children:"route.params.id"})," in ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]}),"\n",(0,a.jsxs)(n.p,{children:["By default, all params are treated as strings. You can also customize how to parse them by specifying a function in the ",(0,a.jsx)(n.code,{children:"parse"})," property to parse the param, and a function in the ",(0,a.jsx)(n.code,{children:"stringify"})," property to convert it back to a string."]}),"\n",(0,a.jsxs)(n.p,{children:["If you wanted to resolve ",(0,a.jsx)(n.code,{children:"/user/@jane/settings"})," to result in the params ",(0,a.jsx)(n.code,{children:"{ id: 'jane' section: 'settings' }"}),", you could make ",(0,a.jsx)(n.code,{children:"Profile"}),"'s config to look like this:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Profile: {\n screen: ProfileScreen,\n // highlight-start\n linking: {\n path: 'user/:id/:section',\n parse: {\n id: (id) => id.replace(/^@/, ''),\n },\n stringify: {\n id: (id) => `@${id}`,\n },\n },\n // highlight-end\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Profile: {\n // highlight-start\n path: 'user/:id/:section',\n parse: {\n id: (id) => id.replace(/^@/, ''),\n },\n stringify: {\n id: (id) => `@${id}`,\n },\n // highlight-end\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/user/@jane/settings"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Profile',\n params: { id: 'jane', section: 'settings' },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsx)(n.h2,{id:"marking-params-as-optional",children:"Marking params as optional"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes a param may or may not be present in the URL depending on certain conditions. For example, in the above scenario, you may not always have the section parameter in the URL, i.e. both ",(0,a.jsx)(n.code,{children:"/user/jane/settings"})," and ",(0,a.jsx)(n.code,{children:"/user/jane"})," should go to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen, but the ",(0,a.jsx)(n.code,{children:"section"})," param (with the value ",(0,a.jsx)(n.code,{children:"settings"})," in this case) may or may not be present."]}),"\n",(0,a.jsxs)(n.p,{children:["In this case, you would need to mark the ",(0,a.jsx)(n.code,{children:"section"})," param as optional. You can do it by adding the ",(0,a.jsx)(n.code,{children:"?"})," suffix after the param name:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Profile: {\n screen: ProfileScreen,\n linking: {\n // highlight-next-line\n path: 'user/:id/:section?',\n parse: {\n id: (id) => `user-${id}`,\n },\n stringify: {\n id: (id) => id.replace(/^user-/, ''),\n },\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Profile: {\n // highlight-next-line\n path: 'user/:id/:section?',\n parse: {\n id: (id) => `user-${id}`,\n },\n stringify: {\n id: (id) => id.replace(/^user-/, ''),\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/user/jane"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Profile',\n params: { id: 'user-jane' },\n },\n ],\n};\n"})}),(0,a.jsxs)(n.p,{children:["If the URL contains a ",(0,a.jsx)(n.code,{children:"section"})," param (e.g. ",(0,a.jsx)(n.code,{children:"/user/jane/settings"}),"), this will result in the following with the same config:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Profile',\n params: { id: 'user-jane', section: 'settings' },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsx)(n.h2,{id:"handling-unmatched-routes-or-404",children:"Handling unmatched routes or 404"}),"\n",(0,a.jsx)(n.p,{children:"If your app is opened with an invalid URL, most of the times you'd want to show an error page with some information. On the web, this is commonly known as 404 - or page not found error."}),"\n",(0,a.jsxs)(n.p,{children:["To handle this, you'll need to define a catch-all route that will be rendered if no other routes match the path. You can do it by specifying ",(0,a.jsx)(n.code,{children:"*"})," for the path matching pattern:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Feed: {\n screen: FeedScreen,\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n Settings: {\n screen: SettingsScreen,\n linking: {\n path: 'settings',\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: HomeTabs,\n },\n NotFound: {\n screen: NotFoundScreen,\n linking: {\n // highlight-next-line\n path: '*',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n initialRouteName: 'Feed',\n screens: {\n Profile: 'users/:id',\n Settings: 'settings',\n },\n },\n NotFound: {\n // highlight-start\n path: '*',\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["Here, we have defined a route named ",(0,a.jsx)(n.code,{children:"NotFound"})," and set it to match ",(0,a.jsx)(n.code,{children:"*"})," aka everything. If the path didn't match ",(0,a.jsx)(n.code,{children:"user/:id"})," or ",(0,a.jsx)(n.code,{children:"settings"}),", it'll be matched by this route."]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, a path like ",(0,a.jsx)(n.code,{children:"/library"})," or ",(0,a.jsx)(n.code,{children:"/settings/notification"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [{ name: 'NotFound' }],\n};\n"})})]}),"\n",(0,a.jsxs)(n.p,{children:["You can even go more specific, for example, say if you want to show a different screen for invalid paths under ",(0,a.jsx)(n.code,{children:"/settings"}),", you can specify such a pattern under ",(0,a.jsx)(n.code,{children:"Settings"}),":"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const SettingsStack = createStackNavigator({\n screens: {\n UserSettings: {\n screen: UserSettingsScreen,\n linking: {\n path: 'user-settings',\n },\n },\n InvalidSettings: {\n screen: InvalidSettingsScreen,\n linking: {\n // highlight-next-line\n path: '*',\n },\n },\n },\n});\n\nconst HomeTabs = createBottomTabNavigator({\n screens: {\n Feed: {\n screen: FeedScreen,\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n Settings: {\n screen: SettingsStack,\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: HomeTabs,\n },\n NotFound: {\n screen: NotFoundScreen,\n linking: {\n path: '*',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n initialRouteName: 'Feed',\n screens: {\n Profile: 'users/:id',\n Settings: {\n path: 'settings',\n screens: {\n InvalidSettings: '*',\n },\n },\n },\n },\n NotFound: '*',\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/settings/notification"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Home',\n state: {\n index: 1,\n routes: [\n { name: 'Feed' },\n {\n name: 'Settings',\n state: {\n routes: [\n { name: 'InvalidSettings', path: '/settings/notification' },\n ],\n },\n },\n ],\n },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"route"})," passed to the ",(0,a.jsx)(n.code,{children:"NotFound"})," screen will contain a ",(0,a.jsx)(n.code,{children:"path"})," property which corresponds to the path that opened the page. If you need, you can use this property to customize what's shown in this screen, e.g. load the page in a ",(0,a.jsx)(n.code,{children:"WebView"}),":"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"function NotFoundScreen({ route }) {\n if (route.path) {\n return ;\n }\n\n return This screen doesn't exist!;\n}\n"})}),"\n",(0,a.jsxs)(n.p,{children:["When doing server rendering, you'd also want to return correct status code for 404 errors. See ",(0,a.jsx)(n.a,{href:"/docs/server-rendering#handling-404-or-other-status-codes",children:"server rendering docs"})," for a guide on how to handle it."]}),"\n",(0,a.jsx)(n.h2,{id:"rendering-an-initial-route",children:"Rendering an initial route"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes you want to ensure that a certain screen will always be present as the first screen in the navigator's state. You can use the ",(0,a.jsx)(n.code,{children:"initialRouteName"})," property to specify the screen to use for the initial screen."]}),"\n",(0,a.jsxs)(n.p,{children:["In the above example, if you want the ",(0,a.jsx)(n.code,{children:"Feed"})," screen to be the initial route in the navigator under ",(0,a.jsx)(n.code,{children:"Home"}),", your config will look like this:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const HomeTabs = createBottomTabNavigator({\n screens: {\n Feed: {\n screen: FeedScreen,\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n Settings: {\n screen: SettingsScreen,\n linking: {\n path: 'settings',\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: HomeTabs,\n linking: {\n // highlight-next-line\n initialRouteName: 'Feed',\n },\n },\n NotFound: {\n screen: NotFoundScreen,\n linking: {\n path: '*',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n // highlight-next-line\n initialRouteName: 'Feed',\n screens: {\n Profile: 'users/:id',\n Settings: 'settings',\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(t,{children:[(0,a.jsx)("summary",{children:"Result Navigation State"}),(0,a.jsxs)(n.p,{children:["With this configuration, the path ",(0,a.jsx)(n.code,{children:"/users/42"})," will resolve to the following state object:"]}),(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const state = {\n routes: [\n {\n name: 'Home',\n state: {\n index: 1,\n routes: [\n { name: 'Feed' },\n {\n name: 'Profile',\n params: { id: '42' },\n },\n ],\n },\n },\n ],\n};\n"})})]}),"\n",(0,a.jsx)(n.admonition,{type:"warning",children:(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"initialRouteName"})," will add the screen to React Navigation's state only. If your app is running on the Web, the browser's history will not contain this screen as the user has never visited it. So, if the user presses the browser's back button, it'll not go back to this screen."]})}),"\n",(0,a.jsxs)(n.p,{children:["Another thing to keep in mind is that it's not possible to pass params to the initial screen through the URL. So make sure that your initial route doesn't need any params or specify ",(0,a.jsx)(n.code,{children:"initialParams"})," in the screen configuration to pass the required params."]}),"\n",(0,a.jsxs)(n.p,{children:["In this case, any params in the URL are only passed to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen which matches the path pattern ",(0,a.jsx)(n.code,{children:"users/:id"}),", and the ",(0,a.jsx)(n.code,{children:"Feed"})," screen doesn't receive any params. If you want to have the same params in the ",(0,a.jsx)(n.code,{children:"Feed"})," screen, you can specify a ",(0,a.jsxs)(n.a,{href:"/docs/navigation-container#linkinggetstatefrompath",children:["custom ",(0,a.jsx)(n.code,{children:"getStateFromPath"})," function"]})," and copy those params."]}),"\n",(0,a.jsxs)(n.p,{children:["Similarly, if you want to access params of a parent screen from a child screen, you can use ",(0,a.jsx)(n.a,{href:"https://react.dev/reference/react/useContext",children:"React Context"})," to expose them."]}),"\n",(0,a.jsx)(n.h2,{id:"matching-exact-paths",children:"Matching exact paths"}),"\n",(0,a.jsx)(n.p,{children:"By default, paths defined for each screen are matched against the URL relative to their parent screen's path. Consider the following config:"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const ProfileTabs = createBottomTabNavigator({\n screens: {\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileTabs,\n linking: {\n path: 'feed',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: 'feed',\n screens: {\n Profile: 'users/:id',\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["Here, you have a ",(0,a.jsx)(n.code,{children:"path"})," property defined for the ",(0,a.jsx)(n.code,{children:"Home"})," screen, as well as the child ",(0,a.jsx)(n.code,{children:"Profile"})," screen. The profile screen specifies the path ",(0,a.jsx)(n.code,{children:"users/:id"}),", but since it's nested inside a screen with the path ",(0,a.jsx)(n.code,{children:"feed"}),", it'll try to match the pattern ",(0,a.jsx)(n.code,{children:"feed/users/:id"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:["This will result in the URL ",(0,a.jsx)(n.code,{children:"/feed"})," navigating to ",(0,a.jsx)(n.code,{children:"Home"})," screen, and ",(0,a.jsx)(n.code,{children:"/feed/users/cal"})," navigating to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen."]}),"\n",(0,a.jsxs)(n.p,{children:["In this case, it makes more sense to navigate to the ",(0,a.jsx)(n.code,{children:"Profile"})," screen using a URL like ",(0,a.jsx)(n.code,{children:"/users/cal"}),", rather than ",(0,a.jsx)(n.code,{children:"/feed/users/cal"}),". To achieve this, you can override the relative matching behavior to ",(0,a.jsx)(n.code,{children:"exact"})," matching:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const ProfileTabs = createBottomTabNavigator({\n screens: {\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n // highlight-next-line\n exact: true,\n },\n },\n },\n});\n\nconst RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileTabs,\n linking: {\n path: 'feed',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: 'feed',\n screens: {\n Profile: {\n path: 'users/:id',\n // highlight-next-line\n exact: true,\n },\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["With ",(0,a.jsx)(n.code,{children:"exact"})," property set to ",(0,a.jsx)(n.code,{children:"true"}),", ",(0,a.jsx)(n.code,{children:"Profile"})," will ignore the parent screen's ",(0,a.jsx)(n.code,{children:"path"})," config and you'll be able to navigate to ",(0,a.jsx)(n.code,{children:"Profile"})," using a URL like ",(0,a.jsx)(n.code,{children:"users/cal"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"omitting-a-screen-from-path",children:"Omitting a screen from path"}),"\n",(0,a.jsxs)(n.p,{children:["Sometimes, you may not want to have the route name of a screen in the path. For example, let's say you have a ",(0,a.jsx)(n.code,{children:"Home"})," screen and the following config. When the page is opened in the browser you'll get ",(0,a.jsx)(n.code,{children:"/home"})," as the URL:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileScreen,\n linking: {\n path: 'home',\n },\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: 'home',\n },\n Profile: 'users/:id',\n },\n};\n"})})})]}),"\n",(0,a.jsxs)(n.p,{children:["But it'll be nicer if the URL was just ",(0,a.jsx)(n.code,{children:"/"})," when visiting the home screen."]}),"\n",(0,a.jsx)(n.p,{children:"You can specify an empty string as path or not specify a path at all, and React Navigation won't add the screen to the path (think of it like adding empty string to the path, which doesn't change anything):"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Home: {\n screen: ProfileScreen,\n linking: {\n path: '',\n },\n },\n Profile: {\n screen: HomeScreen,\n linking: {\n path: 'users/:id',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Home: {\n path: '',\n },\n Profile: 'users/:id',\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.h2,{id:"serializing-and-parsing-params",children:"Serializing and parsing params"}),"\n",(0,a.jsx)(n.p,{children:"Since URLs are strings, any params you have for routes are also converted to strings when constructing the path."}),"\n",(0,a.jsxs)(n.p,{children:["For example, say you have the URL ",(0,a.jsx)(n.code,{children:"/chat/1589842744264"})," with the following config:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Chat: {\n screen: ChatScreen,\n linking: {\n path: 'chat/:date',\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: 'chat/:date',\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.p,{children:"When handling the URL, your params will look like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yml",children:"{ date: '1589842744264' }\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Here, the ",(0,a.jsx)(n.code,{children:"date"})," param was parsed as a string because React Navigation doesn't know that it's supposed to be a timestamp, and hence number. You can customize it by providing a custom function to use for parsing:"]}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Chat: {\n screen: ChatScreen,\n linking: {\n path: 'chat/:date',\n parse: {\n date: Number,\n },\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: {\n path: 'chat/:date',\n parse: {\n date: Number,\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.p,{children:"You can also provide a your own function to serialize the params. For example, let's say that you want to use a DD-MM-YYYY format in the path instead of a timestamp:"}),"\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const RootStack = createStackNavigator({\n screens: {\n Chat: {\n screen: ChatScreen,\n linking: {\n path: 'chat/:date',\n parse: {\n date: (date) => new Date(date).getTime(),\n },\n stringify: {\n date: (date) => {\n const d = new Date(date);\n\n return d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate();\n },\n },\n },\n },\n },\n});\n"})})}),(0,a.jsx)(o.Z,{value:"dynamic",label:"Dynamic",children:(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const config = {\n screens: {\n Chat: {\n path: 'chat/:date',\n parse: {\n date: (date) => new Date(date).getTime(),\n },\n stringify: {\n date: (date) => {\n const d = new Date(date);\n\n return d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate();\n },\n },\n },\n },\n};\n"})})})]}),"\n",(0,a.jsx)(n.p,{children:"Depending on your requirements, you can use this functionality to parse and stringify more complex data."}),"\n",(0,a.jsx)(n.h2,{id:"advanced-cases",children:"Advanced cases"}),"\n",(0,a.jsxs)(n.p,{children:["For some advanced cases, specifying the mapping may not be sufficient. To handle such cases, you can specify a custom function to parse the URL into a state object (",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkinggetstatefrompath",children:(0,a.jsx)(n.code,{children:"getStateFromPath"})}),"), and a custom function to serialize the state object into an URL (",(0,a.jsx)(n.a,{href:"/docs/navigation-container#linkinggetpathfromstate",children:(0,a.jsx)(n.code,{children:"getPathFromState"})}),")."]}),"\n",(0,a.jsx)(n.p,{children:"Example:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-js",children:"const linking = {\n prefixes: ['https://mychat.com', 'mychat://'],\n getStateFromPath: (path, options) => {\n // Return a state object here\n // You can also reuse the default logic by importing `getStateFromPath` from `@react-navigation/native`\n },\n getPathFromState(state, config) {\n // Return a path string here\n // You can also reuse the default logic by importing `getPathFromState` from `@react-navigation/native`\n },\n\n // ...\n};\n"})}),"\n",(0,a.jsx)(n.h2,{id:"playground",children:"Playground"}),"\n","\n",(0,a.jsxs)(r.Z,{groupId:"config",queryString:"config",children:[(0,a.jsx)(o.Z,{value:"static",label:"Static",default:!0,children:(0,a.jsx)(n.p,{children:"Playground is not available for static config."})}),(0,a.jsxs)(o.Z,{value:"dynamic",label:"Dynamic",children:[(0,a.jsx)(n.p,{children:"You can play around with customizing the config and path below, and see how the path is parsed."}),(0,a.jsx)(c.Z,{})]})]})]})}function g(e={}){let{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(u,{...e})}):u(e)}function x(e,n){throw Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},5525:function(e,n,t){t.d(n,{Z:()=>r});var i=t("85893");t("67294");var a=t("67026");let s="tabItem_Ymn6";function r(e){let{children:n,hidden:t,className:r}=e;return(0,i.jsx)("div",{role:"tabpanel",className:(0,a.Z)(s,r),hidden:t,children:n})}},47902:function(e,n,t){t.d(n,{Z:()=>H});var i=t("85893"),a=t("67294"),s=t("67026"),r=t("69599"),o=t("16550"),c=t("32000"),l=t("4520"),d=t("38341"),h=t("76009");function p(e){let{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}function u(e){var n,t;return null!==(t=null===(n=a.Children.toArray(e).filter(e=>"\n"!==e).map(e=>{if(!e||(0,a.isValidElement)(e)&&p(e))return e;throw Error("Docusaurus error: Bad child <".concat("string"==typeof e.type?e.type:e.type.name,'>: all children of the component should be , and every should have a unique "value" prop.'))}))||void 0===n?void 0:n.filter(Boolean))&&void 0!==t?t:[]}function g(e){return u(e).map(e=>{let{props:{value:n,label:t,attributes:i,default:a}}=e;return{value:n,label:t,attributes:i,default:a}})}function x(e){let n=(0,d.lx)(e,(e,n)=>e.value===n.value);if(n.length>0)throw Error('Docusaurus error: Duplicate values "'.concat(n.map(e=>e.value).join(", "),'" found in . Every value needs to be unique.'))}function m(e){let{values:n,children:t}=e;return(0,a.useMemo)(()=>{let e=null!=n?n:g(t);return x(e),e},[n,t])}function j(e){let{value:n,tabValues:t}=e;return t.some(e=>e.value===n)}function f(e){var n;let{defaultValue:t,tabValues:i}=e;if(0===i.length)throw Error("Docusaurus error: the component requires at least one children component");if(t){if(!j({value:t,tabValues:i}))throw Error('Docusaurus error: The has a defaultValue "'.concat(t,'" but none of its children has the corresponding value. Available values are: ').concat(i.map(e=>e.value).join(", "),". If you intend to show no default tab, use defaultValue={null} instead."));return t}let a=null!==(n=i.find(e=>e.default))&&void 0!==n?n:i[0];if(!a)throw Error("Unexpected error: 0 tabValues");return a.value}function v(e){return e?"docusaurus.tab.".concat(e):null}function y(e){let{queryString:n=!1,groupId:t}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!t)throw Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=t?t:null}function b(e){let{queryString:n=!1,groupId:t}=e,i=(0,o.k6)(),s=y({queryString:n,groupId:t}),r=(0,l._X)(s);return[r,(0,a.useCallback)(e=>{if(!s)return;let n=new URLSearchParams(i.location.search);n.set(s,e),i.replace({...i.location,search:n.toString()})},[s,i])]}function k(e){let{groupId:n}=e,t=v(n),[i,s]=(0,h.Nk)(t);return[i,(0,a.useCallback)(e=>{if(!!t)s.set(e)},[t,s])]}function w(e){let{defaultValue:n,queryString:t=!1,groupId:i}=e,s=m(e),[r,o]=(0,a.useState)(()=>f({defaultValue:n,tabValues:s})),[l,d]=b({queryString:t,groupId:i}),[h,p]=k({groupId:i}),u=(()=>{let e=null!=l?l:h;return j({value:e,tabValues:s})?e:null})();return(0,c.Z)(()=>{u&&o(u)},[u]),{selectedValue:r,selectValue:(0,a.useCallback)(e=>{if(!j({value:e,tabValues:s}))throw Error("Can't select invalid tab value=".concat(e));o(e),d(e),p(e)},[d,p,s]),tabValues:s}}var S=t("7227");let N="tabList__CuJ",R="tabItem_LNqP";function P(e){let{className:n,block:t,selectedValue:a,selectValue:o,tabValues:c}=e,l=[],{blockElementScrollPositionUntilNextRender:d}=(0,r.o5)(),h=e=>{let n=e.currentTarget,t=c[l.indexOf(n)].value;t!==a&&(d(n),o(t))},p=e=>{var n,t;let i=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{let t=l.indexOf(e.currentTarget)+1;i=null!==(n=l[t])&&void 0!==n?n:l[0];break}case"ArrowLeft":{let n=l.indexOf(e.currentTarget)-1;i=null!==(t=l[n])&&void 0!==t?t:l[l.length-1]}}null==i||i.focus()};return(0,i.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.Z)("tabs",{"tabs--block":t},n),children:c.map(e=>{let{value:n,label:t,attributes:r}=e;return(0,i.jsx)("li",{role:"tab",tabIndex:a===n?0:-1,"aria-selected":a===n,ref:e=>l.push(e),onKeyDown:p,onClick:h,...r,className:(0,s.Z)("tabs__item",R,null==r?void 0:r.className,{"tabs__item--active":a===n}),children:null!=t?t:n},n)})})}function T(e){let{lazy:n,children:t,selectedValue:r}=e,o=(Array.isArray(t)?t:[t]).filter(Boolean);if(n){let e=o.find(e=>e.props.value===r);return e?(0,a.cloneElement)(e,{className:(0,s.Z)("margin-top--md",e.props.className)}):null}return(0,i.jsx)("div",{className:"margin-top--md",children:o.map((e,n)=>(0,a.cloneElement)(e,{key:n,hidden:e.props.value!==r}))})}function C(e){let n=w(e);return(0,i.jsxs)("div",{className:(0,s.Z)("tabs-container",N),children:[(0,i.jsx)(P,{...n,...e}),(0,i.jsx)(T,{...n,...e})]})}function H(e){let n=(0,S.Z)();return(0,i.jsx)(C,{...e,children:u(e.children)},String(n))}},41665:function(__unused_webpack_module,__webpack_exports__,__webpack_require__){__webpack_require__.d(__webpack_exports__,{Z:function(){return LinkingTester}});var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(85893),_docusaurus_theme_common__WEBPACK_IMPORTED_MODULE_6__=__webpack_require__(84239),_react_navigation_core__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(49640),prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__(83229),react__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__(67294),react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4__=__webpack_require__(40460),react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4___default=__webpack_require__.n(react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4__),_RouteMap__WEBPACK_IMPORTED_MODULE_5__=__webpack_require__(58002);let parse=value=>eval("(function() { return ".concat(value,"; }())"));function Code(e){let{code:n,theme:t,language:i}=e;return(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.y$,{code:n,theme:t,language:i,children:e=>{let{className:n,style:t,tokens:i,getLineProps:a,getTokenProps:s}=e;return(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("pre",{className:n,style:{...t,...styles.json},children:i.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div",{...a({line:e,key:n}),children:e.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span",{...s({token:e,key:n})}))}))})}})}function LinkingTester(){let e,n;let{colorMode:t}=(0,_docusaurus_theme_common__WEBPACK_IMPORTED_MODULE_6__.I)(),i="dark"===t?prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.np.dracula:prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.np.github,[a,s]=react__WEBPACK_IMPORTED_MODULE_3__.useState("{\n screens: {\n Home: {\n initialRouteName: 'Feed',\n screens: {\n Profile: {\n path: 'user/:id',\n parse: {\n id: id => id.replace(/^@/, ''),\n },\n screens: {\n Settings: 'edit',\n },\n },\n },\n },\n NoMatch: '*',\n }\n}"),[r,o]=react__WEBPACK_IMPORTED_MODULE_3__.useState("/user/@vergil/edit"),[c,l]=react__WEBPACK_IMPORTED_MODULE_3__.useState(()=>parse(a)),[d,h]=react__WEBPACK_IMPORTED_MODULE_3__.useState("chart");try{e=(0,_react_navigation_core__WEBPACK_IMPORTED_MODULE_1__.cT)(r.replace(/(^\w+:|^)\/\//,""),c),n=(0,_react_navigation_core__WEBPACK_IMPORTED_MODULE_1__.ft)(e,c)}catch(e){}return(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,{children:[(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("input",{type:"text",value:r,placeholder:"Type a path, e.g. /user/@vergil/edit",onChange:e=>o(e.target.value),style:{...styles.code,...styles.input}}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(react_simple_code_editor__WEBPACK_IMPORTED_MODULE_4___default(),{value:a,placeholder:"Type linking config",onValueChange:e=>{s(e);try{let n=parse(e);l(n)}catch(e){}},highlight:e=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(prism_react_renderer__WEBPACK_IMPORTED_MODULE_2__.y$,{code:e,theme:i,language:"jsx",children:e=>{let{tokens:n,getLineProps:t,getTokenProps:i}=e;return n.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div",{...t({line:e,key:n}),children:e.map((e,n)=>(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span",{...i({token:e,key:n})}))}))}}),padding:16,style:{...styles.code,...styles.editor}}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div",{style:styles.preview,children:[(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div",{style:styles.toggles,children:[(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button",{type:"button",style:styles.button,onClick:()=>h("chart"),children:"Chart"}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button",{type:"button",style:styles.button,onClick:()=>h("state"),children:"State"}),(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button",{type:"button",style:styles.button,onClick:()=>h("action"),children:"Action"})]}),"state"===d?(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Code,{theme:i,code:JSON.stringify(e,null,2)||"",language:"json"}):"action"===d?(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Code,{theme:i,code:JSON.stringify(n,null,2)||"",language:"json"}):"chart"===d?e?(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_RouteMap__WEBPACK_IMPORTED_MODULE_5__.Z,{routes:e.routes}):(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p",{style:styles.error,children:"Failed to parse the path. Make sure that the path matches the patterns specified in the config."}):null]})]})}let styles={code:{display:"block",fontFamily:"var(--ifm-font-family-monospace)",fontSize:"var(--ifm-code-font-size)",borderRadius:"var(--ifm-pre-border-radius)",margin:"var(--ifm-spacing-vertical) 0"},input:{display:"block",width:"100%",padding:"var(--ifm-pre-padding)",backgroundColor:"transparent",color:"inherit",border:"1px solid var(--ifm-contents-border-color)"},editor:{border:"1px solid var(--ifm-contents-border-color)"},preview:{position:"relative",border:"1px solid var(--ifm-contents-border-color)",borderRadius:"var(--ifm-pre-border-radius)",minHeight:70},json:{margin:0,fontFamily:"var(--ifm-font-family-monospace)",fontSize:"var(--ifm-code-font-size)",borderRadius:"var(--ifm-pre-border-radius)",padding:"var(--ifm-pre-padding)",minHeight:70},toggles:{position:"absolute",flexDirection:"row",right:0,top:0,borderBottom:"1px solid var(--ifm-contents-border-color)"},button:{border:0,borderLeft:"1px solid var(--ifm-contents-border-color)",borderRadius:0,cursor:"pointer",display:"inline-flex",fontSize:12,margin:0,padding:"4px 8px",color:"inherit",background:"none",MozAppearance:"none",WebkitAppearance:"none"},error:{margin:24,color:"#A12027"}}},58002:function(e,n,t){t.d(n,{Z:function(){return o}});var i=t(85893);t(67294);let a="#3F51B5",s="#009688",r="#E91E63";function o(e){let{routes:n,root:t=!0}=e;return(0,i.jsx)("div",{style:{...c.container,...t?{overflowX:"auto",padding:"calc(var(--ifm-pre-padding) / 2)"}:null},children:n.map((e,n)=>(0,i.jsxs)("div",{style:c.item,children:[(0,i.jsxs)("div",{style:c.route,children:[(0,i.jsxs)("div",{style:c.name,children:[e.name,t?null:0===n?(0,i.jsx)("div",{style:c.connectLeft}):(0,i.jsx)("div",{style:c.connectUpLeft})]}),e.params?(0,i.jsxs)("div",{style:c.paramsContainer,children:[(0,i.jsx)("table",{style:c.params,children:(0,i.jsx)("tbody",{children:Object.entries(e.params).map(e=>{let[n,t]=e;return(0,i.jsxs)("tr",{style:c.row,children:[(0,i.jsx)("td",{style:c.key,children:n}),(0,i.jsx)("td",{style:c.colon,children:":"}),(0,i.jsx)("td",{style:c.value,children:JSON.stringify(t)})]},n)})})}),(0,i.jsx)("div",{style:c.connectUp})]}):null]}),e.state?(0,i.jsx)(o,{routes:e.state.routes,root:!1}):null]},e.name))})}let c={container:{display:"flex",flexDirection:"column"},item:{display:"flex",flexDirection:"row",alignItems:"flex-start"},route:{minWidth:160},name:{backgroundColor:a,color:"white",fontSize:"var(--ifm-code-font-size)",margin:"calc(var(--ifm-pre-padding) / 2)",padding:"calc(var(--ifm-pre-padding) / 2) var(--ifm-pre-padding)",borderRadius:4,position:"relative",textAlign:"center"},paramsContainer:{position:"relative"},params:{backgroundColor:"rgba(3, 169, 244, 0.08)",border:"1px solid ".concat(a),fontFamily:"var(--ifm-font-family-monospace)",fontSize:"var(--ifm-code-font-size)",margin:"var(--ifm-pre-padding) calc(var(--ifm-pre-padding) / 2)",borderRadius:4,padding:3,width:"auto",overflow:"visible"},row:{border:0,background:"none"},key:{color:s,border:0,padding:"4px 6px",textAlign:"right"},value:{color:r,padding:"4px 6px",border:0},colon:{color:"inherit",opacity:.3,border:0,padding:0},connectLeft:{position:"absolute",width:16,height:1,backgroundColor:a,right:"100%",top:"50%"},connectUpLeft:{position:"absolute",width:9,height:52,border:"1px solid ".concat(a),borderRadius:"0 0 0 3px",borderRight:0,borderTop:0,right:"100%",bottom:"50%"},connectUp:{position:"absolute",width:1,height:16,backgroundColor:a,right:"50%",bottom:"100%"}}}}]); \ No newline at end of file diff --git a/assets/js/main.0f871e38.js b/assets/js/main.ca3f70fa.js similarity index 99% rename from assets/js/main.0f871e38.js rename to assets/js/main.ca3f70fa.js index d6535ed1f7..25d9a8c481 100644 --- a/assets/js/main.0f871e38.js +++ b/assets/js/main.ca3f70fa.js @@ -1 +1 @@ -(self.webpackChunkreact_navigation_website_next=self.webpackChunkreact_navigation_website_next||[]).push([["56909"],{20830:function(e,t,n){"use strict";n.d(t,{W:function(){return a}});var o=n(67294);function a(){return o.createElement("svg",{width:"20",height:"20",className:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},o.createElement("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}},3601:function(e,t,n){"use strict";n.r(t)},17686:function(e,t,n){"use strict";n.r(t)},31381:function(e,t,n){"use strict";n.d(t,{PP:()=>j,Ep:()=>p,lX:()=>y,q_:()=>C,ob:()=>f});var o=n("16019");function a(e){return"/"===e.charAt(0)}function r(e,t){for(var n=t,o=n+1,a=e.length;o=0;p--){var f=i[p];"."===f?r(i,p):".."===f?(r(i,p),u++):u&&(r(i,p),u--)}if(!d)for(;u--;u)i.unshift("..");d&&""!==i[0]&&(!i[0]||!a(i[0]))&&i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var s=n("21835");function c(e){return"/"===e.charAt(0)?e:"/"+e}function d(e){return"/"===e.charAt(0)?e.substr(1):e}function l(e,t){var n,o;return(n=e,o=t,0===n.toLowerCase().indexOf(o.toLowerCase())&&-1!=="/?#".indexOf(n.charAt(o.length)))?e.substr(t.length):e}function u(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,o=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),o&&"#"!==o&&(a+="#"===o.charAt(0)?o:"#"+o),a}function f(e,t,n,a){var r,s,c,d,l,u;if("string"==typeof e){;c="",d="",-1!==(l=(s=e||"/").indexOf("#"))&&(d=s.substr(l),s=s.substr(0,l)),-1!==(u=s.indexOf("?"))&&(c=s.substr(u),s=s.substr(0,u)),(r={pathname:s,search:"?"===c?"":c,hash:"#"===d?"":d}).state=t}else void 0===(r=(0,o.Z)({},e)).pathname&&(r.pathname=""),r.search?"?"!==r.search.charAt(0)&&(r.search="?"+r.search):r.search="",r.hash?"#"!==r.hash.charAt(0)&&(r.hash="#"+r.hash):r.hash="",void 0!==t&&void 0===r.state&&(r.state=t);try{r.pathname=decodeURI(r.pathname)}catch(e){if(e instanceof URIError)throw URIError('Pathname "'+r.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.');throw e}return n&&(r.key=n),a?r.pathname?"/"!==r.pathname.charAt(0)&&(r.pathname=i(r.pathname,a.pathname)):r.pathname=a.pathname:!r.pathname&&(r.pathname="/"),r}function m(){var e=null,t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,o,a){if(null!=e){var r="function"==typeof e?e(t,n):e;"string"==typeof r?"function"==typeof o?o(r,a):a(!0):a(!1!==r)}else a(!0)},appendListener:function(e){var n=!0;function o(){n&&e.apply(void 0,arguments)}return t.push(o),function(){n=!1,t=t.filter(function(e){return e!==o})}},notifyListeners:function(){for(var e=arguments.length,n=Array(e),o=0;ot?n.splice(t,n.length-t,a):n.push(a),l({action:o,location:a,index:t,entries:n})}})},replace:function(e,t){var o="REPLACE",a=f(e,t,u(),v.location);d.confirmTransitionTo(a,o,n,function(e){e&&(v.entries[v.index]=a,l({action:o,location:a}))})},go:b,goBack:function(){b(-1)},goForward:function(){b(1)},canGo:function(e){var t=v.index+e;return t>=0&&t
'};function r(e,t,n){return en?n:e}function i(e){return(-1+e)*100}o.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(a[t]=n);return this},o.status=null,o.set=function(e){var t=o.isStarted();e=r(e,a.minimum,1),o.status=1===e?null:e;var n=o.render(!t),i=n.querySelector(a.barSelector),d=a.speed,l=a.easing;return n.offsetWidth,s(function(t){""===a.positionUsing&&(a.positionUsing=o.getPositioningCSS()),c(i,function(e,t,n){var o;if("translate3d"===a.positionUsing)o={transform:"translate3d("+(-1+e)*100+"%,0,0)"};else if("translate"===a.positionUsing)o={transform:"translate("+(-1+e)*100+"%,0)"};else o={"margin-left":(-1+e)*100+"%"};return o.transition="all "+t+"ms "+n,o}(e,d,l)),1===e?(c(n,{transition:"none",opacity:1}),n.offsetWidth,setTimeout(function(){c(n,{transition:"all "+d+"ms linear",opacity:0}),setTimeout(function(){o.remove(),t()},d)},d)):setTimeout(t,d)}),this},o.isStarted=function(){return"number"==typeof o.status},o.start=function(){!o.status&&o.set(0);var e=function(){setTimeout(function(){o.status&&(o.trickle(),e())},a.trickleSpeed)};return a.trickle&&e(),this},o.done=function(e){return e||o.status?o.inc(.3+.5*Math.random()).set(1):this},o.inc=function(e){var t=o.status;return t?("number"!=typeof e&&(e=(1-t)*r(Math.random()*t,.1,.95)),t=r(t+e,0,.994),o.set(t)):o.start()},o.trickle=function(){return o.inc(Math.random()*a.trickleRate)},e=0,t=0,o.promise=function(n){return n&&"resolved"!==n.state()?(0===t&&o.start(),e++,t++,n.always(function(){0==--t?(e=0,o.done()):o.set((e-t)/e)}),this):this},o.render=function(e){if(o.isRendered())return document.getElementById("nprogress");l(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=a.template;var n,r=t.querySelector(a.barSelector),i=e?"-100":function(e){return(-1+e)*100}(o.status||0),s=document.querySelector(a.parent);return c(r,{transition:"all 0 linear",transform:"translate3d("+i+"%,0,0)"}),!a.showSpinner&&(n=t.querySelector(a.spinnerSelector))&&f(n),s!=document.body&&l(s,"nprogress-custom-parent"),s.appendChild(t),t},o.remove=function(){u(document.documentElement,"nprogress-busy"),u(document.querySelector(a.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},o.isRendered=function(){return!!document.getElementById("nprogress")},o.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective" in e?"translate3d":t+"Transform" in e?"translate":"margin"};var s=(n=[],function(e){n.push(e),1==n.length&&!function e(){var t=n.shift();t&&t(e)}()}),c=function(){var e=["Webkit","O","Moz","ms"],t={};function n(n,o,a){o=function(n){return t[n=n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(e,t){return t.toUpperCase()})]||(t[n]=function(t){var n=document.body.style;if(t in n)return t;for(var o,a=e.length,r=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((o=e[a]+r)in n)return o;return t}(n))}(o),n.style[o]=a}return function(e,t){var o,a,r=arguments;if(2==r.length)for(o in t)void 0!==(a=t[o])&&t.hasOwnProperty(o)&&n(e,o,a);else n(e,r[1],r[2])}}();function d(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function l(e,t){var n=p(e),o=n+t;!d(n,t)&&(e.className=o.substring(1))}function u(e,t){var n,o=p(e);d(e,t)&&(n=o.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return o},"function"==typeof define&&define.amd?define(n):e.exports=n()},29901:function(e){e.exports&&(e.exports={core:{meta:{path:"components/prism-core.js",option:"mandatory"},core:"Core"},themes:{meta:{path:"themes/{id}.css",link:"index.html?theme={id}",exclusive:!0},prism:{title:"Default",option:"default"},"prism-dark":"Dark","prism-funky":"Funky","prism-okaidia":{title:"Okaidia",owner:"ocodia"},"prism-twilight":{title:"Twilight",owner:"remybach"},"prism-coy":{title:"Coy",owner:"tshedor"},"prism-solarizedlight":{title:"Solarized Light",owner:"hectormatos2011 "},"prism-tomorrow":{title:"Tomorrow Night",owner:"Rosey"}},languages:{meta:{path:"components/prism-{id}",noCSS:!0,examplesPath:"examples/prism-{id}",addCheckAll:!0},markup:{title:"Markup",alias:["html","xml","svg","mathml","ssml","atom","rss"],aliasTitles:{html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",ssml:"SSML",atom:"Atom",rss:"RSS"},option:"default"},css:{title:"CSS",option:"default",modify:"markup"},clike:{title:"C-like",option:"default"},javascript:{title:"JavaScript",require:"clike",modify:"markup",optional:"regex",alias:"js",option:"default"},abap:{title:"ABAP",owner:"dellagustin"},abnf:{title:"ABNF",owner:"RunDevelopment"},actionscript:{title:"ActionScript",require:"javascript",modify:"markup",owner:"Golmote"},ada:{title:"Ada",owner:"Lucretia"},agda:{title:"Agda",owner:"xy-ren"},al:{title:"AL",owner:"RunDevelopment"},antlr4:{title:"ANTLR4",alias:"g4",owner:"RunDevelopment"},apacheconf:{title:"Apache Configuration",owner:"GuiTeK"},apex:{title:"Apex",require:["clike","sql"],owner:"RunDevelopment"},apl:{title:"APL",owner:"ngn"},applescript:{title:"AppleScript",owner:"Golmote"},aql:{title:"AQL",owner:"RunDevelopment"},arduino:{title:"Arduino",require:"cpp",alias:"ino",owner:"dkern"},arff:{title:"ARFF",owner:"Golmote"},armasm:{title:"ARM Assembly",alias:"arm-asm",owner:"RunDevelopment"},arturo:{title:"Arturo",alias:"art",optional:["bash","css","javascript","markup","markdown","sql"],owner:"drkameleon"},asciidoc:{alias:"adoc",title:"AsciiDoc",owner:"Golmote"},aspnet:{title:"ASP.NET (C#)",require:["markup","csharp"],owner:"nauzilus"},asm6502:{title:"6502 Assembly",owner:"kzurawel"},asmatmel:{title:"Atmel AVR Assembly",owner:"cerkit"},autohotkey:{title:"AutoHotkey",owner:"aviaryan"},autoit:{title:"AutoIt",owner:"Golmote"},avisynth:{title:"AviSynth",alias:"avs",owner:"Zinfidel"},"avro-idl":{title:"Avro IDL",alias:"avdl",owner:"RunDevelopment"},awk:{title:"AWK",alias:"gawk",aliasTitles:{gawk:"GAWK"},owner:"RunDevelopment"},bash:{title:"Bash",alias:["sh","shell"],aliasTitles:{sh:"Shell",shell:"Shell"},owner:"zeitgeist87"},basic:{title:"BASIC",owner:"Golmote"},batch:{title:"Batch",owner:"Golmote"},bbcode:{title:"BBcode",alias:"shortcode",aliasTitles:{shortcode:"Shortcode"},owner:"RunDevelopment"},bbj:{title:"BBj",owner:"hyyan"},bicep:{title:"Bicep",owner:"johnnyreilly"},birb:{title:"Birb",require:"clike",owner:"Calamity210"},bison:{title:"Bison",require:"c",owner:"Golmote"},bnf:{title:"BNF",alias:"rbnf",aliasTitles:{rbnf:"RBNF"},owner:"RunDevelopment"},bqn:{title:"BQN",owner:"yewscion"},brainfuck:{title:"Brainfuck",owner:"Golmote"},brightscript:{title:"BrightScript",owner:"RunDevelopment"},bro:{title:"Bro",owner:"wayward710"},bsl:{title:"BSL (1C:Enterprise)",alias:"oscript",aliasTitles:{oscript:"OneScript"},owner:"Diversus23"},c:{title:"C",require:"clike",owner:"zeitgeist87"},csharp:{title:"C#",require:"clike",alias:["cs","dotnet"],owner:"mvalipour"},cpp:{title:"C++",require:"c",owner:"zeitgeist87"},cfscript:{title:"CFScript",require:"clike",alias:"cfc",owner:"mjclemente"},chaiscript:{title:"ChaiScript",require:["clike","cpp"],owner:"RunDevelopment"},cil:{title:"CIL",owner:"sbrl"},cilkc:{title:"Cilk/C",require:"c",alias:"cilk-c",owner:"OpenCilk"},cilkcpp:{title:"Cilk/C++",require:"cpp",alias:["cilk-cpp","cilk"],owner:"OpenCilk"},clojure:{title:"Clojure",owner:"troglotit"},cmake:{title:"CMake",owner:"mjrogozinski"},cobol:{title:"COBOL",owner:"RunDevelopment"},coffeescript:{title:"CoffeeScript",require:"javascript",alias:"coffee",owner:"R-osey"},concurnas:{title:"Concurnas",alias:"conc",owner:"jasontatton"},csp:{title:"Content-Security-Policy",owner:"ScottHelme"},cooklang:{title:"Cooklang",owner:"ahue"},coq:{title:"Coq",owner:"RunDevelopment"},crystal:{title:"Crystal",require:"ruby",owner:"MakeNowJust"},"css-extras":{title:"CSS Extras",require:"css",modify:"css",owner:"milesj"},csv:{title:"CSV",owner:"RunDevelopment"},cue:{title:"CUE",owner:"RunDevelopment"},cypher:{title:"Cypher",owner:"RunDevelopment"},d:{title:"D",require:"clike",owner:"Golmote"},dart:{title:"Dart",require:"clike",owner:"Golmote"},dataweave:{title:"DataWeave",owner:"machaval"},dax:{title:"DAX",owner:"peterbud"},dhall:{title:"Dhall",owner:"RunDevelopment"},diff:{title:"Diff",owner:"uranusjr"},django:{title:"Django/Jinja2",require:"markup-templating",alias:"jinja2",owner:"romanvm"},"dns-zone-file":{title:"DNS zone file",owner:"RunDevelopment",alias:"dns-zone"},docker:{title:"Docker",alias:"dockerfile",owner:"JustinBeckwith"},dot:{title:"DOT (Graphviz)",alias:"gv",optional:"markup",owner:"RunDevelopment"},ebnf:{title:"EBNF",owner:"RunDevelopment"},editorconfig:{title:"EditorConfig",owner:"osipxd"},eiffel:{title:"Eiffel",owner:"Conaclos"},ejs:{title:"EJS",require:["javascript","markup-templating"],owner:"RunDevelopment",alias:"eta",aliasTitles:{eta:"Eta"}},elixir:{title:"Elixir",owner:"Golmote"},elm:{title:"Elm",owner:"zwilias"},etlua:{title:"Embedded Lua templating",require:["lua","markup-templating"],owner:"RunDevelopment"},erb:{title:"ERB",require:["ruby","markup-templating"],owner:"Golmote"},erlang:{title:"Erlang",owner:"Golmote"},"excel-formula":{title:"Excel Formula",alias:["xlsx","xls"],owner:"RunDevelopment"},fsharp:{title:"F#",require:"clike",owner:"simonreynolds7"},factor:{title:"Factor",owner:"catb0t"},false:{title:"False",owner:"edukisto"},"firestore-security-rules":{title:"Firestore security rules",require:"clike",owner:"RunDevelopment"},flow:{title:"Flow",require:"javascript",owner:"Golmote"},fortran:{title:"Fortran",owner:"Golmote"},ftl:{title:"FreeMarker Template Language",require:"markup-templating",owner:"RunDevelopment"},gml:{title:"GameMaker Language",alias:"gamemakerlanguage",require:"clike",owner:"LiarOnce"},gap:{title:"GAP (CAS)",owner:"RunDevelopment"},gcode:{title:"G-code",owner:"RunDevelopment"},gdscript:{title:"GDScript",owner:"RunDevelopment"},gedcom:{title:"GEDCOM",owner:"Golmote"},gettext:{title:"gettext",alias:"po",owner:"RunDevelopment"},gherkin:{title:"Gherkin",owner:"hason"},git:{title:"Git",owner:"lgiraudel"},glsl:{title:"GLSL",require:"c",owner:"Golmote"},gn:{title:"GN",alias:"gni",owner:"RunDevelopment"},"linker-script":{title:"GNU Linker Script",alias:"ld",owner:"RunDevelopment"},go:{title:"Go",require:"clike",owner:"arnehormann"},"go-module":{title:"Go module",alias:"go-mod",owner:"RunDevelopment"},gradle:{title:"Gradle",require:"clike",owner:"zeabdelkhalek-badido18"},graphql:{title:"GraphQL",optional:"markdown",owner:"Golmote"},groovy:{title:"Groovy",require:"clike",owner:"robfletcher"},haml:{title:"Haml",require:"ruby",optional:["css","css-extras","coffeescript","erb","javascript","less","markdown","scss","textile"],owner:"Golmote"},handlebars:{title:"Handlebars",require:"markup-templating",alias:["hbs","mustache"],aliasTitles:{mustache:"Mustache"},owner:"Golmote"},haskell:{title:"Haskell",alias:"hs",owner:"bholst"},haxe:{title:"Haxe",require:"clike",optional:"regex",owner:"Golmote"},hcl:{title:"HCL",owner:"outsideris"},hlsl:{title:"HLSL",require:"c",owner:"RunDevelopment"},hoon:{title:"Hoon",owner:"matildepark"},http:{title:"HTTP",optional:["csp","css","hpkp","hsts","javascript","json","markup","uri"],owner:"danielgtaylor"},hpkp:{title:"HTTP Public-Key-Pins",owner:"ScottHelme"},hsts:{title:"HTTP Strict-Transport-Security",owner:"ScottHelme"},ichigojam:{title:"IchigoJam",owner:"BlueCocoa"},icon:{title:"Icon",owner:"Golmote"},"icu-message-format":{title:"ICU Message Format",owner:"RunDevelopment"},idris:{title:"Idris",alias:"idr",owner:"KeenS",require:"haskell"},ignore:{title:".ignore",owner:"osipxd",alias:["gitignore","hgignore","npmignore"],aliasTitles:{gitignore:".gitignore",hgignore:".hgignore",npmignore:".npmignore"}},inform7:{title:"Inform 7",owner:"Golmote"},ini:{title:"Ini",owner:"aviaryan"},io:{title:"Io",owner:"AlesTsurko"},j:{title:"J",owner:"Golmote"},java:{title:"Java",require:"clike",owner:"sherblot"},javadoc:{title:"JavaDoc",require:["markup","java","javadoclike"],modify:"java",optional:"scala",owner:"RunDevelopment"},javadoclike:{title:"JavaDoc-like",modify:["java","javascript","php"],owner:"RunDevelopment"},javastacktrace:{title:"Java stack trace",owner:"RunDevelopment"},jexl:{title:"Jexl",owner:"czosel"},jolie:{title:"Jolie",require:"clike",owner:"thesave"},jq:{title:"JQ",owner:"RunDevelopment"},jsdoc:{title:"JSDoc",require:["javascript","javadoclike","typescript"],modify:"javascript",optional:["actionscript","coffeescript"],owner:"RunDevelopment"},"js-extras":{title:"JS Extras",require:"javascript",modify:"javascript",optional:["actionscript","coffeescript","flow","n4js","typescript"],owner:"RunDevelopment"},json:{title:"JSON",alias:"webmanifest",aliasTitles:{webmanifest:"Web App Manifest"},owner:"CupOfTea696"},json5:{title:"JSON5",require:"json",owner:"RunDevelopment"},jsonp:{title:"JSONP",require:"json",owner:"RunDevelopment"},jsstacktrace:{title:"JS stack trace",owner:"sbrl"},"js-templates":{title:"JS Templates",require:"javascript",modify:"javascript",optional:["css","css-extras","graphql","markdown","markup","sql"],owner:"RunDevelopment"},julia:{title:"Julia",owner:"cdagnino"},keepalived:{title:"Keepalived Configure",owner:"dev-itsheng"},keyman:{title:"Keyman",owner:"mcdurdin"},kotlin:{title:"Kotlin",alias:["kt","kts"],aliasTitles:{kts:"Kotlin Script"},require:"clike",owner:"Golmote"},kumir:{title:"KuMir (\u041A\u0443\u041C\u0438\u0440)",alias:"kum",owner:"edukisto"},kusto:{title:"Kusto",owner:"RunDevelopment"},latex:{title:"LaTeX",alias:["tex","context"],aliasTitles:{tex:"TeX",context:"ConTeXt"},owner:"japborst"},latte:{title:"Latte",require:["clike","markup-templating","php"],owner:"nette"},less:{title:"Less",require:"css",optional:"css-extras",owner:"Golmote"},lilypond:{title:"LilyPond",require:"scheme",alias:"ly",owner:"RunDevelopment"},liquid:{title:"Liquid",require:"markup-templating",owner:"cinhtau"},lisp:{title:"Lisp",alias:["emacs","elisp","emacs-lisp"],owner:"JuanCaicedo"},livescript:{title:"LiveScript",owner:"Golmote"},llvm:{title:"LLVM IR",owner:"porglezomp"},log:{title:"Log file",optional:"javastacktrace",owner:"RunDevelopment"},lolcode:{title:"LOLCODE",owner:"Golmote"},lua:{title:"Lua",owner:"Golmote"},magma:{title:"Magma (CAS)",owner:"RunDevelopment"},makefile:{title:"Makefile",owner:"Golmote"},markdown:{title:"Markdown",require:"markup",optional:"yaml",alias:"md",owner:"Golmote"},"markup-templating":{title:"Markup templating",require:"markup",owner:"Golmote"},mata:{title:"Mata",owner:"RunDevelopment"},matlab:{title:"MATLAB",owner:"Golmote"},maxscript:{title:"MAXScript",owner:"RunDevelopment"},mel:{title:"MEL",owner:"Golmote"},mermaid:{title:"Mermaid",owner:"RunDevelopment"},metafont:{title:"METAFONT",owner:"LaeriExNihilo"},mizar:{title:"Mizar",owner:"Golmote"},mongodb:{title:"MongoDB",owner:"airs0urce",require:"javascript"},monkey:{title:"Monkey",owner:"Golmote"},moonscript:{title:"MoonScript",alias:"moon",owner:"RunDevelopment"},n1ql:{title:"N1QL",owner:"TMWilds"},n4js:{title:"N4JS",require:"javascript",optional:"jsdoc",alias:"n4jsd",owner:"bsmith-n4"},"nand2tetris-hdl":{title:"Nand To Tetris HDL",owner:"stephanmax"},naniscript:{title:"Naninovel Script",owner:"Elringus",alias:"nani"},nasm:{title:"NASM",owner:"rbmj"},neon:{title:"NEON",owner:"nette"},nevod:{title:"Nevod",owner:"nezaboodka"},nginx:{title:"nginx",owner:"volado"},nim:{title:"Nim",owner:"Golmote"},nix:{title:"Nix",owner:"Golmote"},nsis:{title:"NSIS",owner:"idleberg"},objectivec:{title:"Objective-C",require:"c",alias:"objc",owner:"uranusjr"},ocaml:{title:"OCaml",owner:"Golmote"},odin:{title:"Odin",owner:"edukisto"},opencl:{title:"OpenCL",require:"c",modify:["c","cpp"],owner:"Milania1"},openqasm:{title:"OpenQasm",alias:"qasm",owner:"RunDevelopment"},oz:{title:"Oz",owner:"Golmote"},parigp:{title:"PARI/GP",owner:"Golmote"},parser:{title:"Parser",require:"markup",owner:"Golmote"},pascal:{title:"Pascal",alias:"objectpascal",aliasTitles:{objectpascal:"Object Pascal"},owner:"Golmote"},pascaligo:{title:"Pascaligo",owner:"DefinitelyNotAGoat"},psl:{title:"PATROL Scripting Language",owner:"bertysentry"},pcaxis:{title:"PC-Axis",alias:"px",owner:"RunDevelopment"},peoplecode:{title:"PeopleCode",alias:"pcode",owner:"RunDevelopment"},perl:{title:"Perl",owner:"Golmote"},php:{title:"PHP",require:"markup-templating",owner:"milesj"},phpdoc:{title:"PHPDoc",require:["php","javadoclike"],modify:"php",owner:"RunDevelopment"},"php-extras":{title:"PHP Extras",require:"php",modify:"php",owner:"milesj"},"plant-uml":{title:"PlantUML",alias:"plantuml",owner:"RunDevelopment"},plsql:{title:"PL/SQL",require:"sql",owner:"Golmote"},powerquery:{title:"PowerQuery",alias:["pq","mscript"],owner:"peterbud"},powershell:{title:"PowerShell",owner:"nauzilus"},processing:{title:"Processing",require:"clike",owner:"Golmote"},prolog:{title:"Prolog",owner:"Golmote"},promql:{title:"PromQL",owner:"arendjr"},properties:{title:".properties",owner:"Golmote"},protobuf:{title:"Protocol Buffers",require:"clike",owner:"just-boris"},pug:{title:"Pug",require:["markup","javascript"],optional:["coffeescript","ejs","handlebars","less","livescript","markdown","scss","stylus","twig"],owner:"Golmote"},puppet:{title:"Puppet",owner:"Golmote"},pure:{title:"Pure",optional:["c","cpp","fortran"],owner:"Golmote"},purebasic:{title:"PureBasic",require:"clike",alias:"pbfasm",owner:"HeX0R101"},purescript:{title:"PureScript",require:"haskell",alias:"purs",owner:"sriharshachilakapati"},python:{title:"Python",alias:"py",owner:"multipetros"},qsharp:{title:"Q#",require:"clike",alias:"qs",owner:"fedonman"},q:{title:"Q (kdb+ database)",owner:"Golmote"},qml:{title:"QML",require:"javascript",owner:"RunDevelopment"},qore:{title:"Qore",require:"clike",owner:"temnroegg"},r:{title:"R",owner:"Golmote"},racket:{title:"Racket",require:"scheme",alias:"rkt",owner:"RunDevelopment"},cshtml:{title:"Razor C#",alias:"razor",require:["markup","csharp"],optional:["css","css-extras","javascript","js-extras"],owner:"RunDevelopment"},jsx:{title:"React JSX",require:["markup","javascript"],optional:["jsdoc","js-extras","js-templates"],owner:"vkbansal"},tsx:{title:"React TSX",require:["jsx","typescript"]},reason:{title:"Reason",require:"clike",owner:"Golmote"},regex:{title:"Regex",owner:"RunDevelopment"},rego:{title:"Rego",owner:"JordanSh"},renpy:{title:"Ren'py",alias:"rpy",owner:"HyuchiaDiego"},rescript:{title:"ReScript",alias:"res",owner:"vmarcosp"},rest:{title:"reST (reStructuredText)",owner:"Golmote"},rip:{title:"Rip",owner:"ravinggenius"},roboconf:{title:"Roboconf",owner:"Golmote"},robotframework:{title:"Robot Framework",alias:"robot",owner:"RunDevelopment"},ruby:{title:"Ruby",require:"clike",alias:"rb",owner:"samflores"},rust:{title:"Rust",owner:"Golmote"},sas:{title:"SAS",optional:["groovy","lua","sql"],owner:"Golmote"},sass:{title:"Sass (Sass)",require:"css",optional:"css-extras",owner:"Golmote"},scss:{title:"Sass (SCSS)",require:"css",optional:"css-extras",owner:"MoOx"},scala:{title:"Scala",require:"java",owner:"jozic"},scheme:{title:"Scheme",owner:"bacchus123"},"shell-session":{title:"Shell session",require:"bash",alias:["sh-session","shellsession"],owner:"RunDevelopment"},smali:{title:"Smali",owner:"RunDevelopment"},smalltalk:{title:"Smalltalk",owner:"Golmote"},smarty:{title:"Smarty",require:"markup-templating",optional:"php",owner:"Golmote"},sml:{title:"SML",alias:"smlnj",aliasTitles:{smlnj:"SML/NJ"},owner:"RunDevelopment"},solidity:{title:"Solidity (Ethereum)",alias:"sol",require:"clike",owner:"glachaud"},"solution-file":{title:"Solution file",alias:"sln",owner:"RunDevelopment"},soy:{title:"Soy (Closure Template)",require:"markup-templating",owner:"Golmote"},sparql:{title:"SPARQL",require:"turtle",owner:"Triply-Dev",alias:"rq"},"splunk-spl":{title:"Splunk SPL",owner:"RunDevelopment"},sqf:{title:"SQF: Status Quo Function (Arma 3)",require:"clike",owner:"RunDevelopment"},sql:{title:"SQL",owner:"multipetros"},squirrel:{title:"Squirrel",require:"clike",owner:"RunDevelopment"},stan:{title:"Stan",owner:"RunDevelopment"},stata:{title:"Stata Ado",require:["mata","java","python"],owner:"RunDevelopment"},iecst:{title:"Structured Text (IEC 61131-3)",owner:"serhioromano"},stylus:{title:"Stylus",owner:"vkbansal"},supercollider:{title:"SuperCollider",alias:"sclang",owner:"RunDevelopment"},swift:{title:"Swift",owner:"chrischares"},systemd:{title:"Systemd configuration file",owner:"RunDevelopment"},"t4-templating":{title:"T4 templating",owner:"RunDevelopment"},"t4-cs":{title:"T4 Text Templates (C#)",require:["t4-templating","csharp"],alias:"t4",owner:"RunDevelopment"},"t4-vb":{title:"T4 Text Templates (VB)",require:["t4-templating","vbnet"],owner:"RunDevelopment"},tap:{title:"TAP",owner:"isaacs",require:"yaml"},tcl:{title:"Tcl",owner:"PeterChaplin"},tt2:{title:"Template Toolkit 2",require:["clike","markup-templating"],owner:"gflohr"},textile:{title:"Textile",require:"markup",optional:"css",owner:"Golmote"},toml:{title:"TOML",owner:"RunDevelopment"},tremor:{title:"Tremor",alias:["trickle","troy"],owner:"darach",aliasTitles:{trickle:"trickle",troy:"troy"}},turtle:{title:"Turtle",alias:"trig",aliasTitles:{trig:"TriG"},owner:"jakubklimek"},twig:{title:"Twig",require:"markup-templating",owner:"brandonkelly"},typescript:{title:"TypeScript",require:"javascript",optional:"js-templates",alias:"ts",owner:"vkbansal"},typoscript:{title:"TypoScript",alias:"tsconfig",aliasTitles:{tsconfig:"TSConfig"},owner:"dkern"},unrealscript:{title:"UnrealScript",alias:["uscript","uc"],owner:"RunDevelopment"},uorazor:{title:"UO Razor Script",owner:"jaseowns"},uri:{title:"URI",alias:"url",aliasTitles:{url:"URL"},owner:"RunDevelopment"},v:{title:"V",require:"clike",owner:"taggon"},vala:{title:"Vala",require:"clike",optional:"regex",owner:"TemplarVolk"},vbnet:{title:"VB.Net",require:"basic",owner:"Bigsby"},velocity:{title:"Velocity",require:"markup",owner:"Golmote"},verilog:{title:"Verilog",owner:"a-rey"},vhdl:{title:"VHDL",owner:"a-rey"},vim:{title:"vim",owner:"westonganger"},"visual-basic":{title:"Visual Basic",alias:["vb","vba"],aliasTitles:{vba:"VBA"},owner:"Golmote"},warpscript:{title:"WarpScript",owner:"RunDevelopment"},wasm:{title:"WebAssembly",owner:"Golmote"},"web-idl":{title:"Web IDL",alias:"webidl",owner:"RunDevelopment"},wgsl:{title:"WGSL",owner:"Dr4gonthree"},wiki:{title:"Wiki markup",require:"markup",owner:"Golmote"},wolfram:{title:"Wolfram language",alias:["mathematica","nb","wl"],aliasTitles:{mathematica:"Mathematica",nb:"Mathematica Notebook"},owner:"msollami"},wren:{title:"Wren",owner:"clsource"},xeora:{title:"Xeora",require:"markup",alias:"xeoracube",aliasTitles:{xeoracube:"XeoraCube"},owner:"freakmaxi"},"xml-doc":{title:"XML doc (.net)",require:"markup",modify:["csharp","fsharp","vbnet"],owner:"RunDevelopment"},xojo:{title:"Xojo (REALbasic)",owner:"Golmote"},xquery:{title:"XQuery",require:"markup",owner:"Golmote"},yaml:{title:"YAML",alias:"yml",owner:"hason"},yang:{title:"YANG",owner:"RunDevelopment"},zig:{title:"Zig",owner:"RunDevelopment"}},plugins:{meta:{path:"plugins/{id}/prism-{id}",link:"plugins/{id}/"},"line-highlight":{title:"Line Highlight",description:"Highlights specific lines and/or line ranges."},"line-numbers":{title:"Line Numbers",description:"Line number at the beginning of code lines.",owner:"kuba-kubula"},"show-invisibles":{title:"Show Invisibles",description:"Show hidden characters such as tabs and line breaks.",optional:["autolinker","data-uri-highlight"]},autolinker:{title:"Autolinker",description:"Converts URLs and emails in code to clickable links. Parses Markdown links in comments."},wpd:{title:"WebPlatform Docs",description:'Makes tokens link to WebPlatform.org documentation. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the highlightAll and highlightAllUnder methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},2885:function(e,t,n){let o=n(29901),a=n(39642),r=new Set;function i(e){void 0===e?e=Object.keys(o.languages).filter(e=>"meta"!=e):!Array.isArray(e)&&(e=[e]),a(o,e,[...r,...Object.keys(Prism.languages)]).load(e=>{if(!(e in o.languages)){!i.silent&&console.warn("Language does not exist: "+e);return}let t="./prism-"+e;delete n.c[n(69805).resolve(t)],delete Prism.languages[e],n(69805)(t),r.add(e)})}i.silent=!1,e.exports=i},96854:function(){!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,o,a,r){if(n.language===o){var i=n.tokenStack=[];n.code=n.code.replace(a,function(e){if("function"==typeof r&&!r(e))return e;for(var a,s=i.length;-1!==n.code.indexOf(a=t(o,s));)++s;return i[s]=e,a}),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,o){if(n.language===o&&!!n.tokenStack){n.grammar=e.languages[o];var a=0,r=Object.keys(n.tokenStack);!function i(s){for(var c=0;c=r.length);c++){;var d=s[c];if("string"==typeof d||d.content&&"string"==typeof d.content){var l=r[a],u=n.tokenStack[l],p="string"==typeof d?d:d.content,f=t(o,l),m=p.indexOf(f);if(m>-1){++a;var g=p.substring(0,m),h=new e.Token(o,e.tokenize(u,n.grammar),"language-"+o,u),b=p.substring(m+f.length),v=[];g&&v.push.apply(v,i([g])),v.push(h),b&&v.push.apply(v,i([b])),"string"==typeof d?s.splice.apply(s,[c,1].concat(v)):d.content=v}}else d.content&&i(d.content)}return s}(n.tokens)}}}})}(Prism)},69805:function(e,t,n){var o={"./":"2885"};function a(e){return n(r(e))}function r(e){if(!n.o(o,e)){var t=Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return o[e]}a.keys=function(){return Object.keys(o)},a.resolve=r,e.exports=a,a.id="69805"},39642:function(e){"use strict";var t=function(){var e=function(){};function t(e,t){Array.isArray(e)?e.forEach(t):null!=e&&t(e,0)}function n(e){for(var t={},n=0,o=e.length;n "));var r={},i=c[n];if(i){function s(t){if(!(t in c))throw Error(n+" depends on an unknown component "+t);if(!(t in r))for(var a in e(t,o),r[t]=!0,d[t])r[a]=!0}t(i.require,s),t(i.optional,s),t(i.modify,s)}d[n]=r,o.pop()}}(e,l),n=d[e]),n}),b=m;function(e){for(var t in e)return!0;return!1}(b);){for(var v in u={},b){var x=p[v];t(x&&x.modify,function(e){e in g&&(u[e]=!0)})}for(var y in g)if(!(y in m)){for(var _ in h(y))if(_ in m){u[y]=!0;break}}for(var w in b=u)m[w]=!0}var k={getIds:function(){var e=[];return k.load(function(t){e.push(t)}),e},load:function(t,n){return function(t,n,o,a){var r=a?a.series:void 0,i=a?a.parallel:e,s={},c={};for(var d in n)!function e(a){if(a in s)return s[a];c[a]=!0;var d,l=[];for(var u in t(a))u in n&&l.push(u);if(0===l.length)d=o(a);else{var p=i(l.map(function(t){var n=e(t);return delete c[t],n}));r?d=r(p,function(){return o(a)}):o(a)}return s[a]=d}(d);var l=[];for(var u in c)l.push(s[u]);return i(l)}(h,m,t,n)}};return k}}();e.exports=t},92703:function(e,t,n){"use strict";var o=n(50414);function a(){}function r(){}r.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,r,i){if(i!==o){var s=Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw s.name="Invariant Violation",s}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:r,resetWarningCache:a};return n.PropTypes=n,n}},45697:function(e,t,n){e.exports=n(92703)()},50414:function(e){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},64448:function(e,t,n){"use strict";var o,a,r,i,s,c,d=n(67294),l=n(63840);function u(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n