@vtbag/element-crossing
Version:
Sites using cross-document view transitions do full page loads of static content on navigation. The element crossing provides a way to preserve current dynamic state of selected elements across cross-document view transitions for a smoother user experienc
2 lines (1 loc) • 4.39 kB
JavaScript
;(()=>{var p=!1,k="/svg",l=top.__vtbag?.elementCrossing;v();function v(){if(l?.fun){if(self===top)return;top.document.title=self.document.title,top.history.replaceState(self.history.state,"",self.location.href),self.crossingStorage=l.fun}document.addEventListener("astro:after-preparation",u),document.addEventListener("astro:after-swap",m),self.addEventListener("onpageswap"in self?"pageswap":"pagehide",u),self.addEventListener("onpagereveal"in self?"pagereveal":"DOMContentLoaded",m)}function u(){self.crossingStorage?self.crossingStorage.setItem("@vtbag/element-crossing",d()):top.sessionStorage.setItem("@vtbag/element-crossing",JSON.stringify(d()))}function m(){let n,a;(a=self.crossingStorage)?n=a.getItem("@vtbag/element-crossing")??[]:(a=top.sessionStorage,n=JSON.parse(a.getItem("@vtbag/element-crossing")??"[]")),top.sessionStorage.removeItem("@vtbag/element-crossing"),self.crossingStorage?.removeItem("@vtbag/element-crossing"),("navigation"in self&&self.navigation?.activation?.navigationType!=="reload"||performance?.navigation?.type!==1)&&y(n)}function d(){let n=new Set,a=[];return self.document.querySelectorAll("[data-vtbag-x]").forEach(s=>{let e=b(s);e&&(n.has(e.id)&&console.error("[crossing]","non unique id",e.id),a.push(e),n.add(e.id))}),p&&console.log("[crossing]","retrieve",a),a}function b(n){function a(r,o){let[t,i]=r.split(":",2);if(!t)return console.error("[crossing]","syntax error:",r,"is not recognized as a valid specification in",o),["<none>",i];if(i===void 0)switch(i=t.slice(1),t[0]){case"#":t="id";break;case".":t="class";break;case"@":t="prop";break;case"-":t="style";break;case"~":t="anim";break;case"&":if(t="elem",l?.fun)break;default:console.error("[crossing]","syntax error:",r,"is not recognized as a valid specification in",o)}return[t,i]}let s=n.id,e=[];if(n.getAttribute("data-vtbag-x")?.trim().split(/\s+/).forEach(r=>{let[o,t]=a(r,n);switch(o){case"id":s=t;break;case"class":e.push({kind:o,key:t,value:n.classList.contains(t)?"true":"false"});break;case"style":e.push({kind:o,key:t,value:""+(n.style[t]??"")});break;case"bool":case"num":case"prop":let i=t.startsWith("data-")?n.dataset[t.substring(5)]:n[t],g=typeof i;e.push({kind:g==="boolean"?"bool":g==="number"?"num":"prop",key:t,value:""+i});break;case"anim":if(t===k){if(!(n instanceof SVGSVGElement)){console.error("[crossing]",`retrieval: element is not an SVG element, but "${t}" was used for its key`,n);break}let c=n.getCurrentTime();c>0&&e.push({kind:o,key:t,value:c.toString()})}else{let c=n.getAnimations().filter(f=>f instanceof CSSAnimation&&f.animationName===t);c.length>1&&console.error("[crossing]",`retrieval: animation name ${t} is not unique for`,n),c.length>0&&e.push({kind:o,key:t,value:""+(c[0].currentTime??0)})}break;case"elem":top?.__vtbag?.elementCrossing?.fun&&(self.crossingStorage.setItem(t,n),e.push({kind:o,key:t}));break;default:console.error("[crossing]","unknown kind",o);break}}),!s)console.error("[crossing]","missing id in",n);else return{id:s,timestamp:new Date().getTime(),specs:e}}function y(n){p&&console.log("[crossing]","restore",n),n.forEach(a=>{let s=document.querySelector("#"+a.id+",[data-vtbag-x*='#"+a.id+"'],[data-vtbag-x*='id:"+a.id+"']");s&&a.specs.forEach(e=>{switch(e.kind){case"class":s.classList[e.value==="true"?"add":"remove"](e.key);break;case"style":e.key==="length"||e.key==="parentRule"?console.error("[crossing]","Cannot assign to read-only property",e.key,"in",a.id):s.style.setProperty(e.key,e.value??"");break;case"prop":e.key.startsWith("data-")?s.dataset[e.key.substring(5)]=e.value:s[e.key]=e.value;break;case"bool":s[e.key]=e.value==="true";break;case"num":s[e.key]=parseFloat(e.value??"0");break;case"anim":if(e.key===k){if(!(s instanceof SVGSVGElement)){console.error("[crossing]",`restore: element for key ${e.key} is not an SVG element`,s);break}s.setCurrentTime(parseFloat(e.value??"0")+(new Date().getTime()-a.timestamp)/1e3)}else{let o=s.getAnimations().filter(t=>t instanceof CSSAnimation&&t.animationName===e.key);o.length>1&&console.warn("[crossing]",`restore: animation name ${e.key} is not unique for`,s),o.forEach(t=>t.currentTime=~~(e.value??"0")+(new Date().getTime()-a.timestamp))}break;case"elem":if(top?.__vtbag?.elementCrossing?.fun){let o=self.crossingStorage.getItem(e.key);o&&(s.replaceWith(o),s=o)}break;default:console.error("[crossing]","unknown kind",e.kind);break}})})}})();