Skip to content

Commit a2b0997

Browse files
committed
fix(router): tolerate aborted view transitions
1 parent d411bf8 commit a2b0997

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

packages/router/src/client.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ export function getRouterScript(): string {
2929
var containerSel=o.container;
3030
var debug=!!o.debug;
3131
function log(){if(debug&&typeof console!=='undefined'&&console.log)console.log.apply(console,arguments)}
32+
function runViewTransition(callback){
33+
if(!o.viewTransitions||!document.startViewTransition)return false;
34+
try{
35+
var transition=document.startViewTransition(callback);
36+
var onAbort=function(err){log('[router] view transition aborted:',err&&err.message?err.message:err)};
37+
if(transition&&transition.finished&&transition.finished.catch)transition.finished.catch(onAbort);
38+
if(transition&&transition.updateCallbackDone&&transition.updateCallbackDone.catch)transition.updateCallbackDone.catch(onAbort);
39+
return true;
40+
}catch(err){
41+
log('[router] view transition unavailable:',err&&err.message?err.message:err);
42+
return false;
43+
}
44+
}
3245
3346
// ── Progress bar (0→100% at top of viewport) ──
3447
// Native loading indicator baked into the router. Starts when navigation
@@ -363,7 +376,7 @@ else {
363376
// THEN fire stx:load — now _latestSetup is set and processElement has the right scope
364377
window.dispatchEvent(new Event('stx:load'));
365378
}
366-
if(o.viewTransitions&&document.startViewTransition){document.startViewTransition(doFragSwap)}
379+
if(runViewTransition(doFragSwap)){}
367380
else{currentContent.style.transition='opacity 0.12s ease-out';currentContent.style.opacity='0';setTimeout(function(){doFragSwap();currentContent.style.opacity='1';setTimeout(function(){currentContent.style.transition=''},150)},120)}
368381
return;
369382
}
@@ -606,8 +619,7 @@ else {
606619
}
607620
}
608621
609-
if(o.viewTransitions&&document.startViewTransition){
610-
document.startViewTransition(doSwap);
622+
if(runViewTransition(doSwap)){
611623
}
612624
else {
613625
// Fallback fade for browsers without View Transitions API

packages/router/test/client-css.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ describe('getRouterScript — injected CSS defaults', () => {
5050
expect(script).toMatch(/o\.viewTransitions\s*&&\s*['"]startViewTransition['"]\s+in\s+document/)
5151
})
5252

53+
it('observes View Transition promise rejections', () => {
54+
// Browser View Transitions can abort when DOM work takes too long. The
55+
// router should keep navigation stable instead of leaking unhandled errors.
56+
expect(script).toContain('transition.finished.catch')
57+
expect(script).toContain('transition.updateCallbackDone.catch')
58+
})
59+
5360
it('progress-bar color and height come from the config', () => {
5461
// Apps set progressColor + progressHeight via stx.config.ts or
5562
// window.__stxRouterConfig. Defaults are defined in the IIFE.

0 commit comments

Comments
 (0)