stx-router 0.2.313 → 0.2.314

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 +44 -18
  2. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -1037,7 +1037,7 @@ else {
1037
1037
  // Remove old page scripts
1038
1038
  document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});
1039
1039
  if(pushState!==false)writeHistory(pushState,url+(hash||''));
1040
- updateNav(url);
1040
+ updateNav();
1041
1041
  updateActiveLinks();
1042
1042
  if(o.scrollToTop&&!hash)window.scrollTo({top:0,behavior:'instant'});
1043
1043
  else if(hash){var el=document.querySelector(hash);if(el)el.scrollIntoView({behavior:'smooth'})}
@@ -1474,7 +1474,7 @@ else {
1474
1474
  if(pushState!==false)writeHistory(pushState,url+(hash||''));
1475
1475
 
1476
1476
  // Update active nav links
1477
- updateNav(url);
1477
+ updateNav();
1478
1478
  updateActiveLinks();
1479
1479
 
1480
1480
  // Scroll
@@ -1871,33 +1871,59 @@ else {
1871
1871
  }
1872
1872
 
1873
1873
  // \u2500\u2500 Active link management \u2500\u2500
1874
- function updateNav(url){
1874
+ // Which links point at the page being shown. Every href is resolved against
1875
+ // the current URL first, because comparing the raw attribute with
1876
+ // location.pathname got most real links wrong:
1877
+ // - a query-only href (?range=24h, the shape of every range picker and tab
1878
+ // bar) never equalled a pathname, so the active one lost its classes and
1879
+ // had the server's aria-current="page" stripped on every load;
1880
+ // - /dashboard?site=1 was never an exact match for /dashboard;
1881
+ // - http://same-origin/x and /x/ were never matches for /x;
1882
+ // - /blog was "active" on /blogging, a prefix that is not a parent.
1883
+ // Null for links the router does not own (another origin, a bare #fragment,
1884
+ // anything unparseable), which are left exactly as the server rendered them.
1885
+ function normPath(p){return p.length>1&&p.charAt(p.length-1)==='/'?p.slice(0,-1):p}
1886
+ function linkState(href){
1887
+ if(!href||href.charAt(0)==='#')return null;
1888
+ var u;
1889
+ try{u=new URL(href,location.href)}catch(e){return null}
1890
+ if(u.origin!==location.origin)return null;
1891
+ var path=normPath(u.pathname),cur=normPath(location.pathname);
1892
+ // A link with no query matches on its path, so a nav entry stays current
1893
+ // while the page adds filters. A link WITH a query is current only when
1894
+ // every param it names has that value here: of five range links that all
1895
+ // point at this path, exactly one is.
1896
+ var have=new URLSearchParams(location.search),q=true;
1897
+ u.searchParams.forEach(function(v,k){if(have.getAll(k).indexOf(v)===-1)q=false});
1898
+ return {
1899
+ exact:q&&path===cur,
1900
+ active:q&&(path==='/'?cur==='/':(cur===path||cur.indexOf(path+'/')===0))
1901
+ };
1902
+ }
1903
+
1904
+ function updateNav(){
1875
1905
  document.querySelectorAll('nav a[href], #mobileNav a[href], [data-stx-nav] a[href]').forEach(function(a){
1876
- var href=a.getAttribute('href');
1877
- if(!href||href.startsWith('#')||href.startsWith('http'))return;
1878
- var isActive=(href===url)||(href==='/'&&url==='/');
1879
- if(a.hasAttribute('data-stx-link')){
1880
- var ac=a.getAttribute('data-stx-active-class')||'active';
1881
- if(isActive)ac.split(' ').forEach(function(cls){if(cls)a.classList.add(cls)});else ac.split(' ').forEach(function(cls){if(cls)a.classList.remove(cls)});
1882
- }
1906
+ if(!a.hasAttribute('data-stx-link'))return;
1907
+ var st=linkState(a.getAttribute('href'));
1908
+ if(!st)return;
1909
+ var ac=a.getAttribute('data-stx-active-class')||'active';
1910
+ if(st.exact)ac.split(' ').forEach(function(cls){if(cls)a.classList.add(cls)});else ac.split(' ').forEach(function(cls){if(cls)a.classList.remove(cls)});
1883
1911
  });
1884
1912
  }
1885
1913
 
1886
1914
  function updateActiveLinks(){
1887
1915
  // Update active classes on <stx-link> elements (and legacy data-stx-link)
1888
1916
  var links=document.querySelectorAll('[data-stx-link]');
1889
- var cur=location.pathname;
1890
1917
  links.forEach(function(link){
1891
- var href=link.getAttribute('to')||link.getAttribute('href')||'';
1918
+ var st=linkState(link.getAttribute('to')||link.getAttribute('href')||'');
1919
+ if(!st)return;
1892
1920
  var ac=link.getAttribute('active-class')||link.getAttribute('data-stx-active-class')||'active';
1893
1921
  var eac=link.getAttribute('exact-active-class')||link.getAttribute('data-stx-exact-active-class')||'exact-active';
1894
1922
  ac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});
1895
1923
  eac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});
1896
- var isExact=cur===href;
1897
- var isActive=href!=='/'?cur.startsWith(href):cur==='/';
1898
- if(isExact)eac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});
1899
- if(isActive)ac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});
1900
- markCurrent(link,isExact);
1924
+ if(st.exact)eac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});
1925
+ if(st.active)ac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});
1926
+ markCurrent(link,st.exact);
1901
1927
  });
1902
1928
  }
1903
1929
 
@@ -2021,7 +2047,7 @@ else {
2021
2047
  injectStyles();
2022
2048
  injectViewTransitionCSS();
2023
2049
  updateActiveLinks();
2024
- updateNav(location.pathname);
2050
+ updateNav();
2025
2051
  }
2026
2052
 
2027
2053
  if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "stx-router",
3
3
  "type": "module",
4
- "version": "0.2.313",
4
+ "version": "0.2.314",
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",