diff options
Diffstat (limited to 'examples/view-transitions/src/scripts')
-rw-r--r-- | examples/view-transitions/src/scripts/spa-navigation.js | 470 | ||||
-rw-r--r-- | examples/view-transitions/src/scripts/utils.js | 107 |
2 files changed, 283 insertions, 294 deletions
diff --git a/examples/view-transitions/src/scripts/spa-navigation.js b/examples/view-transitions/src/scripts/spa-navigation.js index 39159b5ef..ceaf3a955 100644 --- a/examples/view-transitions/src/scripts/spa-navigation.js +++ b/examples/view-transitions/src/scripts/spa-navigation.js @@ -1,262 +1,254 @@ import { - getNavigationType, - getPathId, - isBackNavigation, - shouldNotIntercept, - updateTheDOMSomehow, - useTvFragment, -} from './utils' + getNavigationType, + getPathId, + isBackNavigation, + shouldNotIntercept, + updateTheDOMSomehow, + useTvFragment, +} from './utils'; // View Transitions support cross-document navigations. // Should compare performace. // https://github.com/WICG/view-transitions/blob/main/explainer.md#cross-document-same-origin-transitions // https://github.com/WICG/view-transitions/blob/main/explainer.md#script-events function shouldDisableSpa() { - return false; + return false; } navigation.addEventListener('navigate', (navigateEvent) => { - if (shouldDisableSpa()) return - if (shouldNotIntercept(navigateEvent)) return - - const toUrl = new URL(navigateEvent.destination.url) - const toPath = toUrl.pathname - const fromPath = location.pathname - const navigationType = getNavigationType(fromPath, toPath) - - if (location.origin !== toUrl.origin) return - - switch (navigationType) { - case 'home-to-movie': - case 'tv-to-show': - handleHomeToMovieTransition(navigateEvent, getPathId(toPath)) - break - case 'movie-to-home': - case 'show-to-tv': - handleMovieToHomeTransition(navigateEvent, getPathId(fromPath)) - break - case 'movie-to-person': - handleMovieToPersonTransition( - navigateEvent, - getPathId(fromPath), - getPathId(toPath) - ) - break - case 'person-to-movie': - case 'person-to-show': - handlePersonToMovieTransition( - navigateEvent, - getPathId(fromPath), - getPathId(toPath) - ) - break - default: - return - } -}) + if (shouldDisableSpa()) return; + if (shouldNotIntercept(navigateEvent)) return; + + const toUrl = new URL(navigateEvent.destination.url); + const toPath = toUrl.pathname; + const fromPath = location.pathname; + const navigationType = getNavigationType(fromPath, toPath); + + if (location.origin !== toUrl.origin) return; + + switch (navigationType) { + case 'home-to-movie': + case 'tv-to-show': + handleHomeToMovieTransition(navigateEvent, getPathId(toPath)); + break; + case 'movie-to-home': + case 'show-to-tv': + handleMovieToHomeTransition(navigateEvent, getPathId(fromPath)); + break; + case 'movie-to-person': + handleMovieToPersonTransition(navigateEvent, getPathId(fromPath), getPathId(toPath)); + break; + case 'person-to-movie': + case 'person-to-show': + handlePersonToMovieTransition(navigateEvent, getPathId(fromPath), getPathId(toPath)); + break; + default: + return; + } +}); // TODO: https://developer.chrome.com/docs/web-platform/view-transitions/#transitions-as-an-enhancement function handleHomeToMovieTransition(navigateEvent, movieId) { - navigateEvent.intercept({ - async handler() { - const fragmentUrl = useTvFragment(navigateEvent) - ? '/fragments/TvDetails' - : '/fragments/MovieDetails' - const response = await fetch(`${fragmentUrl}/${movieId}`) - const data = await response.text() - - if (!document.startViewTransition) { - updateTheDOMSomehow(data); - return; - } - - const thumbnail = document.getElementById(`movie-poster-${movieId}`) - if (thumbnail) { - thumbnail.style.viewTransitionName = 'movie-poster' - } - - const transition = document.startViewTransition(() => { - if (thumbnail) { - thumbnail.style.viewTransitionName = '' - } - document.getElementById('container').scrollTop = 0 - updateTheDOMSomehow(data) - }) - - await transition.finished - }, - }) + navigateEvent.intercept({ + async handler() { + const fragmentUrl = useTvFragment(navigateEvent) + ? '/fragments/TvDetails' + : '/fragments/MovieDetails'; + const response = await fetch(`${fragmentUrl}/${movieId}`); + const data = await response.text(); + + if (!document.startViewTransition) { + updateTheDOMSomehow(data); + return; + } + + const thumbnail = document.getElementById(`movie-poster-${movieId}`); + if (thumbnail) { + thumbnail.style.viewTransitionName = 'movie-poster'; + } + + const transition = document.startViewTransition(() => { + if (thumbnail) { + thumbnail.style.viewTransitionName = ''; + } + document.getElementById('container').scrollTop = 0; + updateTheDOMSomehow(data); + }); + + await transition.finished; + }, + }); } function handleMovieToHomeTransition(navigateEvent, movieId) { - navigateEvent.intercept({ - scroll: 'manual', - async handler() { - const fragmentUrl = useTvFragment(navigateEvent) - ? '/fragments/TvList' - : '/fragments/MovieList' - const response = await fetch(fragmentUrl) - const data = await response.text() - - if (!document.startViewTransition) { - updateTheDOMSomehow(data) - return - } - - const tempHomePage = document.createElement('div') - const moviePoster = document.getElementById(`movie-poster`) - let thumbnail - - // If the movie poster is not in the home page, removes the transition style so that - // the poster doesn't stay on the page while transitioning - tempHomePage.innerHTML = data - if (!tempHomePage.querySelector(`#movie-poster-${movieId}`)) { - moviePoster?.classList.remove('movie-poster') - } - - const transition = document.startViewTransition(() => { - updateTheDOMSomehow(data) - - thumbnail = document.getElementById(`movie-poster-${movieId}`) - if (thumbnail) { - thumbnail.scrollIntoViewIfNeeded() - thumbnail.style.viewTransitionName = 'movie-poster' - } - }) - - await transition.finished - - if (thumbnail) { - thumbnail.style.viewTransitionName = '' - } - }, - }) + navigateEvent.intercept({ + scroll: 'manual', + async handler() { + const fragmentUrl = useTvFragment(navigateEvent) + ? '/fragments/TvList' + : '/fragments/MovieList'; + const response = await fetch(fragmentUrl); + const data = await response.text(); + + if (!document.startViewTransition) { + updateTheDOMSomehow(data); + return; + } + + const tempHomePage = document.createElement('div'); + const moviePoster = document.getElementById(`movie-poster`); + let thumbnail; + + // If the movie poster is not in the home page, removes the transition style so that + // the poster doesn't stay on the page while transitioning + tempHomePage.innerHTML = data; + if (!tempHomePage.querySelector(`#movie-poster-${movieId}`)) { + moviePoster?.classList.remove('movie-poster'); + } + + const transition = document.startViewTransition(() => { + updateTheDOMSomehow(data); + + thumbnail = document.getElementById(`movie-poster-${movieId}`); + if (thumbnail) { + thumbnail.scrollIntoViewIfNeeded(); + thumbnail.style.viewTransitionName = 'movie-poster'; + } + }); + + await transition.finished; + + if (thumbnail) { + thumbnail.style.viewTransitionName = ''; + } + }, + }); } function handleMovieToPersonTransition(navigateEvent, movieId, personId) { - // TODO: https://developer.chrome.com/docs/web-platform/view-transitions/#not-a-polyfill - // ...has example of `back-transition` class applied to document - const isBack = isBackNavigation(navigateEvent) - - navigateEvent.intercept({ - async handler() { - const response = await fetch('/fragments/PersonDetails/' + personId) - const data = await response.text() - - if (!document.startViewTransition) { - updateTheDOMSomehow(data) - return - } - - let personThumbnail - let moviePoster - let movieThumbnail - - if (!isBack) { - // We're transitioning the person photo; we need to remove the transition of the poster - // so that it doesn't stay on the page while transitioning - moviePoster = document.getElementById(`movie-poster`) - if (moviePoster) { - moviePoster.classList.remove('movie-poster') - } - - personThumbnail = document.getElementById(`person-photo-${personId}`) - if (personThumbnail) { - personThumbnail.style.viewTransitionName = 'person-photo' - } - } - - const transition = document.startViewTransition(() => { - updateTheDOMSomehow(data) - - if (personThumbnail) { - personThumbnail.style.viewTransitionName = '' - } - - if (isBack) { - // If we're coming back to the person page, we're transitioning - // into the movie poster thumbnail, so we need to add the tag to it - movieThumbnail = document.getElementById(`movie-poster-${movieId}`) - if (movieThumbnail) { - movieThumbnail.scrollIntoViewIfNeeded() - movieThumbnail.style.viewTransitionName = 'movie-poster' - } - } - - document.getElementById('container').scrollTop = 0 - }) - - await transition.finished - - if (movieThumbnail) { - movieThumbnail.style.viewTransitionName = '' - } - }, - }) + // TODO: https://developer.chrome.com/docs/web-platform/view-transitions/#not-a-polyfill + // ...has example of `back-transition` class applied to document + const isBack = isBackNavigation(navigateEvent); + + navigateEvent.intercept({ + async handler() { + const response = await fetch('/fragments/PersonDetails/' + personId); + const data = await response.text(); + + if (!document.startViewTransition) { + updateTheDOMSomehow(data); + return; + } + + let personThumbnail; + let moviePoster; + let movieThumbnail; + + if (!isBack) { + // We're transitioning the person photo; we need to remove the transition of the poster + // so that it doesn't stay on the page while transitioning + moviePoster = document.getElementById(`movie-poster`); + if (moviePoster) { + moviePoster.classList.remove('movie-poster'); + } + + personThumbnail = document.getElementById(`person-photo-${personId}`); + if (personThumbnail) { + personThumbnail.style.viewTransitionName = 'person-photo'; + } + } + + const transition = document.startViewTransition(() => { + updateTheDOMSomehow(data); + + if (personThumbnail) { + personThumbnail.style.viewTransitionName = ''; + } + + if (isBack) { + // If we're coming back to the person page, we're transitioning + // into the movie poster thumbnail, so we need to add the tag to it + movieThumbnail = document.getElementById(`movie-poster-${movieId}`); + if (movieThumbnail) { + movieThumbnail.scrollIntoViewIfNeeded(); + movieThumbnail.style.viewTransitionName = 'movie-poster'; + } + } + + document.getElementById('container').scrollTop = 0; + }); + + await transition.finished; + + if (movieThumbnail) { + movieThumbnail.style.viewTransitionName = ''; + } + }, + }); } function handlePersonToMovieTransition(navigateEvent, personId, movieId) { - const isBack = isBackNavigation(navigateEvent) - - navigateEvent.intercept({ - scroll: 'manual', - async handler() { - const fragmentUrl = useTvFragment(navigateEvent) - ? '/fragments/TvDetails' - : '/fragments/MovieDetails' - const response = await fetch(`${fragmentUrl}/${movieId}`) - const data = await response.text() - - if (!document.startViewTransition) { - updateTheDOMSomehow(data) - return - } - - let thumbnail - let moviePoster - let movieThumbnail - - if (!isBack) { - movieThumbnail = document.getElementById(`movie-poster-${movieId}`) - if (movieThumbnail) { - movieThumbnail.style.viewTransitionName = 'movie-poster' - } - } - - const transition = document.startViewTransition(() => { - updateTheDOMSomehow(data) - - if (isBack) { - moviePoster = document.getElementById(`movie-poster`) - if (moviePoster) { - moviePoster.classList.remove('movie-poster') - } - - if (personId) { - thumbnail = document.getElementById(`person-photo-${personId}`) - if (thumbnail) { - thumbnail.scrollIntoViewIfNeeded() - thumbnail.style.viewTransitionName = 'person-photo' - } - } - } else { - document.getElementById('container').scrollTop = 0 - - if (movieThumbnail) { - movieThumbnail.style.viewTransitionName = '' - } - } - }) - - await transition.finished - - if (thumbnail) { - thumbnail.style.viewTransitionName = '' - } - - if (moviePoster) { - moviePoster.classList.add('movie-poster') - } - }, - }) + const isBack = isBackNavigation(navigateEvent); + + navigateEvent.intercept({ + scroll: 'manual', + async handler() { + const fragmentUrl = useTvFragment(navigateEvent) + ? '/fragments/TvDetails' + : '/fragments/MovieDetails'; + const response = await fetch(`${fragmentUrl}/${movieId}`); + const data = await response.text(); + + if (!document.startViewTransition) { + updateTheDOMSomehow(data); + return; + } + + let thumbnail; + let moviePoster; + let movieThumbnail; + + if (!isBack) { + movieThumbnail = document.getElementById(`movie-poster-${movieId}`); + if (movieThumbnail) { + movieThumbnail.style.viewTransitionName = 'movie-poster'; + } + } + + const transition = document.startViewTransition(() => { + updateTheDOMSomehow(data); + + if (isBack) { + moviePoster = document.getElementById(`movie-poster`); + if (moviePoster) { + moviePoster.classList.remove('movie-poster'); + } + + if (personId) { + thumbnail = document.getElementById(`person-photo-${personId}`); + if (thumbnail) { + thumbnail.scrollIntoViewIfNeeded(); + thumbnail.style.viewTransitionName = 'person-photo'; + } + } + } else { + document.getElementById('container').scrollTop = 0; + + if (movieThumbnail) { + movieThumbnail.style.viewTransitionName = ''; + } + } + }); + + await transition.finished; + + if (thumbnail) { + thumbnail.style.viewTransitionName = ''; + } + + if (moviePoster) { + moviePoster.classList.add('movie-poster'); + } + }, + }); } diff --git a/examples/view-transitions/src/scripts/utils.js b/examples/view-transitions/src/scripts/utils.js index 3d98181ab..5b7f78535 100644 --- a/examples/view-transitions/src/scripts/utils.js +++ b/examples/view-transitions/src/scripts/utils.js @@ -1,79 +1,76 @@ export function getNavigationType(fromPath, toPath) { - if (fromPath.startsWith('/movies') && toPath === '/') { - return 'movie-to-home' - } + if (fromPath.startsWith('/movies') && toPath === '/') { + return 'movie-to-home'; + } - if (fromPath === '/tv' && toPath.startsWith('/tv/')) { - return 'tv-to-show' - } + if (fromPath === '/tv' && toPath.startsWith('/tv/')) { + return 'tv-to-show'; + } - if (fromPath === '/' && toPath.startsWith('/movies')) { - return 'home-to-movie' - } + if (fromPath === '/' && toPath.startsWith('/movies')) { + return 'home-to-movie'; + } - if (fromPath.startsWith('/tv/') && toPath === '/tv') { - return 'show-to-tv' - } + if (fromPath.startsWith('/tv/') && toPath === '/tv') { + return 'show-to-tv'; + } - if ( - (fromPath.startsWith('/movies') || fromPath.startsWith('/tv')) && - toPath.startsWith('/people') - ) { - return 'movie-to-person' - } + if ( + (fromPath.startsWith('/movies') || fromPath.startsWith('/tv')) && + toPath.startsWith('/people') + ) { + return 'movie-to-person'; + } - if ( - fromPath.startsWith('/people') && - (toPath.startsWith('/movies') || toPath.startsWith('/tv/')) - ) { - return 'person-to-movie' - } + if ( + fromPath.startsWith('/people') && + (toPath.startsWith('/movies') || toPath.startsWith('/tv/')) + ) { + return 'person-to-movie'; + } - return 'other' + return 'other'; } export function isBackNavigation(navigateEvent) { - if ( - navigateEvent.navigationType === 'push' || - navigateEvent.navigationType === 'replace' - ) { - return false - } - if ( - navigateEvent.destination.index !== -1 && - navigateEvent.destination.index < navigation.currentEntry.index - ) { - return true - } - return false + if (navigateEvent.navigationType === 'push' || navigateEvent.navigationType === 'replace') { + return false; + } + if ( + navigateEvent.destination.index !== -1 && + navigateEvent.destination.index < navigation.currentEntry.index + ) { + return true; + } + return false; } export function shouldNotIntercept(navigationEvent) { - return ( - navigationEvent.canIntercept === false || - // If this is just a hashChange, - // just let the browser handle scrolling to the content. - navigationEvent.hashChange || - // If this is a download, - // let the browser perform the download. - navigationEvent.downloadRequest || - // If this is a form submission, - // let that go to the server. - navigationEvent.formData - ) + return ( + navigationEvent.canIntercept === false || + // If this is just a hashChange, + // just let the browser handle scrolling to the content. + navigationEvent.hashChange || + // If this is a download, + // let the browser perform the download. + navigationEvent.downloadRequest || + // If this is a form submission, + // let that go to the server. + navigationEvent.formData + ); } export function useTvFragment(navigateEvent) { - const toUrl = new URL(navigateEvent.destination.url) - const toPath = toUrl.pathname + const toUrl = new URL(navigateEvent.destination.url); + const toPath = toUrl.pathname; - return toPath.startsWith('/tv') + return toPath.startsWith('/tv'); } export function getPathId(path) { - return path.split('/')[2] + return path.split('/')[2]; } export function updateTheDOMSomehow(data) { - document.getElementById('content').innerHTML = data + document.getElementById('content').innerHTML = data; } |