stx-router 0.2.382 → 0.2.384
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 +73 -9
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -182,8 +182,14 @@ function routerSource() {
|
|
|
182
182
|
log('[router] build skew: page is',loadedBuild,'server is',incoming,'\u2014 full navigation');
|
|
183
183
|
location.href=url;
|
|
184
184
|
}
|
|
185
|
+
// A link marked data-stx-transition="none" swaps without the cross-fade. A
|
|
186
|
+
// tab bar is the case: iOS switches tabs instantly, and the fade read as a
|
|
187
|
+
// quarter-second lag on every tap in a phone app. Set by the click that
|
|
188
|
+
// started the navigation, so programmatic and history navigations keep it.
|
|
189
|
+
var instantNext=false;
|
|
190
|
+
var instantNav=false;
|
|
185
191
|
function runViewTransition(callback){
|
|
186
|
-
if(
|
|
192
|
+
if(instantNav||!o.viewTransitions||!document.startViewTransition)return false;
|
|
187
193
|
try{
|
|
188
194
|
var transition=document.startViewTransition(callback);
|
|
189
195
|
var onAbort=function(err){log('[router] view transition aborted:',err&&err.message?err.message:err)};
|
|
@@ -210,19 +216,28 @@ function routerSource() {
|
|
|
210
216
|
progEl.style.opacity=progVal>0?'1':'0';
|
|
211
217
|
progEl.style.transform='scaleX('+(progVal/100)+')';
|
|
212
218
|
}
|
|
219
|
+
// Shown only for a navigation that is actually waiting. A page served from
|
|
220
|
+
// the prefetch cache swaps in a few milliseconds, and drawing then fading a
|
|
221
|
+
// bar for it made every instant navigation look like a load.
|
|
222
|
+
var progDelay=null;
|
|
213
223
|
function startProgress(){
|
|
214
224
|
if(!o.progress||!progEl)return;
|
|
215
225
|
if(progTimer){clearInterval(progTimer);progTimer=null}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
if(progDelay)clearTimeout(progDelay);
|
|
227
|
+
progDelay=setTimeout(function(){
|
|
228
|
+
progDelay=null;
|
|
229
|
+
setProgress(8);
|
|
230
|
+
progTimer=setInterval(function(){
|
|
231
|
+
if(progVal>=90)return;
|
|
232
|
+
// Asymptotic trickle \u2014 fast at first, slower near 90%
|
|
233
|
+
var inc=Math.max(0.4,(90-progVal)*0.08);
|
|
234
|
+
setProgress(progVal+inc);
|
|
235
|
+
},160);
|
|
236
|
+
},150);
|
|
223
237
|
}
|
|
224
238
|
function finishProgress(){
|
|
225
239
|
if(!o.progress||!progEl)return;
|
|
240
|
+
if(progDelay){clearTimeout(progDelay);progDelay=null;return}
|
|
226
241
|
if(progTimer){clearInterval(progTimer);progTimer=null}
|
|
227
242
|
setProgress(100);
|
|
228
243
|
// Fade out, then reset. Delays chosen so the "full" state is briefly
|
|
@@ -472,6 +487,47 @@ function routerSource() {
|
|
|
472
487
|
function isComposablesScript(s){
|
|
473
488
|
return !!s&&((s.hasAttribute&&s.hasAttribute('data-stx-composables'))||COMPOSABLES_TEXT.test(s.textContent||''));
|
|
474
489
|
}
|
|
490
|
+
/*
|
|
491
|
+
* What the block wrap below would otherwise hide (stacksjs/stx#2041).
|
|
492
|
+
*
|
|
493
|
+
* A re-executed script is wrapped in a bare block so that top-level const
|
|
494
|
+
* and let cannot collide across navigations. That wrap is invisible for a
|
|
495
|
+
* plain function declaration -- Annex B.3.3 still hoists its binding to the
|
|
496
|
+
* enclosing scope in sloppy mode -- and NOT invisible for anything else.
|
|
497
|
+
* async function, function*, class, const and let are all block-scoped, so
|
|
498
|
+
* the same source published a global when the browser parsed the script and
|
|
499
|
+
* published nothing when the router re-ran it.
|
|
500
|
+
*
|
|
501
|
+
* The effect is a divergence between development and a built app, because
|
|
502
|
+
* only the built one reaches a route as a fragment: a page served whole runs
|
|
503
|
+
* its script natively. An inline onclick that names such a declaration then
|
|
504
|
+
* worked in dev and threw ReferenceError in the packaged app, where there is
|
|
505
|
+
* no console, so it read as a button that does nothing.
|
|
506
|
+
*
|
|
507
|
+
* So: re-publish what the browser would have published. Only values that are
|
|
508
|
+
* functions, which is what an inline handler calls -- assigning every
|
|
509
|
+
* top-level const would otherwise write over window.name and friends, which
|
|
510
|
+
* a lexical global shadows rather than overwrites. Each name is guarded on
|
|
511
|
+
* its own so an unmatched one cannot take the rest down, and typeof is safe
|
|
512
|
+
* on a name that was never declared.
|
|
513
|
+
*
|
|
514
|
+
* Column-anchored: a declaration nested inside a function is indented, and
|
|
515
|
+
* is not in scope at the end of the block anyway.
|
|
516
|
+
*/
|
|
517
|
+
var TOP_LEVEL_DECL=/^(?:export\\s+)?(?:async\\s+)?(?:function\\s*\\*?|class|const|let|var)\\s+([A-Za-z_$][\\w$]*)/gm;
|
|
518
|
+
function republishTopLevel(src){
|
|
519
|
+
var names=[],m;
|
|
520
|
+
TOP_LEVEL_DECL.lastIndex=0;
|
|
521
|
+
while((m=TOP_LEVEL_DECL.exec(src))!==null){
|
|
522
|
+
if(names.indexOf(m[1])===-1)names.push(m[1]);
|
|
523
|
+
}
|
|
524
|
+
if(!names.length)return '';
|
|
525
|
+
var out='\\n;';
|
|
526
|
+
for(var i=0;i<names.length;i++){
|
|
527
|
+
out+='try{if(typeof '+names[i]+'==="function")window.'+names[i]+'='+names[i]+'}catch(e){}';
|
|
528
|
+
}
|
|
529
|
+
return out;
|
|
530
|
+
}
|
|
475
531
|
function runsAlways(declared, code){
|
|
476
532
|
if(declared==='always')return true;
|
|
477
533
|
if(declared==='once')return false;
|
|
@@ -783,6 +839,8 @@ function routerSource() {
|
|
|
783
839
|
if(pushState!==false&&t.href===location.href&&!t.hash&&!force)return Promise.resolve(false);
|
|
784
840
|
|
|
785
841
|
isNavigating=true;
|
|
842
|
+
instantNav=instantNext;
|
|
843
|
+
instantNext=false;
|
|
786
844
|
document.body.classList.add(o.loadingClass);
|
|
787
845
|
startProgress();
|
|
788
846
|
|
|
@@ -1318,6 +1376,7 @@ else {
|
|
|
1318
1376
|
}catch(err){reject(err)}
|
|
1319
1377
|
}
|
|
1320
1378
|
if(runViewTransition(completeFragSwap)){}
|
|
1379
|
+
else if(instantNav){completeFragSwap()}
|
|
1321
1380
|
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)}
|
|
1322
1381
|
});
|
|
1323
1382
|
}
|
|
@@ -1732,7 +1791,7 @@ else {
|
|
|
1732
1791
|
// ESM, and top-level 'import' is illegal inside a block, which
|
|
1733
1792
|
// would throw SyntaxError before the script ever runs.
|
|
1734
1793
|
var alreadyScoped=runsAlways(typeof entry==='string'?'':entry.run,text);
|
|
1735
|
-
ns.textContent=(hasImport||alreadyScoped)?text:'{'+text+'}';
|
|
1794
|
+
ns.textContent=(hasImport||alreadyScoped)?text:'{'+text+republishTopLevel(text)+'}';
|
|
1736
1795
|
ns.setAttribute('data-stx-page','');
|
|
1737
1796
|
var placeholder=entry.slot?qs('script[data-stx-route-script="'+entry.slot+'"]'):null;
|
|
1738
1797
|
if(placeholder&&placeholder.parentNode){
|
|
@@ -1768,6 +1827,10 @@ else {
|
|
|
1768
1827
|
}
|
|
1769
1828
|
if(runViewTransition(completeSwap)){
|
|
1770
1829
|
}
|
|
1830
|
+
else if(instantNav){
|
|
1831
|
+
// A tab: swap at once, no fade either way.
|
|
1832
|
+
completeSwap();
|
|
1833
|
+
}
|
|
1771
1834
|
else {
|
|
1772
1835
|
// Fallback fade for browsers without View Transitions API
|
|
1773
1836
|
currentContent.style.transition='opacity 0.12s ease-out';
|
|
@@ -1886,6 +1949,7 @@ else {
|
|
|
1886
1949
|
e.preventDefault();
|
|
1887
1950
|
e.stopPropagation();
|
|
1888
1951
|
log('[router] navigating to:',href);
|
|
1952
|
+
instantNext=link.getAttribute('data-stx-transition')==='none';
|
|
1889
1953
|
navigate(withCurrentLocale(href));
|
|
1890
1954
|
});
|
|
1891
1955
|
|
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.384",
|
|
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",
|