stx-router 0.2.139 → 0.2.141

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.
Files changed (2) hide show
  1. package/dist/client.js +49 -32
  2. 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
- applyTitle(titleCache[targetPath]);
357
- done();
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
- // 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);
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&&currentContent.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
- if(runViewTransition(doFragSwap)){}
577
- 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)}
578
- return;
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
- if(runViewTransition(doSwap)){
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
- // Fallback fade for browsers without View Transitions API
881
- currentContent.style.transition='opacity 0.12s ease-out';
882
- currentContent.style.opacity='0';
883
- setTimeout(function(){
884
- doSwap();
885
- currentContent.style.opacity='1';
886
- setTimeout(function(){currentContent.style.transition=''},150);
887
- },120);
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.139",
4
+ "version": "0.2.141",
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",