@@ -62,26 +62,26 @@ export const withoutFragment = href => href.split('#')[0];
6262 *
6363 * @param {Document } doc
6464 * @param {string } base - The document's URL, for relative references
65- * @returns {Array<string > }
65+ * @returns {Array<URL > }
6666 */
6767const getAssets = ( doc , base ) =>
6868 [ ...doc . querySelectorAll ( 'script[src], link[rel~="stylesheet"][href]' ) ] . map (
6969 element =>
7070 new URL ( element . getAttribute ( 'src' ) ?? element . getAttribute ( 'href' ) , base )
71- . href
7271 ) ;
7372
7473/**
75- * Keys the islands of the document by name and occurrence, so that the same
76- * island is found again on the next page.
74+ * Keys an iterable of islands by name and occurrence, so that the same island
75+ * is found again on the next page.
7776 *
77+ * @param {Iterable<HTMLElement> } source
7878 * @returns {Map<string, HTMLElement> }
7979 */
80- const getIslands = ( ) => {
80+ const keyIslands = source => {
8181 const counts = new Map ( ) ;
8282
8383 return new Map (
84- [ ...document . querySelectorAll ( 'is-land[data-island-name]' ) ] . map ( island => {
84+ [ ...source ] . map ( island => {
8585 const name = island . getAttribute ( 'data-island-name' ) ;
8686 counts . set ( name , ( counts . get ( name ) ?? 0 ) + 1 ) ;
8787
@@ -117,45 +117,11 @@ const updateHead = doc => {
117117} ;
118118
119119/**
120- * Announces the new page to assistive technology, as loading it would have.
121- */
122- const announcePage = ( ) => {
123- const region = document . createElement ( 'div' ) ;
124-
125- region . setAttribute ( 'aria-live' , 'assertive' ) ;
126- region . setAttribute ( 'aria-atomic' , 'true' ) ;
127- region . style . cssText =
128- 'position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap' ;
129-
130- document . body . append ( region ) ;
131-
132- // A region filled as it is inserted is not announced
133- setTimeout ( ( ) => ( region . textContent = document . title ) , 100 ) ;
134- } ;
135-
136- /**
137- * Runs a DOM update inside a view transition, where supported and wanted, so
138- * the old page cross-fades into the new one.
120+ * Runs a DOM update, keeping the call-site uniform for a future transition.
139121 *
140122 * @param {() => void } update
141- * @returns {Promise<void> | undefined } Settles once the DOM is updated
142123 */
143- const transition = update => {
144- if (
145- ! document . startViewTransition ||
146- matchMedia ( '(prefers-reduced-motion: reduce)' ) . matches
147- ) {
148- return update ( ) ;
149- }
150-
151- const { ready, updateCallbackDone } = document . startViewTransition ( update ) ;
152-
153- // Skipped transitions (the tab is hidden, or another navigation started)
154- // still update the DOM; only their animation is lost
155- ready . catch ( ( ) => { } ) ;
156-
157- return updateCallbackDone ;
158- } ;
124+ const transition = update => update ( ) ;
159125
160126/**
161127 * Starts handling navigations between the pages of the site, unless the
@@ -165,8 +131,10 @@ const transition = update => {
165131 * @param {object } options
166132 * @param {(root: Node) => void } options.unmount - Unmounts the components
167133 * rendered inside the part of the document that is about to be discarded.
134+ * @param {Set<HTMLElement> } options.islands - The runtime's set of hydrated
135+ * islands; used to save scroll positions before the body is replaced.
168136 */
169- export const startRouter = ( { unmount } ) => {
137+ export const startRouter = ( { unmount, islands } ) => {
170138 const script = document . querySelector ( 'script[data-root]' ) ;
171139
172140 if ( ! ( 'navigation' in window ) || ! script ) {
@@ -177,7 +145,9 @@ export const startRouter = ({ unmount }) => {
177145
178146 // The document's head is never replaced (see `PAGE_HEAD`), so the relative
179147 // URLs in it are resolved while they still point where they did at load
180- const assets = new Set ( getAssets ( document , location . href ) ) ;
148+ const assets = new Set (
149+ getAssets ( document , location . href ) . map ( url => url . href )
150+ ) ;
181151
182152 /** @type {Map<string, { page: Promise<Page | null>, expires: number }> } */
183153 const pages = new Map ( ) ;
@@ -233,7 +203,9 @@ export const startRouter = ({ unmount }) => {
233203 const parsePage = ( { url, html } ) => {
234204 const doc = new DOMParser ( ) . parseFromString ( html , 'text/html' ) ;
235205
236- return getAssets ( doc , url ) . every ( asset => assets . has ( asset ) ) ? doc : null ;
206+ return getAssets ( doc , url ) . every ( asset => assets . has ( asset . href ) )
207+ ? doc
208+ : null ;
237209 } ;
238210
239211 /**
@@ -244,7 +216,7 @@ export const startRouter = ({ unmount }) => {
244216 */
245217 const showPage = ( doc , scroll ) => {
246218 // The sidebar (like any island that scrolls) stays where it was
247- const scrolled = [ ...getIslands ( ) ]
219+ const scrolled = [ ...keyIslands ( islands ) ]
248220 . filter ( ( [ , island ] ) => island . scrollTop || island . scrollLeft )
249221 . map ( ( [ key , { scrollLeft, scrollTop } ] ) => [ key , scrollLeft , scrollTop ] ) ;
250222
@@ -256,14 +228,15 @@ export const startRouter = ({ unmount }) => {
256228 // from animating again with every page
257229 document . documentElement . setAttribute ( 'data-navigated' , '' ) ;
258230
259- const islands = getIslands ( ) ;
231+ const next = keyIslands (
232+ document . body . querySelectorAll ( 'is-land[data-island-name]' )
233+ ) ;
260234
261235 for ( const [ key , left , top ] of scrolled ) {
262- islands . get ( key ) ?. scrollTo ( { left, top, behavior : 'instant' } ) ;
236+ next . get ( key ) ?. scrollTo ( { left, top, behavior : 'instant' } ) ;
263237 }
264238
265239 scroll ( ) ;
266- announcePage ( ) ;
267240 } ;
268241
269242 /**
@@ -329,13 +302,7 @@ export const startRouter = ({ unmount }) => {
329302 return ;
330303 }
331304
332- await transition ( ( ) => {
333- // Another navigation superseded this one while the old page was
334- // being captured for the transition
335- if ( ! event . signal . aborted ) {
336- showPage ( doc , ( ) => event . scroll ( ) ) ;
337- }
338- } ) ;
305+ transition ( ( ) => showPage ( doc , ( ) => event . scroll ( ) ) ) ;
339306 } ,
340307 } ) ;
341308 } ) ;
0 commit comments