shopic 0.1.3 → 0.1.5
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/index.js +1 -1
- package/package.json +15 -16
- package/dist/index.js.map +0 -7
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";(()=>{var tt=new Map,h=(t,o)=>{if(tt.has(t))throw new Error(`[shopic] Animation "${t}" is registered twice.`);tt.set(t,o)},et=(t,o=document)=>{let a=o.querySelectorAll("[data-anim]");for(let n of a){let e=n.dataset.anim;if(!e||n.dataset.animState==="ready")continue;let s=tt.get(e);if(!s){console.warn(`[shopic] No animation registered for data-anim="${e}".`,n);continue}n.dataset.animState="ready",s(n,t)}};var Mt=2,It=150,Ht=4,Ot=1,Ct=5e3,Rt=.75,_t="power3.out",Nt=[0,.25,.5,.6,.7,.8,.9,1],nt="shopic:slide-enter";h("carousel",(t,{gsap:o,reducedMotion:a})=>{let n=Array.from(t.querySelectorAll(":scope > [data-slide]"));if(n.length<2)return;let e=t.closest("section")??t.parentElement??document.body,s=Array.from(e.querySelectorAll("[data-tab]")),r=a?0:Rt,d=n.length,l=new Map(n.map((i,y)=>[i,y])),f=new Map;n.forEach((i,y)=>{let T=i.dataset.slide;T&&!f.has(T)&&f.set(T,y)});let m=[],S=()=>{let i=t.getBoundingClientRect().left,y=t.scrollLeft,T=parseFloat(getComputedStyle(t).paddingLeft)||0,I=t.scrollWidth-t.clientWidth;m=n.map(V=>Math.min(V.getBoundingClientRect().left-i+y-T,I))},L=i=>{for(let y of s){let T=y.dataset.tab===i;y.classList.toggle("is-active",T),T?y.setAttribute("aria-current","true"):y.removeAttribute("aria-current")}},H=-1,x=null,E=!1,u=!1,g,b,v=null,A=0,N=0,C=0,O=0,R=!1,X=()=>v!==null,B=()=>x!==null,_=()=>{clearTimeout(g),g=void 0},W=()=>!a&&!document.hidden&&u&&!X()&&!E&&!e.contains(document.activeElement),P=()=>{_(),W()&&(g=setTimeout(()=>{g=void 0,W()&&q((H+1)%d)},Ct))},K=i=>{let y=n[i],T=y.dataset.slide;if(T&&L(T),i!==H){H=i;for(let I of n)I.classList.toggle("is-current",I===y);y.dispatchEvent(new CustomEvent(nt))}},k=i=>{x=null,K(i),P()},U=()=>{clearTimeout(b),o.killTweensOf(t),x=null};function q(i){if(U(),x=i,r===0){t.scrollLeft=m[i],k(i);return}o.to(t,{scrollLeft:m[i],duration:r,ease:_t,overwrite:"auto",onComplete:()=>k(i),onInterrupt:()=>{x=null}})}let Z=()=>{let i=t.scrollLeft,y=0;return m.forEach((T,I)=>{Math.abs(T-i)<Math.abs(m[y]-i)&&(y=I)}),y},$=()=>{let i=Z();Math.abs(m[i]-t.scrollLeft)<Ot?k(i):q(i)},c=()=>{let i=A>0?m[A]-m[A-1]:1/0,y=A<d-1?m[A+1]-m[A]:1/0,T=Math.min(Math.abs(i),Math.abs(y));if(Math.abs(O)<T*.25){$();return}q((A+Math.sign(O)+d)%d)};for(let i of s)i.addEventListener("click",y=>{y.preventDefault();let T=i.dataset.tab??"",I=f.get(T);I!==void 0&&(_(),L(T),q(I))});let p=new Array(d).fill(0),w=new IntersectionObserver(i=>{for(let I of i){let V=l.get(I.target);V!==void 0&&(p[V]=I.isIntersecting?I.intersectionRatio:0)}let y=-1,T=0;p.forEach((I,V)=>{I<=T||(T=I,y=V)}),y!==-1&&(x!==null&&y!==x||K(y))},{root:t,threshold:Nt});for(let i of n)w.observe(i);S(),t.style.scrollSnapType="none",t.style.touchAction="pan-y",t.addEventListener("dragstart",i=>i.preventDefault());let[M]=m;t.scrollLeft=M;let D=new ResizeObserver(S);D.observe(t);for(let i of n)D.observe(i);"onscrollend"in window?t.addEventListener("scrollend",()=>{!B()&&!X()&&$()}):t.addEventListener("scroll",()=>{B()||X()||(clearTimeout(b),b=setTimeout($,It))}),t.addEventListener("pointerdown",i=>{_(),U(),v=i.pointerId,R=!1,N=i.clientX,C=t.scrollLeft,O=0,A=Z()}),t.addEventListener("pointermove",i=>{if(i.pointerId!==v)return;let y=i.clientX-N;if(!R){if(Math.abs(y)<Ht)return;R=!0,t.classList.add("is-dragging"),t.setPointerCapture(i.pointerId)}O=-y*Mt,t.scrollLeft=C+O,i.pointerType==="mouse"&&i.preventDefault()});let F=i=>{i.pointerId===v&&(v=null,t.hasPointerCapture(i.pointerId)&&t.releasePointerCapture(i.pointerId),R?(t.classList.remove("is-dragging"),c()):$())};window.addEventListener("pointerup",F),window.addEventListener("pointercancel",F),t.addEventListener("click",i=>{R&&(R=!1,i.preventDefault(),i.stopPropagation())},!0),e.addEventListener("pointerenter",i=>{i.pointerType==="mouse"&&(E=!0,_())}),e.addEventListener("pointerleave",i=>{i.pointerType==="mouse"&&(E=!1,P())}),e.addEventListener("focusin",_),e.addEventListener("focusout",()=>queueMicrotask(P)),document.addEventListener("visibilitychange",()=>{document.hidden?_():P()}),new IntersectionObserver(i=>{u=i.some(y=>y.isIntersecting),u?P():_()},{threshold:.2}).observe(t)});var it="!<>-_\\/[]{}=+*^?#$%01",j=new WeakMap,G=(t,{duration:o=1050,stagger:a=.75,text:n,reducedMotion:e=!1,relaunchOnHover:s=!1}={})=>{if(e){n!==void 0&&(t.textContent=n);return}if(n!==void 0)t.dataset.scrambleText=n;else if(!t.dataset.scrambleText){let E=t.textContent;if(!E||!E.trim())return;t.dataset.scrambleText=E}let r=t.dataset.scrambleText;if(!r||!r.trim())return;let d=Array.from(r),l=d.length,f=Array.from(t.children),m;f.length===l&&f.every(E=>E.tagName==="SPAN")?m=f:(m=d.map(E=>{let u=document.createElement("span");return u.textContent=E,u}),t.textContent="",t.append(...m));let S=Symbol("scramble");j.set(t,S);let L=d.map((E,u)=>l<=1?0:u/(l-1)*o*a),H=performance.now(),x=E=>{if(j.get(t)!==S)return;let u=E-H,g=!0;d.forEach((b,v)=>{if(b===" "){m[v].textContent=" ";return}u>=L[v]?m[v].textContent=b:(g=!1,m[v].textContent=it[Math.random()*it.length|0])}),g?j.delete(t):requestAnimationFrame(x)};requestAnimationFrame(x),s&&Pt(t,{duration:o,stagger:a})},Pt=(t,o)=>{t.dataset.scrambleHoverBound||(t.dataset.scrambleHoverBound="true",t.addEventListener("pointerenter",()=>{j.has(t)||G(t,o)}))};var qt=.5,$t="power2.out",Dt=".status-pill, .evidence_label, .evidence_sku",Ft={duration:630,stagger:.6,relaunchOnHover:!0};h("evidence",(t,{gsap:o,reducedMotion:a})=>{let n=Array.from(t.children);if(!n.length)return;if(a){for(let l of n)l.style.height="auto",l.style.opacity="1";return}let e=()=>{o.killTweensOf(n),o.set(n,{height:0,opacity:0,overflow:"hidden"});let l=o.timeline();for(let f of n)l.call(()=>{for(let m of f.querySelectorAll(Dt))G(m,Ft)}),l.to(f,{height:"auto",opacity:1,duration:qt,ease:$t,onComplete:()=>o.set(f,{height:"auto"})})},s=!1,r=!1,d=()=>{if(!s||r)return;let l=t.closest("[data-slide]");l&&!l.classList.contains("is-current")||(r=!0,e())};if("IntersectionObserver"in window){let l=new IntersectionObserver(f=>{for(let m of f)m.isIntersecting&&(s=!0,d(),r&&l.disconnect())},{threshold:.2});l.observe(t)}else s=!0,d();t.closest("[data-slide]")?.addEventListener(nt,()=>{r=!1,d()})});var at="is-open",lt=".faq_row",ct=".faq_toggle";h("faq",t=>{let o=t.querySelectorAll(lt);if(o.length===0){console.warn(`[shopic] faq found no ${lt} to open.`,t);return}let a=[];for(let s of o){let r=s.querySelector(ct);if(!r){console.warn(`[shopic] faq row has no ${ct} to click.`,s);continue}a.push({row:s,toggle:r})}if(a.length===0)return;let n=s=>{for(let{row:r,toggle:d}of a){let l=r===s;r.classList.toggle(at,l),d.setAttribute("aria-expanded",String(l))}};for(let{row:s,toggle:r}of a)r.addEventListener("click",()=>{n(s.classList.contains(at)?null:s)}),r.addEventListener("keydown",d=>{d.key!=="Enter"&&d.key!==" "||(d.preventDefault(),r.click())}),r.hasAttribute("tabindex")||(r.tabIndex=0);let e=a.find(({toggle:s})=>s.getAttribute("aria-expanded")==="true");n((e??a[0]).row)});var dt=8;h("focus-drift",(t,{reducedMotion:o})=>{let a=t.querySelector(":scope > .camera_focus");!a||o||(t.addEventListener("pointermove",n=>{if(n.pointerType!=="mouse")return;let e=t.getBoundingClientRect(),s=(n.clientX-e.left)/e.width-.5,r=(n.clientY-e.top)/e.height-.5,d=(s*dt*2).toFixed(1),l=(r*dt*2).toFixed(1);a.style.transform=`translate(${d}px, ${l}px)`}),t.addEventListener("pointerleave",()=>{a.style.transform=""}))});var ut=42,ft=96,Vt=2600,Gt="is-scanned",Xt="is-fresh";h("foundation-rail",(t,{gsap:o,reducedMotion:a})=>{let n=t.closest(".camera_photo"),e=Array.from(t.querySelectorAll(":scope > .foundation_slot"),u=>({element:u,parts:Array.from(u.querySelectorAll(".foundation_photo, .foundation_card")),tile:u.querySelector(".foundation_scan"),setX:o.quickSetter(u,"x","px"),home:0,turn:0,state:null}));if(!n||e.length===0){console.warn("[shopic] foundation-rail expects a .camera_photo tile around a track of .foundation_slot items.",t);return}let s=o.quickSetter(t,"x","px"),r=0,d=0,l=u=>u,f=()=>{let[u]=e,g=u.element.offsetWidth,b=g+(parseFloat(getComputedStyle(t).columnGap)||0);r=b*e.length,d=r/ut*(Vt/1e3),l=o.utils.wrap(-r/2,r/2),r<n.offsetWidth+g&&console.warn(`[shopic] foundation-rail: ${e.length} slots span ${r}px but the tile needs ${n.offsetWidth+g}px to loop without a gap.`,t);let v=n.getBoundingClientRect(),A=v.width/n.offsetWidth||1,N=(u.element.getBoundingClientRect().left-v.left)/A+g/2-n.offsetWidth/2-(Number(o.getProperty(t,"x"))||0)-(Number(o.getProperty(u.element,"x"))||0);e.forEach((C,O)=>{C.home=N+O*b,C.setX(C.turn*r)})},m=u=>u>ft?"unseen":u>ft-d?"fresh":"seen",S=(u,g)=>{if(u.state!==g){u.state=g;for(let b of u.parts)b.classList.toggle(Gt,g!=="unseen");u.tile?.classList.toggle(Xt,g==="fresh")}},L=u=>{if(r){s(-u);for(let g of e){let b=l(g.home-u),v=Math.round((b-(g.home-u))/r);v!==g.turn&&(g.turn=v,g.setX(v*r)),S(g,m(b))}}},H={t:0},x=()=>H.t*r,E=a?null:o.to(H,{t:1,duration:ut,ease:"none",repeat:-1,paused:!0,onUpdate:()=>L(x())});new ResizeObserver(()=>{f(),L(x())}).observe(t),E&&new IntersectionObserver(u=>{E.paused(!u.some(g=>g.isIntersecting))}).observe(t)});var mt="split_line",Bt="split_word",pt="split_word-inner",Wt=t=>{let o=document.createDocumentFragment(),a=[],n=document.createElement("span");n.className=mt,o.appendChild(n);let e=(r,d)=>{if(!r)return;let l=document.createElement("span");l.className=Bt;let f=document.createElement("span");f.className=d?`${pt} ${d}`:pt,f.textContent=r,l.appendChild(f),n.appendChild(l),a.push(f)},s=(r,d)=>{for(let l of r.split(/(\s+)/))l&&(/^\s+$/.test(l)?n.appendChild(document.createTextNode(" ")):e(l,d))};for(let r of Array.from(t.childNodes))r.nodeType===Node.TEXT_NODE?s(r.textContent??""):r instanceof HTMLBRElement?(n=document.createElement("span"),n.className=mt,o.appendChild(n)):r instanceof HTMLElement&&s(r.textContent??"",r.className||void 0);return t.textContent="",t.appendChild(o),a},gt={yPercent:0,duration:.9,ease:"power4.out",stagger:.035};h("headline",(t,{gsap:o,ScrollTrigger:a,reducedMotion:n})=>{if(n){t.style.visibility="visible";return}let e=Wt(t);if(o.set(e,{yPercent:110}),t.style.visibility="visible",t.dataset.animTrigger==="load"||!a){o.to(e,{...gt,delay:.3});return}o.to(e,{...gt,scrollTrigger:{trigger:t,start:"top 85%"}})});var kt=26;h("marquee",(t,{gsap:o,reducedMotion:a})=>{if(a)return;let n=Number(t.dataset.animSets??4),e=Number(t.dataset.animDuration??kt);if(!Number.isFinite(n)||n<2)return;let s=()=>t.scrollWidth/n,r=o.to(t,{x:()=>-s(),duration:e,ease:"none",repeat:-1,modifiers:{x:l=>`${Number.parseFloat(l)%s()}px`}}),d=t.parentElement;d&&(d.addEventListener("pointerenter",()=>r.pause()),d.addEventListener("pointerleave",()=>r.resume()))});var ot=1.15,yt=.18,J=8,z=.55,ht="is-visible",Et="opacity, width, height",Ut=["name","price","packaging","sku"];h("photo-hover",(t,{reducedMotion:o})=>{let a=t.querySelector(":scope > img"),n=t.querySelector(":scope > .detect_layer"),e=t.querySelector(":scope > .camera_focus");if(!a&&!e)return;let s=e?.querySelector(".is-ring")??null,r=e?.querySelector(".is-corners")??null;e&&(!s||!r)&&console.warn("[shopic] photo-hover expects is-ring and is-corners layers inside the reticle.",e);let d=Array.from(t.querySelectorAll(".detect_box")),l=t.querySelector('[data-match="card"]'),f=l?.querySelector('[data-match="thumb"]')??null,m=0,S=0,L=0,H=0,x=0,E=0,u=0,g=null,b=c=>c.width/t.offsetWidth||1,v=(c,p)=>{let w=t.getBoundingClientRect(),M=b(w);return{x:(c-w.left)/M,y:(p-w.top)/M,width:t.offsetWidth,height:t.offsetHeight}},A=c=>{let p=t.getBoundingClientRect(),w=c.getBoundingClientRect(),M=b(p);return{x:(w.left-p.left)/M-J,y:(w.top-p.top)/M-J,w:w.width/M+J*2,h:w.height/M+J*2}},N=()=>{let{x:c,y:p,width:w,height:M}=v(E,u),D=(c/w-.5)*w*(ot-1),F=(p/M-.5)*M*(ot-1),Y=`translate(${D.toFixed(2)}px, ${F.toFixed(2)}px) scale(${ot})`;a&&(a.style.transform=Y),n&&(n.style.transform=Y)},C=()=>{let{x:c,y:p}=v(E,u);return{x:c-(e?.offsetWidth??0)/2,y:p-(e?.offsetHeight??0)/2}},O=(c,p)=>{e&&(e.style.left=`${c.toFixed(2)}px`,e.style.top=`${p.toFixed(2)}px`)},R=()=>{let c=C();O(c.x,c.y),H=c.x,x=c.y,S=0,L=0,r&&(r.style.transform="")},X=()=>{let c=C();O(c.x,c.y),o||(S-=c.x-H,L-=c.y-x),H=c.x,x=c.y},B=c=>{if(!e)return;let p=A(c);O(p.x,p.y),e.style.width=`${p.w.toFixed(2)}px`,e.style.height=`${p.h.toFixed(2)}px`},_=()=>{if(r){if(S-=S*yt,L-=L*yt,Math.abs(S)>.1||Math.abs(L)>.1){r.style.transform=`translate(${S.toFixed(2)}px, ${L.toFixed(2)}px)`;return}S=0,L=0,r.style.transform=""}},W=()=>{g?B(g):X(),_(),m=requestAnimationFrame(W)},P=c=>{if(l){for(let p of Ut){let w=c.dataset[p],M=l.querySelector(`[data-match="${p}"]`);M&&w!==void 0&&(M.textContent=w)}if(f){let p=c.dataset.thumb;p&&(f.removeAttribute("srcset"),f.removeAttribute("sizes"),f.src=p),f.style.display=p?"":"none"}l.classList.add(ht)}},K=c=>{if(g=c,P(c),!!e&&(e.style.transitionProperty="",B(c),r&&(r.style.opacity="0"),s)){let p=(1-z)/2*100;s.style.width=`${z*100}%`,s.style.height=`${z*100}%`,s.style.left=`${p}%`,s.style.top=`${p}%`,s.style.right="auto",s.style.bottom="auto"}},k=c=>{if(!s)return;let p=A(c),{x:w,y:M}=v(E,u),D=(w-p.x)/p.w-.5,F=(M-p.y)/p.h-.5,Y=D*p.w*(1-z),i=F*p.h*(1-z);s.style.setProperty("translate",`${Y.toFixed(2)}px ${i.toFixed(2)}px`)},U=()=>{g=null,l?.classList.remove(ht),e&&(e.style.width="",e.style.height="",e.style.transitionProperty=Et,r&&(r.style.opacity=""),s&&(s.style.width="",s.style.height="",s.style.left="",s.style.top="",s.style.right="",s.style.bottom="",s.style.removeProperty("translate")))},q=c=>{c.pointerType==="mouse"&&(E=c.clientX,u=c.clientY,N(),e&&(e.style.transitionProperty=Et,R(),cancelAnimationFrame(m),m=requestAnimationFrame(W)))},Z=c=>{c.pointerType==="mouse"&&(E=c.clientX,u=c.clientY,N())},$=()=>{cancelAnimationFrame(m),m=0,a&&(a.style.transform=""),n&&(n.style.transform=""),U(),e&&(e.style.left="",e.style.top="",e.style.transitionProperty="",r&&(r.style.transform=""),S=0,L=0)};t.addEventListener("pointerenter",q),t.addEventListener("pointermove",Z),t.addEventListener("pointerleave",$);for(let c of d)c.addEventListener("pointerenter",p=>{p.pointerType==="mouse"&&K(c)}),c.addEventListener("pointermove",()=>{g===c&&k(c)}),c.addEventListener("pointerleave",()=>{g===c&&(U(),R())})});var bt="is-visible";h("reveal",(t,{reducedMotion:o})=>{let a=Number(t.dataset.animDelay??0);if(a&&(t.style.transitionDelay=`${a}ms`),o||!("IntersectionObserver"in window)){t.classList.add(bt);return}let n=new IntersectionObserver(e=>{for(let s of e)s.isIntersecting&&(s.target.classList.add(bt),n.unobserve(s.target))},{threshold:.15});n.observe(t)});h("scramble",(t,{reducedMotion:o})=>{let a={duration:Number(t.dataset.animDuration??1050),stagger:Number(t.dataset.animStagger??.75),reducedMotion:o};if(o||!("IntersectionObserver"in window)){G(t,a);return}let n=new IntersectionObserver(e=>{for(let s of e)s.isIntersecting&&(G(t,{...a,relaunchOnHover:!0}),n.unobserve(s.target))},{threshold:.2});n.observe(t)});var Q=({grouped:t=!1,prefix:o="",suffix:a="",value:n})=>{let e=Math.round(n),s=t?e.toLocaleString("en-US"):String(e);return`${o}${s}${a}`};var Yt=.5,vt="power4.out",zt=.18,Kt="power2.in",Zt=.35,jt=1400,Jt=.15,Qt=420,te=t=>{let o=t.querySelector("[data-stat-value]");return o||console.warn("[shopic] stats row is missing [data-stat-value]",t),o},rt=t=>({grouped:(t.dataset.statGrouped??t.closest('[data-anim="stats"]')?.dataset.statGrouped)==="true",prefix:t.dataset.statPrefix??t.closest('[data-anim="stats"]')?.dataset.statPrefix??"",suffix:t.dataset.statSuffix??t.closest('[data-anim="stats"]')?.dataset.statSuffix??""}),St=(t,o)=>{t.textContent=Q({...rt(t),value:o})},Tt=(t,o)=>{t.classList.toggle("is-hovered",o);for(let a of t.querySelectorAll("[data-stat-label], [data-stat-hover]"))a.classList.toggle("is-hovered",o)},Lt=(t,o,a,n)=>{if(a){St(t,o);return}let e=performance.now(),s=r=>{if(n!==Number(t.dataset.statsGeneration))return;let d=Math.min((r-e)/jt,1),l=1-(1-d)**3;t.textContent=Q({...rt(t),value:o*l}),d<1&&requestAnimationFrame(s)};requestAnimationFrame(s)},ee=(t,{gsap:o,reducedMotion:a})=>{let n=t,e=te(n);if(!e)return;let s=n.dataset.statCount??e.dataset.statCount,r=s===void 0?null:Number(s),d=n.dataset.statTicker??e.dataset.statTicker,l=d===void 0?null:Number(d),f=null,m=0,S=!1,L=()=>{l!==null&&(e.textContent=Q({...rt(e),value:l}))},H=()=>{a||l===null||f!==null||(f=setInterval(()=>{l!==null&&(l+=1+Math.floor(Math.random()*3),L())},Qt))},x=()=>{f!==null&&(clearInterval(f),f=null)},E=()=>{m+=1,e.dataset.statsGeneration=String(m),r!==null?St(e,r):L(),o.set(e,{clearProps:"transform"})},u=b=>{m+=1,e.dataset.statsGeneration=String(m),o.killTweensOf(e),o.set(e,{yPercent:110}),o.to(e,{duration:Yt,ease:vt,yPercent:0}),b&&r!==null&&Lt(e,r,a,m)};if(a){E();return}L(),o.set(e,{yPercent:110});let g=()=>{S||(S=!0,u(!0))};if("IntersectionObserver"in window){let b=new IntersectionObserver(v=>{v.some(A=>A.isIntersecting)&&(g(),b.disconnect())},{threshold:Jt});b.observe(n)}else g();l!==null&&("IntersectionObserver"in window?new IntersectionObserver(v=>{v.some(A=>A.isIntersecting)?H():x()}).observe(n):H()),n.addEventListener("pointerenter",b=>{b.pointerType==="mouse"&&(Tt(n,!0),m+=1,e.dataset.statsGeneration=String(m),o.killTweensOf(e),o.timeline().to(e,{duration:zt,ease:Kt,yPercent:-110}).set(e,{yPercent:110}).to(e,{duration:Zt,ease:vt,onStart:()=>{r!==null&&Lt(e,r,a,m)},yPercent:0}))}),n.addEventListener("pointerleave",()=>Tt(n,!1))};h("stats",ee);var st=t=>String(t).padStart(2,"0");h("timer",t=>{let o=()=>{let a=new Date;t.textContent=`${st(a.getHours())}:${st(a.getMinutes())}:${st(a.getSeconds())}`};o(),setInterval(o,1e3)});var xt="is-active",ne="(max-width: 991px)";h("versus-tabs",t=>{let o=Array.from(t.querySelectorAll('[role="tab"]')),a=t.nextElementSibling,n=a?Array.from(a.querySelectorAll(":scope > *")):[];if(o.length===0||o.length!==n.length){console.warn(`[shopic] versus-tabs expects one tab per panel; found ${o.length} tabs and ${n.length} panels.`,t);return}let e=window.matchMedia(ne),s=d=>{o.forEach((l,f)=>{l.classList.toggle(xt,f===d),l.setAttribute("aria-selected",String(f===d))}),n.forEach((l,f)=>{l.hidden=e.matches&&f!==d})},r=()=>Math.max(0,o.indexOf(t.querySelector(`.${xt}`)));o.forEach((d,l)=>{d.addEventListener("click",()=>s(l)),d.addEventListener("keydown",f=>{(f.key==="Enter"||f.key===" ")&&(f.preventDefault(),s(l))}),d.hasAttribute("tabindex")||(d.tabIndex=0)}),e.addEventListener("change",()=>s(r())),s(r())});var wt=()=>{let{gsap:t,ScrollTrigger:o}=window;if(!t)throw new Error("[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.");return o&&t.registerPlugin(o),{gsap:t,ScrollTrigger:o}},At=()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{let{gsap:t,ScrollTrigger:o}=wt();et({gsap:t,ScrollTrigger:o,reducedMotion:At()})});})();
|
|
1
|
+
"use strict";(()=>{var tt=new Map,h=(t,o)=>{if(tt.has(t))throw new Error(`[shopic] Animation "${t}" is registered twice.`);tt.set(t,o)},et=(t,o=document)=>{let a=o.querySelectorAll("[data-anim]");for(let n of a){let e=n.dataset.anim;if(!e||n.dataset.animState==="ready")continue;let s=tt.get(e);if(!s){console.warn(`[shopic] No animation registered for data-anim="${e}".`,n);continue}n.dataset.animState="ready",s(n,t)}};var Mt=2,It=150,Ht=4,Ot=1,Rt=5e3,Ct=.75,_t="power3.out",Nt=[0,.25,.5,.6,.7,.8,.9,1],nt="shopic:slide-enter";h("carousel",(t,{gsap:o,reducedMotion:a})=>{let n=Array.from(t.querySelectorAll(":scope > [data-slide]"));if(n.length<2)return;let e=t.closest("section")??t.parentElement??document.body,s=Array.from(e.querySelectorAll("[data-tab]")),r=a?0:Ct,d=n.length,c=new Map(n.map((i,m)=>[i,m])),g=new Map;n.forEach((i,m)=>{let v=i.dataset.slide;v&&!g.has(v)&&g.set(v,m)});let y=[],O=()=>{let i=t.getBoundingClientRect().left,m=t.scrollLeft,v=parseFloat(getComputedStyle(t).paddingLeft)||0,M=t.scrollWidth-t.clientWidth;y=n.map(G=>Math.min(G.getBoundingClientRect().left-i+m-v,M))},w=i=>{for(let m of s){let v=m.dataset.tab===i;m.classList.toggle("is-active",v),v?m.setAttribute("aria-current","true"):m.removeAttribute("aria-current")}},E=-1,T=null,S=!1,u=!1,p,L,b=null,I=0,H=0,C=0,R=0,N=!1,q=()=>b!==null,D=()=>T!==null,_=()=>{clearTimeout(p),p=void 0},B=()=>!a&&!document.hidden&&u&&!q()&&!S&&!e.contains(document.activeElement),P=()=>{_(),B()&&(p=setTimeout(()=>{p=void 0,B()&&V((E+1)%d)},Rt))},W=i=>{let m=n[i],v=m.dataset.slide;if(v&&w(v),i!==E){E=i;for(let M of n)M.classList.toggle("is-current",M===m);m.dispatchEvent(new CustomEvent(nt))}},F=i=>{T=null,W(i),P()},U=()=>{clearTimeout(L),o.killTweensOf(t),T=null};function V(i){if(U(),T=i,r===0){t.scrollLeft=y[i],F(i);return}o.to(t,{scrollLeft:y[i],duration:r,ease:_t,overwrite:"auto",onComplete:()=>F(i),onInterrupt:()=>{T=null}})}let Y=()=>{let i=t.scrollLeft,m=0;return y.forEach((v,M)=>{Math.abs(v-i)<Math.abs(y[m]-i)&&(m=M)}),m},$=()=>{let i=Y();Math.abs(y[i]-t.scrollLeft)<Ot?F(i):V(i)},J=()=>{let i=I>0?y[I]-y[I-1]:1/0,m=I<d-1?y[I+1]-y[I]:1/0,v=Math.min(Math.abs(i),Math.abs(m));if(Math.abs(R)<v*.25){$();return}V((I+Math.sign(R)+d)%d)};for(let i of s)i.addEventListener("click",m=>{m.preventDefault();let v=i.dataset.tab??"",M=g.get(v);M!==void 0&&(_(),w(v),V(M))});let z=new Array(d).fill(0),Q=new IntersectionObserver(i=>{for(let M of i){let G=c.get(M.target);G!==void 0&&(z[G]=M.isIntersecting?M.intersectionRatio:0)}let m=-1,v=0;z.forEach((M,G)=>{M<=v||(v=M,m=G)}),m!==-1&&(T!==null&&m!==T||W(m))},{root:t,threshold:Nt});for(let i of n)Q.observe(i);O(),t.style.scrollSnapType="none",t.style.touchAction="pan-y",t.addEventListener("dragstart",i=>i.preventDefault());let[l]=y;t.scrollLeft=l;let f=new ResizeObserver(O);f.observe(t);for(let i of n)f.observe(i);"onscrollend"in window?t.addEventListener("scrollend",()=>{!D()&&!q()&&$()}):t.addEventListener("scroll",()=>{D()||q()||(clearTimeout(L),L=setTimeout($,It))}),t.addEventListener("pointerdown",i=>{_(),U(),b=i.pointerId,N=!1,H=i.clientX,C=t.scrollLeft,R=0,I=Y()}),t.addEventListener("pointermove",i=>{if(i.pointerId!==b)return;let m=i.clientX-H;if(!N){if(Math.abs(m)<Ht)return;N=!0,t.classList.add("is-dragging"),t.setPointerCapture(i.pointerId)}R=-m*Mt,t.scrollLeft=C+R,i.pointerType==="mouse"&&i.preventDefault()});let x=i=>{i.pointerId===b&&(b=null,t.hasPointerCapture(i.pointerId)&&t.releasePointerCapture(i.pointerId),N?(t.classList.remove("is-dragging"),J()):$())};window.addEventListener("pointerup",x),window.addEventListener("pointercancel",x),t.addEventListener("click",i=>{N&&(N=!1,i.preventDefault(),i.stopPropagation())},!0),e.addEventListener("pointerenter",i=>{i.pointerType==="mouse"&&(S=!0,_())}),e.addEventListener("pointerleave",i=>{i.pointerType==="mouse"&&(S=!1,P())}),e.addEventListener("focusin",_),e.addEventListener("focusout",()=>queueMicrotask(P)),document.addEventListener("visibilitychange",()=>{document.hidden?_():P()}),new IntersectionObserver(i=>{u=i.some(m=>m.isIntersecting),u?P():_()},{threshold:.2}).observe(t)});var st="!<>-_\\/[]{}=+*^?#$%01",K=new WeakMap,X=(t,{duration:o=1050,stagger:a=.75,text:n,reducedMotion:e=!1,relaunchOnHover:s=!1}={})=>{if(e){n!==void 0&&(t.textContent=n);return}if(n!==void 0)t.dataset.scrambleText=n;else if(!t.dataset.scrambleText){let S=t.textContent;if(!S||!S.trim())return;t.dataset.scrambleText=S}let r=t.dataset.scrambleText;if(!r||!r.trim())return;let d=Array.from(r),c=d.length,g=Array.from(t.children),y;g.length===c&&g.every(S=>S.tagName==="SPAN")?y=g:(y=d.map(S=>{let u=document.createElement("span");return u.textContent=S,u}),t.textContent="",t.append(...y));let O=Symbol("scramble");K.set(t,O);let w=d.map((S,u)=>c<=1?0:u/(c-1)*o*a),E=performance.now(),T=S=>{if(K.get(t)!==O)return;let u=S-E,p=!0;d.forEach((L,b)=>{if(L===" "){y[b].textContent=" ";return}u>=w[b]?y[b].textContent=L:(p=!1,y[b].textContent=st[Math.random()*st.length|0])}),p?K.delete(t):requestAnimationFrame(T)};requestAnimationFrame(T),s&&Pt(t,{duration:o,stagger:a})},Pt=(t,o)=>{t.dataset.scrambleHoverBound||(t.dataset.scrambleHoverBound="true",t.addEventListener("pointerenter",()=>{K.has(t)||X(t,o)}))};var $t=.5,qt="power2.out",Dt=".status-pill, .evidence_label, .evidence_sku",Ft={duration:630,stagger:.6,relaunchOnHover:!0};h("evidence",(t,{gsap:o,reducedMotion:a})=>{let n=Array.from(t.children);if(!n.length)return;if(a){for(let c of n)c.style.height="auto",c.style.opacity="1";return}let e=()=>{o.killTweensOf(n),o.set(n,{height:0,opacity:0,overflow:"hidden"});let c=o.timeline();for(let g of n)c.call(()=>{for(let y of g.querySelectorAll(Dt))X(y,Ft)}),c.to(g,{height:"auto",opacity:1,duration:$t,ease:qt,onComplete:()=>o.set(g,{height:"auto"})})},s=!1,r=!1,d=()=>{if(!s||r)return;let c=t.closest("[data-slide]");c&&!c.classList.contains("is-current")||(r=!0,e())};if("IntersectionObserver"in window){let c=new IntersectionObserver(g=>{for(let y of g)y.isIntersecting&&(s=!0,d(),r&&c.disconnect())},{threshold:.2});c.observe(t)}else s=!0,d();t.closest("[data-slide]")?.addEventListener(nt,()=>{r=!1,d()})});var it="is-open",at=".faq_row",lt=".faq_toggle";h("faq",t=>{let o=t.querySelectorAll(at);if(o.length===0){console.warn(`[shopic] faq found no ${at} to open.`,t);return}let a=[];for(let s of o){let r=s.querySelector(lt);if(!r){console.warn(`[shopic] faq row has no ${lt} to click.`,s);continue}a.push({row:s,toggle:r})}if(a.length===0)return;let n=s=>{for(let{row:r,toggle:d}of a){let c=r===s;r.classList.toggle(it,c),d.setAttribute("aria-expanded",String(c))}};for(let{row:s,toggle:r}of a)r.addEventListener("click",()=>{n(s.classList.contains(it)?null:s)}),r.addEventListener("keydown",d=>{d.key!=="Enter"&&d.key!==" "||(d.preventDefault(),r.click())}),r.hasAttribute("tabindex")||(r.tabIndex=0);let e=a.find(({toggle:s})=>s.getAttribute("aria-expanded")==="true");n((e??a[0]).row)});var ct=8;h("focus-drift",(t,{reducedMotion:o})=>{let a=t.querySelector(":scope > .camera_focus");!a||o||(t.addEventListener("pointermove",n=>{if(n.pointerType!=="mouse")return;let e=t.getBoundingClientRect(),s=(n.clientX-e.left)/e.width-.5,r=(n.clientY-e.top)/e.height-.5,d=(s*ct*2).toFixed(1),c=(r*ct*2).toFixed(1);a.style.transform=`translate(${d}px, ${c}px)`}),t.addEventListener("pointerleave",()=>{a.style.transform=""}))});var dt=42,ut=96,Vt=2600,Gt="is-scanned",Xt="is-fresh";h("foundation-rail",(t,{gsap:o,reducedMotion:a})=>{let n=t.closest(".camera_photo"),e=Array.from(t.querySelectorAll(":scope > .foundation_slot"),u=>({element:u,parts:Array.from(u.querySelectorAll(".foundation_photo, .foundation_card")),tile:u.querySelector(".foundation_scan"),setX:o.quickSetter(u,"x","px"),home:0,turn:0,state:null}));if(!n||e.length===0){console.warn("[shopic] foundation-rail expects a .camera_photo tile around a track of .foundation_slot items.",t);return}let s=o.quickSetter(t,"x","px"),r=0,d=0,c=u=>u,g=()=>{let[u]=e,p=u.element.offsetWidth,L=p+(parseFloat(getComputedStyle(t).columnGap)||0);r=L*e.length,d=r/dt*(Vt/1e3),c=o.utils.wrap(-r/2,r/2),r<n.offsetWidth+p&&console.warn(`[shopic] foundation-rail: ${e.length} slots span ${r}px but the tile needs ${n.offsetWidth+p}px to loop without a gap.`,t);let b=n.getBoundingClientRect(),I=b.width/n.offsetWidth||1,H=(u.element.getBoundingClientRect().left-b.left)/I+p/2-n.offsetWidth/2-(Number(o.getProperty(t,"x"))||0)-(Number(o.getProperty(u.element,"x"))||0);e.forEach((C,R)=>{C.home=H+R*L,C.setX(C.turn*r)})},y=u=>u>ut?"unseen":u>ut-d?"fresh":"seen",O=(u,p)=>{if(u.state!==p){u.state=p;for(let L of u.parts)L.classList.toggle(Gt,p!=="unseen");u.tile?.classList.toggle(Xt,p==="fresh")}},w=u=>{if(r){s(-u);for(let p of e){let L=c(p.home-u),b=Math.round((L-(p.home-u))/r);b!==p.turn&&(p.turn=b,p.setX(b*r)),O(p,y(L))}}},E={t:0},T=()=>E.t*r,S=a?null:o.to(E,{t:1,duration:dt,ease:"none",repeat:-1,paused:!0,onUpdate:()=>w(T())});new ResizeObserver(()=>{g(),w(T())}).observe(t),S&&new IntersectionObserver(u=>{S.paused(!u.some(p=>p.isIntersecting))}).observe(t)});var ft="split_line",kt="split_word",mt="split_word-inner",Bt=t=>{let o=document.createDocumentFragment(),a=[],n=document.createElement("span");n.className=ft,o.appendChild(n);let e=(r,d)=>{if(!r)return;let c=document.createElement("span");c.className=kt;let g=document.createElement("span");g.className=d?`${mt} ${d}`:mt,g.textContent=r,c.appendChild(g),n.appendChild(c),a.push(g)},s=(r,d)=>{for(let c of r.split(/(\s+)/))c&&(/^\s+$/.test(c)?n.appendChild(document.createTextNode(" ")):e(c,d))};for(let r of Array.from(t.childNodes))r.nodeType===Node.TEXT_NODE?s(r.textContent??""):r instanceof HTMLBRElement?(n=document.createElement("span"),n.className=ft,o.appendChild(n)):r instanceof HTMLElement&&s(r.textContent??"",r.className||void 0);return t.textContent="",t.appendChild(o),a},pt={yPercent:0,duration:.9,ease:"power4.out",stagger:.035};h("headline",(t,{gsap:o,ScrollTrigger:a,reducedMotion:n})=>{if(n){t.style.visibility="visible";return}let e=Bt(t);if(o.set(e,{yPercent:110}),t.style.visibility="visible",t.dataset.animTrigger==="load"||!a){o.to(e,{...pt,delay:.3});return}o.to(e,{...pt,scrollTrigger:{trigger:t,start:"top 85%"}})});var Wt=26;h("marquee",(t,{gsap:o,reducedMotion:a})=>{if(a)return;let n=Number(t.dataset.animSets??4),e=Number(t.dataset.animDuration??Wt);if(!Number.isFinite(n)||n<2)return;let s=()=>t.scrollWidth/n,r=o.to(t,{x:()=>-s(),duration:e,ease:"none",repeat:-1,modifiers:{x:c=>`${Number.parseFloat(c)%s()}px`}}),d=t.parentElement;d&&(d.addEventListener("pointerenter",()=>r.pause()),d.addEventListener("pointerleave",()=>r.resume()))});var Ut=1.15,gt=.18,yt=10,Z=8,k=.55,ht="is-visible",Et="opacity, width, height",Yt=["name","price","packaging","sku"];h("photo-hover",(t,{reducedMotion:o})=>{let a=t.querySelector(":scope > img"),n=t.querySelector(":scope > .detect_layer"),e=t.querySelector(":scope > .camera_focus");if(!a&&!e)return;let s=e?.querySelector(".is-ring")??null,r=e?.querySelector(".is-corners")??null;e&&(!s||!r)&&console.warn("[shopic] photo-hover expects is-ring and is-corners layers inside the reticle.",e);let d=t.querySelector(":scope > .camera_readout"),c=Number(t.dataset.animZoom)||Ut,g=Array.from(t.querySelectorAll(".detect_box")),y=t.querySelector('[data-match="card"]'),O=y?.querySelector('[data-match="thumb"]')??null,w=0,E=0,T=0,S=0,u=0,p=0,L=0,b=null,I=l=>l.width/t.offsetWidth||1,H=(l,f)=>{let x=t.getBoundingClientRect(),A=I(x);return{x:(l-x.left)/A,y:(f-x.top)/A,width:t.offsetWidth,height:t.offsetHeight}},C=l=>{let f=t.getBoundingClientRect(),x=l.getBoundingClientRect(),A=I(f);return{x:(x.left-f.left)/A-Z,y:(x.top-f.top)/A-Z,w:x.width/A+Z*2,h:x.height/A+Z*2}},R=()=>{let{x:l,y:f,width:x,height:A}=H(p,L),i=(l/x-.5)*x*(c-1),m=(f/A-.5)*A*(c-1),v=`translate(${i.toFixed(2)}px, ${m.toFixed(2)}px) scale(${c})`;a&&(a.style.transform=v),n&&(n.style.transform=v)},N=()=>{if(!d)return;let l=t.getBoundingClientRect();if(!l.width||!l.height)return;let f=(p-l.left)/l.width-.5,x=(L-l.top)/l.height-.5,A=(f*yt*2).toFixed(1),i=(x*yt*2).toFixed(1);d.style.setProperty("translate",`${A}px ${i}px`)},q=()=>{let{x:l,y:f}=H(p,L);return{x:l-(e?.offsetWidth??0)/2,y:f-(e?.offsetHeight??0)/2}},D=(l,f)=>{e&&(e.style.left=`${l.toFixed(2)}px`,e.style.top=`${f.toFixed(2)}px`)},_=()=>{let l=q();D(l.x,l.y),S=l.x,u=l.y,E=0,T=0,r&&(r.style.transform="")},B=()=>{let l=q();D(l.x,l.y),o||(E-=l.x-S,T-=l.y-u),S=l.x,u=l.y},P=l=>{if(!e)return;let f=C(l);D(f.x,f.y),e.style.width=`${f.w.toFixed(2)}px`,e.style.height=`${f.h.toFixed(2)}px`},W=()=>{if(r){if(E-=E*gt,T-=T*gt,Math.abs(E)>.1||Math.abs(T)>.1){r.style.transform=`translate(${E.toFixed(2)}px, ${T.toFixed(2)}px)`;return}E=0,T=0,r.style.transform=""}},F=()=>{b?P(b):B(),W(),w=requestAnimationFrame(F)},U=l=>{if(y){for(let f of Yt){let x=l.dataset[f],A=y.querySelector(`[data-match="${f}"]`);A&&x!==void 0&&(A.textContent=x)}if(O){let f=l.dataset.thumb;f&&(O.removeAttribute("srcset"),O.removeAttribute("sizes"),O.src=f),O.style.display=f?"":"none"}y.classList.add(ht)}},V=l=>{if(b=l,U(l),!!e&&(e.style.transitionProperty="",P(l),r&&(r.style.opacity="0"),s)){let f=(1-k)/2*100;s.style.width=`${k*100}%`,s.style.height=`${k*100}%`,s.style.left=`${f}%`,s.style.top=`${f}%`,s.style.right="auto",s.style.bottom="auto"}},Y=l=>{if(!s)return;let f=C(l),{x,y:A}=H(p,L),i=(x-f.x)/f.w-.5,m=(A-f.y)/f.h-.5,v=i*f.w*(1-k),M=m*f.h*(1-k);s.style.setProperty("translate",`${v.toFixed(2)}px ${M.toFixed(2)}px`)},$=()=>{b=null,y?.classList.remove(ht),e&&(e.style.width="",e.style.height="",e.style.transitionProperty=Et,r&&(r.style.opacity=""),s&&(s.style.width="",s.style.height="",s.style.left="",s.style.top="",s.style.right="",s.style.bottom="",s.style.removeProperty("translate")))},J=l=>{l.pointerType==="mouse"&&(p=l.clientX,L=l.clientY,R(),N(),e&&(e.style.transitionProperty=Et,_(),cancelAnimationFrame(w),w=requestAnimationFrame(F)))},z=l=>{l.pointerType==="mouse"&&(p=l.clientX,L=l.clientY,R(),N())},Q=()=>{cancelAnimationFrame(w),w=0,a&&(a.style.transform=""),n&&(n.style.transform=""),d?.style.setProperty("translate","0px 0px"),$(),e&&(e.style.left="",e.style.top="",e.style.transitionProperty="",r&&(r.style.transform=""),E=0,T=0)};t.addEventListener("pointerenter",J),t.addEventListener("pointermove",z),t.addEventListener("pointerleave",Q);for(let l of g)l.addEventListener("pointerenter",f=>{f.pointerType==="mouse"&&V(l)}),l.addEventListener("pointermove",()=>{b===l&&Y(l)}),l.addEventListener("pointerleave",()=>{b===l&&($(),_())})});var bt="is-visible";h("reveal",(t,{reducedMotion:o})=>{let a=Number(t.dataset.animDelay??0);if(a&&(t.style.transitionDelay=`${a}ms`),o||!("IntersectionObserver"in window)){t.classList.add(bt);return}let n=new IntersectionObserver(e=>{for(let s of e)s.isIntersecting&&(s.target.classList.add(bt),n.unobserve(s.target))},{threshold:.15});n.observe(t)});h("scramble",(t,{reducedMotion:o})=>{let a={duration:Number(t.dataset.animDuration??1050),stagger:Number(t.dataset.animStagger??.75),reducedMotion:o};if(o||!("IntersectionObserver"in window)){X(t,a);return}let n=new IntersectionObserver(e=>{for(let s of e)s.isIntersecting&&(X(t,{...a,relaunchOnHover:!0}),n.unobserve(s.target))},{threshold:.2});n.observe(t)});var j=({grouped:t=!1,prefix:o="",suffix:a="",value:n})=>{let e=Math.round(n),s=t?e.toLocaleString("en-US"):String(e);return`${o}${s}${a}`};var zt=.5,vt="power4.out",Kt=.18,Zt="power2.in",jt=.35,Jt=1400,Qt=.15,te=420,ee=t=>{let o=t.querySelector("[data-stat-value]");return o||console.warn("[shopic] stats row is missing [data-stat-value]",t),o},ot=t=>({grouped:(t.dataset.statGrouped??t.closest('[data-anim="stats"]')?.dataset.statGrouped)==="true",prefix:t.dataset.statPrefix??t.closest('[data-anim="stats"]')?.dataset.statPrefix??"",suffix:t.dataset.statSuffix??t.closest('[data-anim="stats"]')?.dataset.statSuffix??""}),Lt=(t,o)=>{t.textContent=j({...ot(t),value:o})},Tt=(t,o)=>{t.classList.toggle("is-hovered",o);for(let a of t.querySelectorAll("[data-stat-label], [data-stat-hover]"))a.classList.toggle("is-hovered",o)},St=(t,o,a,n)=>{if(a){Lt(t,o);return}let e=performance.now(),s=r=>{if(n!==Number(t.dataset.statsGeneration))return;let d=Math.min((r-e)/Jt,1),c=1-(1-d)**3;t.textContent=j({...ot(t),value:o*c}),d<1&&requestAnimationFrame(s)};requestAnimationFrame(s)},ne=(t,{gsap:o,reducedMotion:a})=>{let n=t,e=ee(n);if(!e)return;let s=n.dataset.statCount??e.dataset.statCount,r=s===void 0?null:Number(s),d=n.dataset.statTicker??e.dataset.statTicker,c=d===void 0?null:Number(d),g=n.dataset.statTickerInterval??e.dataset.statTickerInterval,y=g===void 0?Number.NaN:Number(g),O=y>0?y:te,w=null,E=0,T=!1,S=()=>{c!==null&&(e.textContent=j({...ot(e),value:c}))},u=()=>{a||c===null||w!==null||(w=setInterval(()=>{c!==null&&(c+=1+Math.floor(Math.random()*3),S())},O))},p=()=>{w!==null&&(clearInterval(w),w=null)},L=()=>{E+=1,e.dataset.statsGeneration=String(E),r!==null?Lt(e,r):S(),o.set(e,{clearProps:"transform"})},b=H=>{E+=1,e.dataset.statsGeneration=String(E),o.killTweensOf(e),o.set(e,{yPercent:110}),o.to(e,{duration:zt,ease:vt,yPercent:0}),H&&r!==null&&St(e,r,a,E)};if(a){L();return}S(),o.set(e,{yPercent:110});let I=()=>{T||(T=!0,b(!0))};if("IntersectionObserver"in window){let H=new IntersectionObserver(C=>{C.some(R=>R.isIntersecting)&&(I(),H.disconnect())},{threshold:Qt});H.observe(n)}else I();c!==null&&("IntersectionObserver"in window?new IntersectionObserver(C=>{C.some(R=>R.isIntersecting)?u():p()}).observe(n):u()),n.addEventListener("pointerenter",H=>{H.pointerType==="mouse"&&(Tt(n,!0),E+=1,e.dataset.statsGeneration=String(E),o.killTweensOf(e),o.timeline().to(e,{duration:Kt,ease:Zt,yPercent:-110}).set(e,{yPercent:110}).to(e,{duration:jt,ease:vt,onStart:()=>{r!==null&&St(e,r,a,E)},yPercent:0}))}),n.addEventListener("pointerleave",()=>Tt(n,!1))};h("stats",ne);var rt=t=>String(t).padStart(2,"0");h("timer",t=>{let o=()=>{let a=new Date;t.textContent=`${rt(a.getHours())}:${rt(a.getMinutes())}:${rt(a.getSeconds())}`};o(),setInterval(o,1e3)});var xt="is-active",oe="(max-width: 991px)";h("versus-tabs",t=>{let o=Array.from(t.querySelectorAll('[role="tab"]')),a=t.nextElementSibling,n=a?Array.from(a.querySelectorAll(":scope > *")):[];if(o.length===0||o.length!==n.length){console.warn(`[shopic] versus-tabs expects one tab per panel; found ${o.length} tabs and ${n.length} panels.`,t);return}let e=window.matchMedia(oe),s=d=>{o.forEach((c,g)=>{c.classList.toggle(xt,g===d),c.setAttribute("aria-selected",String(g===d))}),n.forEach((c,g)=>{c.hidden=e.matches&&g!==d})},r=()=>Math.max(0,o.indexOf(t.querySelector(`.${xt}`)));o.forEach((d,c)=>{d.addEventListener("click",()=>s(c)),d.addEventListener("keydown",g=>{(g.key==="Enter"||g.key===" ")&&(g.preventDefault(),s(c))}),d.hasAttribute("tabindex")||(d.tabIndex=0)}),e.addEventListener("change",()=>s(r())),s(r())});var wt=()=>{let{gsap:t,ScrollTrigger:o}=window;if(!t)throw new Error("[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.");return o&&t.registerPlugin(o),{gsap:t,ScrollTrigger:o}},At=()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{let{gsap:t,ScrollTrigger:o}=wt();et({gsap:t,ScrollTrigger:o,reducedMotion:At()})});})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shopic",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Custom code bundle for the Shopic Webflow site.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -9,19 +9,6 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist"
|
|
11
11
|
],
|
|
12
|
-
"scripts": {
|
|
13
|
-
"dev": "cross-env NODE_ENV=development node ./bin/build.js",
|
|
14
|
-
"build": "cross-env NODE_ENV=production node ./bin/build.js",
|
|
15
|
-
"prepublishOnly": "npm run check && npm run lint && npm run build",
|
|
16
|
-
"lint": "eslint ./src ./scripts && prettier --check ./src ./scripts",
|
|
17
|
-
"lint:fix": "eslint ./src ./scripts --fix",
|
|
18
|
-
"check": "tsc --noEmit",
|
|
19
|
-
"format": "prettier --write ./src ./scripts",
|
|
20
|
-
"test": "playwright test",
|
|
21
|
-
"test:unit": "node --test \"tests/unit/**/*.test.js\"",
|
|
22
|
-
"test:ui": "playwright test --ui",
|
|
23
|
-
"update": "pnpm update -i -L -r"
|
|
24
|
-
},
|
|
25
12
|
"devDependencies": {
|
|
26
13
|
"@changesets/changelog-git": "^0.2.0",
|
|
27
14
|
"@changesets/cli": "^2.27.12",
|
|
@@ -48,5 +35,17 @@
|
|
|
48
35
|
"type": "git",
|
|
49
36
|
"url": "git+https://github.com/wlrx/shopic.git"
|
|
50
37
|
},
|
|
51
|
-
"
|
|
52
|
-
|
|
38
|
+
"scripts": {
|
|
39
|
+
"dev": "cross-env NODE_ENV=development node ./bin/build.js",
|
|
40
|
+
"build": "cross-env NODE_ENV=production node ./bin/build.js",
|
|
41
|
+
"release": "changeset publish",
|
|
42
|
+
"lint": "eslint ./src ./scripts && prettier --check ./src ./scripts",
|
|
43
|
+
"lint:fix": "eslint ./src ./scripts --fix",
|
|
44
|
+
"check": "tsc --noEmit",
|
|
45
|
+
"format": "prettier --write ./src ./scripts",
|
|
46
|
+
"test": "playwright test",
|
|
47
|
+
"test:unit": "node --test \"tests/unit/**/*.test.js\"",
|
|
48
|
+
"test:ui": "playwright test --ui",
|
|
49
|
+
"update": "pnpm update -i -L -r"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/dist/index.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../bin/live-reload.js", "../src/anim/carousel-state.ts", "../src/anim/registry.ts", "../src/anim/carousel.ts", "../src/lib/scramble.ts", "../src/anim/evidence.ts", "../src/anim/headline.ts", "../src/anim/marquee.ts", "../src/anim/reveal.ts", "../src/anim/scramble.ts", "../src/lib/gsap.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener('change', () => location.reload());\n", "/**\n * Wrap an index into `0..count - 1`.\n *\n * The carousel addresses slides by a *virtual* index that runs from `-1` (the\n * clone of the last slide, sitting before the first) to `count` (the clone of\n * the first, sitting after the last). This maps any such index back onto the\n * real slide it stands for.\n */\nexport const wrapIndex = (index: number, count: number): number =>\n ((index % count) + count) % count;\n", "import type { Gsap, ScrollTriggerType } from '$lib/gsap';\n\nexport type AnimationContext = {\n gsap: Gsap;\n ScrollTrigger?: ScrollTriggerType;\n reducedMotion: boolean;\n};\n\nexport type AnimationInit = (element: HTMLElement, context: AnimationContext) => void;\n\nconst registry = new Map<string, AnimationInit>();\n\n/**\n * Registers an animation under the name used in `data-anim`.\n * The client edits content in the Designer; the attribute is the only contract\n * between their markup and this bundle.\n */\nexport const registerAnimation = (name: string, init: AnimationInit): void => {\n if (registry.has(name)) {\n throw new Error(`[shopic] Animation \"${name}\" is registered twice.`);\n }\n\n registry.set(name, init);\n};\n\n/**\n * Runs every registered animation against the elements that ask for it.\n * Unknown names warn rather than throw \u2014 a stray attribute in the Designer\n * must not take the whole bundle down.\n *\n * Initialisation is once per element, and the marker lives on the element\n * rather than in module scope so that a *second copy* of this bundle sees it\n * too. That is not hypothetical: a stale inlined copy alongside the CDN one\n * re-split an already-split headline, and because the splitter carries a\n * parent's className onto the words it produces, every word inherited\n * `split_line` (display: block) and stacked one per line.\n */\nexport const runAnimations = (context: AnimationContext, root: ParentNode = document): void => {\n const elements = root.querySelectorAll<HTMLElement>('[data-anim]');\n\n for (const element of elements) {\n const name = element.dataset.anim;\n if (!name) continue;\n if (element.dataset.animState === 'ready') continue;\n\n const init = registry.get(name);\n\n if (!init) {\n // eslint-disable-next-line no-console\n console.warn(`[shopic] No animation registered for data-anim=\"${name}\".`, element);\n continue;\n }\n\n element.dataset.animState = 'ready';\n init(element, context);\n }\n};\n", "import { wrapIndex } from './carousel-state';\nimport { registerAnimation } from './registry';\n\n/**\n * Horizontal carousel driven by an external tab strip.\n *\n * Markup contract \u2014 all attributes, no class coupling, so the client can move\n * things around in the Designer:\n *\n * [data-anim=\"carousel\"] the carousel track\n * > [data-slide=\"<name>\"] one slide per name\n * [data-tab=\"<name>\"] a tab anywhere in the track's section\n *\n * The runtime keeps the existing clone-based infinite loop, but takes control\n * of the horizontal motion with GSAP. Native scroll-snap is left as the\n * no-JavaScript fallback and disabled once this controller is ready, so wheel,\n * touch, drag, tab navigation, and autoplay all finish through the same easing\n * and never fight a second browser animation.\n */\n\nconst DRAG_MULTIPLIER = 2;\nconst SCROLL_SETTLE_MS = 150;\n/** How far a pointer must travel before the gesture counts as a drag, not a click. */\nconst DRAG_THRESHOLD_PX = 4;\n/** Sub-pixel scroll differences are noise, not a slide the user wants to reach. */\nconst SETTLE_EPSILON_PX = 1;\nconst AUTOPLAY_DELAY_MS = 5000;\nconst MOTION_DURATION = 0.75;\nconst MOTION_EASE = 'power3.out';\nconst RATIO_THRESHOLDS = [0, 0.25, 0.5, 0.6, 0.7, 0.8, 0.9, 1];\n\n/** Fired on a slide the moment it becomes the current one. */\nexport const SLIDE_ENTER = 'shopic:slide-enter';\n\nregisterAnimation('carousel', (track, { gsap, reducedMotion }) => {\n const realSlides = Array.from(track.querySelectorAll<HTMLElement>(':scope > [data-slide]'));\n if (realSlides.length < 2) return;\n\n const scope = track.closest<HTMLElement>('section') ?? track.parentElement ?? document.body;\n const tabs = Array.from(scope.querySelectorAll<HTMLElement>('[data-tab]'));\n const motionDuration = reducedMotion ? 0 : MOTION_DURATION;\n\n const startClone = realSlides[realSlides.length - 1].cloneNode(true) as HTMLElement;\n const endClone = realSlides[0].cloneNode(true) as HTMLElement;\n\n for (const clone of [startClone, endClone]) {\n clone.dataset.slideClone = 'true';\n clone.setAttribute('aria-hidden', 'true');\n // Clones must never be initialised by runAnimations: they were produced\n // after their originals were already wired.\n for (const nested of clone.querySelectorAll<HTMLElement>('[data-anim]')) {\n nested.dataset.animState = 'ready';\n }\n }\n\n track.insertBefore(startClone, realSlides[0]);\n track.append(endClone);\n\n // [startClone, ...realSlides, endClone] \u2014 so a slide's index here is its real\n // index shifted by one, and the two clones sit at the virtual -1 and length.\n const slides = Array.from(track.querySelectorAll<HTMLElement>(':scope > [data-slide]'));\n const slideIndices = new Map(slides.map((slide, index) => [slide, index]));\n\n const realIndicesByName = new Map<string, number>();\n realSlides.forEach((slide, index) => {\n const name = slide.dataset.slide;\n if (name && !realIndicesByName.has(name)) realIndicesByName.set(name, index);\n });\n\n // Scroll position of every slide, measured once. Reading these live meant a\n // forced layout per slide on every settle, drag end and tween end; they only\n // actually change when the track is resized.\n let positions: number[] = [];\n\n const measure = (): void => {\n const trackLeft = track.getBoundingClientRect().left;\n const scroll = track.scrollLeft;\n const gutter = parseFloat(getComputedStyle(track).paddingLeft) || 0;\n positions = slides.map(\n (slide) => slide.getBoundingClientRect().left - trackLeft + scroll - gutter\n );\n };\n\n const positionOf = (slide: HTMLElement): number => positions[slideIndices.get(slide) ?? 0];\n\n const setActiveTab = (name: string): void => {\n for (const tab of tabs) {\n const active = tab.dataset.tab === name;\n tab.classList.toggle('is-active', active);\n // aria-selected is only valid on tab/option/row roles, and the markup\n // contract above does not promise one. aria-current is global.\n if (active) tab.setAttribute('aria-current', 'true');\n else tab.removeAttribute('aria-current');\n }\n };\n\n let currentIndex = 0;\n let current: HTMLElement | null = null;\n let hovering = false;\n let sectionInViewport = false;\n let autoplayTimer: ReturnType<typeof setTimeout> | undefined;\n let settleTimer: ReturnType<typeof setTimeout> | undefined;\n let motionInFlight = false;\n let activePointerId: number | null = null;\n\n const dragging = (): boolean => activePointerId !== null;\n\n const clearAutoplay = (): void => {\n if (autoplayTimer !== undefined) {\n clearTimeout(autoplayTimer);\n autoplayTimer = undefined;\n }\n };\n\n const canAutoplay = (): boolean =>\n !reducedMotion &&\n !document.hidden &&\n sectionInViewport &&\n !dragging() &&\n !hovering &&\n !scope.contains(document.activeElement);\n\n const scheduleAutoplay = (): void => {\n clearAutoplay();\n if (!canAutoplay()) return;\n\n autoplayTimer = setTimeout(() => {\n autoplayTimer = undefined;\n if (!canAutoplay()) return;\n\n const nextIndex = wrapIndex(currentIndex + 1, realSlides.length);\n // Wrapping to 0 means we are on the last slide: go through the end clone\n // so the last-to-first transition keeps moving forward. It is normalized\n // to the first real slide when the tween completes.\n animateToSlide(nextIndex === 0 ? endClone : realSlides[nextIndex]);\n }, AUTOPLAY_DELAY_MS);\n };\n\n for (const tab of tabs) {\n tab.addEventListener('click', (event) => {\n event.preventDefault();\n const name = tab.dataset.tab;\n const index = name === undefined ? undefined : realIndicesByName.get(name);\n if (index === undefined || name === undefined) return;\n\n currentIndex = index;\n setActiveTab(name);\n clearAutoplay();\n animateToSlide(realSlides[index]);\n });\n }\n\n // A callback batch only carries slides whose ratio crossed a threshold, not\n // every observed slide. Keep a running ratio per slide so the active tab is\n // always based on the actual most-visible slide.\n const ratios = new Map<HTMLElement, number>(slides.map((slide) => [slide, 0]));\n\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n ratios.set(entry.target as HTMLElement, entry.isIntersecting ? entry.intersectionRatio : 0);\n }\n\n let mostVisible: HTMLElement | null = null;\n let best = 0;\n for (const slide of slides) {\n const ratio = ratios.get(slide) ?? 0;\n if (ratio > best) {\n best = ratio;\n mostVisible = slide;\n }\n }\n // Eight thresholds across nine slides means this fires many times per\n // tween; the tab and class writes below only matter when the winner\n // actually changes.\n if (!mostVisible || mostVisible === current) return;\n\n current = mostVisible;\n const name = mostVisible.dataset.slide;\n if (name) {\n setActiveTab(name);\n const realIndex = realIndicesByName.get(name);\n if (realIndex !== undefined) currentIndex = realIndex;\n }\n for (const slide of slides) slide.classList.toggle('is-current', slide === mostVisible);\n\n mostVisible.dispatchEvent(new CustomEvent(SLIDE_ENTER));\n },\n { root: track, threshold: RATIO_THRESHOLDS }\n );\n\n for (const slide of slides) observer.observe(slide);\n\n const nearestSlide = (): HTMLElement => {\n const scroll = track.scrollLeft;\n let closest = slides[0];\n let closestDistance = Infinity;\n for (const [index, slide] of slides.entries()) {\n const distance = Math.abs(positions[index] - scroll);\n if (distance < closestDistance) {\n closestDistance = distance;\n closest = slide;\n }\n }\n return closest;\n };\n\n const finishMotion = (target: HTMLElement): void => {\n // A clone is a stand-in for a real slide. Once the tween lands on one, jump\n // the scroll to its original \u2014 snap is disabled while this controller is\n // active, so nothing competes with the correction. motionInFlight stays\n // true across the jump so the scroll event it emits cannot schedule a\n // second tween.\n if (target.dataset.slideClone) {\n const virtualIndex = (slideIndices.get(target) ?? 0) - 1;\n track.scrollLeft = positionOf(realSlides[wrapIndex(virtualIndex, realSlides.length)]);\n }\n\n motionInFlight = false;\n scheduleAutoplay();\n };\n\n function animateToSlide(slide: HTMLElement): void {\n clearTimeout(settleTimer);\n gsap.killTweensOf(track);\n motionInFlight = true;\n\n if (motionDuration === 0) {\n track.scrollLeft = positionOf(slide);\n finishMotion(slide);\n return;\n }\n\n gsap.to(track, {\n scrollLeft: positionOf(slide),\n duration: motionDuration,\n ease: MOTION_EASE,\n overwrite: 'auto',\n onComplete: () => finishMotion(slide),\n onInterrupt: () => {\n motionInFlight = false;\n },\n });\n }\n\n const settleToNearest = (): void => {\n const target = nearestSlide();\n // Already parked on it. This is the common case after a clone correction:\n // the jump emits a scroll event of its own, which would otherwise arm a\n // second tween to the slide we are already on.\n if (Math.abs(positionOf(target) - track.scrollLeft) < SETTLE_EPSILON_PX) {\n scheduleAutoplay();\n return;\n }\n\n animateToSlide(target);\n };\n\n // Land on the first real slide before anyone sees it. This touches only the\n // horizontal track and cannot move the page vertically like scrollIntoView.\n measure();\n track.style.scrollSnapType = 'none';\n track.style.touchAction = 'pan-y';\n track.scrollLeft = positionOf(realSlides[0]);\n\n // Slide widths follow the track's, so one observer over the track and its\n // slides catches every layout that invalidates the measured positions.\n const resizeObserver = new ResizeObserver(() => measure());\n resizeObserver.observe(track);\n for (const slide of slides) resizeObserver.observe(slide);\n\n // Wheel, keyboard, and any native scroll source still get a single GSAP\n // settle tween. Pointer gestures use the same settle path below.\n //\n // 'scrollend' fires only once scrolling \u2014 momentum included \u2014 has truly\n // finished. The debounced fallback can fire while momentum is still coasting,\n // and snap is off, so nothing else stops the browser's inertia: the settle\n // tween would then be animating scrollLeft against a live fling.\n if ('onscrollend' in window) {\n track.addEventListener('scrollend', () => {\n if (motionInFlight || dragging()) return;\n settleToNearest();\n });\n } else {\n track.addEventListener('scroll', () => {\n if (motionInFlight || dragging()) return;\n clearTimeout(settleTimer);\n settleTimer = setTimeout(settleToNearest, SCROLL_SETTLE_MS);\n });\n }\n\n let dragStartX = 0;\n let dragStartScroll = 0;\n let dragged = false;\n let suppressClick = false;\n\n // A press is not a drag until it has travelled DRAG_THRESHOLD_PX. Until then\n // the pointer is left completely alone \u2014 no capture, no preventDefault \u2014 so\n // links, buttons and text selection inside a slide behave normally.\n track.addEventListener('pointerdown', (event) => {\n clearAutoplay();\n clearTimeout(settleTimer);\n gsap.killTweensOf(track);\n motionInFlight = false;\n activePointerId = event.pointerId;\n dragged = false;\n suppressClick = false;\n dragStartX = event.clientX;\n dragStartScroll = track.scrollLeft;\n });\n\n track.addEventListener('pointermove', (event) => {\n if (event.pointerId !== activePointerId) return;\n\n const travelled = event.clientX - dragStartX;\n\n if (!dragged) {\n if (Math.abs(travelled) < DRAG_THRESHOLD_PX) return;\n dragged = true;\n track.classList.add('is-dragging');\n // Capture only now, so move/up/cancel keep reaching the track once the\n // pointer wanders outside it. Nothing is bound to window.\n track.setPointerCapture(event.pointerId);\n }\n\n track.scrollLeft = dragStartScroll - travelled * DRAG_MULTIPLIER;\n if (event.pointerType === 'mouse') event.preventDefault();\n });\n\n const stopPointerInteraction = (event: PointerEvent): void => {\n if (event.pointerId !== activePointerId) return;\n\n activePointerId = null;\n if (track.hasPointerCapture(event.pointerId)) track.releasePointerCapture(event.pointerId);\n\n if (dragged) {\n dragged = false;\n suppressClick = true;\n track.classList.remove('is-dragging');\n }\n\n // The press killed any tween in flight, so settle back onto the nearest\n // slide either way. On a plain click nothing has moved, so this only\n // restarts the autoplay clock. The settle tween restores it through\n // finishMotion.\n settleToNearest();\n };\n\n track.addEventListener('pointerup', stopPointerInteraction);\n track.addEventListener('pointercancel', stopPointerInteraction);\n\n // The click that ends a drag would otherwise activate whatever link sits\n // under the finger. Swallowing it here keeps the flag from leaking into the\n // next gesture: pointerdown clears it either way.\n track.addEventListener(\n 'click',\n (event) => {\n if (!suppressClick) return;\n suppressClick = false;\n event.preventDefault();\n event.stopPropagation();\n },\n true\n );\n\n // Bound to the section, not the track: the tab strip sits outside the track\n // and hovering it is still hovering the carousel.\n scope.addEventListener('pointerenter', (event) => {\n if (event.pointerType !== 'mouse') return;\n hovering = true;\n clearAutoplay();\n });\n\n scope.addEventListener('pointerleave', (event) => {\n if (event.pointerType !== 'mouse') return;\n hovering = false;\n scheduleAutoplay();\n });\n\n scope.addEventListener('focusin', clearAutoplay);\n scope.addEventListener('focusout', () => {\n // canAutoplay reads document.activeElement, which is still the old element\n // during focusout itself.\n queueMicrotask(scheduleAutoplay);\n });\n\n document.addEventListener('visibilitychange', () => {\n if (document.hidden) clearAutoplay();\n else scheduleAutoplay();\n });\n\n const visibilityObserver = new IntersectionObserver(\n (entries) => {\n sectionInViewport = entries.some((entry) => entry.isIntersecting);\n if (sectionInViewport) scheduleAutoplay();\n else clearAutoplay();\n },\n { threshold: 0.2 }\n );\n visibilityObserver.observe(track);\n});\n", "/**\n * \"Decipher\" reveal for mono text \u2014 glyphs cycle through a random set and lock\n * into the real character left to right, staggered.\n *\n * Follows the approved reference choreography. There is no ScrambleTextPlugin here\n * on purpose: that one is a paid Club GSAP add-on, and Webflow's native toggle\n * only serves the free build. This is the hand-rolled equivalent the designer's\n * prototype already uses, so the timing matches what she signed off on.\n */\n\nconst SCRAMBLE_CHARS = '!<>-_\\\\/[]{}=+*^?#$%01';\n\n/**\n * Tracks which reveal \"generation\" owns an element's spans. A relaunch has to\n * invalidate a still-running pass, otherwise two rAF loops fight over the same\n * element and the text never settles.\n */\nconst tokens = new WeakMap<HTMLElement, symbol>();\n\nexport type ScrambleOptions = {\n /** Total run length in ms. */\n duration?: number;\n /** How much of `duration` is spent staggering the lock-in, 0\u20131. */\n stagger?: number;\n /** Overrides the cached text. Pass it when the copy changes between reveals. */\n text?: string;\n /** Skip the animation and settle immediately. */\n reducedMotion?: boolean;\n};\n\nexport const scrambleReveal = (\n element: HTMLElement,\n { duration = 1050, stagger = 0.75, text: forcedText, reducedMotion = false }: ScrambleOptions = {}\n): void => {\n if (reducedMotion) {\n if (forcedText !== undefined) element.textContent = forcedText;\n return;\n }\n\n // The canonical text is cached: a relaunch mid-animation would otherwise\n // re-read whatever scrambled state happens to be on screen and lock that in.\n if (forcedText !== undefined) {\n element.dataset.scrambleText = forcedText;\n } else if (!element.dataset.scrambleText) {\n const initial = element.textContent;\n if (!initial || !initial.trim()) return;\n element.dataset.scrambleText = initial;\n }\n\n const text = element.dataset.scrambleText;\n if (!text || !text.trim()) return;\n\n const chars = Array.from(text);\n const count = chars.length;\n\n element.textContent = '';\n const fragment = document.createDocumentFragment();\n const spans = chars.map((char) => {\n const span = document.createElement('span');\n span.textContent = char;\n fragment.append(span);\n return span;\n });\n element.append(fragment);\n\n const token = Symbol('scramble');\n tokens.set(element, token);\n\n const lockTimes = chars.map((_, i) => (count <= 1 ? 0 : (i / (count - 1)) * duration * stagger));\n const start = performance.now();\n\n const tick = (now: number): void => {\n if (tokens.get(element) !== token) return; // superseded by a newer reveal\n\n const elapsed = now - start;\n let allLocked = true;\n\n chars.forEach((char, i) => {\n if (char === ' ') return;\n if (elapsed >= lockTimes[i]) {\n spans[i].textContent = char;\n } else {\n allLocked = false;\n spans[i].textContent = SCRAMBLE_CHARS[(Math.random() * SCRAMBLE_CHARS.length) | 0];\n }\n });\n\n if (!allLocked) requestAnimationFrame(tick);\n };\n\n requestAnimationFrame(tick);\n};\n\n/**\n * Hovering settled text relaunches it with the options it was first revealed\n * with. Bound once per element; safe to call on every reveal.\n */\nexport const bindScrambleRelaunch = (element: HTMLElement, options: ScrambleOptions = {}): void => {\n if (element.dataset.scrambleHoverBound) return;\n element.dataset.scrambleHoverBound = 'true';\n element.addEventListener('pointerenter', () => scrambleReveal(element, options));\n};\n", "import { scrambleReveal } from '$lib/scramble';\n\nimport { SLIDE_ENTER } from './carousel';\nimport { registerAnimation } from './registry';\n\n/**\n * The scan-evidence stack builds itself piece by piece: each slot grows in, in\n * DOM order, one finishing before the next starts.\n *\n * `.evidence` is bottom-anchored, so a growing height pushes the revealed-so-far\n * block UP rather than shifting anything below it \u2014 the stack visibly builds\n * upward even though slots open top to bottom.\n *\n * This animates each slot WRAPPER's height, never the tile inside it. The tile\n * keeps its real height and padding throughout, so every label and image stays\n * correctly positioned, and the wrapper's overflow:hidden just clips how much of\n * that already-correct box shows. Animating the tile's own height was tried in\n * the prototype first: padding cannot compress below itself, so \"collapsed\"\n * tiles never reached zero.\n *\n * GSAP resolves `height: 'auto'` by measuring it, so \u2014 unlike a plain CSS\n * transition \u2014 it interpolates real pixel values instead of snapping.\n *\n * Follows the approved scan-evidence reveal choreography.\n */\n\nconst SLOT_DURATION = 0.5;\nconst SLOT_EASE = 'power2.out';\nconst SCRAMBLE_SELECTOR = '.status-pill, .evidence_label, .evidence_sku';\n\nregisterAnimation('evidence', (element, { gsap, reducedMotion }) => {\n const slots = Array.from(element.children) as HTMLElement[];\n if (!slots.length) return;\n\n if (reducedMotion) {\n for (const slot of slots) {\n slot.style.height = 'auto';\n slot.style.opacity = '1';\n }\n return;\n }\n\n const play = (): void => {\n gsap.killTweensOf(slots);\n gsap.set(slots, { height: 0, opacity: 0, overflow: 'hidden' });\n\n const timeline = gsap.timeline();\n\n for (const slot of slots) {\n // The mono-text decipher starts the instant its slot begins opening, so\n // the label decodes in lockstep with the piece it sits on.\n timeline.call(() => {\n for (const text of slot.querySelectorAll<HTMLElement>(SCRAMBLE_SELECTOR)) {\n scrambleReveal(text, { duration: 630, stagger: 0.6 });\n }\n });\n\n timeline.to(slot, {\n height: 'auto',\n opacity: 1,\n duration: SLOT_DURATION,\n ease: SLOT_EASE,\n // NOT clearProps: the head block's default for a slot is height:0, so\n // clearing the inline height would re-collapse the slot the instant its\n // own tween finished, before the next one even started.\n onComplete: () => gsap.set(slot, { height: 'auto' }),\n });\n }\n };\n\n // Two independent conditions have to hold before the stack may open: the\n // slide has to be the current one, and the section has to have actually\n // reached the viewport. The carousel makes a slide current the moment the\n // page loads, long before this section is on screen, so without the second\n // condition the stack would already be sitting open when it arrives.\n //\n // They must be tracked separately rather than checked once. `runAnimations`\n // walks the DOM in order, so the carousel on the track initialises before the\n // evidence inside a card, and it sets `is-current` from its own observer a\n // frame later. An arrival callback that checks `is-current` inline therefore\n // loses the race on the first card, and \u2014 with the section already in view \u2014\n // no further intersection entry ever arrives to retry. That deadlock is\n // exactly what shipped in the first pass: card one stayed collapsed while\n // every card reached by a tab click played correctly.\n let inViewport = false;\n let hasPlayed = false;\n\n const maybePlay = (): void => {\n if (!inViewport) return;\n const slide = element.closest<HTMLElement>('[data-slide]');\n if (slide && !slide.classList.contains('is-current')) return;\n hasPlayed = true;\n play();\n };\n\n if ('IntersectionObserver' in window) {\n const arrival = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n inViewport = true;\n maybePlay();\n if (hasPlayed) arrival.disconnect();\n }\n },\n { threshold: 0.2 }\n );\n arrival.observe(element);\n } else {\n inViewport = true;\n maybePlay();\n }\n\n // A slide becoming current is the other half of the gate: on load it fires\n // before the section is on screen and does nothing, and on a genuine switch\n // it replays the stack.\n element.closest<HTMLElement>('[data-slide]')?.addEventListener(SLIDE_ENTER, maybePlay);\n});\n", "import { registerAnimation } from './registry';\n\nconst LINE = 'split_line';\nconst WORD = 'split_word';\nconst INNER = 'split_word-inner';\n\n/**\n * Wraps every word in an overflow-hidden span so it can slide up into view.\n * `<br>` starts a new line; existing child spans (accent colours) survive as\n * single words and keep their class. The class names are real Webflow styles \u2014\n * a class that only ever exists at runtime gets stripped from the published CSS.\n */\nconst splitHeadline = (element: HTMLElement): HTMLElement[] => {\n const fragment = document.createDocumentFragment();\n const words: HTMLElement[] = [];\n let line = document.createElement('span');\n line.className = LINE;\n fragment.appendChild(line);\n\n const addWord = (text: string, className?: string): void => {\n if (!text) return;\n\n const outer = document.createElement('span');\n outer.className = WORD;\n\n const inner = document.createElement('span');\n inner.className = className ? `${INNER} ${className}` : INNER;\n inner.textContent = text;\n\n outer.appendChild(inner);\n line.appendChild(outer);\n words.push(inner);\n };\n\n const addChunks = (text: string, className?: string): void => {\n for (const chunk of text.split(/(\\s+)/)) {\n if (!chunk) continue;\n if (/^\\s+$/.test(chunk)) line.appendChild(document.createTextNode(' '));\n else addWord(chunk, className);\n }\n };\n\n for (const node of Array.from(element.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n addChunks(node.textContent ?? '');\n } else if (node instanceof HTMLBRElement) {\n line = document.createElement('span');\n line.className = LINE;\n fragment.appendChild(line);\n } else if (node instanceof HTMLElement) {\n addChunks(node.textContent ?? '', node.className || undefined);\n }\n }\n\n element.textContent = '';\n element.appendChild(fragment);\n\n return words;\n};\n\nconst TWEEN = { yPercent: 0, duration: 0.9, ease: 'power4.out', stagger: 0.035 } as const;\n\nregisterAnimation('headline', (element, { gsap, ScrollTrigger, reducedMotion }) => {\n if (reducedMotion) {\n element.style.visibility = 'visible';\n return;\n }\n\n const words = splitHeadline(element);\n gsap.set(words, { yPercent: 110 });\n element.style.visibility = 'visible';\n\n // The hero headline is above the fold, so it plays on load; everything else\n // waits for the scroll to reach it.\n if (element.dataset.animTrigger === 'load' || !ScrollTrigger) {\n gsap.to(words, { ...TWEEN, delay: 0.3 });\n return;\n }\n\n gsap.to(words, { ...TWEEN, scrollTrigger: { trigger: element, start: 'top 85%' } });\n});\n", "import { registerAnimation } from './registry';\n\nconst DEFAULT_DURATION = 26;\n\n/**\n * Infinite logo strip. The track holds the same set of logos repeated N times,\n * so translating by exactly one set's width lands on an identical frame \u2014 no\n * measuring loop, no drift. N comes from the DOM, not a constant, so adding a\n * logo in the Designer cannot desync the loop.\n */\nregisterAnimation('marquee', (element, { gsap, reducedMotion }) => {\n if (reducedMotion) return;\n\n const sets = Number(element.dataset.animSets ?? 4);\n const duration = Number(element.dataset.animDuration ?? DEFAULT_DURATION);\n if (!Number.isFinite(sets) || sets < 2) return;\n\n const distance = () => element.scrollWidth / sets;\n\n const tween = gsap.to(element, {\n x: () => -distance(),\n duration,\n ease: 'none',\n repeat: -1,\n modifiers: {\n // wrap inside one set so the tween never accumulates a huge offset\n x: (value: string) => `${Number.parseFloat(value) % distance()}px`,\n },\n });\n\n const parent = element.parentElement;\n if (!parent) return;\n\n parent.addEventListener('pointerenter', () => tween.pause());\n parent.addEventListener('pointerleave', () => tween.resume());\n});\n", "import { registerAnimation } from './registry';\n\nconst VISIBLE = 'is-visible';\n\n/**\n * Fade-and-rise on entry. The motion itself is a CSS transition on\n * `.hero_media`; this only decides when to add the state class, so the\n * client can restyle the easing in the Designer without touching the bundle.\n */\nregisterAnimation('reveal', (element, { reducedMotion }) => {\n const delay = Number(element.dataset.animDelay ?? 0);\n if (delay) element.style.transitionDelay = `${delay}ms`;\n\n if (reducedMotion || !('IntersectionObserver' in window)) {\n element.classList.add(VISIBLE);\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n entry.target.classList.add(VISIBLE);\n observer.unobserve(entry.target);\n }\n },\n { threshold: 0.15 }\n );\n\n observer.observe(element);\n});\n", "import { bindScrambleRelaunch, scrambleReveal } from '$lib/scramble';\n\nimport { registerAnimation } from './registry';\n\n/**\n * Standalone decipher reveal for a single piece of mono text, for markup that\n * wants the effect without an evidence stack around it.\n *\n * Fires once on entry, then relaunches on hover \u2014 the same behaviour the\n * prototype gives every `.scan-evidence__label`.\n *\n * Tunable from the Designer:\n * data-anim-duration=\"1050\" total run length in ms\n * data-anim-stagger=\"0.75\" share of the run spent staggering the lock-in\n */\nregisterAnimation('scramble', (element, { reducedMotion }) => {\n const options = {\n duration: Number(element.dataset.animDuration ?? 1050),\n stagger: Number(element.dataset.animStagger ?? 0.75),\n reducedMotion,\n };\n\n if (reducedMotion || !('IntersectionObserver' in window)) {\n scrambleReveal(element, options);\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n scrambleReveal(element, options);\n bindScrambleRelaunch(element, options);\n observer.unobserve(entry.target);\n }\n },\n { threshold: 0.2 }\n );\n\n observer.observe(element);\n});\n", "import type { gsap as GsapStatic } from 'gsap';\nimport type { ScrollTrigger as ScrollTriggerStatic } from 'gsap/ScrollTrigger';\n\ndeclare global {\n interface Window {\n gsap?: typeof GsapStatic;\n ScrollTrigger?: typeof ScrollTriggerStatic;\n }\n}\n\nexport type Gsap = typeof GsapStatic;\nexport type ScrollTriggerType = typeof ScrollTriggerStatic;\n\n/**\n * GSAP ships from Webflow's native Site Settings toggle, not from this bundle.\n * A site transfer wipes Site Settings, so the toggle can silently disappear and\n * take every animation with it. Fail loudly here instead.\n */\nexport const requireGsap = (): { gsap: Gsap; ScrollTrigger?: ScrollTriggerType } => {\n const { gsap, ScrollTrigger } = window;\n\n if (!gsap) {\n throw new Error(\n '[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.'\n );\n }\n\n if (ScrollTrigger) gsap.registerPlugin(ScrollTrigger);\n\n return { gsap, ScrollTrigger };\n};\n\n/**\n * Whether the visitor asked the OS to cut down on motion.\n */\nexport const prefersReducedMotion = (): boolean =>\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n", "import { runAnimations } from '$anim/index';\nimport { prefersReducedMotion, requireGsap } from '$lib/gsap';\n\nwindow.Webflow ||= [];\nwindow.Webflow.push(() => {\n const { gsap, ScrollTrigger } = requireGsap();\n\n runAnimations({ gsap, ScrollTrigger, reducedMotion: prefersReducedMotion() });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|