@multiplatform.one/router 8.2.2 → 8.4.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.
- package/dist/cjs/hooks/index.native.js.map +1 -1
- package/dist/cjs/hooks/useUrlState.native.js +1 -1
- package/dist/cjs/hooks/useUrlState.native.js.map +1 -1
- package/dist/cjs/index.native.js +1 -1
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/index.storybook.native.js +1 -1
- package/dist/cjs/index.storybook.native.js.map +1 -1
- package/dist/cjs/router/EmptyRouter.native.js.map +1 -1
- package/dist/cjs/router/ReactRouter.native.js.map +1 -1
- package/dist/cjs/router/index.native.js +18 -6
- package/dist/cjs/router/index.native.js.map +1 -1
- package/dist/cjs/router/index.storybook-expo.native.js.map +1 -1
- package/dist/cjs/router/index.storybook.native.js.map +1 -1
- package/dist/cjs/router/index.webext.native.js.map +1 -1
- package/dist/cjs/router/nativeFallback.cjs +45 -0
- package/dist/cjs/router/nativeFallback.native.js +53 -0
- package/dist/cjs/router/nativeFallback.native.js.map +1 -0
- package/dist/cjs/seam/DomNavigationHost.cjs +29 -2
- package/dist/cjs/seam/DomNavigationHost.native.js +34 -2
- package/dist/cjs/seam/DomNavigationHost.native.js.map +1 -1
- package/dist/cjs/seam/index.native.js.map +1 -1
- package/dist/cjs/seam/navigator.native.js.map +1 -1
- package/dist/cjs/seam/oneAdapter.native.js.map +1 -1
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/esm/hooks/index.native.js.map +1 -1
- package/dist/esm/hooks/useUrlState.native.js.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/index.storybook.native.js.map +1 -1
- package/dist/esm/router/EmptyRouter.native.js.map +1 -1
- package/dist/esm/router/ReactRouter.native.js.map +1 -1
- package/dist/esm/router/index.native.js +15 -3
- package/dist/esm/router/index.native.js.map +1 -1
- package/dist/esm/router/index.storybook-expo.native.js.map +1 -1
- package/dist/esm/router/index.storybook.native.js.map +1 -1
- package/dist/esm/router/index.webext.native.js.map +1 -1
- package/dist/esm/router/nativeFallback.mjs +19 -0
- package/dist/esm/router/nativeFallback.mjs.map +1 -0
- package/dist/esm/router/nativeFallback.native.js +24 -0
- package/dist/esm/router/nativeFallback.native.js.map +1 -0
- package/dist/esm/seam/DomNavigationHost.mjs +30 -3
- package/dist/esm/seam/DomNavigationHost.mjs.map +1 -1
- package/dist/esm/seam/DomNavigationHost.native.js +35 -3
- package/dist/esm/seam/DomNavigationHost.native.js.map +1 -1
- package/dist/esm/seam/index.native.js.map +1 -1
- package/dist/esm/seam/navigator.native.js.map +1 -1
- package/dist/esm/seam/oneAdapter.native.js.map +1 -1
- package/dist/esm/types.native.js.map +1 -1
- package/dist/jsx/router/index.native.js +18 -6
- package/dist/jsx/router/index.native.js.map +1 -1
- package/dist/jsx/router/nativeFallback.mjs +19 -0
- package/dist/jsx/router/nativeFallback.mjs.map +1 -0
- package/dist/jsx/router/nativeFallback.native.js +53 -0
- package/dist/jsx/router/nativeFallback.native.js.map +1 -0
- package/dist/jsx/seam/DomNavigationHost.mjs +30 -3
- package/dist/jsx/seam/DomNavigationHost.mjs.map +1 -1
- package/dist/jsx/seam/DomNavigationHost.native.js +34 -2
- package/dist/jsx/seam/DomNavigationHost.native.js.map +1 -1
- package/package.json +15 -4
- package/src/router/index.native.tsx +18 -3
- package/src/router/nativeFallback.spec.tsx +46 -0
- package/src/router/nativeFallback.tsx +19 -0
- package/src/seam/DomNavigationHost.routeHold.spec.tsx +78 -0
- package/src/seam/DomNavigationHost.tsx +34 -3
- package/types/router/index.native.d.ts +4 -2
- package/types/router/index.native.d.ts.map +1 -1
- package/types/router/nativeFallback.d.ts +10 -0
- package/types/router/nativeFallback.d.ts.map +1 -0
- package/types/seam/DomNavigationHost.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","DomNavigationHost_exports","DomNavigationHost","DomStackAdapter","module","exports","import_jsx_runtime","require","import_react","import_navigator","_class_call_check","instance","Constructor","TypeError","_defineProperties","props","i","length","descriptor","configurable","writable","_create_class","protoProps","staticProps","_define_property","obj","DomStackAdapter2","rootTag","onChanged","stack","push_by_tag","tag","push","pop","pop_to_tag","idx","lastIndexOf","slice","replace_with_tags","tags","get_navigation_stack","snapshot","get_n_items","get_item","index","get_tag","_snapshot_index"],"sources":["../../../src/seam/DomNavigationHost.tsx"],"sourcesContent":[null],"mappings":"AA4BA,YAAS;;AACT,IAAAA,SAAA,GAAAC,MAAA,CAAAC,cAAA;AAAA,IACEC,gBAAA,GAAAF,MAAA,CAAAG,wBAAA;AAAA,IACAC,iBAAA,GAAAJ,MAAA,CAAAK,mBAAA;AAAA,IACAC,YAAA,GAAAN,MAAA,CAAAO,SAAA,CAAAC,cAAA;AAAA,IAAAC,QAIK,GAAAA,CAAAC,MAAA,EAAAC,GAAA;
|
|
1
|
+
{"version":3,"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","DomNavigationHost_exports","DomNavigationHost","DomStackAdapter","module","exports","import_jsx_runtime","require","import_react","import_navigator","_class_call_check","instance","Constructor","TypeError","_defineProperties","props","i","length","descriptor","configurable","writable","_create_class","protoProps","staticProps","_define_property","obj","DomStackAdapter2","rootTag","onChanged","stack","push_by_tag","tag","push","pop","pop_to_tag","idx","lastIndexOf","slice","replace_with_tags","tags","get_navigation_stack","snapshot","get_n_items","get_item","index","get_tag","_snapshot_index","PAGE_STYLE","position","flex","minHeight","display","flexDirection","overflow","useZeroHeightWarning","ref","useEffect","process","env","NODE_ENV","el","current","raf","requestAnimationFrame","offsetParent","getBoundingClientRect","height"],"sources":["../../../src/seam/DomNavigationHost.tsx"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/router",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.4.0",
|
|
4
4
|
"description": "multiplatform.one router with support for react-router-dom and react-navigation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"access": "public"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@multiplatform.one/platform": "^8.
|
|
64
|
+
"@multiplatform.one/platform": "^8.4.0",
|
|
65
65
|
"@vxrn/color-scheme": "~1.16.5"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@multiplatform.one/config": "8.
|
|
69
|
-
"@multiplatform.one/test-utils": "8.
|
|
68
|
+
"@multiplatform.one/config": "8.4.0",
|
|
69
|
+
"@multiplatform.one/test-utils": "8.4.0",
|
|
70
70
|
"@react-navigation/native": "^7.2.2",
|
|
71
71
|
"@tamagui/build": "2.7.6",
|
|
72
72
|
"@testing-library/react": "^16.3.3",
|
|
@@ -86,6 +86,17 @@
|
|
|
86
86
|
"react": "^19.1.0",
|
|
87
87
|
"react-router-dom": "^7.0.0"
|
|
88
88
|
},
|
|
89
|
+
"peerDependenciesMeta": {
|
|
90
|
+
"@react-navigation/native": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"one": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"react-router-dom": {
|
|
97
|
+
"optional": true
|
|
98
|
+
}
|
|
99
|
+
},
|
|
89
100
|
"engines": {
|
|
90
101
|
"node": ">=16.0.0"
|
|
91
102
|
},
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LinkComponent, UseParams, UseRouter } from "../types";
|
|
2
|
+
import { type NativeRouter, pickRouter } from "./nativeFallback";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
function loadOne(): NativeRouter | undefined {
|
|
5
|
+
try {
|
|
6
|
+
return require("one") as NativeRouter;
|
|
7
|
+
} catch {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const router = pickRouter(loadOne());
|
|
13
|
+
|
|
14
|
+
export const Link: LinkComponent = router.Link;
|
|
15
|
+
export const useParams: UseParams = router.useParams;
|
|
16
|
+
export const useRouter: UseRouter = router.useRouter;
|
|
17
|
+
|
|
18
|
+
const useRouterPathname = router.usePathname;
|
|
4
19
|
|
|
5
20
|
/**
|
|
6
21
|
* One 1.16.5 `usePathname()` reads `useRouteInfo().pathname` with no guard.
|
|
@@ -11,7 +26,7 @@ export { Link, useParams, useRouter };
|
|
|
11
26
|
*/
|
|
12
27
|
export function usePathname(): string {
|
|
13
28
|
try {
|
|
14
|
-
return
|
|
29
|
+
return useRouterPathname() ?? "/";
|
|
15
30
|
} catch {
|
|
16
31
|
return "/";
|
|
17
32
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { render, renderHook, screen } from "@testing-library/react";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import type { LinkComponent } from "../types";
|
|
6
|
+
import { type NativeRouter, nativeFallback, pickRouter } from "./nativeFallback";
|
|
7
|
+
|
|
8
|
+
describe("native router without One", () => {
|
|
9
|
+
it("falls back to the no-op router when one is not installed", () => {
|
|
10
|
+
const router = pickRouter(undefined);
|
|
11
|
+
expect(router).toBe(nativeFallback);
|
|
12
|
+
const { result } = renderHook(() => router.useRouter());
|
|
13
|
+
expect(result.current.canGoBack()).toBe(false);
|
|
14
|
+
expect(() => result.current.push("/a" as never)).not.toThrow();
|
|
15
|
+
expect(renderHook(() => router.usePathname()).result.current).toBe("/");
|
|
16
|
+
expect(renderHook(() => router.useParams()).result.current).toEqual({});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("renders a Link's children with no anchor", () => {
|
|
20
|
+
const { container } = render(
|
|
21
|
+
<nativeFallback.Link href={"/a" as never}>
|
|
22
|
+
<span>go</span>
|
|
23
|
+
</nativeFallback.Link>,
|
|
24
|
+
);
|
|
25
|
+
expect(screen.getByText("go")).toBeTruthy();
|
|
26
|
+
expect(container.querySelector("a")).toBeNull();
|
|
27
|
+
expect(nativeFallback.Link.resolveHref("/a" as never)).toBe("/a");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("uses One's router when one is installed", () => {
|
|
31
|
+
const Link = (() => null) as unknown as LinkComponent;
|
|
32
|
+
const one: NativeRouter = {
|
|
33
|
+
Link,
|
|
34
|
+
useParams: () => ({ id: "1" }),
|
|
35
|
+
usePathname: () => "/one",
|
|
36
|
+
useRouter: nativeFallback.useRouter,
|
|
37
|
+
};
|
|
38
|
+
expect(pickRouter(one)).toBe(one);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("loads one from inside a try block so Metro treats it as optional", () => {
|
|
42
|
+
const source = readFileSync(join(__dirname, "index.native.tsx"), "utf8");
|
|
43
|
+
expect(source).not.toMatch(/^import[^;]*from "one"/m);
|
|
44
|
+
expect(source).toMatch(/try \{\s*return require\("one"\)/);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LinkComponent, UseParams, UsePathname, UseRouter } from "../types";
|
|
2
|
+
import { useParams, usePathname, useRouter } from "./EmptyRouter";
|
|
3
|
+
|
|
4
|
+
export interface NativeRouter {
|
|
5
|
+
Link: LinkComponent;
|
|
6
|
+
useParams: UseParams;
|
|
7
|
+
usePathname: UsePathname;
|
|
8
|
+
useRouter: UseRouter;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const Link: LinkComponent = ({ children }) => <>{children}</>;
|
|
12
|
+
|
|
13
|
+
Link.resolveHref = (href) => href.toString();
|
|
14
|
+
|
|
15
|
+
export const nativeFallback: NativeRouter = { Link, useParams, usePathname, useRouter };
|
|
16
|
+
|
|
17
|
+
export function pickRouter(one: NativeRouter | undefined): NativeRouter {
|
|
18
|
+
return one ?? nativeFallback;
|
|
19
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { act, render, screen } from "@testing-library/react";
|
|
2
|
+
import { lazy, type ReactElement } from "react";
|
|
3
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
4
|
+
import { DomNavigationHost } from "./DomNavigationHost";
|
|
5
|
+
import { stackNavigator } from "./navigator";
|
|
6
|
+
|
|
7
|
+
const ROUTES = [
|
|
8
|
+
{ pattern: "/", tag: "home", title: "Home" },
|
|
9
|
+
{ pattern: "/todos", tag: "todos", title: "Todos" },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
function deferredScreen() {
|
|
13
|
+
let resolve!: () => void;
|
|
14
|
+
const ready = new Promise<{ default: () => ReactElement }>((done) => {
|
|
15
|
+
resolve = () => done({ default: () => <div data-testid="todos-screen" /> });
|
|
16
|
+
});
|
|
17
|
+
return { Screen: lazy(() => ready), resolve: () => act(async () => resolve()) };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function page(container: HTMLElement, tag: string): HTMLElement {
|
|
21
|
+
return container.querySelector(`[data-seam-page="${tag}"]`) as HTMLElement;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function shown(container: HTMLElement): string[] {
|
|
25
|
+
return [...container.querySelectorAll<HTMLElement>("[data-seam-page]")]
|
|
26
|
+
.filter((el) => el.style.display !== "none")
|
|
27
|
+
.map((el) => el.dataset.seamPage ?? "");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("DomNavigationHost route change (LC-198)", () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
stackNavigator.detach();
|
|
33
|
+
stackNavigator.configure(ROUTES);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("holds the current page on screen while the next one is still loading", async () => {
|
|
37
|
+
const todos = deferredScreen();
|
|
38
|
+
const { container } = render(
|
|
39
|
+
<DomNavigationHost
|
|
40
|
+
routes={[
|
|
41
|
+
{ ...ROUTES[0]!, element: <div data-testid="home-screen" /> },
|
|
42
|
+
{ ...ROUTES[1]!, element: <todos.Screen /> },
|
|
43
|
+
]}
|
|
44
|
+
/>,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
act(() => stackNavigator.push("/todos"));
|
|
48
|
+
|
|
49
|
+
expect(shown(container)).toEqual(["home"]);
|
|
50
|
+
expect(page(container, "home").childElementCount).toBeGreaterThan(0);
|
|
51
|
+
expect(page(container, "home").dataset.seamActive).toBe("true");
|
|
52
|
+
expect(page(container, "todos").dataset.seamPending).toBe("true");
|
|
53
|
+
expect(screen.getByTestId("home-screen")).toBeTruthy();
|
|
54
|
+
|
|
55
|
+
await todos.resolve();
|
|
56
|
+
|
|
57
|
+
expect(shown(container)).toEqual(["todos"]);
|
|
58
|
+
expect(page(container, "todos").dataset.seamActive).toBe("true");
|
|
59
|
+
expect(page(container, "todos").dataset.seamPending).toBeUndefined();
|
|
60
|
+
expect(screen.getByTestId("todos-screen")).toBeTruthy();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("shows the page at once when it does not suspend", () => {
|
|
64
|
+
const { container } = render(
|
|
65
|
+
<DomNavigationHost
|
|
66
|
+
routes={[
|
|
67
|
+
{ ...ROUTES[0]!, element: <div data-testid="home-screen" /> },
|
|
68
|
+
{ ...ROUTES[1]!, element: <div data-testid="todos-screen" /> },
|
|
69
|
+
]}
|
|
70
|
+
/>,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
act(() => stackNavigator.push("/todos"));
|
|
74
|
+
|
|
75
|
+
expect(shown(container)).toEqual(["todos"]);
|
|
76
|
+
expect(page(container, "todos").dataset.seamPending).toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
// See the contract above PAGE_STYLE.
|
|
27
27
|
|
|
28
28
|
import type { CSSProperties, ReactNode } from "react";
|
|
29
|
-
import { Suspense, useEffect, useRef } from "react";
|
|
29
|
+
import { Suspense, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
30
30
|
import {
|
|
31
31
|
RouteTagContext,
|
|
32
32
|
stackNavigator,
|
|
@@ -149,6 +149,20 @@ function useZeroHeightWarning(ref: { current: HTMLDivElement | null }): void {
|
|
|
149
149
|
}, [ref]);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
function PageLoading({
|
|
153
|
+
tag,
|
|
154
|
+
onPending,
|
|
155
|
+
}: {
|
|
156
|
+
tag: string;
|
|
157
|
+
onPending: (tag: string, isPending: boolean) => void;
|
|
158
|
+
}): null {
|
|
159
|
+
useLayoutEffect(() => {
|
|
160
|
+
onPending(tag, true);
|
|
161
|
+
return () => onPending(tag, false);
|
|
162
|
+
}, [tag, onPending]);
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
152
166
|
export function DomNavigationHost({
|
|
153
167
|
routes,
|
|
154
168
|
initialHref,
|
|
@@ -183,6 +197,20 @@ export function DomNavigationHost({
|
|
|
183
197
|
useZeroHeightWarning(hostRef);
|
|
184
198
|
|
|
185
199
|
const nav = useNavState();
|
|
200
|
+
const pendingRef = useRef<Set<string>>(new Set());
|
|
201
|
+
const [, setPendingVersion] = useState(0);
|
|
202
|
+
const markPending = useCallback((tag: string, isPending: boolean) => {
|
|
203
|
+
if (pendingRef.current.has(tag) === isPending) return;
|
|
204
|
+
if (isPending) pendingRef.current.add(tag);
|
|
205
|
+
else pendingRef.current.delete(tag);
|
|
206
|
+
setPendingVersion((version) => version + 1);
|
|
207
|
+
}, []);
|
|
208
|
+
const settledRef = useRef(nav.tag);
|
|
209
|
+
useLayoutEffect(() => {
|
|
210
|
+
if (!pendingRef.current.has(nav.tag)) settledRef.current = nav.tag;
|
|
211
|
+
});
|
|
212
|
+
const pending = pendingRef.current;
|
|
213
|
+
const shown = pending.has(nav.tag) ? settledRef.current : nav.tag;
|
|
186
214
|
|
|
187
215
|
return (
|
|
188
216
|
<div
|
|
@@ -198,17 +226,20 @@ export function DomNavigationHost({
|
|
|
198
226
|
}}
|
|
199
227
|
>
|
|
200
228
|
{routes.map((route) => {
|
|
201
|
-
const active =
|
|
229
|
+
const active = shown === route.tag;
|
|
202
230
|
const mounted = stackNavigator.isVisited(route.tag);
|
|
203
231
|
return (
|
|
204
232
|
<div
|
|
205
233
|
key={route.tag}
|
|
206
234
|
data-seam-page={route.tag}
|
|
207
235
|
data-seam-active={active ? "true" : "false"}
|
|
236
|
+
data-seam-pending={pending.has(route.tag) ? "true" : undefined}
|
|
208
237
|
style={{ ...PAGE_STYLE, display: active ? "flex" : "none" }}
|
|
209
238
|
>
|
|
210
239
|
<RouteTagContext.Provider value={route.tag}>
|
|
211
|
-
<Suspense fallback={
|
|
240
|
+
<Suspense fallback={<PageLoading tag={route.tag} onPending={markPending} />}>
|
|
241
|
+
{mounted ? route.element : null}
|
|
242
|
+
</Suspense>
|
|
212
243
|
</RouteTagContext.Provider>
|
|
213
244
|
</div>
|
|
214
245
|
);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
1
|
+
import type { LinkComponent, UseParams, UseRouter } from "../types";
|
|
2
|
+
export declare const Link: LinkComponent;
|
|
3
|
+
export declare const useParams: UseParams;
|
|
4
|
+
export declare const useRouter: UseRouter;
|
|
3
5
|
/**
|
|
4
6
|
* One 1.16.5 `usePathname()` reads `useRouteInfo().pathname` with no guard.
|
|
5
7
|
* On native a layout node sees the router store's `routeInfo`, which is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.native.d.ts","sourceRoot":"","sources":["../../src/router/index.native.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.native.d.ts","sourceRoot":"","sources":["../../src/router/index.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAapE,eAAO,MAAM,IAAI,EAAE,aAA2B,CAAC;AAC/C,eAAO,MAAM,SAAS,EAAE,SAA4B,CAAC;AACrD,eAAO,MAAM,SAAS,EAAE,SAA4B,CAAC;AAIrD;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAMpC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LinkComponent, UseParams, UsePathname, UseRouter } from "../types";
|
|
2
|
+
export interface NativeRouter {
|
|
3
|
+
Link: LinkComponent;
|
|
4
|
+
useParams: UseParams;
|
|
5
|
+
usePathname: UsePathname;
|
|
6
|
+
useRouter: UseRouter;
|
|
7
|
+
}
|
|
8
|
+
export declare const nativeFallback: NativeRouter;
|
|
9
|
+
export declare function pickRouter(one: NativeRouter | undefined): NativeRouter;
|
|
10
|
+
//# sourceMappingURL=nativeFallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeFallback.d.ts","sourceRoot":"","sources":["../../src/router/nativeFallback.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGjF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,SAAS,CAAC;CACtB;AAMD,eAAO,MAAM,cAAc,EAAE,YAA0D,CAAC;AAExF,wBAAgB,UAAU,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,YAAY,CAEtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DomNavigationHost.d.ts","sourceRoot":"","sources":["../../src/seam/DomNavigationHost.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,eAAe,EACpB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAErB;;qBAEqB;AACrB,qBAAa,eAAgB,YAAW,eAAe;IACrD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;gBAE3B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI;IAKlD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAK9B,GAAG,IAAI,OAAO;IAOd,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQhC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAKvC,oBAAoB,IAAI;QACtB,WAAW,IAAI,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG;YAAE,OAAO,IAAI,MAAM,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC;KAC9D;CAQF;AAED,MAAM,WAAW,aAAc,SAAQ,QAAQ;IAC7C,OAAO,EAAE,SAAS,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB;;;8DAG0D;IAC1D,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"DomNavigationHost.d.ts","sourceRoot":"","sources":["../../src/seam/DomNavigationHost.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,OAAO,EAIL,KAAK,IAAI,EACT,KAAK,eAAe,EACpB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAErB;;qBAEqB;AACrB,qBAAa,eAAgB,YAAW,eAAe;IACrD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;gBAE3B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI;IAKlD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAK9B,GAAG,IAAI,OAAO;IAOd,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAQhC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAKvC,oBAAoB,IAAI;QACtB,WAAW,IAAI,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG;YAAE,OAAO,IAAI,MAAM,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC;KAC9D;CAQF;AAED,MAAM,WAAW,aAAc,SAAQ,QAAQ;IAC7C,OAAO,EAAE,SAAS,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB;;;8DAG0D;IAC1D,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAiED,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,WAAW,EACX,KAAK,GACN,EAAE,sBAAsB,GAAG,SAAS,CA+EpC"}
|