situs-kit 0.2.6 → 0.2.7

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
@@ -328,6 +328,7 @@ observer.kill(); // remove this observer
328
328
  | `once` | `boolean` | `false` | Auto-kill after first activation |
329
329
  | `markers` | `boolean` | `false` | Show debug lines for start/end |
330
330
  | `toggleClass` | `string` | — | Class added while active, removed otherwise |
331
+ | `pin` | `boolean \| HTMLElement \| string` | — | Pin an element between start and end. `true` pins the trigger. A string (CSS selector) or HTMLElement pins that specific element. Sticks at the `start.viewport` position |
331
332
 
332
333
  ### ScrollPosition
333
334
 
@@ -343,6 +344,42 @@ start: { dom: "top", viewport: "80%" }
343
344
 
344
345
  Both `dom` and `viewport` tokens support named positions (`top`, `center`, `bottom`, `left`, `right`), percentages (`80%`), and offsets (`top+=100`, `bottom-=50`).
345
346
 
347
+ ### Pin
348
+
349
+ Pin an element in place between `start` and `end` scroll positions. The trigger element determines when pinning starts and ends, while `pin` specifies which element to pin.
350
+
351
+ - `pin: true` — pins the trigger element itself
352
+ - `pin: "#element"` — pins a specific element by CSS selector
353
+ - `pin: element` — pins a specific HTMLElement
354
+
355
+ ```ts
356
+ // Pin the trigger itself
357
+ scroll.observe({
358
+ trigger: "#section",
359
+ start: { dom: "top", viewport: "top" },
360
+ end: { dom: "bottom", viewport: "top" },
361
+ pin: true,
362
+ });
363
+
364
+ // Pin a different element based on the trigger's position
365
+ scroll.observe({
366
+ trigger: "#section",
367
+ start: { dom: "top", viewport: "top" },
368
+ end: { dom: "bottom", viewport: "top" },
369
+ pin: "#sticky-header",
370
+ onUpdate(info) {
371
+ console.log("pin progress:", info.progress);
372
+ },
373
+ });
374
+ ```
375
+
376
+ When pinning:
377
+ - **Window mode**: uses `position: fixed` — GPU-composited, smooth on mobile Safari. A spacer element preserves document flow
378
+ - **Element mode**: uses `transform: translateY()` — element stays in flow, no spacer needed
379
+ - When scrolling past `end`, the element freezes at its last pinned position
380
+ - Scrolling back before `start` restores the element to its original styles
381
+ - `kill()` and `destroy()` clean up and restore original styles
382
+
346
383
  ### Observer Info
347
384
 
348
385
  | Property | Type | Description |
@@ -1,2 +1,2 @@
1
1
  var J=0,G=0;function N(){return G}var v=[],x=0,D=!0,y=0,E=!1;function H(q){if(D){let j=q-y;y=q,G=j/16.666666666666668;for(let B=x-1;B>=0;B--){let A=v[B];if(!A)continue;A.sT||=q;let I=q-A.sT;A.cb(I)}}requestAnimationFrame(H)}function K(){if(document.hidden)D=!1;else{let q=performance.now()-y;y=performance.now();for(let j=x-1;j>=0;j--)v[j].sT+=q;D=!0}}function L(){if(E)return;if(E=!0,y=performance.now(),typeof document<"u")document.addEventListener("visibilitychange",K);requestAnimationFrame(H)}var M={add(q){L();let j=J++;return v.push({id:j,cb:q,sT:0}),x++,()=>M.remove(q)},remove(q){for(let j=x-1;j>=0;j--)if(v[j].cb===q)v.splice(j,1),x--}};
2
- export{N as g,M as h};
2
+ export{N as h,M as i};
@@ -0,0 +1,2 @@
1
+ import{e as T,f as I}from"./chunk-p2rw7d5g.js";import{h as E,i as A}from"./chunk-fatbf8es.js";function U(j,B,G){return Math.min(Math.max(j,B),G)}function f(j,B,G){return j+(B-j)*G}function _(j,B,G){let J=B-j;return J===0?0:U((G-j)/J,0,1)}function k(j,B,G,J){let X=1-Math.exp(-G*J);return f(j,B,X)}var W=[],D=0,O=!1,m=!1;function d(){if(O)return;O=!0,requestAnimationFrame(p)}function p(){O=!1;for(let j=0;j<D;j++)W[j]()}function c(){if(m)return;m=!0,window.addEventListener("resize",d)}var P={add(j){return c(),W.push(j),D++,()=>P.remove(j)},remove(j){for(let B=D-1;B>=0;B--)if(W[B]===j)W.splice(B,1),D--}};var b={top:0,left:0,center:0.5,bottom:1,right:1};function z(j){if(j in b)return b[j];if(j.endsWith("%"))return parseFloat(j)/100;let B=parseFloat(j);return isNaN(B)?0:B}function L(j){let B=j.indexOf("+=");if(B!==-1){let J=z(j.slice(0,B)),X=parseFloat(j.slice(B+2));return[J,isNaN(X)?0:X]}let G=j.indexOf("-=");if(G!==-1){let J=z(j.slice(0,G)),X=parseFloat(j.slice(G+2));return[J,isNaN(X)?0:-X]}return[z(j),0]}function w(j){if(typeof j==="object"){let[N,Q]=L(j.dom),[Z,Y]=L(j.viewport);return[N,Z,Q,Y]}let B=j.trim().split(/\s+/),[G,J]=L(B[0]),[X,K]=B.length>1?L(B[1]):[G,0];return[G,X,J,K]}class F{_k=new Set;_n=null;_g;constructor(j){this._g=j}_m(j,B){let[G,J,X,K]=B,N=this._g,Q,Z,Y;if(N._b)if(Z=j.height,Y=N._d?window.innerHeight:N._c.clientHeight,N._d)Q=j.top+N._a;else{let $=N._c.getBoundingClientRect();Q=j.top-$.top+N._a}else if(Z=j.width,Y=N._d?window.innerWidth:N._c.clientWidth,N._d)Q=j.left+N._a;else{let $=N._c.getBoundingClientRect();Q=j.left-$.left+N._a}return Q+G*Z-J*Y+X+K}_H(j){let B=this._g,G=j.pinData,J=j.el,X=j.pinEl,K=J.getBoundingClientRect(),N=X.getBoundingClientRect();G.startScroll=this._m(K,j.startParsed),G.endScroll=this._m(K,j.endParsed);let Q=B._b?B._d?window.innerHeight:B._c.clientHeight:B._d?window.innerWidth:B._c.clientWidth,Z=B._b?N.height:N.width;if(G.pinViewportOffset=j.pinPosFrac*(Q-Z),G.pinLeftOffset=B._b?N.left:N.top,B._b)G.pinAbsPos=B._d?N.top+B._a:N.top-B._c.getBoundingClientRect().top+B._a;else G.pinAbsPos=B._d?N.left+B._a:N.left-B._c.getBoundingClientRect().left+B._a}_B(j){let B=this._g,G,J;if(j.pinData){if(j.state==="before")this._H(j);G=j.pinData.startScroll,J=j.pinData.endScroll}else{let C=j.el.getBoundingClientRect();G=this._m(C,j.startParsed),J=this._m(C,j.endParsed)}let X=J-G,K=B._a,N=X===0?K>=G?1:0:U((K-G)/X,0,1),Q;if(K<G)Q="before";else if(K>=J)Q="after";else Q="active";let{state:Z,info:Y,cfg:$}=j;if(Y.progress=N,Y.direction=B._h,Y.isActive=Q==="active",Y.state=Q,Z!==Q){if(j.state=Q,$.toggleClass)if(Q==="active")j.el.classList.add($.toggleClass);else j.el.classList.remove($.toggleClass);if(Z==="before"&&Q==="active")$.onEnter?.(Y);else if(Z==="active"&&Q==="after")$.onLeave?.(Y);else if(Z==="after"&&Q==="active")$.onEnterBack?.(Y);else if(Z==="active"&&Q==="before")$.onLeaveBack?.(Y);else if(Z==="before"&&Q==="after")$.onEnter?.(Y),$.onLeave?.(Y);else if(Z==="after"&&Q==="before")$.onEnterBack?.(Y),$.onLeaveBack?.(Y);if($.once&&(Q==="active"||Z==="before"&&Q==="after")){this._A(j);return}}if(j.pinData)this._U(j,Q);if(Q==="active")$.onUpdate?.(Y)}_W(){for(let j of this._k)this._B(j)}_U(j,B){let{pinData:G,pinEl:J}=j,X=this._g;if(B==="active"&&X._d){let K=X._b?"top":"left",N=X._b?"left":"top";if(J.style.position="fixed",J.style[K]=G.pinViewportOffset+"px",J.style[N]=G.pinLeftOffset+"px",J.style.width=G.origStyle._I,J.style.height=G.origStyle._J,J.style.margin="0",J.style.zIndex=G.origStyle.zIndex||"1",J.style.boxSizing="border-box",J.style.transform=G.origStyle.transform,J.style.willChange="",!G.spacer.parentElement)J.parentElement?.insertBefore(G.spacer,J.nextSibling)}else if(B==="active"){let K=G.pinViewportOffset-G.pinAbsPos+X._a,N=X._b?"translateY":"translateX";J.style.transform=`${N}(${K}px)`,J.style.position="relative",J.style.zIndex=G.origStyle.zIndex||"1",J.style.willChange="transform"}else if(B==="after"){this._u(j);let K=G.pinViewportOffset-G.pinAbsPos+G.endScroll,N=X._b?"translateY":"translateX";J.style.transform=`${N}(${K}px)`,J.style.position="relative",J.style.zIndex=G.origStyle.zIndex||"1"}else this._u(j)}_u(j){let{pinData:B,pinEl:G}=j,J=B.origStyle;if(G.style.position=J.position,G.style.top=J.top,G.style.left=J.left,G.style.width=J.width,G.style.height=J.height,G.style.margin=J.margin,G.style.zIndex=J.zIndex,G.style.boxSizing=J.boxSizing,G.style.transform=J.transform,G.style.willChange=J.willChange,B.spacer?.parentElement)B.spacer.parentElement.removeChild(B.spacer)}_$(){for(let j of this._k){if(!j.pinData)continue;this._u(j)}for(let j of this._k){if(!j.pinData)continue;if(this._H(j),this._g._d&&j.pinData.spacer){let B=j.pinEl,G=B.getBoundingClientRect(),J=typeof getComputedStyle<"u"?getComputedStyle(B):null,X=J?J.width:G.width+"px",K=J?J.height:G.height+"px";if(j.pinData.origStyle._I=X,j.pinData.origStyle._J=K,j.pinData.spacer.style.width=X,j.pinData.spacer.style.height=K,J)j.pinData.spacer.style.margin=J.margin}}for(let j of this._k)this._B(j)}_A(j){if(this._k.delete(j),j.cfg.toggleClass&&j.state==="active")j.el.classList.remove(j.cfg.toggleClass);if(j.pinData){if(this._u(j),j.pinData.spacer)j.pinData.spacer.parentElement?.removeChild(j.pinData.spacer);j.pinData=null}if(j.markerEls){for(let B of j.markerEls)B.parentElement?.removeChild(B);j.markerEls=null}if(this._k.size===0&&this._n)this._g.off("scroll",this._n),this._n=null}killAll(){for(let j of this._k)this._A(j);this._k.clear()}_V(j,B){let G=this._g,J=[],X=G._b?"top":"left",K=G._b?"height":"width",N=G._b?"width":"height",Q=G._d?G._b?window.innerHeight:window.innerWidth:G._b?G._c.clientHeight:G._c.clientWidth,Z=(Y,$)=>{let C=document.createElement("div");if(C.style.position="fixed",C.style[X]=Y*Q+"px",C.style[N]="100%",C.style[K]="2px",C.style.background=$,C.style.pointerEvents="none",C.style.zIndex="99999",G._b)C.style.left="0";else C.style.top="0";return document.body.appendChild(C),C};return J.push(Z(j,"#00ff00")),J.push(Z(B,"#ff0000")),J}observe(j){let B=typeof j.trigger==="string"?I(j.trigger):j.trigger;if(!B)throw Error(`ScrollObserver: trigger element not found: ${j.trigger}`);let G=w(j.start??"top bottom"),J=w(j.end??"bottom top"),X={progress:0,isActive:!1,state:"before",direction:this._g._h,trigger:B},K=null;if(j.pin)if(j.pin===!0)K=B;else if(typeof j.pin==="string"){if(K=I(j.pin),!K)throw Error(`ScrollObserver: pin element not found: ${j.pin}`)}else K=j.pin;let N=G[1],Q={el:B,pinEl:K,cfg:j,info:X,state:"before",startParsed:G,endParsed:J,markerEls:null,pinData:null,pinPosFrac:N};if(K){let Z=B.getBoundingClientRect(),Y=K.getBoundingClientRect(),$=this._m(Z,G),C=this._m(Z,J),V=this._g,v=V._b?V._d?window.innerHeight:V._c.clientHeight:V._d?window.innerWidth:V._c.clientWidth,S=V._b?Y.height:Y.width,h=N*(v-S),g=V._b?Y.left:Y.top,x;if(V._b)x=V._d?Y.top+V._a:Y.top-V._c.getBoundingClientRect().top+V._a;else x=V._d?Y.left+V._a:Y.left-V._c.getBoundingClientRect().left+V._a;let H=typeof getComputedStyle<"u"?getComputedStyle(K):null,u=H?H.width:Y.width+"px",R=H?H.height:Y.height+"px",y={position:K.style.position,top:K.style.top,left:K.style.left,width:K.style.width,height:K.style.height,margin:K.style.margin,zIndex:K.style.zIndex,boxSizing:K.style.boxSizing,willChange:K.style.willChange,transform:K.style.transform,_width:u,_height:R},M=null;if(V._d)M=document.createElement("div"),M.style.width=u,M.style.height=R,M.style.margin=H?H.margin:"0",M.style.flexShrink="0";Q.pinData={startScroll:$,endScroll:C,pinViewportOffset:h,pinAbsPos:x,pinLeftOffset:g,origStyle:y,spacer:M}}if(j.markers)Q.markerEls=this._V(G[1],J[1]);if(this._k.add(Q),!this._n)this._n=()=>this._W(),this._g.on("scroll",this._n);return this._B(Q),{kill:()=>this._A(Q),get info(){return Q.info}}}}var q=0.09;class l{_c;_d;_b;_K;_f;_L;_t=!1;_x=!1;_r=new Map;_a=0;_e=0;_q=0;_h=1;_w=!1;_ac={current:0,target:0,velocity:0,direction:1,max:0,scrolling:!1};_i=!1;_F=0;_y=0;_R=0;_j=0;_z=null;_l=q;_o=null;_M;_N;_O;_P;_G=null;_C;_p;constructor(j={}){let B=j.wrapper??window;this._c=typeof B==="string"?I(B)??window:B,this._d=this._c===window,this._b=(j.direction??"vertical")==="vertical",this._K=j.duration??0,this._f=j.ease??q,this._L=j.prevent??!this._d,this._M=this._X.bind(this),this._N=this._Y.bind(this),this._O=this._Z.bind(this),this._P=()=>this._p._$(),this._C=()=>this._aa(),this._p=new F(this);let G=this._d?this._b?window.scrollY:window.scrollX:this._b?this._c.scrollTop:this._c.scrollLeft;if(this._a=G,this._e=G,this.start(),typeof requestAnimationFrame<"u")requestAnimationFrame(()=>this._ab())}_ab(){if(this._i)return;let j=this._d?this._b?window.scrollY:window.scrollX:this._b?this._c.scrollTop:this._c.scrollLeft;if(j===this._a)return;let B=this._a;if(this._a=j,this._e=j,j>B)this._h=1;else if(j<B)this._h=-1;this._v("scroll")}get scroll(){let j=this._ac;return j.current=this._a,j.target=this._e,j.velocity=this._q,j.direction=this._h,j.max=this._D(),j.scrolling=this._w,j}_D(){if(this._d)return this._b?document.documentElement.scrollHeight-window.innerHeight:document.documentElement.scrollWidth-window.innerWidth;let j=this._c;return this._b?j.scrollHeight-j.clientHeight:j.scrollWidth-j.clientWidth}_E(j){return U(j,0,this._D())}on(j,B){let G=this._r.get(j);if(!G)G=new Set,this._r.set(j,G);G.add(B)}off(j,B){this._r.get(j)?.delete(B)}_v(j){let B=this._r.get(j);if(!B)return;let G=this.scroll;for(let J of B)J(G)}_s(){if(this._x)return;this._x=!0,A.add(this._C)}_T(){if(!this._x)return;this._x=!1,A.remove(this._C)}to(j,B={}){let G;if(typeof j==="number")G=j;else{let K=typeof j==="string"?I(j):j;if(!K)return;let N=K.getBoundingClientRect();if(this._d)G=(this._b?N.top:N.left)+this._a;else{let Z=this._c.getBoundingClientRect();G=(this._b?N.top-Z.top:N.left-Z.left)+this._a}}if(G+=B.offset??0,G=this._E(G),B.immediate){this._a=G,this._e=G,this._i=!0,this._Q(),this._v("scroll"),this._i=!1,B.onComplete?.();return}this._i=!0,this._s();let J=B.ease??this._f,X=B.duration??this._K;if(typeof J==="number")this._j=0,this._e=G,this._l=J,this._o=B.onComplete??null;else if(X>0)this._F=this._a,this._y=G,this._R=performance.now(),this._j=X,this._l=J,this._z=B.onComplete??null,this._o=null;else this._j=0,this._e=G,this._l=typeof this._f==="number"?this._f:q,this._o=B.onComplete??null}_S(j){let B=this._d?window:this._c;T(B,j,"wheel",this._M),T(B,j,"scroll",this._N,{passive:!0}),T(window,j,"keydown",this._O)}start(){if(this._t)return;this._t=!0,this._S("a"),this._G=P.add(this._P)}stop(){if(!this._t)return;this._t=!1,this._S("r"),this._G?.(),this._G=null,this._T()}destroy(){this._p.killAll(),this.stop(),this._r.clear()}_X(j){if(j.preventDefault(),this._L)j.stopPropagation();let B=this._b?j.deltaY:j.deltaX;if(j.deltaMode===1)B*=0.833333;else if(j.deltaMode===2)B*=0.555556;this._e=this._E(this._e+B),this._j=0,this._l=typeof this._f==="number"?this._f:q,this._i=!0,this._s(),this._h=B>0?1:-1}_Y(){if(this._i)return;let j=this._d?this._b?window.scrollY:window.scrollX:this._b?this._c.scrollTop:this._c.scrollLeft,B=this._a;if(this._a=j,this._e=j,j>B)this._h=1;else if(j<B)this._h=-1;if(j!==B)this._v("scroll")}_Z(j){if(!this._d){let J=document.activeElement;if(J!==this._c&&!this._c.contains(J))return}let B=0,G=this._b?this._d?window.innerHeight:this._c.clientHeight:this._d?window.innerWidth:this._c.clientWidth;switch(j.key){case"ArrowDown":B=100;break;case"ArrowUp":B=-100;break;case"ArrowRight":if(!this._b)B=100;break;case"ArrowLeft":if(!this._b)B=-100;break;case" ":B=j.shiftKey?-G:G;break;case"PageDown":B=G;break;case"PageUp":B=-G;break;case"Home":this._e=0,this._j=0,this._l=typeof this._f==="number"?this._f:q,this._i=!0,this._s();return;case"End":this._e=this._D(),this._j=0,this._l=typeof this._f==="number"?this._f:q,this._i=!0,this._s();return;default:return}if(B)j.preventDefault(),this._e=this._E(this._e+B),this._j=0,this._l=typeof this._f==="number"?this._f:q,this._i=!0,this._s(),this._h=B>0?1:-1}_Q(){if(this._d)if(this._b)window.scrollTo(0,this._a);else window.scrollTo(this._a,0);else{let j=this._c;if(this._b)j.scrollTop=this._a;else j.scrollLeft=this._a}}_aa(){if(!this._t)return;let j=this._a,B=!1;if(this._i){if(this._j>0){let J=performance.now()-this._R,X=_(0,this._j,J),K=this._l(X);if(this._a=this._F+(this._y-this._F)*K,this._e=this._y,X>=1)this._a=this._y,this._j=0,B=!0}else{let J=this._l;if(this._a=k(this._a,this._e,J,E()),Math.abs(this._e-this._a)<0.5)this._a=this._e,B=!0}this._Q()}this._q=this._a-j;let G=this._w;if(this._w=Math.abs(this._q)>0.01,this._q>0)this._h=1;else if(this._q<0)this._h=-1;if(this._w||G)this._v("scroll");if(B){if(this._i=!1,this._T(),this._z){let J=this._z;this._z=null,J()}if(this._o){let J=this._o;this._o=null,J()}}}observe(j){return this._p.observe(j)}obs(j){return this._p.observe(j)}}
2
+ export{P as b,l as c};
@@ -1,2 +1,2 @@
1
- import{c as L,e as a,f as r}from"./chunk-0t3a7kj5.js";var I=1,B=2,K=4,C="inline-block",f="nowrap",E="baseline",S="0px",g="block",m="maskChar",p="maskWord",l="maskLine",t=/^\s+$/,e=/(\s+)/,c=",div,span,svg,img,br,hr,canvas,video,audio,iframe,input,textarea,select,button,picture,figure,",w={u:"underline",ins:"underline",s:"line-through",strike:"line-through",del:"line-through"};class i{dom;chars;words;lines;masks;_n;_k;_g;_j;_f=[];_o=new Map;_i=null;_h=0;_l=!1;_c="";_d;_e;_a;_b=null;constructor(z,J={}){let F;if(typeof z==="string"){let q=r(z);if(q.length>1)F=q;else{let $=q[0]??a(z);if(!$)throw Error("SplitText: element not found");F=$}}else F=z;if(J.children){if(Array.isArray(F)||typeof F==="object"&&F!==null&&"length"in F&&typeof F.item==="function")F=Array.from(F).flatMap((U)=>Array.from(U.children));else F=Array.from(F.children);let{children:q,...$}=J;J=$}if(Array.isArray(F)||typeof F==="object"&&F!==null&&"length"in F&&typeof F.item==="function"){let q=Array.from(F);if(q.length===0)throw Error("SplitText: empty element array");this._b=q.map(($)=>new i($,J)),this.dom=q,this.chars=this._b.flatMap(($)=>$.chars),this.words=this._b.flatMap(($)=>$.words),this.lines=this._b.flatMap(($)=>$.lines),this.masks={chars:this._b.flatMap(($)=>$.masks.chars),words:this._b.flatMap(($)=>$.masks.words),lines:this._b.flatMap(($)=>$.masks.lines)},this._n="",this._k=0,this._g=0,this._j="";return}let G=F;this._a=G,this.dom=G,this._n=G.innerHTML,this.chars=[],this.words=[],this.lines=[],this.masks={chars:[],words:[],lines:[]};let Q=J.type?Array.isArray(J.type)?J.type:[J.type]:["chars","words","lines"],Y=0;for(let q of Q)if(q==="chars")Y|=I;else if(q==="words")Y|=B;else if(q==="lines")Y|=K;this._k=Y,this._j=J.tag??"span";let D=0;if(J.mask===!0)D=Y;else if(Array.isArray(J.mask)){for(let q of J.mask)if(q==="chars")D|=I;else if(q==="words")D|=B;else if(q==="lines")D|=K}if(this._g=D,this._d=J.style,this._e=J.class,this._w(),(J.resize??!0)&&Y&K)this._x()}_p(z,J){let F=document.createElement(this._j);if(z)F.dataset[z]="";if(F.style.display=C,J!==void 0)F.textContent=J;return F}_s(z,J){let F=document.createElement(this._j);if(F.dataset[J]="",F.style.overflow="hidden",F.style.display=z,this._d?.mask)Object.assign(F.style,this._d.mask);if(this._e?.mask)F.classList.add(this._e.mask);return F}_r(z,J,F,H,G){if(this._g&J){let Q=this._s(F,H);return Q.appendChild(z),G.push(Q),Q}return z}_m(z,J,F,H){if(F){let{outer:G,inner:Q}=F();if(Q.appendChild(J),H)this._o.set(H,G);z.appendChild(G)}else z.appendChild(J)}_q(z,J,F){if(z.style.textDecoration=J,F)z.style.textDecorationColor=F}_w(){this._l=!0;let z=this._a,J=L(z),F=J?parseFloat(J.letterSpacing)||0:0;if(this._c=J?J.textIndent:"",this._c&&this._c!==S)z.style.textIndent="0";let H=this._k,G=!!(H&I),Q=!!(H&B),Y=!!(H&K),D=Q||Y,q=!!(this._g&I),$=new Map,U=new Set,O=(R)=>{for(let j of Array.from(R.childNodes))if(j.nodeType===1){let X=j.tagName.toLowerCase();if(w[X]){let b=L(j)?.textDecorationColor;if(b)$.set(j,b)}if(c.includes(","+X+",")&&L(j)?.display==="contents")U.add(j);O(j)}};O(z);let d=Array.from(z.childNodes),M=document.createDocumentFragment();z.replaceChildren();let W=(R,j,X,b)=>{if(R.nodeType===3){let Z=(R.textContent??"").split(e);for(let N of Z){if(!N)continue;if(t.test(N)){M.appendChild(document.createTextNode(N));continue}let V=D?this._p(Q?"word":""):null;if(V){if(V.style.whiteSpace=f,X&&!G)this._q(V,X,b)}if(G){let P=[...N],u=this.chars.length;for(let T=0;T<P.length;T++){let x=this._p("char",P[T]);if(F&&T<P.length-1)x.style.marginRight=`${F}px`;if(X)this._q(x,X,b);if(this.chars.push(x),this._d?.chars)Object.assign(x.style,this._d.chars);if(this._e?.chars)x.classList.add(this._e.chars);let y=q?this._r(x,I,C,m,this.masks.chars):x;if(V)V.appendChild(y)}if(!V){let T=j?j():null,x=T?T.inner:M;for(let y=u;y<this.chars.length;y++){let k=this.chars[y];x.appendChild(q&&k.parentElement?.dataset?.[m]!==void 0?k.parentElement:k)}if(T)M.appendChild(T.outer)}}else if(V){if(V.textContent=N,F)V.style.letterSpacing=`${F}px`}if(V){if(Q){if(this.words.push(V),this._d?.words)Object.assign(V.style,this._d.words);if(this._e?.words)V.classList.add(this._e.words)}this._f.push(V);let P=this._g&B?this._r(V,B,C,p,this.masks.words):V;this._m(M,P,j,V)}else if(!G)this._m(M,document.createTextNode(N),j)}return}if(R.nodeType!==1)return;let v=R,h=v.tagName.toLowerCase();if(c.includes(","+h+",")){if(U.has(v)){let V=M,P=document.createDocumentFragment();M=P;for(let T of Array.from(v.childNodes))W(T,j,X,b);M=V;let u=v.cloneNode(!1);u.appendChild(P),M.appendChild(u);return}let Z=v.cloneNode(!0);if(X)this._q(Z,X,b);let N=L(v)?.verticalAlign;if(N&&N!==E)Z.style.verticalAlign=N;if(D){let V=this._p(Q?"word":"");if(V.style.whiteSpace=f,N&&N!==E)V.style.verticalAlign=N;if(V.appendChild(Z),Q){if(this.words.push(V),this._d?.words)Object.assign(V.style,this._d.words);if(this._e?.words)V.classList.add(this._e.words)}this._f.push(V);let P=this._g&B?this._r(V,B,C,p,this.masks.words):V;this._m(M,P,j,V)}else this._m(M,Z,j);return}let s=()=>{let Z=v.cloneNode(!1);if(j){let{outer:N,inner:V}=j();return V.appendChild(Z),{outer:N,inner:Z}}return{outer:Z,inner:Z}},_=w[h],n=_?X?`${X} ${_}`:_:X,o=_?$.get(v)||b:b;for(let Z of Array.from(v.childNodes))W(Z,s,n,o)};for(let R of d)W(R,null,"","");z.appendChild(M);let A=!!(this._c&&this._c!==S);if(Y)this._y(A);else if(A){let R=Q?this.words[0]:G?this.chars[0]:null;if(R)R.style.marginLeft=this._c,z.style.textIndent="0"}this._l=!1}_y(z){if(z&&this._f[0])this._f[0].style.marginLeft=this._c;this._t();let J=[];if(typeof document.fonts?.status==="string"&&document.fonts.status!=="loaded")J.push(document.fonts.ready);let F=this._a.querySelectorAll("img");for(let H=0;H<F.length;H++){let G=F[H];if(!G.complete)J.push(new Promise((Q)=>{G.addEventListener("load",Q,{once:!0}),G.addEventListener("error",Q,{once:!0})}))}if(J.length){let H=this._a.offsetHeight===0&&this._a.parentElement?this._a.parentElement:this._a,G=H.offsetHeight;Promise.all(J).then(()=>{if(H.offsetHeight!==G)this.reflow()})}}_u(z){return this._o.get(z)??z}_t(){let z=this._f;if(!z.length)return;let J=z[0].offsetTop,F=J+z[0].offsetHeight,H=[],G=[];for(let q of z){let $=q.offsetTop,U=$+q.offsetHeight;if($<F&&U>J)J=Math.min(J,$),F=Math.max(F,U);else G.push(H),H=[],J=$,F=U;H.push(q)}if(H.length)G.push(H);let Q=!!(this._c&&this._c!==S);if(Q&&z[0])z[0].style.marginLeft="";let Y=!!(this._g&K),D=document.createDocumentFragment();for(let q=0;q<G.length;q++){let $=G[q],U=document.createElement(this._j);if(U.dataset.line="",U.style.display=g,q===0&&Q)U.style.paddingLeft=this._c;for(let O=0;O<$.length;O++){if(O>0)U.appendChild(document.createTextNode(" "));U.appendChild(this._u($[O]))}if(this.lines.push(U),this._d?.lines)Object.assign(U.style,this._d.lines);if(this._e?.lines)U.classList.add(this._e.lines);if(Y){let O=this._s(g,l);O.appendChild(U),this.masks.lines.push(O),D.appendChild(O)}else D.appendChild(U)}this._a.replaceChildren(D)}_x(){let z=this._a.offsetParent?this._a.offsetParent.offsetWidth:window.innerWidth,J=()=>{if(this._l)return;let H=this._a.offsetParent,G=H?H.offsetWidth:window.innerWidth;if(G===z)return;if(z=G,this._h)cancelAnimationFrame(this._h);this._h=requestAnimationFrame(()=>this.reflow())};this._i=new ResizeObserver(J);let F=this._a.offsetParent??this._a.parentElement;if(F)this._i.observe(F);else this._i.observe(this._a)}reflow(){if(this._b){this._b.forEach((J)=>J.reflow()),this._v();return}if(!(this._k&K)||this._l)return;let z=document.createDocumentFragment();for(let J=0;J<this._f.length;J++){if(J>0)z.appendChild(document.createTextNode(" "));z.appendChild(this._u(this._f[J]))}if(this._a.replaceChildren(z),this.lines.length=0,this.masks.lines.length=0,this._c&&this._c!==S&&this._f[0])this._f[0].style.marginLeft=this._c;this._t()}revert(){if(this._b){this._b.forEach((z)=>z.revert()),this._v();return}this.destroy(),this._a.innerHTML=this._n,this.chars.length=0,this.words.length=0,this._f.length=0,this._o.clear(),this.lines.length=0,this.masks.chars.length=0,this.masks.words.length=0,this.masks.lines.length=0}destroy(){if(this._b){this._b.forEach((z)=>z.destroy());return}if(this._h)cancelAnimationFrame(this._h),this._h=0;if(this._i)this._i.disconnect(),this._i=null}_v(){if(!this._b)return;this.chars.length=0,this.words.length=0,this.lines.length=0,this.masks.chars.length=0,this.masks.words.length=0,this.masks.lines.length=0;for(let z of this._b)this.chars.push(...z.chars),this.words.push(...z.words),this.lines.push(...z.lines),this.masks.chars.push(...z.masks.chars),this.masks.words.push(...z.masks.words),this.masks.lines.push(...z.masks.lines)}}
1
+ import{d as L,f as a,g as r}from"./chunk-p2rw7d5g.js";var I=1,B=2,K=4,C="inline-block",f="nowrap",E="baseline",S="0px",g="block",m="maskChar",p="maskWord",l="maskLine",t=/^\s+$/,e=/(\s+)/,c=",div,span,svg,img,br,hr,canvas,video,audio,iframe,input,textarea,select,button,picture,figure,",w={u:"underline",ins:"underline",s:"line-through",strike:"line-through",del:"line-through"};class i{dom;chars;words;lines;masks;_n;_k;_g;_j;_f=[];_o=new Map;_i=null;_h=0;_l=!1;_c="";_d;_e;_a;_b=null;constructor(z,J={}){let F;if(typeof z==="string"){let q=r(z);if(q.length>1)F=q;else{let $=q[0]??a(z);if(!$)throw Error("SplitText: element not found");F=$}}else F=z;if(J.children){if(Array.isArray(F)||typeof F==="object"&&F!==null&&"length"in F&&typeof F.item==="function")F=Array.from(F).flatMap((U)=>Array.from(U.children));else F=Array.from(F.children);let{children:q,...$}=J;J=$}if(Array.isArray(F)||typeof F==="object"&&F!==null&&"length"in F&&typeof F.item==="function"){let q=Array.from(F);if(q.length===0)throw Error("SplitText: empty element array");this._b=q.map(($)=>new i($,J)),this.dom=q,this.chars=this._b.flatMap(($)=>$.chars),this.words=this._b.flatMap(($)=>$.words),this.lines=this._b.flatMap(($)=>$.lines),this.masks={chars:this._b.flatMap(($)=>$.masks.chars),words:this._b.flatMap(($)=>$.masks.words),lines:this._b.flatMap(($)=>$.masks.lines)},this._n="",this._k=0,this._g=0,this._j="";return}let G=F;this._a=G,this.dom=G,this._n=G.innerHTML,this.chars=[],this.words=[],this.lines=[],this.masks={chars:[],words:[],lines:[]};let Q=J.type?Array.isArray(J.type)?J.type:[J.type]:["chars","words","lines"],Y=0;for(let q of Q)if(q==="chars")Y|=I;else if(q==="words")Y|=B;else if(q==="lines")Y|=K;this._k=Y,this._j=J.tag??"span";let D=0;if(J.mask===!0)D=Y;else if(Array.isArray(J.mask)){for(let q of J.mask)if(q==="chars")D|=I;else if(q==="words")D|=B;else if(q==="lines")D|=K}if(this._g=D,this._d=J.style,this._e=J.class,this._w(),(J.resize??!0)&&Y&K)this._x()}_p(z,J){let F=document.createElement(this._j);if(z)F.dataset[z]="";if(F.style.display=C,J!==void 0)F.textContent=J;return F}_s(z,J){let F=document.createElement(this._j);if(F.dataset[J]="",F.style.overflow="hidden",F.style.display=z,this._d?.mask)Object.assign(F.style,this._d.mask);if(this._e?.mask)F.classList.add(this._e.mask);return F}_r(z,J,F,H,G){if(this._g&J){let Q=this._s(F,H);return Q.appendChild(z),G.push(Q),Q}return z}_m(z,J,F,H){if(F){let{outer:G,inner:Q}=F();if(Q.appendChild(J),H)this._o.set(H,G);z.appendChild(G)}else z.appendChild(J)}_q(z,J,F){if(z.style.textDecoration=J,F)z.style.textDecorationColor=F}_w(){this._l=!0;let z=this._a,J=L(z),F=J?parseFloat(J.letterSpacing)||0:0;if(this._c=J?J.textIndent:"",this._c&&this._c!==S)z.style.textIndent="0";let H=this._k,G=!!(H&I),Q=!!(H&B),Y=!!(H&K),D=Q||Y,q=!!(this._g&I),$=new Map,U=new Set,O=(R)=>{for(let j of Array.from(R.childNodes))if(j.nodeType===1){let X=j.tagName.toLowerCase();if(w[X]){let b=L(j)?.textDecorationColor;if(b)$.set(j,b)}if(c.includes(","+X+",")&&L(j)?.display==="contents")U.add(j);O(j)}};O(z);let d=Array.from(z.childNodes),M=document.createDocumentFragment();z.replaceChildren();let W=(R,j,X,b)=>{if(R.nodeType===3){let Z=(R.textContent??"").split(e);for(let N of Z){if(!N)continue;if(t.test(N)){M.appendChild(document.createTextNode(N));continue}let V=D?this._p(Q?"word":""):null;if(V){if(V.style.whiteSpace=f,X&&!G)this._q(V,X,b)}if(G){let P=[...N],u=this.chars.length;for(let T=0;T<P.length;T++){let x=this._p("char",P[T]);if(F&&T<P.length-1)x.style.marginRight=`${F}px`;if(X)this._q(x,X,b);if(this.chars.push(x),this._d?.chars)Object.assign(x.style,this._d.chars);if(this._e?.chars)x.classList.add(this._e.chars);let y=q?this._r(x,I,C,m,this.masks.chars):x;if(V)V.appendChild(y)}if(!V){let T=j?j():null,x=T?T.inner:M;for(let y=u;y<this.chars.length;y++){let k=this.chars[y];x.appendChild(q&&k.parentElement?.dataset?.[m]!==void 0?k.parentElement:k)}if(T)M.appendChild(T.outer)}}else if(V){if(V.textContent=N,F)V.style.letterSpacing=`${F}px`}if(V){if(Q){if(this.words.push(V),this._d?.words)Object.assign(V.style,this._d.words);if(this._e?.words)V.classList.add(this._e.words)}this._f.push(V);let P=this._g&B?this._r(V,B,C,p,this.masks.words):V;this._m(M,P,j,V)}else if(!G)this._m(M,document.createTextNode(N),j)}return}if(R.nodeType!==1)return;let v=R,h=v.tagName.toLowerCase();if(c.includes(","+h+",")){if(U.has(v)){let V=M,P=document.createDocumentFragment();M=P;for(let T of Array.from(v.childNodes))W(T,j,X,b);M=V;let u=v.cloneNode(!1);u.appendChild(P),M.appendChild(u);return}let Z=v.cloneNode(!0);if(X)this._q(Z,X,b);let N=L(v)?.verticalAlign;if(N&&N!==E)Z.style.verticalAlign=N;if(D){let V=this._p(Q?"word":"");if(V.style.whiteSpace=f,N&&N!==E)V.style.verticalAlign=N;if(V.appendChild(Z),Q){if(this.words.push(V),this._d?.words)Object.assign(V.style,this._d.words);if(this._e?.words)V.classList.add(this._e.words)}this._f.push(V);let P=this._g&B?this._r(V,B,C,p,this.masks.words):V;this._m(M,P,j,V)}else this._m(M,Z,j);return}let s=()=>{let Z=v.cloneNode(!1);if(j){let{outer:N,inner:V}=j();return V.appendChild(Z),{outer:N,inner:Z}}return{outer:Z,inner:Z}},_=w[h],n=_?X?`${X} ${_}`:_:X,o=_?$.get(v)||b:b;for(let Z of Array.from(v.childNodes))W(Z,s,n,o)};for(let R of d)W(R,null,"","");z.appendChild(M);let A=!!(this._c&&this._c!==S);if(Y)this._y(A);else if(A){let R=Q?this.words[0]:G?this.chars[0]:null;if(R)R.style.marginLeft=this._c,z.style.textIndent="0"}this._l=!1}_y(z){if(z&&this._f[0])this._f[0].style.marginLeft=this._c;this._t();let J=[];if(typeof document.fonts?.status==="string"&&document.fonts.status!=="loaded")J.push(document.fonts.ready);let F=this._a.querySelectorAll("img");for(let H=0;H<F.length;H++){let G=F[H];if(!G.complete)J.push(new Promise((Q)=>{G.addEventListener("load",Q,{once:!0}),G.addEventListener("error",Q,{once:!0})}))}if(J.length){let H=this._a.offsetHeight===0&&this._a.parentElement?this._a.parentElement:this._a,G=H.offsetHeight;Promise.all(J).then(()=>{if(H.offsetHeight!==G)this.reflow()})}}_u(z){return this._o.get(z)??z}_t(){let z=this._f;if(!z.length)return;let J=z[0].offsetTop,F=J+z[0].offsetHeight,H=[],G=[];for(let q of z){let $=q.offsetTop,U=$+q.offsetHeight;if($<F&&U>J)J=Math.min(J,$),F=Math.max(F,U);else G.push(H),H=[],J=$,F=U;H.push(q)}if(H.length)G.push(H);let Q=!!(this._c&&this._c!==S);if(Q&&z[0])z[0].style.marginLeft="";let Y=!!(this._g&K),D=document.createDocumentFragment();for(let q=0;q<G.length;q++){let $=G[q],U=document.createElement(this._j);if(U.dataset.line="",U.style.display=g,q===0&&Q)U.style.paddingLeft=this._c;for(let O=0;O<$.length;O++){if(O>0)U.appendChild(document.createTextNode(" "));U.appendChild(this._u($[O]))}if(this.lines.push(U),this._d?.lines)Object.assign(U.style,this._d.lines);if(this._e?.lines)U.classList.add(this._e.lines);if(Y){let O=this._s(g,l);O.appendChild(U),this.masks.lines.push(O),D.appendChild(O)}else D.appendChild(U)}this._a.replaceChildren(D)}_x(){let z=this._a.offsetParent?this._a.offsetParent.offsetWidth:window.innerWidth,J=()=>{if(this._l)return;let H=this._a.offsetParent,G=H?H.offsetWidth:window.innerWidth;if(G===z)return;if(z=G,this._h)cancelAnimationFrame(this._h);this._h=requestAnimationFrame(()=>this.reflow())};this._i=new ResizeObserver(J);let F=this._a.offsetParent??this._a.parentElement;if(F)this._i.observe(F);else this._i.observe(this._a)}reflow(){if(this._b){this._b.forEach((J)=>J.reflow()),this._v();return}if(!(this._k&K)||this._l)return;let z=document.createDocumentFragment();for(let J=0;J<this._f.length;J++){if(J>0)z.appendChild(document.createTextNode(" "));z.appendChild(this._u(this._f[J]))}if(this._a.replaceChildren(z),this.lines.length=0,this.masks.lines.length=0,this._c&&this._c!==S&&this._f[0])this._f[0].style.marginLeft=this._c;this._t()}revert(){if(this._b){this._b.forEach((z)=>z.revert()),this._v();return}this.destroy(),this._a.innerHTML=this._n,this.chars.length=0,this.words.length=0,this._f.length=0,this._o.clear(),this.lines.length=0,this.masks.chars.length=0,this.masks.words.length=0,this.masks.lines.length=0}destroy(){if(this._b){this._b.forEach((z)=>z.destroy());return}if(this._h)cancelAnimationFrame(this._h),this._h=0;if(this._i)this._i.disconnect(),this._i=null}_v(){if(!this._b)return;this.chars.length=0,this.words.length=0,this.lines.length=0,this.masks.chars.length=0,this.masks.words.length=0,this.masks.lines.length=0;for(let z of this._b)this.chars.push(...z.chars),this.words.push(...z.words),this.lines.push(...z.lines),this.masks.chars.push(...z.masks.chars),this.masks.words.push(...z.masks.words),this.masks.lines.push(...z.masks.lines)}}
2
2
  export{i as a};
@@ -1,2 +1,2 @@
1
1
  function R(j,k){return typeof globalThis.getComputedStyle==="function"?globalThis.getComputedStyle(j,k??null):null}var K=["whe","mou","tou","poi"];function J(j){return K.includes(j.slice(0,3))}function L(j,k){if(!k)return J(j)?{passive:!1}:!1;if(typeof k==="object"&&k.passive===void 0&&J(j))return{...k,passive:!1};return k}function M(j){if(!j)return!1;if(typeof j==="object")return j.capture??!1;return j}function V(j,k,w,B,D){let E=k==="a"?"addEventListener":"removeEventListener",G=k==="a"?L(w,D):M(D);if(typeof j==="string"){let H=Q(j);for(let z=0;z<H.length;z++)H[z][E](w,B,G)}else j[E](w,B,G)}function W(j,k){let w=k??document;return typeof w.querySelector==="function"?w.querySelector(j):null}function Q(j,k){let w=k??document;return typeof w.querySelectorAll==="function"?Array.from(w.querySelectorAll(j)):[]}
2
- export{R as c,V as d,W as e,Q as f};
2
+ export{R as d,V as e,W as f,Q as g};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { SplitText, type SplitTextOptions, type SplitType, } from "./split-text/index.ts";
2
2
  export { SmoothScroll, type SmoothScrollOptions, type ScrollToOptions, type ScrollState, type ScrollObserverConfig, type ScrollObserverInfo, type ScrollObserverInstance, type ScrollPosition, } from "./smooth-scroll/index.ts";
3
3
  export { Ticker, getDeltaFrame, type TickerCallback } from "./ticker/index.ts";
4
+ export { Resize, type ResizeCallback } from "./resize/index.ts";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{a as e}from"./chunk-bx1fe9dn.js";import{b as r}from"./chunk-s9ce6x50.js";import"./chunk-0t3a7kj5.js";import{g as t,h as o}from"./chunk-qjsknche.js";export{t as getDeltaFrame,o as Ticker,e as SplitText,r as SmoothScroll};
1
+ import{a as e}from"./chunk-hyjajve1.js";import{b as r,c as l}from"./chunk-hqe73gam.js";import"./chunk-p2rw7d5g.js";import{h as t,i as o}from"./chunk-fatbf8es.js";export{t as getDeltaFrame,o as Ticker,e as SplitText,l as SmoothScroll,r as Resize};
@@ -0,0 +1,17 @@
1
+ export type ResizeCallback = () => void;
2
+ /**
3
+ * Centralized window resize handler.
4
+ *
5
+ * Single `resize` listener on `window`, batched to the next animation frame
6
+ * so callbacks fire at most once per frame.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const off = Resize.add(() => console.log("resized"));
11
+ * off(); // remove
12
+ * ```
13
+ */
14
+ export declare const Resize: {
15
+ add(cb: ResizeCallback): () => void;
16
+ remove(cb: ResizeCallback): void;
17
+ };
@@ -51,9 +51,13 @@ export declare class SmoothScroll {
51
51
  /** @internal */ _onWheelBound: (e: WheelEvent) => void;
52
52
  /** @internal */ _onScrollBound: () => void;
53
53
  /** @internal */ _onKeyDownBound: (e: KeyboardEvent) => void;
54
+ /** @internal */ _onResizeBound: () => void;
55
+ /** @internal */ _removeResize: (() => void) | null;
54
56
  /** @internal */ _tickBound: () => void;
55
57
  /** @internal */ _obs: _ObserverManager;
56
58
  constructor(options?: SmoothScrollOptions);
59
+ /** @internal — force-read native scroll position; emits "scroll" if changed. */
60
+ _syncNativeScroll(): void;
57
61
  get scroll(): ScrollState;
58
62
  /** @internal */
59
63
  _max(): number;
@@ -83,6 +87,25 @@ export declare class SmoothScroll {
83
87
  _applyScroll(): void;
84
88
  /** @internal */
85
89
  _tick(): void;
90
+ /**
91
+ * Observe when an element enters/leaves the viewport.
92
+ *
93
+ * @example
94
+ * scroll.observe({
95
+ * trigger: "#my-element",
96
+ * start: { dom: "top", viewport: "80%" },
97
+ * end: { dom: "bottom", viewport: "20%" },
98
+ * onEnter(info) {},
99
+ * onLeave(info) {},
100
+ * onEnterBack(info) {},
101
+ * onLeaveBack(info) {},
102
+ * onUpdate(info) {},
103
+ * once: false,
104
+ * markers: false,
105
+ * toggleClass: "is-active",
106
+ * });
107
+ */
86
108
  observe(config: ScrollObserverConfig): ScrollObserverInstance;
109
+ /** Alias for {@link observe}. */
87
110
  obs(config: ScrollObserverConfig): ScrollObserverInstance;
88
111
  }
@@ -1 +1 @@
1
- import{b as a}from"../chunk-s9ce6x50.js";import"../chunk-0t3a7kj5.js";import"../chunk-qjsknche.js";export{a as SmoothScroll};
1
+ import{c as a}from"../chunk-hqe73gam.js";import"../chunk-p2rw7d5g.js";import"../chunk-fatbf8es.js";export{a as SmoothScroll};
@@ -1,30 +1,97 @@
1
1
  type ObserverState = "before" | "active" | "after";
2
+ interface _PinOrigStyle {
3
+ position: string;
4
+ top: string;
5
+ left: string;
6
+ width: string;
7
+ height: string;
8
+ margin: string;
9
+ zIndex: string;
10
+ boxSizing: string;
11
+ willChange: string;
12
+ transform: string;
13
+ _width: string;
14
+ _height: string;
15
+ }
16
+ interface _PinData {
17
+ startScroll: number;
18
+ endScroll: number;
19
+ pinViewportOffset: number;
20
+ /** Pin element's absolute position in the document/container. */
21
+ pinAbsPos: number;
22
+ /** Cross-axis viewport offset (for window fixed positioning). */
23
+ pinLeftOffset: number;
24
+ origStyle: _PinOrigStyle;
25
+ /** Spacer element to hold flow space (window mode only). */
26
+ spacer: HTMLElement | null;
27
+ }
28
+ /**
29
+ * Position for `start`/`end`. String form: `"top 80%"`. Object form: `{ dom: "top", viewport: "80%" }`.
30
+ *
31
+ * Tokens: `top`, `center`, `bottom`, `left`, `right`, percentages (`80%`), offsets (`top+=100`, `bottom-=50`).
32
+ */
2
33
  export type ScrollPosition = string | {
3
34
  dom: string;
4
35
  viewport: string;
5
36
  };
6
37
  export interface ScrollObserverConfig {
38
+ /** Element to observe — CSS selector or HTMLElement. */
7
39
  trigger: HTMLElement | string;
40
+ /**
41
+ * When the observer activates.
42
+ * @default "top bottom"
43
+ * @example
44
+ * start: "top 80%"
45
+ * start: { dom: "top", viewport: "80%" }
46
+ */
8
47
  start?: ScrollPosition;
48
+ /**
49
+ * When the observer deactivates.
50
+ * @default "bottom top"
51
+ * @example
52
+ * end: "bottom 20%"
53
+ * end: { dom: "bottom", viewport: "20%" }
54
+ */
9
55
  end?: ScrollPosition;
56
+ /** Fires when scrolling forward past `start` (before → active). */
10
57
  onEnter?: (self: ScrollObserverInfo) => void;
58
+ /** Fires when scrolling forward past `end` (active → after). */
11
59
  onLeave?: (self: ScrollObserverInfo) => void;
60
+ /** Fires when scrolling backward past `end` (after → active). */
12
61
  onEnterBack?: (self: ScrollObserverInfo) => void;
62
+ /** Fires when scrolling backward past `start` (active → before). */
13
63
  onLeaveBack?: (self: ScrollObserverInfo) => void;
64
+ /** Fires every frame while the observer is active. */
14
65
  onUpdate?: (self: ScrollObserverInfo) => void;
66
+ /** Auto-kill after the first activation. */
15
67
  once?: boolean;
68
+ /** Show fixed debug lines for start/end viewport positions. */
16
69
  markers?: boolean;
70
+ /** Class added to the trigger while active, removed otherwise. */
17
71
  toggleClass?: string;
72
+ /**
73
+ * Pin an element between start and end.
74
+ * `true` pins the trigger at the `start.viewport` position.
75
+ * A string (CSS selector) or HTMLElement pins that specific element.
76
+ */
77
+ pin?: boolean | HTMLElement | string;
18
78
  }
19
79
  export interface ScrollObserverInfo {
80
+ /** Progress between start and end (0–1). */
20
81
  progress: number;
82
+ /** Whether the observer is currently between start and end. */
21
83
  isActive: boolean;
84
+ /** Current state: `"before"`, `"active"`, or `"after"`. */
22
85
  state: ObserverState;
86
+ /** Scroll direction: `1` = forward, `-1` = backward. */
23
87
  direction: 1 | -1;
88
+ /** The observed element. */
24
89
  trigger: HTMLElement;
25
90
  }
26
91
  export interface ScrollObserverInstance {
92
+ /** Remove this observer and stop all callbacks. */
27
93
  kill(): void;
94
+ /** Current observer state (progress, isActive, etc.). */
28
95
  readonly info: ScrollObserverInfo;
29
96
  }
30
97
  /** Minimal contract the observer needs from the scroll host. */
@@ -34,17 +101,22 @@ export interface ScrollHost {
34
101
  _vertical: boolean;
35
102
  _wrapper: Window | HTMLElement;
36
103
  _dir: 1 | -1;
104
+ _driving: boolean;
37
105
  on(event: string, callback: (...args: any[]) => void): void;
38
106
  off(event: string, callback: (...args: any[]) => void): void;
39
107
  }
40
108
  interface _ObserverEntry {
41
109
  el: HTMLElement;
110
+ pinEl: HTMLElement | null;
42
111
  cfg: ScrollObserverConfig;
43
112
  info: ScrollObserverInfo;
44
113
  state: ObserverState;
45
114
  startParsed: [number, number, number, number];
46
115
  endParsed: [number, number, number, number];
47
116
  markerEls: HTMLElement[] | null;
117
+ pinData: _PinData | null;
118
+ /** Viewport fraction for pin position (from start.viewport). */
119
+ pinPosFrac: number;
48
120
  }
49
121
  export declare class _ObserverManager {
50
122
  _entries: Set<_ObserverEntry>;
@@ -52,8 +124,13 @@ export declare class _ObserverManager {
52
124
  _host: ScrollHost;
53
125
  constructor(host: ScrollHost);
54
126
  _computeScrollPos(rect: DOMRect, parsed: [number, number, number, number]): number;
127
+ _recomputePin(entry: _ObserverEntry): void;
55
128
  _check(entry: _ObserverEntry): void;
56
129
  _update(): void;
130
+ _applyPin(entry: _ObserverEntry, state: ObserverState): void;
131
+ _restorePin(entry: _ObserverEntry): void;
132
+ /** Called on resize — restore pinned elements, recompute, re-evaluate state. */
133
+ _onResize(): void;
57
134
  _kill(entry: _ObserverEntry): void;
58
135
  killAll(): void;
59
136
  _createMarkers(scrollerStartFrac: number, scrollerEndFrac: number): HTMLElement[];
@@ -1 +1 @@
1
- import{a}from"../chunk-bx1fe9dn.js";import"../chunk-0t3a7kj5.js";export{a as SplitText};
1
+ import{a}from"../chunk-hyjajve1.js";import"../chunk-p2rw7d5g.js";export{a as SplitText};
@@ -1 +1 @@
1
- import{g as a,h as b}from"../chunk-qjsknche.js";export{a as getDeltaFrame,b as Ticker};
1
+ import{h as a,i as b}from"../chunk-fatbf8es.js";export{a as getDeltaFrame,b as Ticker};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "situs-kit",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "A creative developer helper library",
5
5
  "license": "MIT",
6
6
  "module": "./dist/index.js",
@@ -1,2 +0,0 @@
1
- import{d as M,e as q}from"./chunk-0t3a7kj5.js";import{g as L,h as U}from"./chunk-qjsknche.js";function C(j,B,G){return Math.min(Math.max(j,B),G)}function O(j,B,G){return j+(B-j)*G}function z(j,B,G){let H=B-j;return H===0?0:C((G-j)/H,0,1)}function D(j,B,G,H){let Q=1-Math.exp(-G*H);return O(j,B,Q)}var P={top:0,left:0,center:0.5,bottom:1,right:1};function R(j){if(j in P)return P[j];if(j.endsWith("%"))return parseFloat(j)/100;let B=parseFloat(j);return isNaN(B)?0:B}function W(j){let B=j.indexOf("+=");if(B!==-1){let H=R(j.slice(0,B)),Q=parseFloat(j.slice(B+2));return[H,isNaN(Q)?0:Q]}let G=j.indexOf("-=");if(G!==-1){let H=R(j.slice(0,G)),Q=parseFloat(j.slice(G+2));return[H,isNaN(Q)?0:-Q]}return[R(j),0]}function x(j){if(typeof j==="object"){let[K,Z]=W(j.dom),[J,Y]=W(j.viewport);return[K,J,Z,Y]}let B=j.trim().split(/\s+/),[G,H]=W(B[0]),[Q,V]=B.length>1?W(B[1]):[G,0];return[G,Q,H,V]}class I{_l=new Set;_m=null;_j;constructor(j){this._j=j}_C(j,B){let[G,H,Q,V]=B,K=this._j,Z,J,Y;if(K._b)if(J=j.height,Y=K._d?window.innerHeight:K._c.clientHeight,K._d)Z=j.top+K._a;else{let X=K._c.getBoundingClientRect();Z=j.top-X.top+K._a}else if(J=j.width,Y=K._d?window.innerWidth:K._c.clientWidth,K._d)Z=j.left+K._a;else{let X=K._c.getBoundingClientRect();Z=j.left-X.left+K._a}return Z+G*J-H*Y+Q+V}_D(j){let B=this._j,G=j.el.getBoundingClientRect(),H=this._C(G,j.startParsed),Q=this._C(G,j.endParsed),V=Q-H,K=B._a,Z=V===0?K>=H?1:0:C((K-H)/V,0,1),J;if(K<H)J="before";else if(K>=Q)J="after";else J="active";let{state:Y,info:X,cfg:N}=j;if(X.progress=Z,X.direction=B._k,X.isActive=J==="active",X.state=J,Y!==J){if(j.state=J,N.toggleClass)if(J==="active")j.el.classList.add(N.toggleClass);else j.el.classList.remove(N.toggleClass);if(Y==="before"&&J==="active")N.onEnter?.(X);else if(Y==="active"&&J==="after")N.onLeave?.(X);else if(Y==="after"&&J==="active")N.onEnterBack?.(X);else if(Y==="active"&&J==="before")N.onLeaveBack?.(X);else if(Y==="before"&&J==="after")N.onEnter?.(X),N.onLeave?.(X);else if(Y==="after"&&J==="before")N.onEnterBack?.(X),N.onLeaveBack?.(X);if(N.once&&(J==="active"||Y==="before"&&J==="after")){this._x(j);return}}if(J==="active")N.onUpdate?.(X)}_P(){for(let j of this._l)this._D(j)}_x(j){if(this._l.delete(j),j.cfg.toggleClass&&j.state==="active")j.el.classList.remove(j.cfg.toggleClass);if(j.markerEls){for(let B of j.markerEls)B.parentElement?.removeChild(B);j.markerEls=null}if(this._l.size===0&&this._m)this._j.off("scroll",this._m),this._m=null}killAll(){for(let j of this._l)this._x(j);this._l.clear()}_O(j,B){let G=this._j,H=[],Q=G._b?"top":"left",V=G._b?"height":"width",K=G._b?"width":"height",Z=G._d?G._b?window.innerHeight:window.innerWidth:G._b?G._c.clientHeight:G._c.clientWidth,J=(Y,X)=>{let N=document.createElement("div");if(N.style.position="fixed",N.style[Q]=Y*Z+"px",N.style[K]="100%",N.style[V]="2px",N.style.background=X,N.style.pointerEvents="none",N.style.zIndex="99999",G._b)N.style.left="0";else N.style.top="0";return document.body.appendChild(N),N};return H.push(J(j,"#00ff00")),H.push(J(B,"#ff0000")),H}observe(j){let B=typeof j.trigger==="string"?q(j.trigger):j.trigger;if(!B)throw Error(`ScrollObserver: trigger element not found: ${j.trigger}`);let G=x(j.start??"top bottom"),H=x(j.end??"bottom top"),Q={progress:0,isActive:!1,state:"before",direction:this._j._k,trigger:B},V={el:B,cfg:j,info:Q,state:"before",startParsed:G,endParsed:H,markerEls:null};if(j.markers)V.markerEls=this._O(G[1],H[1]);if(this._l.add(V),!this._m)this._m=()=>this._P(),this._j.on("scroll",this._m);return this._D(V),{kill:()=>this._x(V),get info(){return V.info}}}}var $=0.09;class T{_c;_d;_b;_E;_f;_F;_r=!1;_u=!1;_p=new Map;_a=0;_e=0;_o=0;_k=1;_t=!1;_U={current:0,target:0,velocity:0,direction:1,max:0,scrolling:!1};_g=!1;_B=0;_v=0;_L=0;_h=0;_w=null;_i=$;_n=null;_G;_H;_I;_y;_s;constructor(j={}){let B=j.wrapper??window;this._c=typeof B==="string"?q(B)??window:B,this._d=this._c===window,this._b=(j.direction??"vertical")==="vertical",this._E=j.duration??0,this._f=j.ease??$,this._F=j.prevent??!this._d,this._G=this._Q.bind(this),this._H=this._R.bind(this),this._I=this._S.bind(this),this._y=()=>this._T(),this._s=new I(this);let G=this._d?this._b?window.scrollY:window.scrollX:this._b?this._c.scrollTop:this._c.scrollLeft;this._a=G,this._e=G,this.start()}get scroll(){let j=this._U;return j.current=this._a,j.target=this._e,j.velocity=this._o,j.direction=this._k,j.max=this._z(),j.scrolling=this._t,j}_z(){if(this._d)return this._b?document.documentElement.scrollHeight-window.innerHeight:document.documentElement.scrollWidth-window.innerWidth;let j=this._c;return this._b?j.scrollHeight-j.clientHeight:j.scrollWidth-j.clientWidth}_A(j){return C(j,0,this._z())}on(j,B){let G=this._p.get(j);if(!G)G=new Set,this._p.set(j,G);G.add(B)}off(j,B){this._p.get(j)?.delete(B)}_K(j){let B=this._p.get(j);if(!B)return;let G=this.scroll;for(let H of B)H(G)}_q(){if(this._u)return;this._u=!0,U.add(this._y)}_N(){if(!this._u)return;this._u=!1,U.remove(this._y)}to(j,B={}){let G;if(typeof j==="number")G=j;else{let V=typeof j==="string"?q(j):j;if(!V)return;let K=V.getBoundingClientRect();if(this._d)G=(this._b?K.top:K.left)+this._a;else{let J=this._c.getBoundingClientRect();G=(this._b?K.top-J.top:K.left-J.left)+this._a}}if(G+=B.offset??0,G=this._A(G),B.immediate){this._a=G,this._e=G,this._g=!0,this._J(),this._K("scroll"),this._g=!1,B.onComplete?.();return}this._g=!0,this._q();let H=B.ease??this._f,Q=B.duration??this._E;if(typeof H==="number")this._h=0,this._e=G,this._i=H,this._n=B.onComplete??null;else if(Q>0)this._B=this._a,this._v=G,this._L=performance.now(),this._h=Q,this._i=H,this._w=B.onComplete??null,this._n=null;else this._h=0,this._e=G,this._i=typeof this._f==="number"?this._f:$,this._n=B.onComplete??null}_M(j){let B=this._d?window:this._c;M(B,j,"wheel",this._G),M(B,j,"scroll",this._H,{passive:!0}),M(window,j,"keydown",this._I)}start(){if(this._r)return;this._r=!0,this._M("a")}stop(){if(!this._r)return;this._r=!1,this._M("r"),this._N()}destroy(){this._s.killAll(),this.stop(),this._p.clear()}_Q(j){if(j.preventDefault(),this._F)j.stopPropagation();let B=this._b?j.deltaY:j.deltaX;if(j.deltaMode===1)B*=0.833333;else if(j.deltaMode===2)B*=0.555556;this._e=this._A(this._e+B),this._h=0,this._i=typeof this._f==="number"?this._f:$,this._g=!0,this._q(),this._k=B>0?1:-1}_R(){if(this._g)return;let j=this._d?this._b?window.scrollY:window.scrollX:this._b?this._c.scrollTop:this._c.scrollLeft;this._a=j,this._e=j}_S(j){if(!this._d){let H=document.activeElement;if(H!==this._c&&!this._c.contains(H))return}let B=0,G=this._b?this._d?window.innerHeight:this._c.clientHeight:this._d?window.innerWidth:this._c.clientWidth;switch(j.key){case"ArrowDown":B=100;break;case"ArrowUp":B=-100;break;case"ArrowRight":if(!this._b)B=100;break;case"ArrowLeft":if(!this._b)B=-100;break;case" ":B=j.shiftKey?-G:G;break;case"PageDown":B=G;break;case"PageUp":B=-G;break;case"Home":this._e=0,this._h=0,this._i=typeof this._f==="number"?this._f:$,this._g=!0,this._q();return;case"End":this._e=this._z(),this._h=0,this._i=typeof this._f==="number"?this._f:$,this._g=!0,this._q();return;default:return}if(B)j.preventDefault(),this._e=this._A(this._e+B),this._h=0,this._i=typeof this._f==="number"?this._f:$,this._g=!0,this._q(),this._k=B>0?1:-1}_J(){if(this._d)if(this._b)window.scrollTo(0,this._a);else window.scrollTo(this._a,0);else{let j=this._c;if(this._b)j.scrollTop=this._a;else j.scrollLeft=this._a}}_T(){if(!this._r)return;let j=this._a,B=!1;if(this._g){if(this._h>0){let H=performance.now()-this._L,Q=z(0,this._h,H),V=this._i(Q);if(this._a=this._B+(this._v-this._B)*V,this._e=this._v,Q>=1)this._a=this._v,this._h=0,B=!0}else{let H=this._i;if(this._a=D(this._a,this._e,H,L()),Math.abs(this._e-this._a)<0.5)this._a=this._e,B=!0}this._J()}this._o=this._a-j;let G=this._t;if(this._t=Math.abs(this._o)>0.01,this._o>0)this._k=1;else if(this._o<0)this._k=-1;if(this._t||G)this._K("scroll");if(B){if(this._g=!1,this._N(),this._w){let H=this._w;this._w=null,H()}if(this._n){let H=this._n;this._n=null,H()}}}observe(j){return this._s.observe(j)}obs(j){return this._s.observe(j)}}
2
- export{T as b};