svg-scroll-draw 0.7.0 → 1.0.0

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.
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -1,3 +1,3 @@
1
- 'use strict';var me={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2)};function de(e="top bottom"){let r=e.trim();if(/^\d+(\.\d+)?%$/.test(r))return {element:"top",viewport:r};let[s="top",n="bottom"]=r.split(/\s+/).filter(Boolean);return {element:s,viewport:n}}function ke(e,r,s,n){switch(n){case "top":return e+s;case "center":return e+s+r/2;case "bottom":return e+s+r;default:return e+s}}function Te(e,r){if(/^\d+(\.\d+)?%$/.test(e))return r*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return r/2;case "bottom":return r;default:return r}}function ye(e){let r=e.tagName.toLowerCase();if(r==="rect"){let s=parseFloat(e.getAttribute("width")??"0"),n=parseFloat(e.getAttribute("height")??"0");return 2*(s+n)}if(r==="circle"){let s=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*s}return e.getTotalLength()}function We(e,r,s){return Math.min(s,Math.max(r,e))}function z(e,r,s,n){return s===r?0:We((e-r)/(s-r)*n,0,1)}function Me(e,r,s,n,l){let c=ke(e.top,e.height,r,n.element)-Te(n.viewport,s),a=ke(e.top,e.height,r,l.element)-Te(l.viewport,s);return {tStart:c,tEnd:a}}function Se(e){let r=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(r)return [parseInt(r[1]+r[1],16),parseInt(r[2]+r[2],16),parseInt(r[3]+r[3],16)];let s=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(s)return [parseInt(s[1],16),parseInt(s[2],16),parseInt(s[3],16)];let n=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return n?[parseInt(n[1]),parseInt(n[2]),parseInt(n[3])]:null}function ge(e,r,s){let n=Se(e),l=Se(r);return !n||!l?e:`rgb(${Math.round(n[0]+(l[0]-n[0])*s)},${Math.round(n[1]+(l[1]-n[1])*s)},${Math.round(n[2]+(l[2]-n[2])*s)})`}function De(e,r){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,r);}function Ve(e){let r=e.getAttribute("stroke"),s=e.getAttribute("fill");!r||r==="none"?De("Element has no stroke \u2014 path will not be visible.",e):s&&s!=="none"&&s!=="transparent"&&De("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ze(e,r,s){let n=document.createElement("div");n.setAttribute("data-svg-scroll-draw-debug",""),n.style.cssText="position:fixed;pointer-events:none;z-index:9999;font-family:monospace;font-size:11px;top:0;left:0;right:0;bottom:0;";function l(){let c=s==="x"?window.scrollX:window.scrollY,a=e-c,P=r-c,B=s==="x";n.innerHTML=`
2
- <div style="position:absolute;${B?`left:${a}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${a}px;left:0;right:0;border-top:2px dashed #22c55e;`}padding:2px 6px;color:#22c55e;background:rgba(0,0,0,.6)">\u25B6 start</div>
3
- <div style="position:absolute;${B?`left:${P}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${P}px;left:0;right:0;border-top:2px dashed #ef4444;`}padding:2px 6px;color:#ef4444;background:rgba(0,0,0,.6)">\u25A0 end</div>`;}return document.body.appendChild(n),window.addEventListener("scroll",l,{passive:true}),l(),n}function Pe(e,r,s){let n=(r.match(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g)??[]).map(Number),l=0;return e.replace(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g,c=>{let a=parseFloat(c),P=n[l++]??a;return String(+(a+(P-a)*s).toFixed(4))})}function he(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let s=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:n="path, polyline, line, polygon, rect, circle",speed:l=1,fade:c=false,easing:a="linear",trigger:P={},stagger:B=0,direction:L="forward",once:X=false,debug:Ie=false,axis:E="y",scrollContainer:ne,autoReverse:se=false,delay:be=0,strokeColor:F,strokeWidth:N,fillOpacity:R,waypoints:oe,velocityScale:ie=false,threshold:Oe=0,rootMargin:Ce="0px",repeat:_=0,repeatDelay:we=0,morphTo:I,clip:le,onProgress:ve,onStart:Ee,onComplete:j}=r,H=le===true?"left":typeof le=="string"?le:false,ae=typeof a=="function"?a:me[a]??me.linear,Fe=de(P.start??"top bottom"),Ne=de(P.end??"bottom top"),d=typeof ne=="string"?document.querySelector(ne):ne??null,A=Array.isArray(F)?F[0]:null,y=Array.isArray(F)?F[1]:typeof F=="string"?F:null,g=Array.isArray(N)?N[0]:null,h=Array.isArray(N)?N[1]:typeof N=="number"?N:null,b=Array.isArray(R)?R[0]:null,w=Array.isArray(R)?R[1]:typeof R=="number"?R:null;function W(t){let o=t*100;switch(H){case "right":return `inset(0 0 0 ${100-o}%)`;case "top":return `inset(0 0 ${100-o}% 0)`;case "bottom":return `inset(${100-o}% 0 0 0)`;case "center":return `circle(${t*150}% at 50% 50%)`;default:return `inset(0 ${100-o}% 0 0)`}}let G=H?[]:Array.from(e.querySelectorAll(n)),x=[],k=[],T=0,S=0,$=false,O=false,M=0,J=false,v=-1,K=-1,C=false,Q=0,q=0,U,ue=null,Y=new Set,Z=-1,xe=performance.now();function ce(){return d?E==="x"?d.scrollLeft:d.scrollTop:E==="x"?window.scrollX:window.scrollY}function Re(){return d?E==="x"?d.clientWidth:d.clientHeight:E==="x"?window.innerWidth:window.innerHeight}function $e(){let t=e.getBoundingClientRect(),o,u,m;if(d){let V=d.getBoundingClientRect();o=E==="x"?t.left-V.left+d.scrollLeft:t.top-V.top+d.scrollTop,u=E==="x"?t.width:t.height,m=ce();}else o=E==="x"?t.left:t.top,u=E==="x"?t.width:t.height,m=ce();let re=Me({top:o,height:u},m,Re(),Fe,Ne);T=re.tStart,S=re.tEnd,Ie&&process.env.NODE_ENV!=="production"&&(ue?.remove(),ue=ze(T,S,E));}function He(t,o){if(e.style.setProperty("--scroll-draw-progress",String(t)),H){let u=o==="reverse"?1-t:t;e.style.clipPath=W(u);return}G.forEach((u,m)=>{u.style.strokeDashoffset=o==="reverse"?`${x[m]*t}`:`${x[m]*(1-t)}`,c&&(u.style.opacity=o==="reverse"?`${1-t}`:`${t}`),A&&y?u.style.stroke=ge(A,y,t):y&&(u.style.stroke=y),g!==null&&h!==null?u.style.strokeWidth=`${g+(h-g)*t}`:h!==null&&(u.style.strokeWidth=`${h}`),b!==null&&w!==null?u.style.fillOpacity=`${b+(w-b)*t}`:w!==null&&(u.style.fillOpacity=`${w}`),I&&u.tagName.toLowerCase()==="path"&&k[m]&&u.setAttribute("d",Pe(k[m],I,t));});}function Ae(){if(e.style.setProperty("--scroll-draw-progress","0"),H){e.style.clipPath=W(0);return}G.forEach((t,o)=>{t.style.strokeDasharray=`${x[o]}`,t.style.strokeDashoffset=L==="reverse"?"0":`${x[o]}`,c?t.style.opacity=L==="reverse"?"1":"0":t.style.opacity="",A&&(t.style.stroke=A),g!==null&&(t.style.strokeWidth=`${g}`),b!==null&&(t.style.fillOpacity=`${b}`),I&&t.tagName.toLowerCase()==="path"&&k[o]&&t.setAttribute("d",k[o]);});}if(G.forEach(t=>{Ve(t);let o=ye(t);x.push(o),t.tagName.toLowerCase()==="path"?k.push(t.getAttribute("d")??""):k.push(""),s?(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=L==="reverse"?`${o}`:"0",c&&(t.style.opacity="1"),y&&(t.style.stroke=y),h!==null&&(t.style.strokeWidth=`${h}`),w!==null&&(t.style.fillOpacity=`${w}`),I&&t.tagName.toLowerCase()==="path"&&t.setAttribute("d",I)):(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=L==="reverse"?"0":`${o}`,c?t.style.opacity=L==="reverse"?"1":"0":t.style.opacity="",A&&(t.style.stroke=A),g!==null&&(t.style.strokeWidth=`${g}`),b!==null&&(t.style.fillOpacity=`${b}`));}),H){if(s)return e.style.clipPath=W(1),j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};e.style.clipPath=W(0);}else if(s)return j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};$e();function ee(){if(!J||C)return;let t=performance.now(),o=ce(),u=l;if(ie!==false){let i=t-xe,p=i>0?Math.abs(o-(Z<0?o:Z))/i:0;u=l*Math.max(.2,1+p*(typeof ie=="number"?ie:1)*.04);}Z=o,xe=t;let m=se?K===-1||o>=K?"forward":"reverse":L;K=o;let re=S-T,V=true;if(H){let i=ae(z(o,T,S,u));X&&!se&&(v=Math.max(v,i),i=v),Q=i,e.style.setProperty("--scroll-draw-progress",String(i));let p=m==="reverse"?1-i:i;e.style.clipPath=W(p),ve?.(i),!O&&z(o,T,S,u)>0&&(O=true,Ee?.()),i>=1&&!$?($=true,j?.(),q<(_==="infinite"?1/0:_??0)&&(q++,U=setTimeout(()=>{v=-1,O=false,$=false,e.style.clipPath=W(0);},we))):i<1&&!X&&($=false),M=requestAnimationFrame(ee);return}if(G.forEach((i,p)=>{let D=p*B*re,f=ae(z(o,T+D,S+D,u));X&&!se&&(v=Math.max(v,f),f=v),Q=f,i.style.strokeDashoffset=m==="reverse"?`${x[p]*f}`:`${x[p]*(1-f)}`,c&&(i.style.opacity=m==="reverse"?`${1-f}`:`${f}`),A&&y?i.style.stroke=ge(A,y,f):y&&(i.style.stroke=y),g!==null&&h!==null?i.style.strokeWidth=`${g+(h-g)*f}`:h!==null&&(i.style.strokeWidth=`${h}`),b!==null&&w!==null?i.style.fillOpacity=`${b+(w-b)*f}`:w!==null&&(i.style.fillOpacity=`${w}`),I&&i.tagName.toLowerCase()==="path"&&k[p]&&i.setAttribute("d",Pe(k[p],I,f)),p===0&&(ve?.(f),e.style.setProperty("--scroll-draw-progress",String(f))),f<1&&(V=false);}),oe){let i=ae(z(o,T,S,u));for(let p in oe){let D=parseFloat(p);i>=D&&!Y.has(D)&&(Y.add(D),oe[p]?.());}}!O&&z(o,T,S,u)>0&&(O=true,Ee?.()),V&&!$?($=true,j?.(),q<(_==="infinite"?1/0:_??0)&&(q++,U=setTimeout(()=>{v=-1,O=false,$=false,Y.clear(),Ae();},we))):!V&&!X&&($=false),M=requestAnimationFrame(ee);}let fe=new IntersectionObserver(t=>{t.forEach(o=>{J=o.isIntersecting,J&&!C?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:d??null,threshold:Oe,rootMargin:Ce}),pe;function te(){clearTimeout(pe),pe=setTimeout(()=>{G.forEach((t,o)=>{x[o]=ye(t),t.style.strokeDasharray=`${x[o]}`;}),$e();},150);}return window.addEventListener("resize",te),window.addEventListener("orientationchange",te),be>0?setTimeout(()=>fe.observe(e),be):fe.observe(e),{destroy(){cancelAnimationFrame(M),clearTimeout(U),fe.disconnect(),window.removeEventListener("resize",te),window.removeEventListener("orientationchange",te),clearTimeout(pe),ue?.remove();},replay(){v=-1,K=-1,Z=-1,O=false,$=false,q=0,C=false,Y.clear(),clearTimeout(U),Ae();},pause(){C=true,cancelAnimationFrame(M);},resume(){C&&(C=false,J&&(M=requestAnimationFrame(ee)));},seek(t){let o=Math.min(1,Math.max(0,t));Q=o,v=o,C=true,cancelAnimationFrame(M),He(o,L);},getProgress(){return Q}}}function Le(e){return e.map(r=>typeof r=="string"?document.querySelector(r):r).filter(r=>r!==null)}function _e(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let s=Le(e).map(n=>he(n,r));return {destroy(){s.forEach(n=>n.destroy());},replay(){s.forEach(n=>n.replay());},pause(){s.forEach(n=>n.pause());},resume(){s.forEach(n=>n.resume());},seek(n){s.forEach(l=>l.seek(n));},getProgress(){return s[0]?.getProgress()??0}}}function je(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let s=Le(e),n=new Array(s.length).fill(null),l=0;function c(a){a>=s.length||(n[a]=he(s[a],{...r,onComplete:()=>{r.onComplete?.(),c(a+1);}}));}return c(0),{destroy(){n.forEach(a=>a?.destroy()),n.fill(null);},replay(){n.forEach(a=>a?.destroy()),n.fill(null),l=0,c(0);},pause(){n[l]?.pause();},resume(){n[l]?.resume();},seek(a){n[l]?.seek(a);},getProgress(){return n[l]?.getProgress()??0}}}exports.scrollDrawGroup=_e;exports.scrollDrawSequence=je;
1
+ 'use strict';var me={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2)};function de(e="top bottom"){let r=e.trim();if(/^\d+(\.\d+)?%$/.test(r))return {element:"top",viewport:r};let[n="top",s="bottom"]=r.split(/\s+/).filter(Boolean);return {element:n,viewport:s}}function Ae(e,r,n,s){switch(s){case "top":return e+n;case "center":return e+n+r/2;case "bottom":return e+n+r;default:return e+n}}function Se(e,r){if(/^\d+(\.\d+)?%$/.test(e))return r*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return r/2;case "bottom":return r;default:return r}}function ye(e){let r=e.tagName.toLowerCase();if(r==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),s=parseFloat(e.getAttribute("height")??"0");return 2*(n+s)}if(r==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function We(e,r,n){return Math.min(n,Math.max(r,e))}function G(e,r,n,s){return n===r?0:We((e-r)/(n-r)*s,0,1)}function De(e,r,n,s,l){let a=Ae(e.top,e.height,r,s.element)-Se(s.viewport,n),f=Ae(e.top,e.height,r,l.element)-Se(l.viewport,n);return {tStart:a,tEnd:f}}function Te(e){let r=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(r)return [parseInt(r[1]+r[1],16),parseInt(r[2]+r[2],16),parseInt(r[3]+r[3],16)];let n=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(n)return [parseInt(n[1],16),parseInt(n[2],16),parseInt(n[3],16)];let s=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return s?[parseInt(s[1]),parseInt(s[2]),parseInt(s[3])]:null}function ge(e,r,n){let s=Te(e),l=Te(r);return !s||!l?e:`rgb(${Math.round(s[0]+(l[0]-s[0])*n)},${Math.round(s[1]+(l[1]-s[1])*n)},${Math.round(s[2]+(l[2]-s[2])*n)})`}function Me(e,r){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,r);}function Ve(e){let r=e.getAttribute("stroke"),n=e.getAttribute("fill");!r||r==="none"?Me("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&Me("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ze(e,r,n){let s=document.createElement("div");s.setAttribute("data-svg-scroll-draw-debug",""),s.style.cssText="position:fixed;pointer-events:none;z-index:9999;font-family:monospace;font-size:11px;top:0;left:0;right:0;bottom:0;";function l(){let a=n==="x"?window.scrollX:window.scrollY,f=e-a,g=r-a,c=n==="x";s.innerHTML=`
2
+ <div style="position:absolute;${c?`left:${f}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${f}px;left:0;right:0;border-top:2px dashed #22c55e;`}padding:2px 6px;color:#22c55e;background:rgba(0,0,0,.6)">\u25B6 start</div>
3
+ <div style="position:absolute;${c?`left:${g}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${g}px;left:0;right:0;border-top:2px dashed #ef4444;`}padding:2px 6px;color:#ef4444;background:rgba(0,0,0,.6)">\u25A0 end</div>`;}return document.body.appendChild(s),window.addEventListener("scroll",l,{passive:true}),l(),s}function Pe(e,r,n){let s=(r.match(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g)??[]).map(Number),l=0;return e.replace(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g,a=>{let f=parseFloat(a),g=s[l++]??f;return String(+(f+(g-f)*n).toFixed(4))})}function he(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:s="path, polyline, line, polygon, rect, circle",speed:l=1,fade:a=false,easing:f="linear",trigger:g={},stagger:c=0,direction:h="forward",once:_=false,debug:Ie=false,axis:k="y",scrollContainer:ne,autoReverse:se=false,delay:be=0,strokeColor:N,strokeWidth:R,fillOpacity:H,waypoints:oe,velocityScale:ie=false,threshold:Oe=0,rootMargin:Ce="0px",repeat:X=0,repeatDelay:we=0,morphTo:O,clip:le,onProgress:ve,onStart:Ee,onComplete:j}=r,W=le===true?"left":typeof le=="string"?le:false,ae=typeof f=="function"?f:me[f]??me.linear,Fe=de(g.start??"top bottom"),Ne=de(g.end??"bottom top"),y=typeof ne=="string"?document.querySelector(ne):ne??null,T=Array.isArray(N)?N[0]:null,b=Array.isArray(N)?N[1]:typeof N=="string"?N:null,w=Array.isArray(R)?R[0]:null,v=Array.isArray(R)?R[1]:typeof R=="number"?R:null,E=Array.isArray(H)?H[0]:null,x=Array.isArray(H)?H[1]:typeof H=="number"?H:null;function V(t){let o=t*100;switch(W){case "right":return `inset(0 0 0 ${100-o}%)`;case "top":return `inset(0 0 ${100-o}% 0)`;case "bottom":return `inset(${100-o}% 0 0 0)`;case "center":return `circle(${t*150}% at 50% 50%)`;default:return `inset(0 ${100-o}% 0 0)`}}let q=W?[]:Array.from(e.querySelectorAll(s)),A=[],D=[],M=0,P=0,S=false,C=false,L=0,J=false,$=-1,K=-1,F=false,Q=0,B=0,U,ue=null,Y=new Set,Z=-1,xe=performance.now();function ce(){return y?k==="x"?y.scrollLeft:y.scrollTop:k==="x"?window.scrollX:window.scrollY}function Re(){return y?k==="x"?y.clientWidth:y.clientHeight:k==="x"?window.innerWidth:window.innerHeight}function $e(){let t=e.getBoundingClientRect(),o,u,d;if(y){let z=y.getBoundingClientRect();o=k==="x"?t.left-z.left+y.scrollLeft:t.top-z.top+y.scrollTop,u=k==="x"?t.width:t.height,d=ce();}else o=k==="x"?t.left:t.top,u=k==="x"?t.width:t.height,d=ce();let re=De({top:o,height:u},d,Re(),Fe,Ne);M=re.tStart,P=re.tEnd,Ie&&process.env.NODE_ENV!=="production"&&(ue?.remove(),ue=ze(M,P,k));}function He(t,o){if(e.style.setProperty("--scroll-draw-progress",String(t)),W){let u=o==="reverse"?1-t:t;e.style.clipPath=V(u);return}q.forEach((u,d)=>{u.style.strokeDashoffset=o==="reverse"?`${A[d]*t}`:`${A[d]*(1-t)}`,a&&(u.style.opacity=o==="reverse"?`${1-t}`:`${t}`),T&&b?u.style.stroke=ge(T,b,t):b&&(u.style.stroke=b),w!==null&&v!==null?u.style.strokeWidth=`${w+(v-w)*t}`:v!==null&&(u.style.strokeWidth=`${v}`),E!==null&&x!==null?u.style.fillOpacity=`${E+(x-E)*t}`:x!==null&&(u.style.fillOpacity=`${x}`),O&&u.tagName.toLowerCase()==="path"&&D[d]&&u.setAttribute("d",Pe(D[d],O,t));});}function ke(){if(e.style.setProperty("--scroll-draw-progress","0"),W){e.style.clipPath=V(0);return}q.forEach((t,o)=>{t.style.strokeDasharray=`${A[o]}`,t.style.strokeDashoffset=h==="reverse"?"0":`${A[o]}`,a?t.style.opacity=h==="reverse"?"1":"0":t.style.opacity="",T&&(t.style.stroke=T),w!==null&&(t.style.strokeWidth=`${w}`),E!==null&&(t.style.fillOpacity=`${E}`),O&&t.tagName.toLowerCase()==="path"&&D[o]&&t.setAttribute("d",D[o]);});}if(q.forEach(t=>{Ve(t);let o=ye(t);A.push(o),t.tagName.toLowerCase()==="path"?D.push(t.getAttribute("d")??""):D.push(""),n?(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=h==="reverse"?`${o}`:"0",a&&(t.style.opacity="1"),b&&(t.style.stroke=b),v!==null&&(t.style.strokeWidth=`${v}`),x!==null&&(t.style.fillOpacity=`${x}`),O&&t.tagName.toLowerCase()==="path"&&t.setAttribute("d",O)):(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=h==="reverse"?"0":`${o}`,a?t.style.opacity=h==="reverse"?"1":"0":t.style.opacity="",T&&(t.style.stroke=T),w!==null&&(t.style.strokeWidth=`${w}`),E!==null&&(t.style.fillOpacity=`${E}`));}),W){if(n)return e.style.clipPath=V(1),j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};e.style.clipPath=V(0);}else if(n)return j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};$e();function ee(){if(!J||F)return;let t=performance.now(),o=ce(),u=l;if(ie!==false){let i=t-xe,m=i>0?Math.abs(o-(Z<0?o:Z))/i:0;u=l*Math.max(.2,1+m*(typeof ie=="number"?ie:1)*.04);}Z=o,xe=t;let d=se?K===-1||o>=K?"forward":"reverse":h;K=o;let re=P-M,z=true;if(W){let i=ae(G(o,M,P,u));_&&!se&&($=Math.max($,i),i=$),Q=i,e.style.setProperty("--scroll-draw-progress",String(i));let m=d==="reverse"?1-i:i;e.style.clipPath=V(m),ve?.(i),!C&&G(o,M,P,u)>0&&(C=true,Ee?.()),i>=1&&!S?(S=true,j?.(),B<(X==="infinite"?1/0:X??0)&&(B++,U=setTimeout(()=>{$=-1,C=false,S=false,e.style.clipPath=V(0);},we))):i<1&&!_&&(S=false),L=requestAnimationFrame(ee);return}if(q.forEach((i,m)=>{let I=m*c*re,p=ae(G(o,M+I,P+I,u));_&&!se&&($=Math.max($,p),p=$),Q=p,i.style.strokeDashoffset=d==="reverse"?`${A[m]*p}`:`${A[m]*(1-p)}`,a&&(i.style.opacity=d==="reverse"?`${1-p}`:`${p}`),T&&b?i.style.stroke=ge(T,b,p):b&&(i.style.stroke=b),w!==null&&v!==null?i.style.strokeWidth=`${w+(v-w)*p}`:v!==null&&(i.style.strokeWidth=`${v}`),E!==null&&x!==null?i.style.fillOpacity=`${E+(x-E)*p}`:x!==null&&(i.style.fillOpacity=`${x}`),O&&i.tagName.toLowerCase()==="path"&&D[m]&&i.setAttribute("d",Pe(D[m],O,p)),m===0&&(ve?.(p),e.style.setProperty("--scroll-draw-progress",String(p))),p<1&&(z=false);}),oe){let i=ae(G(o,M,P,u));for(let m in oe){let I=parseFloat(m);i>=I&&!Y.has(I)&&(Y.add(I),oe[m]?.());}}!C&&G(o,M,P,u)>0&&(C=true,Ee?.()),z&&!S?(S=true,j?.(),B<(X==="infinite"?1/0:X??0)&&(B++,U=setTimeout(()=>{$=-1,C=false,S=false,Y.clear(),ke();},we))):!z&&!_&&(S=false),L=requestAnimationFrame(ee);}let fe=new IntersectionObserver(t=>{t.forEach(o=>{J=o.isIntersecting,J&&!F?L=requestAnimationFrame(ee):cancelAnimationFrame(L);});},{root:y??null,threshold:Oe,rootMargin:Ce}),pe;function te(){clearTimeout(pe),pe=setTimeout(()=>{q.forEach((t,o)=>{A[o]=ye(t),t.style.strokeDasharray=`${A[o]}`;}),$e();},150);}return window.addEventListener("resize",te),window.addEventListener("orientationchange",te),be>0?setTimeout(()=>fe.observe(e),be):fe.observe(e),{destroy(){cancelAnimationFrame(L),clearTimeout(U),fe.disconnect(),window.removeEventListener("resize",te),window.removeEventListener("orientationchange",te),clearTimeout(pe),ue?.remove();},replay(){$=-1,K=-1,Z=-1,C=false,S=false,B=0,F=false,Y.clear(),clearTimeout(U),ke();},pause(){F=true,cancelAnimationFrame(L);},resume(){F&&(F=false,J&&(L=requestAnimationFrame(ee)));},seek(t){let o=Math.min(1,Math.max(0,t));Q=o,$=o,F=true,cancelAnimationFrame(L),He(o,h);},getProgress(){return Q}}}function Le(e){return e.map(r=>typeof r=="string"?document.querySelector(r):r).filter(r=>r!==null)}function Xe(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let n=Le(e).map(s=>he(s,r));return {destroy(){n.forEach(s=>s.destroy());},replay(){n.forEach(s=>s.replay());},pause(){n.forEach(s=>s.pause());},resume(){n.forEach(s=>s.resume());},seek(s){n.forEach(l=>l.seek(s));},getProgress(){return n[0]?.getProgress()??0}}}function je(e,r={}){let n={destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};if(typeof window>"u")return n;let s=Le(e);if(s.length===0)return n;let l=0,a=[];function f(c){return he(s[c],{...r,once:true,onComplete(){r.onComplete?.(),l=c+1,a[l]?.resume();}})}function g(){s.forEach((c,h)=>{a[h]=f(h);});for(let c=1;c<a.length;c++)a[c].pause();}return g(),{destroy(){a.forEach(c=>c.destroy()),a.length=0;},replay(){a.forEach(c=>c.destroy()),a.length=0,l=0,g();},pause(){a[l]?.pause();},resume(){a[l]?.resume();},seek(c){a[l]?.seek(c);},getProgress(){return a[l]?.getProgress()??0}}}exports.scrollDrawGroup=Xe;exports.scrollDrawSequence=je;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -85,6 +95,11 @@ declare function scrollDrawGroup(targets: Array<string | Element>, options?: Scr
85
95
  * Animate multiple SVG containers in sequence — each one starts only after
86
96
  * the previous has reached 100% draw progress.
87
97
  *
98
+ * **Note:** each step is internally forced to `once: true` regardless of the
99
+ * option you pass. This prevents a completed step from being reset when the
100
+ * user scrolls back, which would break the chain. If you need every step to
101
+ * be reversible, use `scrollDrawGroup` with `autoReverse` instead.
102
+ *
88
103
  * @example
89
104
  * import { scrollDrawSequence } from 'svg-scroll-draw/group';
90
105
  *
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -85,6 +95,11 @@ declare function scrollDrawGroup(targets: Array<string | Element>, options?: Scr
85
95
  * Animate multiple SVG containers in sequence — each one starts only after
86
96
  * the previous has reached 100% draw progress.
87
97
  *
98
+ * **Note:** each step is internally forced to `once: true` regardless of the
99
+ * option you pass. This prevents a completed step from being reset when the
100
+ * user scrolls back, which would break the chain. If you need every step to
101
+ * be reversible, use `scrollDrawGroup` with `autoReverse` instead.
102
+ *
88
103
  * @example
89
104
  * import { scrollDrawSequence } from 'svg-scroll-draw/group';
90
105
  *
@@ -1,3 +1,3 @@
1
- var me={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2)};function de(e="top bottom"){let r=e.trim();if(/^\d+(\.\d+)?%$/.test(r))return {element:"top",viewport:r};let[s="top",n="bottom"]=r.split(/\s+/).filter(Boolean);return {element:s,viewport:n}}function ke(e,r,s,n){switch(n){case "top":return e+s;case "center":return e+s+r/2;case "bottom":return e+s+r;default:return e+s}}function Te(e,r){if(/^\d+(\.\d+)?%$/.test(e))return r*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return r/2;case "bottom":return r;default:return r}}function ye(e){let r=e.tagName.toLowerCase();if(r==="rect"){let s=parseFloat(e.getAttribute("width")??"0"),n=parseFloat(e.getAttribute("height")??"0");return 2*(s+n)}if(r==="circle"){let s=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*s}return e.getTotalLength()}function We(e,r,s){return Math.min(s,Math.max(r,e))}function z(e,r,s,n){return s===r?0:We((e-r)/(s-r)*n,0,1)}function Me(e,r,s,n,l){let c=ke(e.top,e.height,r,n.element)-Te(n.viewport,s),a=ke(e.top,e.height,r,l.element)-Te(l.viewport,s);return {tStart:c,tEnd:a}}function Se(e){let r=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(r)return [parseInt(r[1]+r[1],16),parseInt(r[2]+r[2],16),parseInt(r[3]+r[3],16)];let s=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(s)return [parseInt(s[1],16),parseInt(s[2],16),parseInt(s[3],16)];let n=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return n?[parseInt(n[1]),parseInt(n[2]),parseInt(n[3])]:null}function ge(e,r,s){let n=Se(e),l=Se(r);return !n||!l?e:`rgb(${Math.round(n[0]+(l[0]-n[0])*s)},${Math.round(n[1]+(l[1]-n[1])*s)},${Math.round(n[2]+(l[2]-n[2])*s)})`}function De(e,r){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,r);}function Ve(e){let r=e.getAttribute("stroke"),s=e.getAttribute("fill");!r||r==="none"?De("Element has no stroke \u2014 path will not be visible.",e):s&&s!=="none"&&s!=="transparent"&&De("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ze(e,r,s){let n=document.createElement("div");n.setAttribute("data-svg-scroll-draw-debug",""),n.style.cssText="position:fixed;pointer-events:none;z-index:9999;font-family:monospace;font-size:11px;top:0;left:0;right:0;bottom:0;";function l(){let c=s==="x"?window.scrollX:window.scrollY,a=e-c,P=r-c,B=s==="x";n.innerHTML=`
2
- <div style="position:absolute;${B?`left:${a}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${a}px;left:0;right:0;border-top:2px dashed #22c55e;`}padding:2px 6px;color:#22c55e;background:rgba(0,0,0,.6)">\u25B6 start</div>
3
- <div style="position:absolute;${B?`left:${P}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${P}px;left:0;right:0;border-top:2px dashed #ef4444;`}padding:2px 6px;color:#ef4444;background:rgba(0,0,0,.6)">\u25A0 end</div>`;}return document.body.appendChild(n),window.addEventListener("scroll",l,{passive:true}),l(),n}function Pe(e,r,s){let n=(r.match(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g)??[]).map(Number),l=0;return e.replace(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g,c=>{let a=parseFloat(c),P=n[l++]??a;return String(+(a+(P-a)*s).toFixed(4))})}function he(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let s=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:n="path, polyline, line, polygon, rect, circle",speed:l=1,fade:c=false,easing:a="linear",trigger:P={},stagger:B=0,direction:L="forward",once:X=false,debug:Ie=false,axis:E="y",scrollContainer:ne,autoReverse:se=false,delay:be=0,strokeColor:F,strokeWidth:N,fillOpacity:R,waypoints:oe,velocityScale:ie=false,threshold:Oe=0,rootMargin:Ce="0px",repeat:_=0,repeatDelay:we=0,morphTo:I,clip:le,onProgress:ve,onStart:Ee,onComplete:j}=r,H=le===true?"left":typeof le=="string"?le:false,ae=typeof a=="function"?a:me[a]??me.linear,Fe=de(P.start??"top bottom"),Ne=de(P.end??"bottom top"),d=typeof ne=="string"?document.querySelector(ne):ne??null,A=Array.isArray(F)?F[0]:null,y=Array.isArray(F)?F[1]:typeof F=="string"?F:null,g=Array.isArray(N)?N[0]:null,h=Array.isArray(N)?N[1]:typeof N=="number"?N:null,b=Array.isArray(R)?R[0]:null,w=Array.isArray(R)?R[1]:typeof R=="number"?R:null;function W(t){let o=t*100;switch(H){case "right":return `inset(0 0 0 ${100-o}%)`;case "top":return `inset(0 0 ${100-o}% 0)`;case "bottom":return `inset(${100-o}% 0 0 0)`;case "center":return `circle(${t*150}% at 50% 50%)`;default:return `inset(0 ${100-o}% 0 0)`}}let G=H?[]:Array.from(e.querySelectorAll(n)),x=[],k=[],T=0,S=0,$=false,O=false,M=0,J=false,v=-1,K=-1,C=false,Q=0,q=0,U,ue=null,Y=new Set,Z=-1,xe=performance.now();function ce(){return d?E==="x"?d.scrollLeft:d.scrollTop:E==="x"?window.scrollX:window.scrollY}function Re(){return d?E==="x"?d.clientWidth:d.clientHeight:E==="x"?window.innerWidth:window.innerHeight}function $e(){let t=e.getBoundingClientRect(),o,u,m;if(d){let V=d.getBoundingClientRect();o=E==="x"?t.left-V.left+d.scrollLeft:t.top-V.top+d.scrollTop,u=E==="x"?t.width:t.height,m=ce();}else o=E==="x"?t.left:t.top,u=E==="x"?t.width:t.height,m=ce();let re=Me({top:o,height:u},m,Re(),Fe,Ne);T=re.tStart,S=re.tEnd,Ie&&process.env.NODE_ENV!=="production"&&(ue?.remove(),ue=ze(T,S,E));}function He(t,o){if(e.style.setProperty("--scroll-draw-progress",String(t)),H){let u=o==="reverse"?1-t:t;e.style.clipPath=W(u);return}G.forEach((u,m)=>{u.style.strokeDashoffset=o==="reverse"?`${x[m]*t}`:`${x[m]*(1-t)}`,c&&(u.style.opacity=o==="reverse"?`${1-t}`:`${t}`),A&&y?u.style.stroke=ge(A,y,t):y&&(u.style.stroke=y),g!==null&&h!==null?u.style.strokeWidth=`${g+(h-g)*t}`:h!==null&&(u.style.strokeWidth=`${h}`),b!==null&&w!==null?u.style.fillOpacity=`${b+(w-b)*t}`:w!==null&&(u.style.fillOpacity=`${w}`),I&&u.tagName.toLowerCase()==="path"&&k[m]&&u.setAttribute("d",Pe(k[m],I,t));});}function Ae(){if(e.style.setProperty("--scroll-draw-progress","0"),H){e.style.clipPath=W(0);return}G.forEach((t,o)=>{t.style.strokeDasharray=`${x[o]}`,t.style.strokeDashoffset=L==="reverse"?"0":`${x[o]}`,c?t.style.opacity=L==="reverse"?"1":"0":t.style.opacity="",A&&(t.style.stroke=A),g!==null&&(t.style.strokeWidth=`${g}`),b!==null&&(t.style.fillOpacity=`${b}`),I&&t.tagName.toLowerCase()==="path"&&k[o]&&t.setAttribute("d",k[o]);});}if(G.forEach(t=>{Ve(t);let o=ye(t);x.push(o),t.tagName.toLowerCase()==="path"?k.push(t.getAttribute("d")??""):k.push(""),s?(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=L==="reverse"?`${o}`:"0",c&&(t.style.opacity="1"),y&&(t.style.stroke=y),h!==null&&(t.style.strokeWidth=`${h}`),w!==null&&(t.style.fillOpacity=`${w}`),I&&t.tagName.toLowerCase()==="path"&&t.setAttribute("d",I)):(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=L==="reverse"?"0":`${o}`,c?t.style.opacity=L==="reverse"?"1":"0":t.style.opacity="",A&&(t.style.stroke=A),g!==null&&(t.style.strokeWidth=`${g}`),b!==null&&(t.style.fillOpacity=`${b}`));}),H){if(s)return e.style.clipPath=W(1),j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};e.style.clipPath=W(0);}else if(s)return j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};$e();function ee(){if(!J||C)return;let t=performance.now(),o=ce(),u=l;if(ie!==false){let i=t-xe,p=i>0?Math.abs(o-(Z<0?o:Z))/i:0;u=l*Math.max(.2,1+p*(typeof ie=="number"?ie:1)*.04);}Z=o,xe=t;let m=se?K===-1||o>=K?"forward":"reverse":L;K=o;let re=S-T,V=true;if(H){let i=ae(z(o,T,S,u));X&&!se&&(v=Math.max(v,i),i=v),Q=i,e.style.setProperty("--scroll-draw-progress",String(i));let p=m==="reverse"?1-i:i;e.style.clipPath=W(p),ve?.(i),!O&&z(o,T,S,u)>0&&(O=true,Ee?.()),i>=1&&!$?($=true,j?.(),q<(_==="infinite"?1/0:_??0)&&(q++,U=setTimeout(()=>{v=-1,O=false,$=false,e.style.clipPath=W(0);},we))):i<1&&!X&&($=false),M=requestAnimationFrame(ee);return}if(G.forEach((i,p)=>{let D=p*B*re,f=ae(z(o,T+D,S+D,u));X&&!se&&(v=Math.max(v,f),f=v),Q=f,i.style.strokeDashoffset=m==="reverse"?`${x[p]*f}`:`${x[p]*(1-f)}`,c&&(i.style.opacity=m==="reverse"?`${1-f}`:`${f}`),A&&y?i.style.stroke=ge(A,y,f):y&&(i.style.stroke=y),g!==null&&h!==null?i.style.strokeWidth=`${g+(h-g)*f}`:h!==null&&(i.style.strokeWidth=`${h}`),b!==null&&w!==null?i.style.fillOpacity=`${b+(w-b)*f}`:w!==null&&(i.style.fillOpacity=`${w}`),I&&i.tagName.toLowerCase()==="path"&&k[p]&&i.setAttribute("d",Pe(k[p],I,f)),p===0&&(ve?.(f),e.style.setProperty("--scroll-draw-progress",String(f))),f<1&&(V=false);}),oe){let i=ae(z(o,T,S,u));for(let p in oe){let D=parseFloat(p);i>=D&&!Y.has(D)&&(Y.add(D),oe[p]?.());}}!O&&z(o,T,S,u)>0&&(O=true,Ee?.()),V&&!$?($=true,j?.(),q<(_==="infinite"?1/0:_??0)&&(q++,U=setTimeout(()=>{v=-1,O=false,$=false,Y.clear(),Ae();},we))):!V&&!X&&($=false),M=requestAnimationFrame(ee);}let fe=new IntersectionObserver(t=>{t.forEach(o=>{J=o.isIntersecting,J&&!C?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:d??null,threshold:Oe,rootMargin:Ce}),pe;function te(){clearTimeout(pe),pe=setTimeout(()=>{G.forEach((t,o)=>{x[o]=ye(t),t.style.strokeDasharray=`${x[o]}`;}),$e();},150);}return window.addEventListener("resize",te),window.addEventListener("orientationchange",te),be>0?setTimeout(()=>fe.observe(e),be):fe.observe(e),{destroy(){cancelAnimationFrame(M),clearTimeout(U),fe.disconnect(),window.removeEventListener("resize",te),window.removeEventListener("orientationchange",te),clearTimeout(pe),ue?.remove();},replay(){v=-1,K=-1,Z=-1,O=false,$=false,q=0,C=false,Y.clear(),clearTimeout(U),Ae();},pause(){C=true,cancelAnimationFrame(M);},resume(){C&&(C=false,J&&(M=requestAnimationFrame(ee)));},seek(t){let o=Math.min(1,Math.max(0,t));Q=o,v=o,C=true,cancelAnimationFrame(M),He(o,L);},getProgress(){return Q}}}function Le(e){return e.map(r=>typeof r=="string"?document.querySelector(r):r).filter(r=>r!==null)}function _e(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let s=Le(e).map(n=>he(n,r));return {destroy(){s.forEach(n=>n.destroy());},replay(){s.forEach(n=>n.replay());},pause(){s.forEach(n=>n.pause());},resume(){s.forEach(n=>n.resume());},seek(n){s.forEach(l=>l.seek(n));},getProgress(){return s[0]?.getProgress()??0}}}function je(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let s=Le(e),n=new Array(s.length).fill(null),l=0;function c(a){a>=s.length||(n[a]=he(s[a],{...r,onComplete:()=>{r.onComplete?.(),c(a+1);}}));}return c(0),{destroy(){n.forEach(a=>a?.destroy()),n.fill(null);},replay(){n.forEach(a=>a?.destroy()),n.fill(null),l=0,c(0);},pause(){n[l]?.pause();},resume(){n[l]?.resume();},seek(a){n[l]?.seek(a);},getProgress(){return n[l]?.getProgress()??0}}}export{_e as scrollDrawGroup,je as scrollDrawSequence};
1
+ var me={linear:e=>e,"ease-in":e=>e*e,"ease-out":e=>e*(2-e),"ease-in-out":e=>e<.5?2*e*e:-1+(4-2*e)*e,spring:e=>1-Math.cos(e*Math.PI*2.5)*Math.pow(1-e,2.2)};function de(e="top bottom"){let r=e.trim();if(/^\d+(\.\d+)?%$/.test(r))return {element:"top",viewport:r};let[n="top",s="bottom"]=r.split(/\s+/).filter(Boolean);return {element:n,viewport:s}}function Ae(e,r,n,s){switch(s){case "top":return e+n;case "center":return e+n+r/2;case "bottom":return e+n+r;default:return e+n}}function Se(e,r){if(/^\d+(\.\d+)?%$/.test(e))return r*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return r/2;case "bottom":return r;default:return r}}function ye(e){let r=e.tagName.toLowerCase();if(r==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),s=parseFloat(e.getAttribute("height")??"0");return 2*(n+s)}if(r==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function We(e,r,n){return Math.min(n,Math.max(r,e))}function G(e,r,n,s){return n===r?0:We((e-r)/(n-r)*s,0,1)}function De(e,r,n,s,l){let a=Ae(e.top,e.height,r,s.element)-Se(s.viewport,n),f=Ae(e.top,e.height,r,l.element)-Se(l.viewport,n);return {tStart:a,tEnd:f}}function Te(e){let r=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(r)return [parseInt(r[1]+r[1],16),parseInt(r[2]+r[2],16),parseInt(r[3]+r[3],16)];let n=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(n)return [parseInt(n[1],16),parseInt(n[2],16),parseInt(n[3],16)];let s=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return s?[parseInt(s[1]),parseInt(s[2]),parseInt(s[3])]:null}function ge(e,r,n){let s=Te(e),l=Te(r);return !s||!l?e:`rgb(${Math.round(s[0]+(l[0]-s[0])*n)},${Math.round(s[1]+(l[1]-s[1])*n)},${Math.round(s[2]+(l[2]-s[2])*n)})`}function Me(e,r){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,r);}function Ve(e){let r=e.getAttribute("stroke"),n=e.getAttribute("fill");!r||r==="none"?Me("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&Me("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ze(e,r,n){let s=document.createElement("div");s.setAttribute("data-svg-scroll-draw-debug",""),s.style.cssText="position:fixed;pointer-events:none;z-index:9999;font-family:monospace;font-size:11px;top:0;left:0;right:0;bottom:0;";function l(){let a=n==="x"?window.scrollX:window.scrollY,f=e-a,g=r-a,c=n==="x";s.innerHTML=`
2
+ <div style="position:absolute;${c?`left:${f}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${f}px;left:0;right:0;border-top:2px dashed #22c55e;`}padding:2px 6px;color:#22c55e;background:rgba(0,0,0,.6)">\u25B6 start</div>
3
+ <div style="position:absolute;${c?`left:${g}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${g}px;left:0;right:0;border-top:2px dashed #ef4444;`}padding:2px 6px;color:#ef4444;background:rgba(0,0,0,.6)">\u25A0 end</div>`;}return document.body.appendChild(s),window.addEventListener("scroll",l,{passive:true}),l(),s}function Pe(e,r,n){let s=(r.match(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g)??[]).map(Number),l=0;return e.replace(/[-+]?(?:\d*\.)?\d+(?:[eE][-+]?\d+)?/g,a=>{let f=parseFloat(a),g=s[l++]??f;return String(+(f+(g-f)*n).toFixed(4))})}function he(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:s="path, polyline, line, polygon, rect, circle",speed:l=1,fade:a=false,easing:f="linear",trigger:g={},stagger:c=0,direction:h="forward",once:_=false,debug:Ie=false,axis:k="y",scrollContainer:ne,autoReverse:se=false,delay:be=0,strokeColor:N,strokeWidth:R,fillOpacity:H,waypoints:oe,velocityScale:ie=false,threshold:Oe=0,rootMargin:Ce="0px",repeat:X=0,repeatDelay:we=0,morphTo:O,clip:le,onProgress:ve,onStart:Ee,onComplete:j}=r,W=le===true?"left":typeof le=="string"?le:false,ae=typeof f=="function"?f:me[f]??me.linear,Fe=de(g.start??"top bottom"),Ne=de(g.end??"bottom top"),y=typeof ne=="string"?document.querySelector(ne):ne??null,T=Array.isArray(N)?N[0]:null,b=Array.isArray(N)?N[1]:typeof N=="string"?N:null,w=Array.isArray(R)?R[0]:null,v=Array.isArray(R)?R[1]:typeof R=="number"?R:null,E=Array.isArray(H)?H[0]:null,x=Array.isArray(H)?H[1]:typeof H=="number"?H:null;function V(t){let o=t*100;switch(W){case "right":return `inset(0 0 0 ${100-o}%)`;case "top":return `inset(0 0 ${100-o}% 0)`;case "bottom":return `inset(${100-o}% 0 0 0)`;case "center":return `circle(${t*150}% at 50% 50%)`;default:return `inset(0 ${100-o}% 0 0)`}}let q=W?[]:Array.from(e.querySelectorAll(s)),A=[],D=[],M=0,P=0,S=false,C=false,L=0,J=false,$=-1,K=-1,F=false,Q=0,B=0,U,ue=null,Y=new Set,Z=-1,xe=performance.now();function ce(){return y?k==="x"?y.scrollLeft:y.scrollTop:k==="x"?window.scrollX:window.scrollY}function Re(){return y?k==="x"?y.clientWidth:y.clientHeight:k==="x"?window.innerWidth:window.innerHeight}function $e(){let t=e.getBoundingClientRect(),o,u,d;if(y){let z=y.getBoundingClientRect();o=k==="x"?t.left-z.left+y.scrollLeft:t.top-z.top+y.scrollTop,u=k==="x"?t.width:t.height,d=ce();}else o=k==="x"?t.left:t.top,u=k==="x"?t.width:t.height,d=ce();let re=De({top:o,height:u},d,Re(),Fe,Ne);M=re.tStart,P=re.tEnd,Ie&&process.env.NODE_ENV!=="production"&&(ue?.remove(),ue=ze(M,P,k));}function He(t,o){if(e.style.setProperty("--scroll-draw-progress",String(t)),W){let u=o==="reverse"?1-t:t;e.style.clipPath=V(u);return}q.forEach((u,d)=>{u.style.strokeDashoffset=o==="reverse"?`${A[d]*t}`:`${A[d]*(1-t)}`,a&&(u.style.opacity=o==="reverse"?`${1-t}`:`${t}`),T&&b?u.style.stroke=ge(T,b,t):b&&(u.style.stroke=b),w!==null&&v!==null?u.style.strokeWidth=`${w+(v-w)*t}`:v!==null&&(u.style.strokeWidth=`${v}`),E!==null&&x!==null?u.style.fillOpacity=`${E+(x-E)*t}`:x!==null&&(u.style.fillOpacity=`${x}`),O&&u.tagName.toLowerCase()==="path"&&D[d]&&u.setAttribute("d",Pe(D[d],O,t));});}function ke(){if(e.style.setProperty("--scroll-draw-progress","0"),W){e.style.clipPath=V(0);return}q.forEach((t,o)=>{t.style.strokeDasharray=`${A[o]}`,t.style.strokeDashoffset=h==="reverse"?"0":`${A[o]}`,a?t.style.opacity=h==="reverse"?"1":"0":t.style.opacity="",T&&(t.style.stroke=T),w!==null&&(t.style.strokeWidth=`${w}`),E!==null&&(t.style.fillOpacity=`${E}`),O&&t.tagName.toLowerCase()==="path"&&D[o]&&t.setAttribute("d",D[o]);});}if(q.forEach(t=>{Ve(t);let o=ye(t);A.push(o),t.tagName.toLowerCase()==="path"?D.push(t.getAttribute("d")??""):D.push(""),n?(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=h==="reverse"?`${o}`:"0",a&&(t.style.opacity="1"),b&&(t.style.stroke=b),v!==null&&(t.style.strokeWidth=`${v}`),x!==null&&(t.style.fillOpacity=`${x}`),O&&t.tagName.toLowerCase()==="path"&&t.setAttribute("d",O)):(t.style.strokeDasharray=`${o}`,t.style.strokeDashoffset=h==="reverse"?"0":`${o}`,a?t.style.opacity=h==="reverse"?"1":"0":t.style.opacity="",T&&(t.style.stroke=T),w!==null&&(t.style.strokeWidth=`${w}`),E!==null&&(t.style.fillOpacity=`${E}`));}),W){if(n)return e.style.clipPath=V(1),j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};e.style.clipPath=V(0);}else if(n)return j?.(),{destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>1};$e();function ee(){if(!J||F)return;let t=performance.now(),o=ce(),u=l;if(ie!==false){let i=t-xe,m=i>0?Math.abs(o-(Z<0?o:Z))/i:0;u=l*Math.max(.2,1+m*(typeof ie=="number"?ie:1)*.04);}Z=o,xe=t;let d=se?K===-1||o>=K?"forward":"reverse":h;K=o;let re=P-M,z=true;if(W){let i=ae(G(o,M,P,u));_&&!se&&($=Math.max($,i),i=$),Q=i,e.style.setProperty("--scroll-draw-progress",String(i));let m=d==="reverse"?1-i:i;e.style.clipPath=V(m),ve?.(i),!C&&G(o,M,P,u)>0&&(C=true,Ee?.()),i>=1&&!S?(S=true,j?.(),B<(X==="infinite"?1/0:X??0)&&(B++,U=setTimeout(()=>{$=-1,C=false,S=false,e.style.clipPath=V(0);},we))):i<1&&!_&&(S=false),L=requestAnimationFrame(ee);return}if(q.forEach((i,m)=>{let I=m*c*re,p=ae(G(o,M+I,P+I,u));_&&!se&&($=Math.max($,p),p=$),Q=p,i.style.strokeDashoffset=d==="reverse"?`${A[m]*p}`:`${A[m]*(1-p)}`,a&&(i.style.opacity=d==="reverse"?`${1-p}`:`${p}`),T&&b?i.style.stroke=ge(T,b,p):b&&(i.style.stroke=b),w!==null&&v!==null?i.style.strokeWidth=`${w+(v-w)*p}`:v!==null&&(i.style.strokeWidth=`${v}`),E!==null&&x!==null?i.style.fillOpacity=`${E+(x-E)*p}`:x!==null&&(i.style.fillOpacity=`${x}`),O&&i.tagName.toLowerCase()==="path"&&D[m]&&i.setAttribute("d",Pe(D[m],O,p)),m===0&&(ve?.(p),e.style.setProperty("--scroll-draw-progress",String(p))),p<1&&(z=false);}),oe){let i=ae(G(o,M,P,u));for(let m in oe){let I=parseFloat(m);i>=I&&!Y.has(I)&&(Y.add(I),oe[m]?.());}}!C&&G(o,M,P,u)>0&&(C=true,Ee?.()),z&&!S?(S=true,j?.(),B<(X==="infinite"?1/0:X??0)&&(B++,U=setTimeout(()=>{$=-1,C=false,S=false,Y.clear(),ke();},we))):!z&&!_&&(S=false),L=requestAnimationFrame(ee);}let fe=new IntersectionObserver(t=>{t.forEach(o=>{J=o.isIntersecting,J&&!F?L=requestAnimationFrame(ee):cancelAnimationFrame(L);});},{root:y??null,threshold:Oe,rootMargin:Ce}),pe;function te(){clearTimeout(pe),pe=setTimeout(()=>{q.forEach((t,o)=>{A[o]=ye(t),t.style.strokeDasharray=`${A[o]}`;}),$e();},150);}return window.addEventListener("resize",te),window.addEventListener("orientationchange",te),be>0?setTimeout(()=>fe.observe(e),be):fe.observe(e),{destroy(){cancelAnimationFrame(L),clearTimeout(U),fe.disconnect(),window.removeEventListener("resize",te),window.removeEventListener("orientationchange",te),clearTimeout(pe),ue?.remove();},replay(){$=-1,K=-1,Z=-1,C=false,S=false,B=0,F=false,Y.clear(),clearTimeout(U),ke();},pause(){F=true,cancelAnimationFrame(L);},resume(){F&&(F=false,J&&(L=requestAnimationFrame(ee)));},seek(t){let o=Math.min(1,Math.max(0,t));Q=o,$=o,F=true,cancelAnimationFrame(L),He(o,h);},getProgress(){return Q}}}function Le(e){return e.map(r=>typeof r=="string"?document.querySelector(r):r).filter(r=>r!==null)}function Xe(e,r={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};let n=Le(e).map(s=>he(s,r));return {destroy(){n.forEach(s=>s.destroy());},replay(){n.forEach(s=>s.replay());},pause(){n.forEach(s=>s.pause());},resume(){n.forEach(s=>s.resume());},seek(s){n.forEach(l=>l.seek(s));},getProgress(){return n[0]?.getProgress()??0}}}function je(e,r={}){let n={destroy:()=>{},replay:()=>{},pause:()=>{},resume:()=>{},seek:()=>{},getProgress:()=>0};if(typeof window>"u")return n;let s=Le(e);if(s.length===0)return n;let l=0,a=[];function f(c){return he(s[c],{...r,once:true,onComplete(){r.onComplete?.(),l=c+1,a[l]?.resume();}})}function g(){s.forEach((c,h)=>{a[h]=f(h);});for(let c=1;c<a.length;c++)a[c].pause();}return g(),{destroy(){a.forEach(c=>c.destroy()),a.length=0;},replay(){a.forEach(c=>c.destroy()),a.length=0,l=0,g();},pause(){a[l]?.pause();},resume(){a[l]?.resume();},seek(c){a[l]?.seek(c);},getProgress(){return a[l]?.getProgress()??0}}}export{Xe as scrollDrawGroup,je as scrollDrawSequence};
package/dist/index.d.mts CHANGED
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
package/dist/index.d.ts CHANGED
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -33,7 +33,11 @@ interface ScrollDrawOptions {
33
33
  /**
34
34
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
35
35
  * Works on any content — SVG, images, text, divs.
36
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
36
+ *
37
+ * Pass a direction string to control which edge the reveal starts from,
38
+ * or `true` as shorthand for `'left'`.
39
+ *
40
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
37
41
  */
38
42
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
39
43
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -48,7 +52,13 @@ interface ScrollDrawOptions {
48
52
  repeat?: number | 'infinite';
49
53
  /** Milliseconds to wait between repeats. Default 0. */
50
54
  repeatDelay?: number;
51
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
55
+ /**
56
+ * Target path `d` attribute to morph toward as the animation progresses.
57
+ * Paths must have compatible command structures (same number of numeric tokens).
58
+ *
59
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
60
+ * `<line>`, and other SVG shape elements.
61
+ */
52
62
  morphTo?: string;
53
63
  onProgress?: (alpha: number) => void;
54
64
  onStart?: () => void;
@@ -33,7 +33,11 @@ interface ScrollDrawOptions {
33
33
  /**
34
34
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
35
35
  * Works on any content — SVG, images, text, divs.
36
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
36
+ *
37
+ * Pass a direction string to control which edge the reveal starts from,
38
+ * or `true` as shorthand for `'left'`.
39
+ *
40
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
37
41
  */
38
42
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
39
43
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -48,7 +52,13 @@ interface ScrollDrawOptions {
48
52
  repeat?: number | 'infinite';
49
53
  /** Milliseconds to wait between repeats. Default 0. */
50
54
  repeatDelay?: number;
51
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
55
+ /**
56
+ * Target path `d` attribute to morph toward as the animation progresses.
57
+ * Paths must have compatible command structures (same number of numeric tokens).
58
+ *
59
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
60
+ * `<line>`, and other SVG shape elements.
61
+ */
52
62
  morphTo?: string;
53
63
  onProgress?: (alpha: number) => void;
54
64
  onStart?: () => void;
@@ -33,7 +33,11 @@ interface ScrollDrawOptions {
33
33
  /**
34
34
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
35
35
  * Works on any content — SVG, images, text, divs.
36
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
36
+ *
37
+ * Pass a direction string to control which edge the reveal starts from,
38
+ * or `true` as shorthand for `'left'`.
39
+ *
40
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
37
41
  */
38
42
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
39
43
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -48,7 +52,13 @@ interface ScrollDrawOptions {
48
52
  repeat?: number | 'infinite';
49
53
  /** Milliseconds to wait between repeats. Default 0. */
50
54
  repeatDelay?: number;
51
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
55
+ /**
56
+ * Target path `d` attribute to morph toward as the animation progresses.
57
+ * Paths must have compatible command structures (same number of numeric tokens).
58
+ *
59
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
60
+ * `<line>`, and other SVG shape elements.
61
+ */
52
62
  morphTo?: string;
53
63
  onProgress?: (alpha: number) => void;
54
64
  onStart?: () => void;
@@ -33,7 +33,11 @@ interface ScrollDrawOptions {
33
33
  /**
34
34
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
35
35
  * Works on any content — SVG, images, text, divs.
36
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
36
+ *
37
+ * Pass a direction string to control which edge the reveal starts from,
38
+ * or `true` as shorthand for `'left'`.
39
+ *
40
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
37
41
  */
38
42
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
39
43
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -48,7 +52,13 @@ interface ScrollDrawOptions {
48
52
  repeat?: number | 'infinite';
49
53
  /** Milliseconds to wait between repeats. Default 0. */
50
54
  repeatDelay?: number;
51
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
55
+ /**
56
+ * Target path `d` attribute to morph toward as the animation progresses.
57
+ * Paths must have compatible command structures (same number of numeric tokens).
58
+ *
59
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
60
+ * `<line>`, and other SVG shape elements.
61
+ */
52
62
  morphTo?: string;
53
63
  onProgress?: (alpha: number) => void;
54
64
  onStart?: () => void;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -30,7 +30,11 @@ interface ScrollDrawOptions {
30
30
  /**
31
31
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
32
32
  * Works on any content — SVG, images, text, divs.
33
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
33
+ *
34
+ * Pass a direction string to control which edge the reveal starts from,
35
+ * or `true` as shorthand for `'left'`.
36
+ *
37
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
34
38
  */
35
39
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
36
40
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -45,7 +49,13 @@ interface ScrollDrawOptions {
45
49
  repeat?: number | 'infinite';
46
50
  /** Milliseconds to wait between repeats. Default 0. */
47
51
  repeatDelay?: number;
48
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
52
+ /**
53
+ * Target path `d` attribute to morph toward as the animation progresses.
54
+ * Paths must have compatible command structures (same number of numeric tokens).
55
+ *
56
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
57
+ * `<line>`, and other SVG shape elements.
58
+ */
49
59
  morphTo?: string;
50
60
  onProgress?: (alpha: number) => void;
51
61
  onStart?: () => void;
@@ -32,7 +32,11 @@ interface ScrollDrawOptions {
32
32
  /**
33
33
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
34
34
  * Works on any content — SVG, images, text, divs.
35
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
35
+ *
36
+ * Pass a direction string to control which edge the reveal starts from,
37
+ * or `true` as shorthand for `'left'`.
38
+ *
39
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
36
40
  */
37
41
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
38
42
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -47,7 +51,13 @@ interface ScrollDrawOptions {
47
51
  repeat?: number | 'infinite';
48
52
  /** Milliseconds to wait between repeats. Default 0. */
49
53
  repeatDelay?: number;
50
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
54
+ /**
55
+ * Target path `d` attribute to morph toward as the animation progresses.
56
+ * Paths must have compatible command structures (same number of numeric tokens).
57
+ *
58
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
59
+ * `<line>`, and other SVG shape elements.
60
+ */
51
61
  morphTo?: string;
52
62
  onProgress?: (alpha: number) => void;
53
63
  onStart?: () => void;
@@ -32,7 +32,11 @@ interface ScrollDrawOptions {
32
32
  /**
33
33
  * Reveal the container using CSS clip-path instead of stroke-dashoffset.
34
34
  * Works on any content — SVG, images, text, divs.
35
- * `true` defaults to `'left'`. Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`.
35
+ *
36
+ * Pass a direction string to control which edge the reveal starts from,
37
+ * or `true` as shorthand for `'left'`.
38
+ *
39
+ * Values: `'left' | 'right' | 'top' | 'bottom' | 'center'`
36
40
  */
37
41
  clip?: boolean | 'left' | 'right' | 'top' | 'bottom' | 'center';
38
42
  /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
@@ -47,7 +51,13 @@ interface ScrollDrawOptions {
47
51
  repeat?: number | 'infinite';
48
52
  /** Milliseconds to wait between repeats. Default 0. */
49
53
  repeatDelay?: number;
50
- /** Target path `d` attribute to morph toward as the animation progresses. Paths must have compatible structures. */
54
+ /**
55
+ * Target path `d` attribute to morph toward as the animation progresses.
56
+ * Paths must have compatible command structures (same number of numeric tokens).
57
+ *
58
+ * Only applies to `<path>` elements — silently no-ops on `<rect>`, `<circle>`,
59
+ * `<line>`, and other SVG shape elements.
60
+ */
51
61
  morphTo?: string;
52
62
  onProgress?: (alpha: number) => void;
53
63
  onStart?: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svg-scroll-draw",
3
- "version": "0.7.0",
3
+ "version": "1.0.0",
4
4
  "description": "Scroll-driven SVG path drawing animation library — zero dependencies, ~3 KB gzipped, works with React, Vue, and vanilla JS",
5
5
  "keywords": [
6
6
  "svg",