main
js 92 lines 2.68 KB
Raw
1 import React, {
2 startTransition,
3 useLayoutEffect,
4 useEffect,
5 useState,
6 addTransitionType,
7 } from 'react';
8
9 import Chrome from './Chrome.js';
10 import Page from './Page.js';
11
12 const enableNavigationAPI = typeof navigation === 'object';
13
14 export default function App({assets, initialURL}) {
15 const [routerState, setRouterState] = useState({
16 pendingNav: () => {},
17 url: initialURL,
18 });
19 function navigate(url) {
20 if (enableNavigationAPI) {
21 window.navigation.navigate(url);
22 } else {
23 startTransition(() => {
24 setRouterState({
25 url,
26 pendingNav() {
27 window.history.pushState({}, '', url);
28 },
29 });
30 });
31 }
32 }
33 useEffect(() => {
34 if (enableNavigationAPI) {
35 window.navigation.addEventListener('navigate', event => {
36 if (!event.canIntercept) {
37 return;
38 }
39 const navigationType = event.navigationType;
40 const previousIndex = window.navigation.currentEntry.index;
41 const newURL = new URL(event.destination.url);
42 event.intercept({
43 handler() {
44 let promise;
45 startTransition(() => {
46 addTransitionType('navigation-' + navigationType);
47 if (navigationType === 'traverse') {
48 // For traverse types it's useful to distinguish going back or forward.
49 const nextIndex = event.destination.index;
50 if (nextIndex > previousIndex) {
51 addTransitionType('navigation-forward');
52 } else if (nextIndex < previousIndex) {
53 addTransitionType('navigation-back');
54 }
55 }
56 promise = new Promise(resolve => {
57 setRouterState({
58 url: newURL.pathname + newURL.search,
59 pendingNav: resolve,
60 });
61 });
62 });
63 return promise;
64 },
65 commit: 'after-transition', // plz ship this, browsers
66 });
67 });
68 } else {
69 window.addEventListener('popstate', () => {
70 // This should not animate because restoration has to be synchronous.
71 // Even though it's a transition.
72 startTransition(() => {
73 setRouterState({
74 url: document.location.pathname + document.location.search,
75 pendingNav() {
76 // Noop. URL has already updated.
77 },
78 });
79 });
80 });
81 }
82 }, []);
83 const pendingNav = routerState.pendingNav;
84 useLayoutEffect(() => {
85 pendingNav();
86 }, [pendingNav]);
87 return (
88 <Chrome title="Hello World" assets={assets}>
89 <Page url={routerState.url} navigate={navigate} />
90 </Chrome>
91 );
92 }