mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
94 lines
2.7 KiB
JavaScript
94 lines
2.7 KiB
JavaScript
import React, {
|
|
startTransition,
|
|
useLayoutEffect,
|
|
useEffect,
|
|
useState,
|
|
unstable_addTransitionType as addTransitionType,
|
|
use,
|
|
} from 'react';
|
|
|
|
import Chrome from './Chrome';
|
|
import Page from './Page';
|
|
|
|
const enableNavigationAPI = typeof navigation === 'object';
|
|
|
|
export default function App({assets, initialURL}) {
|
|
const [routerState, setRouterState] = useState({
|
|
pendingNav: () => {},
|
|
url: initialURL,
|
|
});
|
|
function navigate(url) {
|
|
if (enableNavigationAPI) {
|
|
window.navigation.navigate(url);
|
|
} else {
|
|
startTransition(() => {
|
|
setRouterState({
|
|
url,
|
|
pendingNav() {
|
|
window.history.pushState({}, '', url);
|
|
},
|
|
});
|
|
});
|
|
}
|
|
}
|
|
useEffect(() => {
|
|
if (enableNavigationAPI) {
|
|
window.navigation.addEventListener('navigate', event => {
|
|
if (!event.canIntercept) {
|
|
return;
|
|
}
|
|
const navigationType = event.navigationType;
|
|
const previousIndex = window.navigation.currentEntry.index;
|
|
const newURL = new URL(event.destination.url);
|
|
event.intercept({
|
|
handler() {
|
|
let promise;
|
|
startTransition(() => {
|
|
addTransitionType('navigation-' + navigationType);
|
|
if (navigationType === 'traverse') {
|
|
// For traverse types it's useful to distinguish going back or forward.
|
|
const nextIndex = event.destination.index;
|
|
if (nextIndex > previousIndex) {
|
|
addTransitionType('navigation-forward');
|
|
} else if (nextIndex < previousIndex) {
|
|
addTransitionType('navigation-back');
|
|
}
|
|
}
|
|
promise = new Promise(resolve => {
|
|
setRouterState({
|
|
url: newURL.pathname + newURL.search,
|
|
pendingNav: resolve,
|
|
});
|
|
});
|
|
});
|
|
return promise;
|
|
},
|
|
commit: 'after-transition', // plz ship this, browsers
|
|
});
|
|
});
|
|
} else {
|
|
window.addEventListener('popstate', () => {
|
|
// This should not animate because restoration has to be synchronous.
|
|
// Even though it's a transition.
|
|
startTransition(() => {
|
|
setRouterState({
|
|
url: document.location.pathname + document.location.search,
|
|
pendingNav() {
|
|
// Noop. URL has already updated.
|
|
},
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}, []);
|
|
const pendingNav = routerState.pendingNav;
|
|
useLayoutEffect(() => {
|
|
pendingNav();
|
|
}, [pendingNav]);
|
|
return (
|
|
<Chrome title="Hello World" assets={assets}>
|
|
<Page url={routerState.url} navigate={navigate} />
|
|
</Chrome>
|
|
);
|
|
}
|