shopic 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -59,7 +59,9 @@ the allow list, so every Webflow write still prompts.
59
59
  That is the only granularity available. The MCP bundles reads and writes into one
60
60
  tool — `data_style_tool` carries `get_styles` alongside `create_style` — so a
61
61
  tool-level allow would auto-approve writes with the reads. Leaving Webflow off the
62
- list entirely is what keeps the prompt.
62
+ list entirely is what keeps the prompt. The same file runs
63
+ `scripts/style-payload-hook.js` before every `data_style_tool` call; it rewrites
64
+ the payload and the prompt shows what changed.
63
65
 
64
66
  Figma URLs and node ids belong in the ignored `DEV-LINKS.local.md` and must not
65
67
  be committed. The staging URL is committed — it is stable and every agent needs
@@ -217,8 +219,9 @@ Run by hand or from a build step; `scripts/README.md` says what each one proves.
217
219
 
218
220
  | Command | Does |
219
221
  | -------------------------------------------------------------- | --------------------------------------------------------------------- |
220
- | `node scripts/class-index.js build \| append \| check \| stat` | The class vocabulary, and the duplicate-class guard |
221
- | `node scripts/lint-style-payload.js <payload>` | Rejects CSS shorthands, px, hidden start state before the API does |
222
+ | `node scripts/class-index.js build \| find \| check \| append` | The class vocabulary from the published CSS, and the duplicate guard |
223
+ | `node scripts/style-payload-hook.js < hook-input.json` | What the PreToolUse hook does to a `data_style_tool` call |
224
+ | `node scripts/lint-style-payload.js <payload>` | The same rules as a report, for a harness with no hooks |
222
225
  | `node scripts/check-runtime-classes.js` | Every class the bundle adds at runtime exists as a real Webflow style |
223
226
  | `node scripts/check-agent-refs.js` | Agent and skill definitions still point at things that exist |
224
227
  | `node scripts/preview-anim.js --seek <t> --measure <sel>` | The motion, on the real page, before the publish gate |
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";(()=>{var W=new Map,y=(e,o)=>{if(W.has(e))throw new Error(`[shopic] Animation "${e}" is registered twice.`);W.set(e,o)},B=(e,o=document)=>{let a=o.querySelectorAll("[data-anim]");for(let t of a){let r=t.dataset.anim;if(!r||t.dataset.animState==="ready")continue;let l=W.get(r);if(!l){console.warn(`[shopic] No animation registered for data-anim="${r}".`,t);continue}t.dataset.animState="ready",l(t,e)}};var pe=2,me=150,ge=4,ye=1,he=5e3,ve=.75,Ee="power3.out",be=[0,.25,.5,.6,.7,.8,.9,1],Y="shopic:slide-enter";y("carousel",(e,{gsap:o,reducedMotion:a})=>{let t=Array.from(e.querySelectorAll(":scope > [data-slide]"));if(t.length<2)return;let r=e.closest("section")??e.parentElement??document.body,l=Array.from(r.querySelectorAll("[data-tab]")),d=a?0:ve,i=t.length,s=new Map(t.map((n,f)=>[n,f])),c=new Map;t.forEach((n,f)=>{let g=n.dataset.slide;g&&!c.has(g)&&c.set(g,f)});let u=[],A=()=>{let n=e.getBoundingClientRect().left,f=e.scrollLeft,g=parseFloat(getComputedStyle(e).paddingLeft)||0,E=e.scrollWidth-e.clientWidth;u=t.map(R=>Math.min(R.getBoundingClientRect().left-n+f-g,E))},I=n=>{for(let f of l){let g=f.dataset.tab===n;f.classList.toggle("is-active",g),g?f.setAttribute("aria-current","true"):f.removeAttribute("aria-current")}},O=-1,b=null,h=!1,T=!1,C,p,m=null,v=0,x=0,S=0,w=0,M=!1,_=()=>m!==null,H=()=>b!==null,L=()=>{clearTimeout(C),C=void 0},V=()=>!a&&!document.hidden&&T&&!_()&&!h&&!r.contains(document.activeElement),P=()=>{L(),V()&&(C=setTimeout(()=>{C=void 0,V()&&$((O+1)%i)},he))},K=n=>{let f=t[n],g=f.dataset.slide;if(g&&I(g),n!==O){O=n;for(let E of t)E.classList.toggle("is-current",E===f);f.dispatchEvent(new CustomEvent(Y))}},X=n=>{b=null,K(n),P()},z=()=>{clearTimeout(p),o.killTweensOf(e),b=null};function $(n){if(z(),b=n,d===0){e.scrollLeft=u[n],X(n);return}o.to(e,{scrollLeft:u[n],duration:d,ease:Ee,overwrite:"auto",onComplete:()=>X(n),onInterrupt:()=>{b=null}})}let Z=()=>{let n=e.scrollLeft,f=0;return u.forEach((g,E)=>{Math.abs(g-n)<Math.abs(u[f]-n)&&(f=E)}),f},D=()=>{let n=Z();Math.abs(u[n]-e.scrollLeft)<ye?X(n):$(n)},de=()=>{let n=v>0?u[v]-u[v-1]:1/0,f=v<i-1?u[v+1]-u[v]:1/0,g=Math.min(Math.abs(n),Math.abs(f));if(Math.abs(w)<g*.25){D();return}$((v+Math.sign(w)+i)%i)};for(let n of l)n.addEventListener("click",f=>{f.preventDefault();let g=n.dataset.tab??"",E=c.get(g);E!==void 0&&(L(),I(g),$(E))});let j=new Array(i).fill(0),fe=new IntersectionObserver(n=>{for(let E of n){let R=s.get(E.target);R!==void 0&&(j[R]=E.isIntersecting?E.intersectionRatio:0)}let f=-1,g=0;j.forEach((E,R)=>{E<=g||(g=E,f=R)}),f!==-1&&(b!==null&&f!==b||K(f))},{root:e,threshold:be});for(let n of t)fe.observe(n);A(),e.style.scrollSnapType="none",e.style.touchAction="pan-y",e.addEventListener("dragstart",n=>n.preventDefault());let[ue]=u;e.scrollLeft=ue;let J=new ResizeObserver(A);J.observe(e);for(let n of t)J.observe(n);"onscrollend"in window?e.addEventListener("scrollend",()=>{!H()&&!_()&&D()}):e.addEventListener("scroll",()=>{H()||_()||(clearTimeout(p),p=setTimeout(D,me))}),e.addEventListener("pointerdown",n=>{L(),z(),m=n.pointerId,M=!1,x=n.clientX,S=e.scrollLeft,w=0,v=Z()}),e.addEventListener("pointermove",n=>{if(n.pointerId!==m)return;let f=n.clientX-x;if(!M){if(Math.abs(f)<ge)return;M=!0,e.classList.add("is-dragging"),e.setPointerCapture(n.pointerId)}w=-f*pe,e.scrollLeft=S+w,n.pointerType==="mouse"&&n.preventDefault()});let Q=n=>{n.pointerId===m&&(m=null,e.hasPointerCapture(n.pointerId)&&e.releasePointerCapture(n.pointerId),M?(e.classList.remove("is-dragging"),de()):D())};window.addEventListener("pointerup",Q),window.addEventListener("pointercancel",Q),e.addEventListener("click",n=>{M&&(M=!1,n.preventDefault(),n.stopPropagation())},!0),r.addEventListener("pointerenter",n=>{n.pointerType==="mouse"&&(h=!0,L())}),r.addEventListener("pointerleave",n=>{n.pointerType==="mouse"&&(h=!1,P())}),r.addEventListener("focusin",L),r.addEventListener("focusout",()=>queueMicrotask(P)),document.addEventListener("visibilitychange",()=>{document.hidden?L():P()}),new IntersectionObserver(n=>{T=n.some(f=>f.isIntersecting),T?P():L()},{threshold:.2}).observe(e)});var k="!<>-_\\/[]{}=+*^?#$%01",q=new WeakMap,N=(e,{duration:o=1050,stagger:a=.75,text:t,reducedMotion:r=!1,relaunchOnHover:l=!1}={})=>{if(r){t!==void 0&&(e.textContent=t);return}if(t!==void 0)e.dataset.scrambleText=t;else if(!e.dataset.scrambleText){let h=e.textContent;if(!h||!h.trim())return;e.dataset.scrambleText=h}let d=e.dataset.scrambleText;if(!d||!d.trim())return;let i=Array.from(d),s=i.length,c=Array.from(e.children),u;c.length===s&&c.every(h=>h.tagName==="SPAN")?u=c:(u=i.map(h=>{let T=document.createElement("span");return T.textContent=h,T}),e.textContent="",e.append(...u));let A=Symbol("scramble");q.set(e,A);let I=i.map((h,T)=>s<=1?0:T/(s-1)*o*a),O=performance.now(),b=h=>{if(q.get(e)!==A)return;let T=h-O,C=!0;i.forEach((p,m)=>{if(p===" "){u[m].textContent=" ";return}T>=I[m]?u[m].textContent=p:(C=!1,u[m].textContent=k[Math.random()*k.length|0])}),C?q.delete(e):requestAnimationFrame(b)};requestAnimationFrame(b),l&&Te(e,{duration:o,stagger:a})},Te=(e,o)=>{e.dataset.scrambleHoverBound||(e.dataset.scrambleHoverBound="true",e.addEventListener("pointerenter",()=>{q.has(e)||N(e,o)}))};var Le=.5,Se="power2.out",Ae=".status-pill, .evidence_label, .evidence_sku",xe={duration:630,stagger:.6,relaunchOnHover:!0};y("evidence",(e,{gsap:o,reducedMotion:a})=>{let t=Array.from(e.children);if(!t.length)return;if(a){for(let s of t)s.style.height="auto",s.style.opacity="1";return}let r=()=>{o.killTweensOf(t),o.set(t,{height:0,opacity:0,overflow:"hidden"});let s=o.timeline();for(let c of t)s.call(()=>{for(let u of c.querySelectorAll(Ae))N(u,xe)}),s.to(c,{height:"auto",opacity:1,duration:Le,ease:Se,onComplete:()=>o.set(c,{height:"auto"})})},l=!1,d=!1,i=()=>{if(!l||d)return;let s=e.closest("[data-slide]");s&&!s.classList.contains("is-current")||(d=!0,r())};if("IntersectionObserver"in window){let s=new IntersectionObserver(c=>{for(let u of c)u.isIntersecting&&(l=!0,i(),d&&s.disconnect())},{threshold:.2});s.observe(e)}else l=!0,i();e.closest("[data-slide]")?.addEventListener(Y,()=>{d=!1,i()})});var ee=8;y("focus-drift",(e,{reducedMotion:o})=>{let a=e.querySelector(":scope > .camera_focus");!a||o||(e.addEventListener("pointermove",t=>{if(t.pointerType!=="mouse")return;let r=e.getBoundingClientRect(),l=(t.clientX-r.left)/r.width-.5,d=(t.clientY-r.top)/r.height-.5,i=(l*ee*2).toFixed(1),s=(d*ee*2).toFixed(1);a.style.transform=`translate(${i}px, ${s}px)`}),e.addEventListener("pointerleave",()=>{a.style.transform=""}))});var te="split_line",we="split_word",ne="split_word-inner",Me=e=>{let o=document.createDocumentFragment(),a=[],t=document.createElement("span");t.className=te,o.appendChild(t);let r=(d,i)=>{if(!d)return;let s=document.createElement("span");s.className=we;let c=document.createElement("span");c.className=i?`${ne} ${i}`:ne,c.textContent=d,s.appendChild(c),t.appendChild(s),a.push(c)},l=(d,i)=>{for(let s of d.split(/(\s+)/))s&&(/^\s+$/.test(s)?t.appendChild(document.createTextNode(" ")):r(s,i))};for(let d of Array.from(e.childNodes))d.nodeType===Node.TEXT_NODE?l(d.textContent??""):d instanceof HTMLBRElement?(t=document.createElement("span"),t.className=te,o.appendChild(t)):d instanceof HTMLElement&&l(d.textContent??"",d.className||void 0);return e.textContent="",e.appendChild(o),a},oe={yPercent:0,duration:.9,ease:"power4.out",stagger:.035};y("headline",(e,{gsap:o,ScrollTrigger:a,reducedMotion:t})=>{if(t){e.style.visibility="visible";return}let r=Me(e);if(o.set(r,{yPercent:110}),e.style.visibility="visible",e.dataset.animTrigger==="load"||!a){o.to(r,{...oe,delay:.3});return}o.to(r,{...oe,scrollTrigger:{trigger:e,start:"top 85%"}})});var Ie=26;y("marquee",(e,{gsap:o,reducedMotion:a})=>{if(a)return;let t=Number(e.dataset.animSets??4),r=Number(e.dataset.animDuration??Ie);if(!Number.isFinite(t)||t<2)return;let l=()=>e.scrollWidth/t,d=o.to(e,{x:()=>-l(),duration:r,ease:"none",repeat:-1,modifiers:{x:s=>`${Number.parseFloat(s)%l()}px`}}),i=e.parentElement;i&&(i.addEventListener("pointerenter",()=>d.pause()),i.addEventListener("pointerleave",()=>d.resume()))});var re=1.15,se=.18,F=8,Ce=.55,G=(e,o,a)=>Math.min(a,Math.max(o,e));y("photo-hover",(e,{reducedMotion:o})=>{let a=e.querySelector(":scope > img");if(!a)return;let t=e.querySelector(":scope > .camera_focus"),r=t?.querySelector(":scope > img:first-child")??null,l=t?.querySelector(":scope > img:nth-child(2)")??null;t&&(!r||!l)&&console.warn("[shopic] photo-hover expects two image layers inside the reticle.",t);let d=Array.from(e.querySelectorAll(".detect_box")),i=0,s=0,c=0,u=0,A=0,I=!1,O=p=>{let m=e.getBoundingClientRect(),v=e.offsetWidth,x=e.offsetHeight,S=m.width/v||1,w=(p.clientX-m.left)/S,M=(p.clientY-m.top)/S;return{x:w,y:M,width:v,height:x}},b=()=>{if(i=0,!!r){if(s-=s*se,c-=c*se,r.style.transform=`translate(${s.toFixed(2)}px, ${c.toFixed(2)}px)`,Math.abs(s)>.1||Math.abs(c)>.1){i=requestAnimationFrame(b);return}r.style.transform=""}},h=p=>{if(p.pointerType!=="mouse")return;let{x:m,y:v,width:x,height:S}=O(p),w=re-1,M=-(m/x-.5)*x*w,_=-(v/S-.5)*S*w;if(a.style.transform=`translate(${M.toFixed(2)}px, ${_.toFixed(2)}px) scale(${re})`,!t||I)return;let H=G(m,0,x),L=G(v,0,S);if(t.style.left=`${H.toFixed(2)}px`,t.style.top=`${L.toFixed(2)}px`,o){u=H,A=L;return}s-=H-u,c-=L-A,u=H,A=L,i||(i=requestAnimationFrame(b))},T=()=>{a.style.transform="",t&&(I=!1,t.style.left="",t.style.top="",t.style.width="",t.style.height="",t.style.transitionProperty="",l&&(l.style.transform=""),r&&(r.style.opacity="",r.style.transform=""),s=0,c=0,cancelAnimationFrame(i),i=0)},C=p=>{if(p.pointerType!=="mouse"||!t)return;t.style.transitionProperty="opacity, width, height";let{x:m,y:v,width:x,height:S}=O(p);u=G(m,0,x),A=G(v,0,S),s=0,c=0};e.addEventListener("pointerenter",C),e.addEventListener("pointermove",h),e.addEventListener("pointerleave",T);for(let p of d)p.addEventListener("pointerenter",m=>{m.pointerType!=="mouse"||!t||(I=!0,t.style.transitionProperty="",t.style.left=`${p.offsetLeft-F}px`,t.style.top=`${p.offsetTop-F}px`,t.style.width=`${p.offsetWidth+F*2}px`,t.style.height=`${p.offsetHeight+F*2}px`,r&&(r.style.opacity="0"),l&&(l.style.transform=`scale(${Ce})`))}),p.addEventListener("pointerleave",()=>{I=!1,r&&(r.style.opacity=""),l&&(l.style.transform="")})});var ie="is-visible";y("reveal",(e,{reducedMotion:o})=>{let a=Number(e.dataset.animDelay??0);if(a&&(e.style.transitionDelay=`${a}ms`),o||!("IntersectionObserver"in window)){e.classList.add(ie);return}let t=new IntersectionObserver(r=>{for(let l of r)l.isIntersecting&&(l.target.classList.add(ie),t.unobserve(l.target))},{threshold:.15});t.observe(e)});y("scramble",(e,{reducedMotion:o})=>{let a={duration:Number(e.dataset.animDuration??1050),stagger:Number(e.dataset.animStagger??.75),reducedMotion:o};if(o||!("IntersectionObserver"in window)){N(e,a);return}let t=new IntersectionObserver(r=>{for(let l of r)l.isIntersecting&&(N(e,{...a,relaunchOnHover:!0}),t.unobserve(l.target))},{threshold:.2});t.observe(e)});var U=e=>String(e).padStart(2,"0");y("timer",e=>{let o=()=>{let a=new Date;e.textContent=`${U(a.getHours())}:${U(a.getMinutes())}:${U(a.getSeconds())}`};o(),setInterval(o,1e3)});var ae="is-active",Oe="(max-width: 991px)";y("versus-tabs",e=>{let o=Array.from(e.querySelectorAll('[role="tab"]')),a=e.nextElementSibling,t=a?Array.from(a.querySelectorAll(":scope > *")):[];if(o.length===0||o.length!==t.length){console.warn(`[shopic] versus-tabs expects one tab per panel; found ${o.length} tabs and ${t.length} panels.`,e);return}let r=window.matchMedia(Oe),l=i=>{o.forEach((s,c)=>{s.classList.toggle(ae,c===i),s.setAttribute("aria-selected",String(c===i))}),t.forEach((s,c)=>{s.hidden=r.matches&&c!==i})},d=()=>Math.max(0,o.indexOf(e.querySelector(`.${ae}`)));o.forEach((i,s)=>{i.addEventListener("click",()=>l(s)),i.addEventListener("keydown",c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),l(s))}),i.hasAttribute("tabindex")||(i.tabIndex=0)}),r.addEventListener("change",()=>l(d())),l(d())});var le=()=>{let{gsap:e,ScrollTrigger:o}=window;if(!e)throw new Error("[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.");return o&&e.registerPlugin(o),{gsap:e,ScrollTrigger:o}},ce=()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{let{gsap:e,ScrollTrigger:o}=le();B({gsap:e,ScrollTrigger:o,reducedMotion:ce()})});})();
1
+ "use strict";(()=>{var G=new Map,y=(t,n)=>{if(G.has(t))throw new Error(`[shopic] Animation "${t}" is registered twice.`);G.set(t,n)},W=(t,n=document)=>{let a=n.querySelectorAll("[data-anim]");for(let e of a){let o=e.dataset.anim;if(!o||e.dataset.animState==="ready")continue;let c=G.get(o);if(!c){console.warn(`[shopic] No animation registered for data-anim="${o}".`,e);continue}e.dataset.animState="ready",c(e,t)}};var vt=2,St=150,Tt=4,Lt=1,xt=5e3,wt=.75,At="power3.out",Mt=[0,.25,.5,.6,.7,.8,.9,1],B="shopic:slide-enter";y("carousel",(t,{gsap:n,reducedMotion:a})=>{let e=Array.from(t.querySelectorAll(":scope > [data-slide]"));if(e.length<2)return;let o=t.closest("section")??t.parentElement??document.body,c=Array.from(o.querySelectorAll("[data-tab]")),s=a?0:wt,l=e.length,i=new Map(e.map((r,m)=>[r,m])),d=new Map;e.forEach((r,m)=>{let b=r.dataset.slide;b&&!d.has(b)&&d.set(b,m)});let f=[],x=()=>{let r=t.getBoundingClientRect().left,m=t.scrollLeft,b=parseFloat(getComputedStyle(t).paddingLeft)||0,L=t.scrollWidth-t.clientWidth;f=e.map(R=>Math.min(R.getBoundingClientRect().left-r+m-b,L))},E=r=>{for(let m of c){let b=m.dataset.tab===r;m.classList.toggle("is-active",b),b?m.setAttribute("aria-current","true"):m.removeAttribute("aria-current")}},M=-1,S=null,v=!1,u=!1,g,p,h=null,T=0,O=0,w=0,A=0,I=!1,H=()=>h!==null,P=()=>S!==null,C=()=>{clearTimeout(g),g=void 0},z=()=>!a&&!document.hidden&&u&&!H()&&!v&&!o.contains(document.activeElement),N=()=>{C(),z()&&(g=setTimeout(()=>{g=void 0,z()&&D((M+1)%l)},xt))},K=r=>{let m=e[r],b=m.dataset.slide;if(b&&E(b),r!==M){M=r;for(let L of e)L.classList.toggle("is-current",L===m);m.dispatchEvent(new CustomEvent(B))}},X=r=>{S=null,K(r),N()},Z=()=>{clearTimeout(p),n.killTweensOf(t),S=null};function D(r){if(Z(),S=r,s===0){t.scrollLeft=f[r],X(r);return}n.to(t,{scrollLeft:f[r],duration:s,ease:At,overwrite:"auto",onComplete:()=>X(r),onInterrupt:()=>{S=null}})}let j=()=>{let r=t.scrollLeft,m=0;return f.forEach((b,L)=>{Math.abs(b-r)<Math.abs(f[m]-r)&&(m=L)}),m},$=()=>{let r=j();Math.abs(f[r]-t.scrollLeft)<Lt?X(r):D(r)},yt=()=>{let r=T>0?f[T]-f[T-1]:1/0,m=T<l-1?f[T+1]-f[T]:1/0,b=Math.min(Math.abs(r),Math.abs(m));if(Math.abs(A)<b*.25){$();return}D((T+Math.sign(A)+l)%l)};for(let r of c)r.addEventListener("click",m=>{m.preventDefault();let b=r.dataset.tab??"",L=d.get(b);L!==void 0&&(C(),E(b),D(L))});let J=new Array(l).fill(0),Et=new IntersectionObserver(r=>{for(let L of r){let R=i.get(L.target);R!==void 0&&(J[R]=L.isIntersecting?L.intersectionRatio:0)}let m=-1,b=0;J.forEach((L,R)=>{L<=b||(b=L,m=R)}),m!==-1&&(S!==null&&m!==S||K(m))},{root:t,threshold:Mt});for(let r of e)Et.observe(r);x(),t.style.scrollSnapType="none",t.style.touchAction="pan-y",t.addEventListener("dragstart",r=>r.preventDefault());let[bt]=f;t.scrollLeft=bt;let Q=new ResizeObserver(x);Q.observe(t);for(let r of e)Q.observe(r);"onscrollend"in window?t.addEventListener("scrollend",()=>{!P()&&!H()&&$()}):t.addEventListener("scroll",()=>{P()||H()||(clearTimeout(p),p=setTimeout($,St))}),t.addEventListener("pointerdown",r=>{C(),Z(),h=r.pointerId,I=!1,O=r.clientX,w=t.scrollLeft,A=0,T=j()}),t.addEventListener("pointermove",r=>{if(r.pointerId!==h)return;let m=r.clientX-O;if(!I){if(Math.abs(m)<Tt)return;I=!0,t.classList.add("is-dragging"),t.setPointerCapture(r.pointerId)}A=-m*vt,t.scrollLeft=w+A,r.pointerType==="mouse"&&r.preventDefault()});let k=r=>{r.pointerId===h&&(h=null,t.hasPointerCapture(r.pointerId)&&t.releasePointerCapture(r.pointerId),I?(t.classList.remove("is-dragging"),yt()):$())};window.addEventListener("pointerup",k),window.addEventListener("pointercancel",k),t.addEventListener("click",r=>{I&&(I=!1,r.preventDefault(),r.stopPropagation())},!0),o.addEventListener("pointerenter",r=>{r.pointerType==="mouse"&&(v=!0,C())}),o.addEventListener("pointerleave",r=>{r.pointerType==="mouse"&&(v=!1,N())}),o.addEventListener("focusin",C),o.addEventListener("focusout",()=>queueMicrotask(N)),document.addEventListener("visibilitychange",()=>{document.hidden?C():N()}),new IntersectionObserver(r=>{u=r.some(m=>m.isIntersecting),u?N():C()},{threshold:.2}).observe(t)});var tt="!<>-_\\/[]{}=+*^?#$%01",q=new WeakMap,_=(t,{duration:n=1050,stagger:a=.75,text:e,reducedMotion:o=!1,relaunchOnHover:c=!1}={})=>{if(o){e!==void 0&&(t.textContent=e);return}if(e!==void 0)t.dataset.scrambleText=e;else if(!t.dataset.scrambleText){let v=t.textContent;if(!v||!v.trim())return;t.dataset.scrambleText=v}let s=t.dataset.scrambleText;if(!s||!s.trim())return;let l=Array.from(s),i=l.length,d=Array.from(t.children),f;d.length===i&&d.every(v=>v.tagName==="SPAN")?f=d:(f=l.map(v=>{let u=document.createElement("span");return u.textContent=v,u}),t.textContent="",t.append(...f));let x=Symbol("scramble");q.set(t,x);let E=l.map((v,u)=>i<=1?0:u/(i-1)*n*a),M=performance.now(),S=v=>{if(q.get(t)!==x)return;let u=v-M,g=!0;l.forEach((p,h)=>{if(p===" "){f[h].textContent=" ";return}u>=E[h]?f[h].textContent=p:(g=!1,f[h].textContent=tt[Math.random()*tt.length|0])}),g?q.delete(t):requestAnimationFrame(S)};requestAnimationFrame(S),c&&It(t,{duration:n,stagger:a})},It=(t,n)=>{t.dataset.scrambleHoverBound||(t.dataset.scrambleHoverBound="true",t.addEventListener("pointerenter",()=>{q.has(t)||_(t,n)}))};var Ot=.5,Ct="power2.out",Ht=".status-pill, .evidence_label, .evidence_sku",Rt={duration:630,stagger:.6,relaunchOnHover:!0};y("evidence",(t,{gsap:n,reducedMotion:a})=>{let e=Array.from(t.children);if(!e.length)return;if(a){for(let i of e)i.style.height="auto",i.style.opacity="1";return}let o=()=>{n.killTweensOf(e),n.set(e,{height:0,opacity:0,overflow:"hidden"});let i=n.timeline();for(let d of e)i.call(()=>{for(let f of d.querySelectorAll(Ht))_(f,Rt)}),i.to(d,{height:"auto",opacity:1,duration:Ot,ease:Ct,onComplete:()=>n.set(d,{height:"auto"})})},c=!1,s=!1,l=()=>{if(!c||s)return;let i=t.closest("[data-slide]");i&&!i.classList.contains("is-current")||(s=!0,o())};if("IntersectionObserver"in window){let i=new IntersectionObserver(d=>{for(let f of d)f.isIntersecting&&(c=!0,l(),s&&i.disconnect())},{threshold:.2});i.observe(t)}else c=!0,l();t.closest("[data-slide]")?.addEventListener(B,()=>{s=!1,l()})});var et=8;y("focus-drift",(t,{reducedMotion:n})=>{let a=t.querySelector(":scope > .camera_focus");!a||n||(t.addEventListener("pointermove",e=>{if(e.pointerType!=="mouse")return;let o=t.getBoundingClientRect(),c=(e.clientX-o.left)/o.width-.5,s=(e.clientY-o.top)/o.height-.5,l=(c*et*2).toFixed(1),i=(s*et*2).toFixed(1);a.style.transform=`translate(${l}px, ${i}px)`}),t.addEventListener("pointerleave",()=>{a.style.transform=""}))});var nt=42,ot=96,_t=2600,Nt="is-scanned",Pt="is-fresh";y("foundation-rail",(t,{gsap:n,reducedMotion:a})=>{let e=t.closest(".camera_photo"),o=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:n.quickSetter(u,"x","px"),home:0,turn:0,state:null}));if(!e||o.length===0){console.warn("[shopic] foundation-rail expects a .camera_photo tile around a track of .foundation_slot items.",t);return}let c=n.quickSetter(t,"x","px"),s=0,l=0,i=u=>u,d=()=>{let[u]=o,g=u.element.offsetWidth,p=g+(parseFloat(getComputedStyle(t).columnGap)||0);s=p*o.length,l=s/nt*(_t/1e3),i=n.utils.wrap(-s/2,s/2),s<e.offsetWidth+g&&console.warn(`[shopic] foundation-rail: ${o.length} slots span ${s}px but the tile needs ${e.offsetWidth+g}px to loop without a gap.`,t);let h=e.getBoundingClientRect(),T=h.width/e.offsetWidth||1,O=(u.element.getBoundingClientRect().left-h.left)/T+g/2-e.offsetWidth/2-(Number(n.getProperty(t,"x"))||0)-(Number(n.getProperty(u.element,"x"))||0);o.forEach((w,A)=>{w.home=O+A*p,w.setX(w.turn*s)})},f=u=>u>ot?"unseen":u>ot-l?"fresh":"seen",x=(u,g)=>{if(u.state!==g){u.state=g;for(let p of u.parts)p.classList.toggle(Nt,g!=="unseen");u.tile?.classList.toggle(Pt,g==="fresh")}},E=u=>{if(s){c(-u);for(let g of o){let p=i(g.home-u),h=Math.round((p-(g.home-u))/s);h!==g.turn&&(g.turn=h,g.setX(h*s)),x(g,f(p))}}},M={t:0},S=()=>M.t*s,v=a?null:n.to(M,{t:1,duration:nt,ease:"none",repeat:-1,paused:!0,onUpdate:()=>E(S())});new ResizeObserver(()=>{d(),E(S())}).observe(t),v&&new IntersectionObserver(u=>{v.paused(!u.some(g=>g.isIntersecting))}).observe(t)});var rt="split_line",Dt="split_word",st="split_word-inner",$t=t=>{let n=document.createDocumentFragment(),a=[],e=document.createElement("span");e.className=rt,n.appendChild(e);let o=(s,l)=>{if(!s)return;let i=document.createElement("span");i.className=Dt;let d=document.createElement("span");d.className=l?`${st} ${l}`:st,d.textContent=s,i.appendChild(d),e.appendChild(i),a.push(d)},c=(s,l)=>{for(let i of s.split(/(\s+)/))i&&(/^\s+$/.test(i)?e.appendChild(document.createTextNode(" ")):o(i,l))};for(let s of Array.from(t.childNodes))s.nodeType===Node.TEXT_NODE?c(s.textContent??""):s instanceof HTMLBRElement?(e=document.createElement("span"),e.className=rt,n.appendChild(e)):s instanceof HTMLElement&&c(s.textContent??"",s.className||void 0);return t.textContent="",t.appendChild(n),a},it={yPercent:0,duration:.9,ease:"power4.out",stagger:.035};y("headline",(t,{gsap:n,ScrollTrigger:a,reducedMotion:e})=>{if(e){t.style.visibility="visible";return}let o=$t(t);if(n.set(o,{yPercent:110}),t.style.visibility="visible",t.dataset.animTrigger==="load"||!a){n.to(o,{...it,delay:.3});return}n.to(o,{...it,scrollTrigger:{trigger:t,start:"top 85%"}})});var qt=26;y("marquee",(t,{gsap:n,reducedMotion:a})=>{if(a)return;let e=Number(t.dataset.animSets??4),o=Number(t.dataset.animDuration??qt);if(!Number.isFinite(e)||e<2)return;let c=()=>t.scrollWidth/e,s=n.to(t,{x:()=>-c(),duration:o,ease:"none",repeat:-1,modifiers:{x:i=>`${Number.parseFloat(i)%c()}px`}}),l=t.parentElement;l&&(l.addEventListener("pointerenter",()=>s.pause()),l.addEventListener("pointerleave",()=>s.resume()))});var at=1.15,lt=.18,F=8,Ft=.55,V=(t,n,a)=>Math.min(a,Math.max(n,t));y("photo-hover",(t,{reducedMotion:n})=>{let a=t.querySelector(":scope > img"),e=t.querySelector(":scope > .camera_focus");if(!a&&!e)return;let o=e?.querySelector(":scope > img:first-child")??null,c=e?.querySelector(":scope > img:nth-child(2)")??null;e&&(!o||!c)&&console.warn("[shopic] photo-hover expects two image layers inside the reticle.",e);let s=Array.from(t.querySelectorAll(".detect_box")),l=0,i=0,d=0,f=0,x=0,E=!1,M=p=>{let h=t.getBoundingClientRect(),T=t.offsetWidth,O=t.offsetHeight,w=h.width/T||1,A=(p.clientX-h.left)/w,I=(p.clientY-h.top)/w;return{x:A,y:I,width:T,height:O}},S=()=>{if(l=0,!!o){if(i-=i*lt,d-=d*lt,o.style.transform=`translate(${i.toFixed(2)}px, ${d.toFixed(2)}px)`,Math.abs(i)>.1||Math.abs(d)>.1){l=requestAnimationFrame(S);return}o.style.transform=""}},v=p=>{if(p.pointerType!=="mouse")return;let{x:h,y:T,width:O,height:w}=M(p);if(a){let H=at-1,P=-(h/O-.5)*O*H,C=-(T/w-.5)*w*H;a.style.transform=`translate(${P.toFixed(2)}px, ${C.toFixed(2)}px) scale(${at})`}if(!e||E)return;let A=V(h,0,O),I=V(T,0,w);if(e.style.left=`${A.toFixed(2)}px`,e.style.top=`${I.toFixed(2)}px`,n){f=A,x=I;return}i-=A-f,d-=I-x,f=A,x=I,l||(l=requestAnimationFrame(S))},u=()=>{a&&(a.style.transform=""),e&&(E=!1,e.style.left="",e.style.top="",e.style.width="",e.style.height="",e.style.transitionProperty="",c&&(c.style.transform=""),o&&(o.style.opacity="",o.style.transform=""),i=0,d=0,cancelAnimationFrame(l),l=0)},g=p=>{if(p.pointerType!=="mouse"||!e)return;e.style.transitionProperty="opacity, width, height";let{x:h,y:T,width:O,height:w}=M(p);f=V(h,0,O),x=V(T,0,w),i=0,d=0};t.addEventListener("pointerenter",g),t.addEventListener("pointermove",v),t.addEventListener("pointerleave",u);for(let p of s)p.addEventListener("pointerenter",h=>{h.pointerType!=="mouse"||!e||(E=!0,e.style.transitionProperty="",e.style.left=`${p.offsetLeft-F}px`,e.style.top=`${p.offsetTop-F}px`,e.style.width=`${p.offsetWidth+F*2}px`,e.style.height=`${p.offsetHeight+F*2}px`,o&&(o.style.opacity="0"),c&&(c.style.transform=`scale(${Ft})`))}),p.addEventListener("pointerleave",()=>{E=!1,o&&(o.style.opacity=""),c&&(c.style.transform="")})});var ct="is-visible";y("reveal",(t,{reducedMotion:n})=>{let a=Number(t.dataset.animDelay??0);if(a&&(t.style.transitionDelay=`${a}ms`),n||!("IntersectionObserver"in window)){t.classList.add(ct);return}let e=new IntersectionObserver(o=>{for(let c of o)c.isIntersecting&&(c.target.classList.add(ct),e.unobserve(c.target))},{threshold:.15});e.observe(t)});y("scramble",(t,{reducedMotion:n})=>{let a={duration:Number(t.dataset.animDuration??1050),stagger:Number(t.dataset.animStagger??.75),reducedMotion:n};if(n||!("IntersectionObserver"in window)){_(t,a);return}let e=new IntersectionObserver(o=>{for(let c of o)c.isIntersecting&&(_(t,{...a,relaunchOnHover:!0}),e.unobserve(c.target))},{threshold:.2});e.observe(t)});var U=({prefix:t="",suffix:n="",value:a})=>`${t}${Math.round(a)}${n}`;var Vt=.5,dt="power4.out",Xt=.18,Gt="power2.in",Wt=.35,Bt=1400,Ut=.15,Yt=t=>{let n=t.querySelector("[data-stat-value]");return n||console.warn("[shopic] stats row is missing [data-stat-value]",t),n},ft=t=>({prefix:t.dataset.statPrefix??t.closest('[data-anim="stats"]')?.dataset.statPrefix??"",suffix:t.dataset.statSuffix??t.closest('[data-anim="stats"]')?.dataset.statSuffix??""}),mt=(t,n)=>{t.textContent=U({...ft(t),value:n})},ut=(t,n,a,e)=>{if(a){mt(t,n);return}let o=performance.now(),c=s=>{if(e!==Number(t.dataset.statsGeneration))return;let l=Math.min((s-o)/Bt,1),i=1-(1-l)**3;t.textContent=U({...ft(t),value:n*i}),l<1&&requestAnimationFrame(c)};requestAnimationFrame(c)},zt=(t,{gsap:n,reducedMotion:a})=>{let e=t,o=Yt(e);if(!o)return;let c=Number(e.dataset.statCount??o.dataset.statCount??0),s=0,l=!1,i=()=>{s+=1,o.dataset.statsGeneration=String(s),mt(o,c),n.set(o,{clearProps:"transform"})},d=E=>{s+=1,o.dataset.statsGeneration=String(s),n.killTweensOf(o),n.set(o,{yPercent:110}),n.to(o,{duration:Vt,ease:dt,yPercent:0}),E&&ut(o,c,a,s)},f=E=>{e.classList.toggle("is-hovered",E),e.querySelector("[data-stat-label]")?.classList.toggle("is-hovered",E)};if(a){i();return}n.set(o,{yPercent:110});let x=()=>{l||(l=!0,d(!0))};if("IntersectionObserver"in window){let E=new IntersectionObserver(M=>{M.some(S=>S.isIntersecting)&&(x(),E.disconnect())},{threshold:Ut});E.observe(e)}else x();e.addEventListener("pointerenter",E=>{E.pointerType==="mouse"&&(f(!0),s+=1,o.dataset.statsGeneration=String(s),n.killTweensOf(o),n.timeline().to(o,{duration:Xt,ease:Gt,yPercent:-110}).set(o,{yPercent:110}).to(o,{duration:Wt,ease:dt,onStart:()=>ut(o,c,a,s),yPercent:0}))}),e.addEventListener("pointerleave",()=>f(!1))};y("stats",zt);var Y=t=>String(t).padStart(2,"0");y("timer",t=>{let n=()=>{let a=new Date;t.textContent=`${Y(a.getHours())}:${Y(a.getMinutes())}:${Y(a.getSeconds())}`};n(),setInterval(n,1e3)});var pt="is-active",Kt="(max-width: 991px)";y("versus-tabs",t=>{let n=Array.from(t.querySelectorAll('[role="tab"]')),a=t.nextElementSibling,e=a?Array.from(a.querySelectorAll(":scope > *")):[];if(n.length===0||n.length!==e.length){console.warn(`[shopic] versus-tabs expects one tab per panel; found ${n.length} tabs and ${e.length} panels.`,t);return}let o=window.matchMedia(Kt),c=l=>{n.forEach((i,d)=>{i.classList.toggle(pt,d===l),i.setAttribute("aria-selected",String(d===l))}),e.forEach((i,d)=>{i.hidden=o.matches&&d!==l})},s=()=>Math.max(0,n.indexOf(t.querySelector(`.${pt}`)));n.forEach((l,i)=>{l.addEventListener("click",()=>c(i)),l.addEventListener("keydown",d=>{(d.key==="Enter"||d.key===" ")&&(d.preventDefault(),c(i))}),l.hasAttribute("tabindex")||(l.tabIndex=0)}),o.addEventListener("change",()=>c(s())),c(s())});var gt=()=>{let{gsap:t,ScrollTrigger:n}=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 n&&t.registerPlugin(n),{gsap:t,ScrollTrigger:n}},ht=()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{let{gsap:t,ScrollTrigger:n}=gt();W({gsap:t,ScrollTrigger:n,reducedMotion:ht()})});})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopic",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Custom code bundle for the Shopic Webflow site.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,