bun-plugin-stx 0.2.291 → 0.2.292
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.
|
@@ -647,7 +647,7 @@ function getRouterScript() {
|
|
|
647
647
|
if(window.__stxRouter&&window.__stxRouter.__rev===ROUTER_REV)return;
|
|
648
648
|
|
|
649
649
|
// \u2500\u2500 Configuration \u2500\u2500
|
|
650
|
-
var defaults={container:'main',loadingClass:'stx-navigating',viewTransitions:true,cache:true,scrollToTop:true,prefetch:true,progress:true,progressColor:'#78dce8',progressHeight:'2px',interceptAllLinks:false,prefetchCacheMax:50,routeFocus:true,announceRoute:true,interceptForms:false};
|
|
650
|
+
var defaults={container:'main',loadingClass:'stx-navigating',viewTransitions:true,cache:true,scrollToTop:true,prefetch:true,progress:true,progressColor:'#78dce8',progressHeight:'2px',interceptAllLinks:false,prefetchCacheMax:50,routeFocus:true,announceRoute:true,interceptForms:false,cssLoadTimeout:1500};
|
|
651
651
|
var o=Object.assign({},defaults,window.__stxRouterConfig||{},window.STX_ROUTER_OPTIONS||{});
|
|
652
652
|
var containerSel=o.container;
|
|
653
653
|
var debug=!!o.debug;
|
|
@@ -1411,6 +1411,99 @@ else {
|
|
|
1411
1411
|
try{target.focus({preventScroll:true})}catch(e){try{target.focus()}catch(e2){}}
|
|
1412
1412
|
}
|
|
1413
1413
|
|
|
1414
|
+
// \u2500\u2500 Generated utility stylesheets \u2500\u2500
|
|
1415
|
+
// Every page ships its own content-addressed utility sheet as
|
|
1416
|
+
// <link data-css="generated">, and none of them is ever removed on a
|
|
1417
|
+
// navigation, so they pile up in <head>. Two of them can define the same
|
|
1418
|
+
// class at the same specificity, which makes their ORDER decide the cascade:
|
|
1419
|
+
// the later sheet wins. Deduping alone left that order as "first seen", so
|
|
1420
|
+
// after Records \u2192 Feed \u2192 Records the Feed sheet still sat after the Records
|
|
1421
|
+
// one and its .flex-col beat Records' own responsive sm:flex-row \u2014 the header
|
|
1422
|
+
// stacked into a column on desktop. The current page's complete sheet has to
|
|
1423
|
+
// be the last one, every navigation, not just the first time it is seen.
|
|
1424
|
+
function findGeneratedCss(abs){
|
|
1425
|
+
var found=null;
|
|
1426
|
+
document.querySelectorAll('head link[data-css][href]').forEach(function(link){
|
|
1427
|
+
if(new URL(link.getAttribute('href'),location.href).href!==abs)return;
|
|
1428
|
+
// Collapse duplicates, so moving one copy to the end can never leave an
|
|
1429
|
+
// older copy of the same sheet behind to fight it.
|
|
1430
|
+
if(found){link.parentNode.removeChild(link);return}
|
|
1431
|
+
found=link;
|
|
1432
|
+
});
|
|
1433
|
+
return found;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// Before the swap: add each sheet the page does not have yet, as
|
|
1437
|
+
// media="print" so it downloads without restyling the page still on screen.
|
|
1438
|
+
// Returns a promise for them to finish (load OR error, capped at
|
|
1439
|
+
// cssLoadTimeout so a slow or missing sheet never stalls navigation), or null
|
|
1440
|
+
// when nothing new is needed and the swap can go ahead in the same turn.
|
|
1441
|
+
function preloadGeneratedCss(hrefs,base){
|
|
1442
|
+
var pending=[];
|
|
1443
|
+
hrefs.forEach(function(href){
|
|
1444
|
+
var abs;
|
|
1445
|
+
try{abs=new URL(href,base).href}catch(e){return}
|
|
1446
|
+
var link=findGeneratedCss(abs);
|
|
1447
|
+
if(link){
|
|
1448
|
+
// Still downloading for a navigation that never swapped \u2014 wait on it
|
|
1449
|
+
// rather than on nothing.
|
|
1450
|
+
if(link.__stxCssReady)pending.push(link.__stxCssReady);
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
link=document.createElement('link');
|
|
1454
|
+
link.setAttribute('data-css','generated');
|
|
1455
|
+
link.setAttribute('rel','stylesheet');
|
|
1456
|
+
link.setAttribute('href',new URL(href,location.href).href===abs?href:abs);
|
|
1457
|
+
link.setAttribute('media','print');
|
|
1458
|
+
link.setAttribute('data-stx-css-pending','');
|
|
1459
|
+
link.__stxCssReady=new Promise(function(resolve){
|
|
1460
|
+
var timer=setTimeout(finish,o.cssLoadTimeout);
|
|
1461
|
+
function finish(){clearTimeout(timer);link.onload=null;link.onerror=null;link.__stxCssReady=null;resolve()}
|
|
1462
|
+
link.onload=finish;
|
|
1463
|
+
link.onerror=finish;
|
|
1464
|
+
});
|
|
1465
|
+
pending.push(link.__stxCssReady);
|
|
1466
|
+
document.head.appendChild(link);
|
|
1467
|
+
});
|
|
1468
|
+
return pending.length?Promise.all(pending):null;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// At the swap: make the destination's sheets live and move them to the end
|
|
1472
|
+
// of <head>. appendChild on a node that is already there MOVES it \u2014 no
|
|
1473
|
+
// duplicate, and the browser keeps the parsed sheet rather than refetching.
|
|
1474
|
+
// Only generated sheets are reordered; app and font stylesheets keep the
|
|
1475
|
+
// order they were declared in.
|
|
1476
|
+
function promoteGeneratedCss(hrefs,base){
|
|
1477
|
+
hrefs.forEach(function(href){
|
|
1478
|
+
var abs;
|
|
1479
|
+
try{abs=new URL(href,base).href}catch(e){return}
|
|
1480
|
+
var link=findGeneratedCss(abs);
|
|
1481
|
+
if(!link){
|
|
1482
|
+
preloadGeneratedCss([href],base);
|
|
1483
|
+
link=findGeneratedCss(abs);
|
|
1484
|
+
if(!link)return;
|
|
1485
|
+
}
|
|
1486
|
+
if(link.hasAttribute('data-stx-css-pending')){
|
|
1487
|
+
link.removeAttribute('data-stx-css-pending');
|
|
1488
|
+
link.removeAttribute('media');
|
|
1489
|
+
}
|
|
1490
|
+
document.head.appendChild(link);
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// The generated-sheet hrefs a fragment carries. Scripts are skipped so a
|
|
1495
|
+
// <link> written inside a string in page code is not mistaken for one.
|
|
1496
|
+
function fragmentCssHrefs(html){
|
|
1497
|
+
var hrefs=[];
|
|
1498
|
+
html.replace(new RegExp('<scr'+'ipt\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/scr'+'ipt>','gi'),'').replace(new RegExp('<link\\\\b([^>]*)>','gi'),function(m,attrs){
|
|
1499
|
+
if(attrs.indexOf('data-css')===-1)return m;
|
|
1500
|
+
var hrefMatch=attrs.match(/\\bhref=(["'])(.*?)\\1/i);
|
|
1501
|
+
if(hrefMatch&&hrefMatch[2])hrefs.push(hrefMatch[2]);
|
|
1502
|
+
return m;
|
|
1503
|
+
});
|
|
1504
|
+
return hrefs;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1414
1507
|
function swap(html,url,pushState,hash){
|
|
1415
1508
|
var fragMark=/^<!--stx-fragment(?: rt=([01]))?-->/.exec(html);
|
|
1416
1509
|
var isFragment=!!fragMark;
|
|
@@ -1431,7 +1524,6 @@ else {
|
|
|
1431
1524
|
location.href=url;
|
|
1432
1525
|
return Promise.resolve(false);
|
|
1433
1526
|
}
|
|
1434
|
-
if(window.stx&&window.stx._cleanupContainer)window.stx._cleanupContainer(currentContent);
|
|
1435
1527
|
function doFragSwap(){
|
|
1436
1528
|
// Extract scripts from fragment before injecting HTML
|
|
1437
1529
|
var fragScripts=[];
|
|
@@ -1508,19 +1600,9 @@ else {
|
|
|
1508
1600
|
document.head.appendChild(cw);
|
|
1509
1601
|
}
|
|
1510
1602
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
document.querySelectorAll('head link[data-css][href]').forEach(function(link){
|
|
1515
|
-
if(new URL(link.getAttribute('href'),location.href).href===absolute)exists=true;
|
|
1516
|
-
});
|
|
1517
|
-
if(exists)return;
|
|
1518
|
-
var link=document.createElement('link');
|
|
1519
|
-
link.setAttribute('data-css','generated');
|
|
1520
|
-
link.setAttribute('rel','stylesheet');
|
|
1521
|
-
link.setAttribute('href',href);
|
|
1522
|
-
document.head.appendChild(link);
|
|
1523
|
-
});
|
|
1603
|
+
// Already present ones are MOVED last, not skipped \u2014 see
|
|
1604
|
+
// promoteGeneratedCss for why their order is the whole bug.
|
|
1605
|
+
promoteGeneratedCss(fragCssHrefs,location.href);
|
|
1524
1606
|
// Add new page styles
|
|
1525
1607
|
fragStyles.forEach(function(s){
|
|
1526
1608
|
var el=document.createElement('style');
|
|
@@ -1639,16 +1721,25 @@ else {
|
|
|
1639
1721
|
if(fragPending.length)Promise.all(fragPending).then(runFragScripts).catch(runFragScripts);
|
|
1640
1722
|
else runFragScripts();
|
|
1641
1723
|
}
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1724
|
+
function startFragSwap(){
|
|
1725
|
+
if(window.stx&&window.stx._cleanupContainer)window.stx._cleanupContainer(currentContent);
|
|
1726
|
+
return new Promise(function(resolve,reject){
|
|
1727
|
+
function completeFragSwap(){
|
|
1728
|
+
try{
|
|
1729
|
+
doFragSwap();
|
|
1730
|
+
resolve(true);
|
|
1731
|
+
}catch(err){reject(err)}
|
|
1732
|
+
}
|
|
1733
|
+
if(runViewTransition(completeFragSwap)){}
|
|
1734
|
+
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)}
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
// A stylesheet this page has never loaded is fetched BEFORE the content
|
|
1738
|
+
// swaps, or the new markup paints once without its utilities and then
|
|
1739
|
+
// jumps. Cleanup waits with it so the outgoing page stays live meanwhile.
|
|
1740
|
+
// With nothing new to load this runs in the same turn, as it always did.
|
|
1741
|
+
var fragCssReady=preloadGeneratedCss(fragmentCssHrefs(html),location.href);
|
|
1742
|
+
return fragCssReady?fragCssReady.then(startFragSwap):startFragSwap();
|
|
1652
1743
|
}
|
|
1653
1744
|
|
|
1654
1745
|
// Full document mode: parse with DOMParser and extract container content
|
|
@@ -1678,10 +1769,13 @@ else {
|
|
|
1678
1769
|
var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');
|
|
1679
1770
|
if(!newContent){location.href=url;return Promise.resolve(false)}
|
|
1680
1771
|
|
|
1681
|
-
//
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1772
|
+
// The destination's generated utility sheets, resolved against the page
|
|
1773
|
+
// being navigated to. Loaded before the swap and moved last during it \u2014
|
|
1774
|
+
// same reasons as the fragment path (promoteGeneratedCss).
|
|
1775
|
+
var docCssBase;
|
|
1776
|
+
try{docCssBase=new URL(url,location.href).href}catch(e){docCssBase=location.href}
|
|
1777
|
+
var docCssHrefs=[];
|
|
1778
|
+
doc.querySelectorAll('head link[data-css][href]').forEach(function(l){docCssHrefs.push(l.getAttribute('href'))});
|
|
1685
1779
|
|
|
1686
1780
|
function doSwap(){
|
|
1687
1781
|
// \u2500\u2500 Swap <head> styles \u2500\u2500
|
|
@@ -1748,6 +1842,9 @@ else {
|
|
|
1748
1842
|
doc.querySelectorAll('head '+linkSel).forEach(function(l){
|
|
1749
1843
|
var href=l.getAttribute('href');
|
|
1750
1844
|
if(!href)return;
|
|
1845
|
+
// Generated utility sheets are not additive-only: promoteGeneratedCss
|
|
1846
|
+
// below also reorders them.
|
|
1847
|
+
if(l.hasAttribute('data-css'))return;
|
|
1751
1848
|
var abs=new URL(href,docBase).href;
|
|
1752
1849
|
if(curLinks[abs])return;
|
|
1753
1850
|
curLinks[abs]=1;
|
|
@@ -1755,6 +1852,9 @@ else {
|
|
|
1755
1852
|
Array.from(l.attributes).forEach(function(a){nl.setAttribute(a.name,a.value)});
|
|
1756
1853
|
document.head.appendChild(nl);
|
|
1757
1854
|
});
|
|
1855
|
+
// After every other stylesheet link, so the destination's complete
|
|
1856
|
+
// utility sheet is last in the cascade.
|
|
1857
|
+
promoteGeneratedCss(docCssHrefs,docBase);
|
|
1758
1858
|
|
|
1759
1859
|
// \u2500\u2500 Swap content \u2500\u2500
|
|
1760
1860
|
// For layout changes: swap the entire <body> to replace layout chrome (nav, footer, etc.)
|
|
@@ -2048,26 +2148,34 @@ else {
|
|
|
2048
2148
|
}
|
|
2049
2149
|
}
|
|
2050
2150
|
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
resolve(true);
|
|
2056
|
-
}catch(err){reject(err)}
|
|
2057
|
-
}
|
|
2058
|
-
if(runViewTransition(completeSwap)){
|
|
2151
|
+
function startSwap(){
|
|
2152
|
+
// Clean up existing signals/effects
|
|
2153
|
+
if(window.stx&&window.stx._cleanupContainer){
|
|
2154
|
+
window.stx._cleanupContainer(currentContent);
|
|
2059
2155
|
}
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
}
|
|
2069
|
-
|
|
2070
|
-
|
|
2156
|
+
return new Promise(function(resolve,reject){
|
|
2157
|
+
function completeSwap(){
|
|
2158
|
+
try{
|
|
2159
|
+
doSwap();
|
|
2160
|
+
resolve(true);
|
|
2161
|
+
}catch(err){reject(err)}
|
|
2162
|
+
}
|
|
2163
|
+
if(runViewTransition(completeSwap)){
|
|
2164
|
+
}
|
|
2165
|
+
else {
|
|
2166
|
+
// Fallback fade for browsers without View Transitions API
|
|
2167
|
+
currentContent.style.transition='opacity 0.12s ease-out';
|
|
2168
|
+
currentContent.style.opacity='0';
|
|
2169
|
+
setTimeout(function(){
|
|
2170
|
+
completeSwap();
|
|
2171
|
+
currentContent.style.opacity='1';
|
|
2172
|
+
setTimeout(function(){currentContent.style.transition=''},150);
|
|
2173
|
+
},120);
|
|
2174
|
+
}
|
|
2175
|
+
});
|
|
2176
|
+
}
|
|
2177
|
+
var docCssReady=preloadGeneratedCss(docCssHrefs,docCssBase);
|
|
2178
|
+
return docCssReady?docCssReady.then(startSwap):startSwap();
|
|
2071
2179
|
}
|
|
2072
2180
|
|
|
2073
2181
|
// \u2500\u2500 Link interception \u2500\u2500
|
package/dist/serve.js
CHANGED
|
@@ -9700,7 +9700,7 @@ function __stxOverlay(errs){
|
|
|
9700
9700
|
pageMiddlewarePatterns.length = 0;
|
|
9701
9701
|
await Promise.all(files.map((f) => detectPageMiddleware(f)));
|
|
9702
9702
|
try {
|
|
9703
|
-
const { Router } = await import("./chunk-
|
|
9703
|
+
const { Router } = await import("./chunk-nb1x6zdk.js");
|
|
9704
9704
|
const pagesDirs = patterns.map((p) => p.replace(/\/$/, "")).filter(Boolean);
|
|
9705
9705
|
const router = new Router(process19.cwd(), { pagesDirs, stateDir: stateDirName() });
|
|
9706
9706
|
if (!options.quiet)
|
package/package.json
CHANGED