expo-router 2.0.0-rc.8 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,10 @@ type InitialRouteConfig = {
13
13
  export type ResultState = PartialState<NavigationState> & {
14
14
  state?: ResultState;
15
15
  };
16
+ export declare function getUrlWithReactNavigationConcessions(path: string): {
17
+ nonstandardPathname: string;
18
+ inputPathnameWithoutHash: string;
19
+ };
16
20
  /**
17
21
  * Utility to parse a path string to initial state object accepted by the container.
18
22
  * This is useful for deep linking when we need to handle the incoming URL.
@@ -1 +1 @@
1
- {"version":3,"file":"getStateFromPath.d.ts","sourceRoot":"","sources":["../../src/fork/getStateFromPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAEV,eAAe,EACf,YAAY,EACb,MAAM,2BAA2B,CAAC;AAInC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAKrC,KAAK,OAAO,CAAC,SAAS,SAAS,MAAM,IAAI;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;CACnC,CAAC;AAEF,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC;AAe1D,KAAK,kBAAkB,GAAG;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,YAAY,CAAC,eAAe,CAAC,GAAG;IACxD,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AAkBF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,SAAS,SAAS,MAAM,EAC/D,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAC3B,WAAW,GAAG,SAAS,CAIzB;AAED,wBAAgB,wBAAwB,CAAC,SAAS,SAAS,MAAM,EAC/D,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;;;;;;;;;;;;;;EA+C7B"}
1
+ {"version":3,"file":"getStateFromPath.d.ts","sourceRoot":"","sources":["../../src/fork/getStateFromPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAEV,eAAe,EACf,YAAY,EACb,MAAM,2BAA2B,CAAC;AAKnC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAKrC,KAAK,OAAO,CAAC,SAAS,SAAS,MAAM,IAAI;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;CACnC,CAAC;AAEF,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC;AAe1D,KAAK,kBAAkB,GAAG;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,YAAY,CAAC,eAAe,CAAC,GAAG;IACxD,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AAQF,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,MAAM;;;EAYhE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,SAAS,SAAS,MAAM,EAC/D,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAC3B,WAAW,GAAG,SAAS,CAIzB;AAED,wBAAgB,wBAAwB,CAAC,SAAS,SAAS,MAAM,EAC/D,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;;;;;;;;;;;;;;EA+C7B"}
@@ -26,6 +26,7 @@ export declare class RouterStore {
26
26
  linkTo: (href: string, event?: string | undefined) => void;
27
27
  getSortedRoutes: () => RouteNode[];
28
28
  goBack: () => void;
29
+ canGoBack: () => boolean;
29
30
  push: (url: import("../link/href").Href) => void;
30
31
  replace: (url: import("../link/href").Href) => void;
31
32
  setParams: (params?: Record<string, string | number> | undefined) => any;
@@ -1 +1 @@
1
- {"version":3,"file":"router-store.d.ts","sourceRoot":"","sources":["../../src/global-state/router-store.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,iCAAiC,EAGlC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAiC,aAAa,EAAY,MAAM,OAAO,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAyB,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAoB,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAM1C;;;;GAIG;AACH,qBAAa,WAAW;IACtB,SAAS,EAAG,SAAS,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAG,aAAa,CAAC;IAC9B,OAAO,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,OAAO,CAAS;IAEzB,YAAY,EAAE,WAAW,GAAG,SAAS,CAAC;IACtC,SAAS,EAAE,WAAW,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,WAAW,GAAG,SAAS,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAElC,aAAa,EAAG,iCAAiC,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;IACjF,yBAAyB,EAAG,MAAM,IAAI,CAAC;IAEvC,oBAAoB,YAAiB,IAAI,EAAI;IAC7C,gBAAgB,YAAiB,IAAI,EAAI;IAEzC,MAAM,qDAAqB;IAC3B,eAAe,oBAA8B;IAC7C,MAAM,aAAqB;IAC3B,IAAI,6CAAmB;IACvB,OAAO,6CAAsB;IAC7B,SAAS,gEAAwB;IAEjC,UAAU,CACR,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,iCAAiC,CAAC,eAAe,CAAC,aAAa,CAAC,EAC/E,eAAe,CAAC,EAAE,GAAG;IAgGvB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,cAAQ;IAWjD,YAAY,CAAC,KAAK,EAAE,WAAW;IAgB/B,kBAAkB;IAIlB,uEAAuE;IACvE,OAAO,aAKL;IACF,oBAAoB,eAAgB,MAAM,IAAI,mBAG5C;IACF,gBAAgB,eAAgB,MAAM,IAAI,mBAGxC;IACF,QAAQ,aAEN;IACF,iBAAiB,oBAEf;IACF,iBAAiB,kBAEf;CACH;AAED,eAAO,MAAM,KAAK,aAAoB,CAAC;AAEvC,wBAAgB,aAAa,gBAM5B;AAaD,wBAAgB,iBAAiB,gBAOhC;AAED,wBAAgB,iBAAiB,cAOhC;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,cAAc,EACvB,eAAe,EAAE,GAAG,GAAG,SAAS,eASjC"}
1
+ {"version":3,"file":"router-store.d.ts","sourceRoot":"","sources":["../../src/global-state/router-store.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,iCAAiC,EAGlC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAiC,aAAa,EAAY,MAAM,OAAO,CAAC;AAE/E,OAAO,EAAE,SAAS,EAAyB,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAoB,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAM1C;;;;GAIG;AACH,qBAAa,WAAW;IACtB,SAAS,EAAG,SAAS,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAG,aAAa,CAAC;IAC9B,OAAO,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,OAAO,CAAS;IAEzB,YAAY,EAAE,WAAW,GAAG,SAAS,CAAC;IACtC,SAAS,EAAE,WAAW,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,WAAW,GAAG,SAAS,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAElC,aAAa,EAAG,iCAAiC,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;IACjF,yBAAyB,EAAG,MAAM,IAAI,CAAC;IAEvC,oBAAoB,YAAiB,IAAI,EAAI;IAC7C,gBAAgB,YAAiB,IAAI,EAAI;IAEzC,MAAM,qDAAqB;IAC3B,eAAe,oBAA8B;IAC7C,MAAM,aAAqB;IAC3B,SAAS,gBAAwB;IACjC,IAAI,6CAAmB;IACvB,OAAO,6CAAsB;IAC7B,SAAS,gEAAwB;IAEjC,UAAU,CACR,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,iCAAiC,CAAC,eAAe,CAAC,aAAa,CAAC,EAC/E,eAAe,CAAC,EAAE,GAAG;IAgGvB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,cAAQ;IAWjD,YAAY,CAAC,KAAK,EAAE,WAAW;IAgB/B,kBAAkB;IAIlB,uEAAuE;IACvE,OAAO,aAKL;IACF,oBAAoB,eAAgB,MAAM,IAAI,mBAG5C;IACF,gBAAgB,eAAgB,MAAM,IAAI,mBAGxC;IACF,QAAQ,aAEN;IACF,iBAAiB,oBAEf;IACF,iBAAiB,kBAEf;CACH;AAED,eAAO,MAAM,KAAK,aAAoB,CAAC;AAEvC,wBAAgB,aAAa,gBAM5B;AAaD,wBAAgB,iBAAiB,gBAOhC;AAED,wBAAgB,iBAAiB,cAOhC;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,cAAc,EACvB,eAAe,EAAE,GAAG,GAAG,SAAS,eASjC"}
@@ -5,6 +5,7 @@ import type { RouterStore } from "./router-store";
5
5
  export declare function push(this: RouterStore, url: Href): void;
6
6
  export declare function replace(this: RouterStore, url: Href): void;
7
7
  export declare function goBack(this: RouterStore): void;
8
+ export declare function canGoBack(this: RouterStore): boolean;
8
9
  export declare function setParams(this: RouterStore, params?: Record<string, string | number>): any;
9
10
  export declare function linkTo(this: RouterStore, href: string, event?: string): void;
10
11
  /** @returns `true` if the action is moving to the first screen of all the navigators in the action. */
@@ -1 +1 @@
1
- {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/global-state/routing.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kBAAkB,EAEnB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAAE,IAAI,EAAe,MAAM,cAAc,CAAC;AAEjD,OAAO,EACL,cAAc,EAKf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAQlD,wBAAgB,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,QAEhD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,QAEnD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,WAAW,QAGvC;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,WAAW,EACjB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAM,OAI7C;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,QAkHrE;AAED,uGAAuG;AACvG,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,GAC5C,MAAM,IAAI,cAAc,CAqB1B"}
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/global-state/routing.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,kBAAkB,EAEnB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAAE,IAAI,EAAe,MAAM,cAAc,CAAC;AAEjD,OAAO,EACL,cAAc,EAKf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAUlD,wBAAgB,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,QAEhD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,QAEnD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,WAAW,QAGvC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAGpD;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,WAAW,EACjB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAM,OAI7C;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,QAwHrE;AAED,uGAAuG;AACvG,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,GAC5C,MAAM,IAAI,cAAc,CAqB1B"}
@@ -1,4 +1,3 @@
1
- import { RouteNode } from "../Route";
2
1
  import type { RouterStore } from "./router-store";
3
- export declare function getSortedRoutes(this: RouterStore): RouteNode[];
2
+ export declare function getSortedRoutes(this: RouterStore): import("../Route").RouteNode[];
4
3
  //# sourceMappingURL=sort-routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sort-routes.d.ts","sourceRoot":"","sources":["../../src/global-state/sort-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,eA2ChD"}
1
+ {"version":3,"file":"sort-routes.d.ts","sourceRoot":"","sources":["../../src/global-state/sort-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,kCAQhD"}
@@ -1 +1 @@
1
- {"version":3,"file":"imperative-api.d.ts","sourceRoot":"","sources":["../src/imperative-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,eAAO,MAAM,MAAM,EAAE,MAKpB,CAAC"}
1
+ {"version":3,"file":"imperative-api.d.ts","sourceRoot":"","sources":["../src/imperative-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,eAAO,MAAM,MAAM,EAAE,MAMpB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useLinkToPathProps.d.ts","sourceRoot":"","sources":["../../src/link/useLinkToPathProps.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,qBAAqB,EAAY,MAAM,cAAc,CAAC;AA6B/D,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,KAAK,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;;;kBAIO,gBAAgB,CAAC,iBAAiB,EAAE,UAAU,CAAC,GAAG,qBAAqB;EAqB9E"}
1
+ {"version":3,"file":"useLinkToPathProps.d.ts","sourceRoot":"","sources":["../../src/link/useLinkToPathProps.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,qBAAqB,EAAY,MAAM,cAAc,CAAC;AA6B/D,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,KAAK,EAAE;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;;;kBAIO,gBAAgB,CAAC,iBAAiB,EAAE,UAAU,CAAC,GAAG,qBAAqB;EAsB9E"}
@@ -3,9 +3,13 @@ import requireContext from "./require-context-ponyfill";
3
3
  export type ReactComponent = () => React.ReactElement<any, any> | null;
4
4
  export type FileStub = (Record<string, unknown> & {
5
5
  default: ReactComponent;
6
+ unstable_settings?: Record<string, any>;
6
7
  }) | ReactComponent;
7
8
  export { requireContext };
8
- export declare function inMemoryContext(context: Record<string, FileStub>): ((id: string) => ReactComponent | {
9
+ export declare function inMemoryContext(context: Record<string, FileStub>): ((id: string) => ReactComponent | (Record<string, unknown> & {
10
+ default: ReactComponent;
11
+ unstable_settings?: Record<string, any> | undefined;
12
+ }) | {
9
13
  default: FileStub;
10
14
  }) & {
11
15
  keys: () => string[];
@@ -1 +1 @@
1
- {"version":3,"file":"context-stubs.d.ts","sourceRoot":"","sources":["../../src/testing-library/context-stubs.ts"],"names":[],"mappings":";AAEA,OAAO,cAAc,MAAM,4BAA4B,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;AACvE,MAAM,MAAM,QAAQ,GAChB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,GACvD,cAAc,CAAC;AAEnB,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,SAE/C,MAAM;;;;mBAQH,MAAM;;EAI1B;AAED,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,SAKnB,MAAM;;mBAUH,MAAM;;EAI1B"}
1
+ {"version":3,"file":"context-stubs.d.ts","sourceRoot":"","sources":["../../src/testing-library/context-stubs.ts"],"names":[],"mappings":";AAEA,OAAO,cAAc,MAAM,4BAA4B,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;AACvE,MAAM,MAAM,QAAQ,GAChB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACzB,OAAO,EAAE,cAAc,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACzC,CAAC,GACF,cAAc,CAAC;AAEnB,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,SAE/C,MAAM;;;;;;;mBAQH,MAAM;;EAI1B;AAED,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,SAKnB,MAAM;;mBAUH,MAAM;;EAI1B"}
package/build/types.d.ts CHANGED
@@ -18,6 +18,8 @@ export type Router = {
18
18
  replace: (href: Href) => void;
19
19
  /** Go back in the history. */
20
20
  back: () => void;
21
+ /** If there's history that supports invoking the `back` function. */
22
+ canGoBack: () => boolean;
21
23
  /** Update the current route query params. */
22
24
  setParams: (params?: Record<string, string>) => void;
23
25
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnC,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,IAAI,IAAI,MAAM,EAAE,CAAC;IACjB,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;IACnB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,yFAAyF;AACzF,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GACxD,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAEtB,MAAM,MAAM,MAAM,GAAG;IACnB,qCAAqC;IACrC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC3B,0DAA0D;IAC1D,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,6CAA6C;IAC7C,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;CACtD,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnC,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,IAAI,IAAI,MAAM,EAAE,CAAC;IACjB,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;IACnB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,yFAAyF;AACzF,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GACxD,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAEtB,MAAM,MAAM,MAAM,GAAG;IACnB,qCAAqC;IACrC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC3B,0DAA0D;IAC1D,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,qEAAqE;IACrE,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,6CAA6C;IAC7C,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;CACtD,CAAC"}
@@ -13,6 +13,9 @@ export type ScreenProps<TOptions extends Record<string, any> = Record<string, an
13
13
  };
14
14
  options?: TOptions;
15
15
  listeners?: any;
16
+ getId?: ({ params, }: {
17
+ params?: Record<string, any> | undefined;
18
+ }) => string | undefined;
16
19
  };
17
20
  /**
18
21
  * @returns React Navigation screens sorted by the `route` property.
@@ -1 +1 @@
1
- {"version":3,"file":"useScreens.d.ts","sourceRoot":"","sources":["../src/useScreens.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAIL,SAAS,EAGV,MAAM,SAAS,CAAC;AAOjB,MAAM,MAAM,WAAW,CACrB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IACxD;IACF,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IACvC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAGnB,SAAS,CAAC,EAAE,GAAG,CAAC;CACjB,CAAC;AA8DF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAUxE;AAsCD,mFAAmF;AACnF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,kIAuE1D;AAED,oGAAoG;AACpG,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC;;sCA0B5C"}
1
+ {"version":3,"file":"useScreens.d.ts","sourceRoot":"","sources":["../src/useScreens.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAIL,SAAS,EAGV,MAAM,SAAS,CAAC;AAOjB,MAAM,MAAM,WAAW,CACrB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IACxD;IACF,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IACvC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAGnB,SAAS,CAAC,EAAE,GAAG,CAAC;IAEhB,KAAK,CAAC,EAAE,CAAC,EACP,MAAM,GACP,EAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;KAC1C,KAAK,MAAM,GAAG,SAAS,CAAC;CAC1B,CAAC;AAiEF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAUxE;AAsCD,mFAAmF;AACnF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,kIAuE1D;AAED,oGAAoG;AACpG,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC;;sCA0B5C"}
@@ -1 +1 @@
1
- {"version":3,"file":"Sitemap.d.ts","sourceRoot":"","sources":["../../src/views/Sitemap.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAiB9E,wBAAgB,aAAa,IAAI,4BAA4B,CAqB5D;AAED,wBAAgB,OAAO,gBA6BtB"}
1
+ {"version":3,"file":"Sitemap.d.ts","sourceRoot":"","sources":["../../src/views/Sitemap.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAkB9E,wBAAgB,aAAa,IAAI,4BAA4B,CAqB5D;AAED,wBAAgB,OAAO,gBA6BtB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-router",
3
- "version": "2.0.0-rc.8",
3
+ "version": "2.0.0",
4
4
  "main": "src/index.tsx",
5
5
  "types": "build/index.d.ts",
6
6
  "files": [
@@ -104,13 +104,13 @@
104
104
  },
105
105
  "dependencies": {
106
106
  "@bacons/react-views": "^1.1.3",
107
- "@expo/metro-runtime": "2.1.10",
107
+ "@expo/metro-runtime": "2.2.3",
108
108
  "@radix-ui/react-slot": "1.0.1",
109
109
  "@react-navigation/bottom-tabs": "~6.5.7",
110
110
  "@react-navigation/native": "~6.1.6",
111
111
  "@react-navigation/native-stack": "~6.9.12",
112
112
  "expo-head": "0.0.11",
113
- "expo-splash-screen": "*",
113
+ "expo-splash-screen": "~0.20.2",
114
114
  "query-string": "7.1.3",
115
115
  "react-helmet-async": "^1.3.0",
116
116
  "schema-utils": "^4.0.1",
package/src/ExpoRoot.tsx CHANGED
@@ -104,6 +104,9 @@ function ContextNavigator({
104
104
  ref={store.navigationRef}
105
105
  initialState={store.initialState}
106
106
  linking={store.linking}
107
+ documentTitle={{
108
+ enabled: false,
109
+ }}
107
110
  >
108
111
  <WrapperComponent>
109
112
  <Component />
@@ -6,6 +6,7 @@ import type {
6
6
  } from "@react-navigation/routers";
7
7
  import escape from "escape-string-regexp";
8
8
  import * as queryString from "query-string";
9
+ import URL from "url-parse";
9
10
 
10
11
  import { RouteNode } from "../Route";
11
12
  import { matchGroupName, stripGroupSegmentsFromPath } from "../matchers";
@@ -47,14 +48,18 @@ type ParsedRoute = {
47
48
  params?: Record<string, any> | undefined;
48
49
  };
49
50
 
50
- function getPathname(path: string) {
51
- const remaining = path
52
- .replace(/\/+/g, "/") // Replace multiple slash (//) with single ones
53
- .replace(/^\//, "") // Remove extra leading slash
54
- .replace(/\?.*$/, ""); // Remove query params which we will handle later
51
+ export function getUrlWithReactNavigationConcessions(path: string) {
52
+ const parsed = new URL(path, "https://acme.com");
53
+ const pathname = parsed.pathname;
55
54
 
56
55
  // Make sure there is a trailing slash
57
- return remaining.endsWith("/") ? remaining : `${remaining}/`;
56
+ return {
57
+ // The slashes are at the end, not the beginning
58
+ nonstandardPathname:
59
+ pathname.replace(/^\/+/g, "").replace(/\/+$/g, "") + "/",
60
+ // React Navigation doesn't support hashes, so here
61
+ inputPathnameWithoutHash: path.replace(/#.*$/, ""),
62
+ };
58
63
  }
59
64
 
60
65
  /**
@@ -316,10 +321,15 @@ function getStateFromEmptyPathWithConfigs(
316
321
  return undefined;
317
322
  }
318
323
 
319
- const routes = match.routeNames.map((name) => ({
320
- name,
321
- _route: match._route,
322
- }));
324
+ const routes = match.routeNames.map((name) => {
325
+ if (!match._route) {
326
+ return { name };
327
+ }
328
+ return {
329
+ name,
330
+ _route: match._route,
331
+ };
332
+ });
323
333
 
324
334
  return createNestedStateObject(path, routes, configs, initialRoutes);
325
335
  }
@@ -329,21 +339,33 @@ function getStateFromPathWithConfigs(
329
339
  configs: RouteConfig[],
330
340
  initialRoutes: InitialRouteConfig[]
331
341
  ): ResultState | undefined {
332
- const pathname = getPathname(path);
342
+ const formattedPaths = getUrlWithReactNavigationConcessions(path);
333
343
 
334
- if (pathname === "/") {
335
- return getStateFromEmptyPathWithConfigs(path, configs, initialRoutes);
344
+ if (formattedPaths.nonstandardPathname === "/") {
345
+ return getStateFromEmptyPathWithConfigs(
346
+ formattedPaths.inputPathnameWithoutHash,
347
+ configs,
348
+ initialRoutes
349
+ );
336
350
  }
337
351
 
338
352
  // We match the whole path against the regex instead of segments
339
353
  // This makes sure matches such as wildcard will catch any unmatched routes, even if nested
340
- const routes = matchAgainstConfigs(pathname, configs);
354
+ const routes = matchAgainstConfigs(
355
+ formattedPaths.nonstandardPathname,
356
+ configs
357
+ );
341
358
 
342
359
  if (routes == null) {
343
360
  return undefined;
344
361
  }
345
362
  // This will always be empty if full path matched
346
- return createNestedStateObject(path, routes, configs, initialRoutes);
363
+ return createNestedStateObject(
364
+ formattedPaths.inputPathnameWithoutHash,
365
+ routes,
366
+ configs,
367
+ initialRoutes
368
+ );
347
369
  }
348
370
 
349
371
  const joinPaths = (...paths: string[]): string =>
@@ -424,10 +446,15 @@ function matchAgainstConfigs(
424
446
  return { name };
425
447
  };
426
448
 
427
- routes = config.routeNames.map((name) => ({
428
- ...routeFromName(name),
429
- _route: config._route,
430
- }));
449
+ routes = config.routeNames.map((name) => {
450
+ if (!config._route) {
451
+ return { ...routeFromName(name) };
452
+ }
453
+ return {
454
+ ...routeFromName(name),
455
+ _route: config._route,
456
+ };
457
+ });
431
458
 
432
459
  // TODO(EvanBacon): Maybe we should warn / assert if multiple slugs use the same param name.
433
460
  const combinedParams = routes.reduce<Record<string, any>>(
@@ -14,7 +14,7 @@ import { getRoutes } from "../getRoutes";
14
14
  import { RequireContext } from "../types";
15
15
  import { getQualifiedRouteComponent } from "../useScreens";
16
16
  import { _internal_maybeHideAsync } from "../views/Splash";
17
- import { goBack, linkTo, push, replace, setParams } from "./routing";
17
+ import { canGoBack, goBack, linkTo, push, replace, setParams } from "./routing";
18
18
  import { getSortedRoutes } from "./sort-routes";
19
19
 
20
20
  /**
@@ -42,6 +42,7 @@ export class RouterStore {
42
42
  linkTo = linkTo.bind(this);
43
43
  getSortedRoutes = getSortedRoutes.bind(this);
44
44
  goBack = goBack.bind(this);
45
+ canGoBack = canGoBack.bind(this);
45
46
  push = push.bind(this);
46
47
  replace = replace.bind(this);
47
48
  setParams = setParams.bind(this);
@@ -20,7 +20,9 @@ import type { RouterStore } from "./router-store";
20
20
 
21
21
  function assertIsReady(store: RouterStore) {
22
22
  if (!store.isReady || !store.navigationRef.current) {
23
- throw new Error("Attempted to use navigation outside of Expo Router");
23
+ throw new Error(
24
+ "Attempted to navigate before mounting the Root Layout component. Ensure the Root Layout component is rendering a Slot, or other navigator on the first render."
25
+ );
24
26
  }
25
27
  }
26
28
 
@@ -37,6 +39,11 @@ export function goBack(this: RouterStore) {
37
39
  this.navigationRef?.current?.goBack();
38
40
  }
39
41
 
42
+ export function canGoBack(this: RouterStore): boolean {
43
+ assertIsReady(this);
44
+ return this.navigationRef?.current?.canGoBack() ?? false;
45
+ }
46
+
40
47
  export function setParams(
41
48
  this: RouterStore,
42
49
  params: Record<string, string | number> = {}
@@ -105,9 +112,15 @@ export function linkTo(this: RouterStore, href: string, event?: string) {
105
112
  const nextRoute = findTopRouteForTarget(state);
106
113
 
107
114
  if (knownOwnerState.type === "tab") {
108
- navigationRef.dispatch(
109
- TabActions.jumpTo(nextRoute.name, nextRoute.params)
110
- );
115
+ if (event === "REPLACE") {
116
+ navigationRef.dispatch(
117
+ TabActions.jumpTo(nextRoute.name, nextRoute.params)
118
+ );
119
+ } else {
120
+ navigationRef.dispatch(
121
+ CommonActions.navigate(nextRoute.name, nextRoute.params)
122
+ );
123
+ }
111
124
  return;
112
125
  } else {
113
126
  if (event === "REPLACE") {
@@ -1,5 +1,4 @@
1
- import { RouteNode } from "../Route";
2
- import { matchGroupName } from "../matchers";
1
+ import { sortRoutes } from "../Route";
3
2
  import type { RouterStore } from "./router-store";
4
3
 
5
4
  export function getSortedRoutes(this: RouterStore) {
@@ -9,40 +8,5 @@ export function getSortedRoutes(this: RouterStore) {
9
8
 
10
9
  return this.routeNode.children
11
10
  .filter((route) => !route.internal)
12
- .sort((a: RouteNode, b: RouteNode): number => {
13
- if (a.dynamic && !b.dynamic) {
14
- return 1;
15
- }
16
- if (!a.dynamic && b.dynamic) {
17
- return -1;
18
- }
19
- if (a.dynamic && b.dynamic) {
20
- if (a.dynamic.length !== b.dynamic.length) {
21
- return b.dynamic.length - a.dynamic.length;
22
- }
23
- for (let i = 0; i < a.dynamic.length; i++) {
24
- const aDynamic = a.dynamic[i];
25
- const bDynamic = b.dynamic[i];
26
- if (aDynamic.deep && !bDynamic.deep) {
27
- return 1;
28
- }
29
- if (!aDynamic.deep && bDynamic.deep) {
30
- return -1;
31
- }
32
- }
33
- return 0;
34
- }
35
-
36
- const aIndex = a.route === "index" || matchGroupName(a.route) != null;
37
- const bIndex = b.route === "index" || matchGroupName(b.route) != null;
38
-
39
- if (aIndex && !bIndex) {
40
- return -1;
41
- }
42
- if (!aIndex && bIndex) {
43
- return 1;
44
- }
45
-
46
- return a.route.length - b.route.length;
47
- });
11
+ .sort(sortRoutes);
48
12
  }
package/src/hooks.ts CHANGED
@@ -38,8 +38,8 @@ export function useRouter(): Router {
38
38
  back: store.goBack,
39
39
  replace: store.replace,
40
40
  setParams: store.setParams,
41
+ canGoBack: store.canGoBack,
41
42
  // TODO(EvanBacon): add `reload`
42
- // TODO(EvanBacon): add `canGoBack` but maybe more like a `hasContext`
43
43
  };
44
44
  }
45
45
 
@@ -5,5 +5,6 @@ export const router: Router = {
5
5
  push: (href) => store.push(href),
6
6
  replace: (href) => store.replace(href),
7
7
  back: () => store.goBack(),
8
+ canGoBack: () => store.canGoBack(),
8
9
  setParams: (params) => store.setParams(params),
9
10
  };
@@ -52,7 +52,8 @@ export default function useLinkToPathProps(props: {
52
52
  };
53
53
 
54
54
  return {
55
- href: stripGroupSegmentsFromPath(props.href),
55
+ // Ensure there's always a value for href
56
+ href: stripGroupSegmentsFromPath(props.href) || "/",
56
57
  accessibilityRole: "link" as const,
57
58
  onPress,
58
59
  };
@@ -4,7 +4,10 @@ import requireContext from "./require-context-ponyfill";
4
4
 
5
5
  export type ReactComponent = () => React.ReactElement<any, any> | null;
6
6
  export type FileStub =
7
- | (Record<string, unknown> & { default: ReactComponent })
7
+ | (Record<string, unknown> & {
8
+ default: ReactComponent;
9
+ unstable_settings?: Record<string, any>;
10
+ })
8
11
  | ReactComponent;
9
12
 
10
13
  export { requireContext };
package/src/types.ts CHANGED
@@ -23,6 +23,8 @@ export type Router = {
23
23
  replace: (href: Href) => void;
24
24
  /** Go back in the history. */
25
25
  back: () => void;
26
+ /** If there's history that supports invoking the `back` function. */
27
+ canGoBack: () => boolean;
26
28
  /** Update the current route query params. */
27
29
  setParams: (params?: Record<string, string>) => void;
28
30
  };
@@ -29,6 +29,12 @@ export type ScreenProps<
29
29
 
30
30
  // TODO: types
31
31
  listeners?: any;
32
+
33
+ getId?: ({
34
+ params,
35
+ }: {
36
+ params?: Record<string, any> | undefined;
37
+ }) => string | undefined;
32
38
  };
33
39
 
34
40
  function getSortedChildren(
@@ -44,7 +50,7 @@ function getSortedChildren(
44
50
  const entries = [...children];
45
51
 
46
52
  const ordered = order
47
- .map(({ name, redirect, initialParams, listeners, options }) => {
53
+ .map(({ name, redirect, initialParams, listeners, options, getId }) => {
48
54
  if (!entries.length) {
49
55
  console.warn(
50
56
  `[Layout children]: Too many screens defined. Route "${name}" is extraneous.`
@@ -73,7 +79,10 @@ function getSortedChildren(
73
79
  return null;
74
80
  }
75
81
 
76
- return { route: match, props: { initialParams, listeners, options } };
82
+ return {
83
+ route: match,
84
+ props: { initialParams, listeners, options, getId },
85
+ };
77
86
  }
78
87
  })
79
88
  .filter(Boolean) as {
@@ -1,5 +1,4 @@
1
1
  import { Image, Pressable, StyleSheet, Text, View } from "@bacons/react-views";
2
- import { useNavigation } from "@react-navigation/native";
3
2
  import { NativeStackNavigationOptions } from "@react-navigation/native-stack";
4
3
  import React from "react";
5
4
  import {
@@ -12,6 +11,7 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
12
11
 
13
12
  import { RouteNode } from "../Route";
14
13
  import { useExpoRouter } from "../global-state/router-store";
14
+ import { router } from "../imperative-api";
15
15
  import { Link } from "../link/Link";
16
16
  import { matchDeepDynamicRouteName } from "../matchers";
17
17
 
@@ -98,8 +98,6 @@ function FileItem({
98
98
  }) {
99
99
  const disabled = route.children.length > 0;
100
100
 
101
- const navigation = useNavigation();
102
-
103
101
  const segments = React.useMemo(
104
102
  () => [...parents, ...route.route.split("/")],
105
103
  [parents, route.route]
@@ -147,9 +145,9 @@ function FileItem({
147
145
  accessibilityLabel={route.contextKey}
148
146
  href={href}
149
147
  onPress={() => {
150
- if (Platform.OS !== "web") {
148
+ if (Platform.OS !== "web" && router.canGoBack()) {
151
149
  // Ensure the modal pops
152
- navigation.goBack();
150
+ router.back();
153
151
  }
154
152
  }}
155
153
  style={{ flex: 1, display: "flex" }}
@@ -52,8 +52,8 @@ export function Unmatched() {
52
52
  Page could not be found.{" "}
53
53
  <Text
54
54
  onPress={() => {
55
- if (navigation.canGoBack()) {
56
- navigation.goBack();
55
+ if (router.canGoBack()) {
56
+ router.back();
57
57
  } else {
58
58
  router.replace("/");
59
59
  }