shopic 0.1.1 → 0.1.3

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
@@ -74,6 +76,20 @@ src/*.ts → esbuild → dist/*.js → npm publish → cdn.jsdelivr.net/
74
76
  npm stores the versions; jsDelivr is the CDN that serves them. The published package
75
77
  is public even though this repository is not — that is the price of a free CDN.
76
78
 
79
+ ## Machine setup
80
+
81
+ Node and pnpm; `packageManager` pins the pnpm version and `corepack enable` installs
82
+ it. Publishing also needs **npm CLI 11.9 or newer** — older versions cannot drive the
83
+ passkey hand-off and ask for a code that does not exist.
84
+
85
+ ```bash
86
+ corepack enable
87
+ pnpm install
88
+ npm login # publishing only
89
+ ```
90
+
91
+ The environment is complete when `pnpm check`, `pnpm lint` and `pnpm build` pass.
92
+
77
93
  ## Local checks
78
94
 
79
95
  ```bash
@@ -217,8 +233,9 @@ Run by hand or from a build step; `scripts/README.md` says what each one proves.
217
233
 
218
234
  | Command | Does |
219
235
  | -------------------------------------------------------------- | --------------------------------------------------------------------- |
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 |
236
+ | `node scripts/class-index.js build \| find \| check \| append` | The class vocabulary from the published CSS, and the duplicate guard |
237
+ | `node scripts/style-payload-hook.js < hook-input.json` | What the PreToolUse hook does to a `data_style_tool` call |
238
+ | `node scripts/lint-style-payload.js <payload>` | The same rules as a report, for a harness with no hooks |
222
239
  | `node scripts/check-runtime-classes.js` | Every class the bundle adds at runtime exists as a real Webflow style |
223
240
  | `node scripts/check-agent-refs.js` | Agent and skill definitions still point at things that exist |
224
241
  | `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 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()})});})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopic",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Custom code bundle for the Shopic Webflow site.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,