stx-router 0.2.138 → 0.2.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.js +49 -32
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -297,7 +297,7 @@ export function getRouterScript() {
|
|
|
297
297
|
// Re-localizing would map it back to the *current* locale and no-op.
|
|
298
298
|
if(!force) url=withCurrentLocale(url);
|
|
299
299
|
log('[router] navigate() called:',url,'isNavigating:',isNavigating);
|
|
300
|
-
if(isNavigating)return;
|
|
300
|
+
if(isNavigating)return Promise.resolve(false);
|
|
301
301
|
// Resolve against the current document URL, matching native <a> semantics.
|
|
302
302
|
// With location.origin as the base, any relative href ('?status=resolved',
|
|
303
303
|
// '#anchor', './sibling') resolved to the SITE ROOT \u2014 so filter tabs,
|
|
@@ -305,13 +305,13 @@ export function getRouterScript() {
|
|
|
305
305
|
// the SPA interceptor was active (#1777).
|
|
306
306
|
var t=new URL(url,location.href);
|
|
307
307
|
|
|
308
|
-
if(t.origin!==location.origin){location.href=url;return}
|
|
308
|
+
if(t.origin!==location.origin){location.href=url;return Promise.resolve(false)}
|
|
309
309
|
|
|
310
310
|
if(t.pathname===location.pathname&&t.hash){
|
|
311
311
|
if(pushState!==false)history.pushState({},'',t.href);
|
|
312
312
|
var el=document.querySelector(t.hash);
|
|
313
313
|
if(el)el.scrollIntoView({behavior:'smooth'});
|
|
314
|
-
return;
|
|
314
|
+
return Promise.resolve(true);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
317
|
// Skip if user clicks a link to the page they're already on. We
|
|
@@ -320,7 +320,7 @@ export function getRouterScript() {
|
|
|
320
320
|
// entry \u2014 without this allowance, hitting back would early-return
|
|
321
321
|
// and the visible page content would be left frozen on the
|
|
322
322
|
// forward-navigation page.
|
|
323
|
-
if(pushState!==false&&t.href===location.href&&!t.hash&&!force)return;
|
|
323
|
+
if(pushState!==false&&t.href===location.href&&!t.hash&&!force)return Promise.resolve(false);
|
|
324
324
|
|
|
325
325
|
isNavigating=true;
|
|
326
326
|
document.body.classList.add(o.loadingClass);
|
|
@@ -339,22 +339,22 @@ export function getRouterScript() {
|
|
|
339
339
|
if(checkLayoutChange(layoutCache[targetPath],url,layoutGroupCache[targetPath])){
|
|
340
340
|
// Layout changed \u2014 fetch full page and do full document swap
|
|
341
341
|
log('[router] cache hit but layout changed \u2014 fetching full page');
|
|
342
|
-
fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){
|
|
342
|
+
return fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){
|
|
343
343
|
if(!r.ok)throw new Error(r.status);
|
|
344
344
|
return r.text();
|
|
345
345
|
}).then(function(html){
|
|
346
346
|
log('[router] full page fetched from cache path, len:',html.length);
|
|
347
|
-
swap(html,targetPath,pushState,targetHash);
|
|
347
|
+
return swap(html,targetPath,pushState,targetHash);
|
|
348
348
|
}).catch(function(err){
|
|
349
349
|
console.error('[router] full page fetch error:',err);
|
|
350
350
|
location.href=url;
|
|
351
351
|
}).finally(done);
|
|
352
|
-
return;
|
|
353
352
|
}
|
|
354
353
|
pendingContainerAttrs=attrsCache[targetPath]||'';
|
|
355
|
-
swap(cache[targetPath],targetPath,pushState,targetHash)
|
|
356
|
-
|
|
357
|
-
|
|
354
|
+
return Promise.resolve(swap(cache[targetPath],targetPath,pushState,targetHash)).then(function(){
|
|
355
|
+
applyTitle(titleCache[targetPath]);
|
|
356
|
+
return true;
|
|
357
|
+
}).finally(done);
|
|
358
358
|
}
|
|
359
359
|
else {
|
|
360
360
|
if(force&&cache[targetPath])evictCache(targetPath);
|
|
@@ -362,7 +362,7 @@ else {
|
|
|
362
362
|
// the page content. Custom app-shell containers need full documents so
|
|
363
363
|
// the router does not inject a <main> fragment into the wrong element.
|
|
364
364
|
var wantsFragment=shouldUseFragmentResponse();
|
|
365
|
-
fetch(url,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
365
|
+
return fetch(url,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
366
366
|
if(!r.ok)throw new Error(r.status);
|
|
367
367
|
var isFragment=wantsFragment&&r.headers.get('X-STX-Fragment')==='true';
|
|
368
368
|
var newLayout=r.headers.get('X-STX-Layout')||'';
|
|
@@ -387,10 +387,12 @@ else {
|
|
|
387
387
|
if(result.isFragment)result.html='<!--stx-fragment-->'+result.html;
|
|
388
388
|
if(o.cache)setCache(targetPath,result.html,result.layout,result.layoutGroup,result.title,result.containerAttrs);
|
|
389
389
|
pendingContainerAttrs=result.isFragment?(result.containerAttrs||''):'';
|
|
390
|
-
swap(result.html,targetPath,pushState,targetHash)
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
390
|
+
return Promise.resolve(swap(result.html,targetPath,pushState,targetHash)).then(function(){
|
|
391
|
+
// Fragment swaps carry no <head>; apply the title from the header.
|
|
392
|
+
// Full-document swaps already set document.title from the <title> tag.
|
|
393
|
+
if(result.isFragment)applyTitle(result.title);
|
|
394
|
+
return true;
|
|
395
|
+
});
|
|
394
396
|
}).catch(function(err){
|
|
395
397
|
console.error('[router] fetch error:',err);
|
|
396
398
|
location.href=url;
|
|
@@ -412,10 +414,10 @@ else {
|
|
|
412
414
|
function swap(html,url,pushState,hash){
|
|
413
415
|
var isFragment=html.indexOf('<!--stx-fragment-->')===0;
|
|
414
416
|
if(isFragment)html=html.slice('<!--stx-fragment-->'.length);
|
|
415
|
-
if(!isFragment&&!isStxDocument(html)){log('[router] non-stx document \u2014 full navigation to:',url);location.href=url;return}
|
|
417
|
+
if(!isFragment&&!isStxDocument(html)){log('[router] non-stx document \u2014 full navigation to:',url);location.href=url;return Promise.resolve(false)}
|
|
416
418
|
var currentContent=getContainer();
|
|
417
419
|
log('[router] swap: isFragment='+isFragment+' container='+!!currentContent+' tag='+(currentContent&¤tContent.tagName)+' selector='+containerSel+' htmlLen='+html.length);
|
|
418
|
-
if(!currentContent){log('[router] no container \u2014 falling back');location.href=url;return}
|
|
420
|
+
if(!currentContent){log('[router] no container \u2014 falling back');location.href=url;return Promise.resolve(false)}
|
|
419
421
|
|
|
420
422
|
// Fragment mode: server returned just the page content (no document wrapper)
|
|
421
423
|
if(isFragment){
|
|
@@ -573,16 +575,23 @@ else {
|
|
|
573
575
|
// THEN fire stx:load \u2014 now _latestSetup is set and processElement has the right scope
|
|
574
576
|
window.dispatchEvent(new Event('stx:load'));
|
|
575
577
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
578
|
+
return new Promise(function(resolve,reject){
|
|
579
|
+
function completeFragSwap(){
|
|
580
|
+
try{
|
|
581
|
+
doFragSwap();
|
|
582
|
+
resolve(true);
|
|
583
|
+
}catch(err){reject(err)}
|
|
584
|
+
}
|
|
585
|
+
if(runViewTransition(completeFragSwap)){}
|
|
586
|
+
else{currentContent.style.transition='opacity 0.12s ease-out';currentContent.style.opacity='0';setTimeout(function(){completeFragSwap();currentContent.style.opacity='1';setTimeout(function(){currentContent.style.transition=''},150)},120)}
|
|
587
|
+
});
|
|
579
588
|
}
|
|
580
589
|
|
|
581
590
|
// Full document mode: parse with DOMParser and extract container content
|
|
582
591
|
var parser=new DOMParser();
|
|
583
592
|
var doc=parser.parseFromString(html,'text/html');
|
|
584
593
|
var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');
|
|
585
|
-
if(!newContent){location.href=url;return}
|
|
594
|
+
if(!newContent){location.href=url;return Promise.resolve(false)}
|
|
586
595
|
|
|
587
596
|
// Clean up existing signals/effects
|
|
588
597
|
if(window.stx&&window.stx._cleanupContainer){
|
|
@@ -874,18 +883,26 @@ else {
|
|
|
874
883
|
}
|
|
875
884
|
}
|
|
876
885
|
|
|
877
|
-
|
|
878
|
-
|
|
886
|
+
return new Promise(function(resolve,reject){
|
|
887
|
+
function completeSwap(){
|
|
888
|
+
try{
|
|
889
|
+
doSwap();
|
|
890
|
+
resolve(true);
|
|
891
|
+
}catch(err){reject(err)}
|
|
892
|
+
}
|
|
893
|
+
if(runViewTransition(completeSwap)){
|
|
894
|
+
}
|
|
879
895
|
else {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
896
|
+
// Fallback fade for browsers without View Transitions API
|
|
897
|
+
currentContent.style.transition='opacity 0.12s ease-out';
|
|
898
|
+
currentContent.style.opacity='0';
|
|
899
|
+
setTimeout(function(){
|
|
900
|
+
completeSwap();
|
|
901
|
+
currentContent.style.opacity='1';
|
|
902
|
+
setTimeout(function(){currentContent.style.transition=''},150);
|
|
903
|
+
},120);
|
|
904
|
+
}
|
|
905
|
+
});
|
|
889
906
|
}
|
|
890
907
|
|
|
891
908
|
// \u2500\u2500 Link interception \u2500\u2500
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stx-router",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.140",
|
|
5
5
|
"description": "File-based router for STX — .stx template discovery, nested layouts, typed route params, middleware, and client-side SPA navigation.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
7
|
"license": "MIT",
|