svg-scroll-draw 0.3.0 → 0.4.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.
@@ -0,0 +1,3 @@
1
+ 'use strict';var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[n="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:n,viewport:o}}function te(e,t,n,o){switch(o){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function re(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(n+o)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function ye(e,t,n){return Math.min(n,Math.max(t,e))}function z(e,t,n,o){return n===t?0:ye((e-t)/(n-t)*o,0,1)}function oe(e,t,n,o,i){let p=te(e.top,e.height,t,o.element)-re(o.viewport,n),d=te(e.top,e.height,t,i.element)-re(i.viewport,n);return {tStart:p,tEnd:d}}function ne(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[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 o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function se(e,t,n){let o=ne(e),i=ne(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*n)},${Math.round(o[1]+(i[1]-o[1])*n)},${Math.round(o[2]+(i[2]-o[2])*n)})`}function ie(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function be(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?ie("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&ie("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ge(e,t,n){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let p=n==="x"?window.scrollX:window.scrollY,d=e-p,A=t-p,T=n==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function le(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:p=false,easing:d="linear",trigger:A={},stagger:T=0,direction:b="forward",once:J=false,debug:ce=false,axis:f="y",scrollContainer:W,autoReverse:K=false,delay:Q=0,strokeColor:g,strokeWidth:w,waypoints:G,onProgress:ue,onStart:pe,onComplete:U}=t,Y=typeof d=="function"?d:X[d]??X.linear,fe=_(A.start??"top bottom"),de=_(A.end??"bottom top"),l=typeof W=="string"?document.querySelector(W):W??null,v=Array.isArray(g)?g[0]:null,x=Array.isArray(g)?g[1]:typeof g=="string"?g:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),h=[],$=0,k=0,L=false,V=false,M=0,N=false,F=-1,C=-1,P=null,R=new Set;function q(){return l?f==="x"?l.scrollLeft:l.scrollTop:f==="x"?window.scrollX:window.scrollY}function me(){return l?f==="x"?l.clientWidth:l.clientHeight:f==="x"?window.innerWidth:window.innerHeight}function Z(){let r=e.getBoundingClientRect(),s,D,y;if(l){let c=l.getBoundingClientRect();s=f==="x"?r.left-c.left+l.scrollLeft:r.top-c.top+l.scrollTop,D=f==="x"?r.width:r.height,y=q();}else s=f==="x"?r.left:r.top,D=f==="x"?r.width:r.height,y=q();let a=oe({top:s,height:D},y,me(),fe,de);$=a.tStart,k=a.tEnd,ce&&process.env.NODE_ENV!=="production"&&(P?.remove(),P=ge($,k,f));}function he(){I.forEach((r,s)=>{r.style.strokeDasharray=`${h[s]}`,r.style.strokeDashoffset=b==="reverse"?"0":`${h[s]}`,p?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`);});}if(I.forEach(r=>{be(r);let s=j(r);h.push(s),n?(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?`${s}`:"0",p&&(r.style.opacity="1"),x&&(r.style.stroke=x),E!==null&&(r.style.strokeWidth=`${E}`)):(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?"0":`${s}`,p?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`));}),n)return U?.(),{destroy:()=>{},replay:()=>{}};Z();function ee(){if(!N)return;let r=q(),s=K?C===-1||r>=C?"forward":"reverse":b;C=r;let D=k-$,y=true;if(I.forEach((a,c)=>{let S=c*T*D,u=Y(z(r,$+S,k+S,i));J&&!K&&(F=Math.max(F,u),u=F),a.style.strokeDashoffset=s==="reverse"?`${h[c]*u}`:`${h[c]*(1-u)}`,p&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=se(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&ue?.(u),u<1&&(y=false);}),G){let a=Y(z(r,$,k,i));for(let c in G){let S=parseFloat(c);a>=S&&!R.has(S)&&(R.add(S),G[c]?.());}}!V&&z(r,$,k,i)>0&&(V=true,pe?.()),y&&!L?(L=true,U?.()):!y&&!J&&(L=false),M=requestAnimationFrame(ee);}let B=new IntersectionObserver(r=>{r.forEach(s=>{N=s.isIntersecting,N?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:l??null}),H;function O(){clearTimeout(H),H=setTimeout(()=>{I.forEach((r,s)=>{h[s]=j(r),r.style.strokeDasharray=`${h[s]}`;}),Z();},150);}return window.addEventListener("resize",O),window.addEventListener("orientationchange",O),Q>0?setTimeout(()=>B.observe(e),Q):B.observe(e),{destroy(){cancelAnimationFrame(M),B.disconnect(),window.removeEventListener("resize",O),window.removeEventListener("orientationchange",O),clearTimeout(H),P?.remove();},replay(){F=-1,C=-1,V=false,L=false,R.clear(),he();}}}var ae=class{constructor(){this.instance=null;}init(t,n={}){return this.destroy(),this.instance=le(t,n),this}replay(){return this.instance?.replay(),this}destroy(){return this.instance?.destroy(),this.instance=null,this}};exports.ScrollDrawRef=ae;
@@ -0,0 +1,73 @@
1
+ type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
2
+ interface TriggerConfig {
3
+ start?: string;
4
+ end?: string;
5
+ }
6
+ interface ScrollDrawOptions {
7
+ selector?: string;
8
+ speed?: number;
9
+ fade?: boolean;
10
+ easing?: EasingName | ((t: number) => number);
11
+ trigger?: TriggerConfig;
12
+ stagger?: number;
13
+ direction?: 'forward' | 'reverse';
14
+ once?: boolean;
15
+ debug?: boolean;
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
17
+ axis?: 'x' | 'y';
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
30
+ onProgress?: (alpha: number) => void;
31
+ onStart?: () => void;
32
+ onComplete?: () => void;
33
+ }
34
+ interface ScrollDrawInstance {
35
+ destroy: () => void;
36
+ /** Reset and replay the animation from the beginning. */
37
+ replay: () => void;
38
+ }
39
+
40
+ /**
41
+ * Framework-agnostic class for use in Angular components.
42
+ * No @angular/core dependency required.
43
+ *
44
+ * @example
45
+ * // In your Angular component:
46
+ * import { ScrollDrawRef } from 'svg-scroll-draw/angular';
47
+ *
48
+ * @Component({ template: '<div #container><svg>...</svg></div>' })
49
+ * export class HeroComponent implements AfterViewInit, OnDestroy {
50
+ * @ViewChild('container') containerRef!: ElementRef<HTMLElement>;
51
+ * private draw = new ScrollDrawRef();
52
+ *
53
+ * ngAfterViewInit() {
54
+ * this.draw.init(this.containerRef.nativeElement, {
55
+ * easing: 'ease-out',
56
+ * speed: 1.2,
57
+ * fade: true,
58
+ * });
59
+ * }
60
+ *
61
+ * ngOnDestroy() { this.draw.destroy(); }
62
+ *
63
+ * replay() { this.draw.replay(); }
64
+ * }
65
+ */
66
+ declare class ScrollDrawRef {
67
+ private instance;
68
+ init(element: HTMLElement, options?: ScrollDrawOptions): this;
69
+ replay(): this;
70
+ destroy(): this;
71
+ }
72
+
73
+ export { type ScrollDrawInstance, type ScrollDrawOptions, ScrollDrawRef };
@@ -0,0 +1,73 @@
1
+ type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
2
+ interface TriggerConfig {
3
+ start?: string;
4
+ end?: string;
5
+ }
6
+ interface ScrollDrawOptions {
7
+ selector?: string;
8
+ speed?: number;
9
+ fade?: boolean;
10
+ easing?: EasingName | ((t: number) => number);
11
+ trigger?: TriggerConfig;
12
+ stagger?: number;
13
+ direction?: 'forward' | 'reverse';
14
+ once?: boolean;
15
+ debug?: boolean;
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
17
+ axis?: 'x' | 'y';
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
30
+ onProgress?: (alpha: number) => void;
31
+ onStart?: () => void;
32
+ onComplete?: () => void;
33
+ }
34
+ interface ScrollDrawInstance {
35
+ destroy: () => void;
36
+ /** Reset and replay the animation from the beginning. */
37
+ replay: () => void;
38
+ }
39
+
40
+ /**
41
+ * Framework-agnostic class for use in Angular components.
42
+ * No @angular/core dependency required.
43
+ *
44
+ * @example
45
+ * // In your Angular component:
46
+ * import { ScrollDrawRef } from 'svg-scroll-draw/angular';
47
+ *
48
+ * @Component({ template: '<div #container><svg>...</svg></div>' })
49
+ * export class HeroComponent implements AfterViewInit, OnDestroy {
50
+ * @ViewChild('container') containerRef!: ElementRef<HTMLElement>;
51
+ * private draw = new ScrollDrawRef();
52
+ *
53
+ * ngAfterViewInit() {
54
+ * this.draw.init(this.containerRef.nativeElement, {
55
+ * easing: 'ease-out',
56
+ * speed: 1.2,
57
+ * fade: true,
58
+ * });
59
+ * }
60
+ *
61
+ * ngOnDestroy() { this.draw.destroy(); }
62
+ *
63
+ * replay() { this.draw.replay(); }
64
+ * }
65
+ */
66
+ declare class ScrollDrawRef {
67
+ private instance;
68
+ init(element: HTMLElement, options?: ScrollDrawOptions): this;
69
+ replay(): this;
70
+ destroy(): this;
71
+ }
72
+
73
+ export { type ScrollDrawInstance, type ScrollDrawOptions, ScrollDrawRef };
@@ -0,0 +1,3 @@
1
+ var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[n="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:n,viewport:o}}function te(e,t,n,o){switch(o){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function re(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(n+o)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function ye(e,t,n){return Math.min(n,Math.max(t,e))}function z(e,t,n,o){return n===t?0:ye((e-t)/(n-t)*o,0,1)}function oe(e,t,n,o,i){let p=te(e.top,e.height,t,o.element)-re(o.viewport,n),d=te(e.top,e.height,t,i.element)-re(i.viewport,n);return {tStart:p,tEnd:d}}function ne(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[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 o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function se(e,t,n){let o=ne(e),i=ne(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*n)},${Math.round(o[1]+(i[1]-o[1])*n)},${Math.round(o[2]+(i[2]-o[2])*n)})`}function ie(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function be(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?ie("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&ie("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ge(e,t,n){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let p=n==="x"?window.scrollX:window.scrollY,d=e-p,A=t-p,T=n==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function le(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:p=false,easing:d="linear",trigger:A={},stagger:T=0,direction:b="forward",once:J=false,debug:ce=false,axis:f="y",scrollContainer:W,autoReverse:K=false,delay:Q=0,strokeColor:g,strokeWidth:w,waypoints:G,onProgress:ue,onStart:pe,onComplete:U}=t,Y=typeof d=="function"?d:X[d]??X.linear,fe=_(A.start??"top bottom"),de=_(A.end??"bottom top"),l=typeof W=="string"?document.querySelector(W):W??null,v=Array.isArray(g)?g[0]:null,x=Array.isArray(g)?g[1]:typeof g=="string"?g:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),h=[],$=0,k=0,L=false,V=false,M=0,N=false,F=-1,C=-1,P=null,R=new Set;function q(){return l?f==="x"?l.scrollLeft:l.scrollTop:f==="x"?window.scrollX:window.scrollY}function me(){return l?f==="x"?l.clientWidth:l.clientHeight:f==="x"?window.innerWidth:window.innerHeight}function Z(){let r=e.getBoundingClientRect(),s,D,y;if(l){let c=l.getBoundingClientRect();s=f==="x"?r.left-c.left+l.scrollLeft:r.top-c.top+l.scrollTop,D=f==="x"?r.width:r.height,y=q();}else s=f==="x"?r.left:r.top,D=f==="x"?r.width:r.height,y=q();let a=oe({top:s,height:D},y,me(),fe,de);$=a.tStart,k=a.tEnd,ce&&process.env.NODE_ENV!=="production"&&(P?.remove(),P=ge($,k,f));}function he(){I.forEach((r,s)=>{r.style.strokeDasharray=`${h[s]}`,r.style.strokeDashoffset=b==="reverse"?"0":`${h[s]}`,p?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`);});}if(I.forEach(r=>{be(r);let s=j(r);h.push(s),n?(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?`${s}`:"0",p&&(r.style.opacity="1"),x&&(r.style.stroke=x),E!==null&&(r.style.strokeWidth=`${E}`)):(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?"0":`${s}`,p?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`));}),n)return U?.(),{destroy:()=>{},replay:()=>{}};Z();function ee(){if(!N)return;let r=q(),s=K?C===-1||r>=C?"forward":"reverse":b;C=r;let D=k-$,y=true;if(I.forEach((a,c)=>{let S=c*T*D,u=Y(z(r,$+S,k+S,i));J&&!K&&(F=Math.max(F,u),u=F),a.style.strokeDashoffset=s==="reverse"?`${h[c]*u}`:`${h[c]*(1-u)}`,p&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=se(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&ue?.(u),u<1&&(y=false);}),G){let a=Y(z(r,$,k,i));for(let c in G){let S=parseFloat(c);a>=S&&!R.has(S)&&(R.add(S),G[c]?.());}}!V&&z(r,$,k,i)>0&&(V=true,pe?.()),y&&!L?(L=true,U?.()):!y&&!J&&(L=false),M=requestAnimationFrame(ee);}let B=new IntersectionObserver(r=>{r.forEach(s=>{N=s.isIntersecting,N?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:l??null}),H;function O(){clearTimeout(H),H=setTimeout(()=>{I.forEach((r,s)=>{h[s]=j(r),r.style.strokeDasharray=`${h[s]}`;}),Z();},150);}return window.addEventListener("resize",O),window.addEventListener("orientationchange",O),Q>0?setTimeout(()=>B.observe(e),Q):B.observe(e),{destroy(){cancelAnimationFrame(M),B.disconnect(),window.removeEventListener("resize",O),window.removeEventListener("orientationchange",O),clearTimeout(H),P?.remove();},replay(){F=-1,C=-1,V=false,L=false,R.clear(),he();}}}var ae=class{constructor(){this.instance=null;}init(t,n={}){return this.destroy(),this.instance=le(t,n),this}replay(){return this.instance?.replay(),this}destroy(){return this.instance?.destroy(),this.instance=null,this}};export{ae as ScrollDrawRef};
@@ -1,8 +1,3 @@
1
- "use strict";var SvgScrollDraw=(()=>{var I=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var oe=Object.prototype.hasOwnProperty;var se=(e,t)=>{for(var r in t)I(e,r,{get:t[r],enumerable:!0})},ie=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of ne(t))!oe.call(e,i)&&i!==r&&I(e,i,{get:()=>t[i],enumerable:!(o=re(t,i))||o.enumerable});return e};var ae=e=>ie(I({},"__esModule",{value:!0}),e);var fe={};se(fe,{scrollDraw:()=>pe});var M={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 L(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return{element:"top",viewport:t};let r=t.split(/\s+/).filter(Boolean),[o="top",i="bottom"]=r;return{element:o,viewport:i}}function X(e,t,r,o){switch(o){case"top":return e+r;case"center":return e+r+t/2;case"bottom":return e+r+t;default:return e+r}}function B(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case"top":return 0;case"center":return t/2;case"bottom":return t;default:return t}}function F(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ce(e,t,r){return Math.min(r,Math.max(t,e))}function P(e,t,r,o){return r===t?0:ce((e-t)/(r-t)*o,0,1)}function _(e,t,r,o,i){let c=X(e.top,e.height,t,o.element)-B(o.viewport,r),a=X(e.top,e.height,t,i.element)-B(i.viewport,r);return{tStart:c,tEnd:a}}function H(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t)}function le(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?H("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&H("Element has a fill \u2014 it may obscure the stroke animation.",e)}function ue(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let a=r==="x"?window.scrollX:window.scrollY,u=e-a,b=t-a,l=r==="x";o.innerHTML=`
2
- <div style="position:absolute;
3
- ${l?`left:${u}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${u}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${l?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `}return document.body.appendChild(o),window.addEventListener("scroll",i,{passive:!0}),i(),o}function S(e,t={}){if(typeof window>"u")return{destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:c=!1,easing:a="linear",trigger:u={},stagger:b=0,direction:l="forward",once:C=!1,debug:W=!1,axis:d="y",onProgress:j,onStart:J,onComplete:G}=t,K=typeof a=="function"?a:M[a]??M.linear,Q=L(u.start??"top bottom"),U=L(u.end??"bottom top"),h=Array.from(e.querySelectorAll(o)),f=[],m=0,g=0,w=!1,D=!1,y=0,A=!1,v=-1,$=null;function k(){return d==="x"?window.scrollX:window.scrollY}function Y(){return d==="x"?window.innerWidth:window.innerHeight}function Z(n){return d==="x"?n.left:n.top}function ee(n){return d==="x"?n.width:n.height}function V(){let n=e.getBoundingClientRect(),s=_({top:Z(n),height:ee(n)},k(),Y(),Q,U);m=s.tStart,g=s.tEnd,W&&process.env.NODE_ENV!=="production"&&($?.remove(),$=ue(m,g,d))}function te(){h.forEach((n,s)=>{n.style.strokeDasharray=`${f[s]}`,n.style.strokeDashoffset=l==="reverse"?"0":`${f[s]}`,c?n.style.opacity=l==="reverse"?"1":"0":n.style.opacity=""})}if(h.forEach(n=>{le(n);let s=F(n);f.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=l==="reverse"?`${s}`:"0",c&&(n.style.opacity="1")):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=l==="reverse"?"0":`${s}`,c&&(n.style.opacity=l==="reverse"?"1":"0"))}),r)return G?.(),{destroy:()=>{},replay:()=>{}};V();function N(){if(!A)return;let n=g-m,s=!0;h.forEach((O,x)=>{let q=x*b*n,p=K(P(k(),m+q,g+q,i));C&&(v=Math.max(v,p),p=v),O.style.strokeDashoffset=l==="reverse"?`${f[x]*p}`:`${f[x]*(1-p)}`,c&&(O.style.opacity=l==="reverse"?`${1-p}`:`${p}`),x===0&&j?.(p),p<1&&(s=!1)}),D||P(k(),m,g,i)>0&&(D=!0,J?.()),s&&!w?(w=!0,G?.()):!s&&!C&&(w=!1),y=requestAnimationFrame(N)}let R=new IntersectionObserver(n=>{n.forEach(s=>{A=s.isIntersecting,A?y=requestAnimationFrame(N):cancelAnimationFrame(y)})});R.observe(e);let T;function E(){clearTimeout(T),T=setTimeout(()=>{h.forEach((n,s)=>{f[s]=F(n),n.style.strokeDasharray=`${f[s]}`}),V()},150)}return window.addEventListener("resize",E),window.addEventListener("orientationchange",E),{destroy(){cancelAnimationFrame(y),R.disconnect(),window.removeEventListener("resize",E),window.removeEventListener("orientationchange",E),clearTimeout(T),$?.remove()},replay(){v=-1,D=!1,w=!1,te()}}}function pe(e,t){let r={destroy:()=>{},replay:()=>{}};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;return o?S(o,t):(console.warn("[svg-scroll-draw] Container not found:",e),r)}var z=class extends HTMLElement{constructor(){super(...arguments);this.instance=null}connectedCallback(){let r={},o=this.getAttribute("speed"),i=this.getAttribute("easing"),c=this.getAttribute("stagger"),a=this.getAttribute("direction"),u=this.getAttribute("selector");o&&(r.speed=parseFloat(o)),i&&(r.easing=i),c&&(r.stagger=parseFloat(c)),a&&(r.direction=a),u&&(r.selector=u),this.hasAttribute("fade")&&(r.fade=this.getAttribute("fade")!=="false"),this.instance=S(this,r)}disconnectedCallback(){this.instance?.destroy(),this.instance=null}};typeof customElements<"u"&&!customElements.get("scroll-draw")&&customElements.define("scroll-draw",z);return ae(fe);})();
1
+ "use strict";var SvgScrollDraw=(()=>{var _=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var ve=(e,t)=>{for(var r in t)_(e,r,{get:t[r],enumerable:!0})},xe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of ye(t))!we.call(e,s)&&s!==r&&_(e,s,{get:()=>t[s],enumerable:!(n=be(t,s))||n.enumerable});return e};var Ee=e=>xe(_({},"__esModule",{value:!0}),e);var De={};ve(De,{scrollDraw:()=>$e});var j={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 J(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return{element:"top",viewport:t};let[r="top",n="bottom"]=t.split(/\s+/).filter(Boolean);return{element:r,viewport:n}}function oe(e,t,r,n){switch(n){case"top":return e+r;case"center":return e+r+t/2;case"bottom":return e+r+t;default:return e+r}}function se(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case"top":return 0;case"center":return t/2;case"bottom":return t;default:return t}}function K(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),n=parseFloat(e.getAttribute("height")??"0");return 2*(r+n)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function Se(e,t,r){return Math.min(r,Math.max(t,e))}function z(e,t,r,n){return r===t?0:Se((e-t)/(r-t)*n,0,1)}function le(e,t,r,n,s){let l=oe(e.top,e.height,t,n.element)-se(n.viewport,r),a=oe(e.top,e.height,t,s.element)-se(s.viewport,r);return{tStart:l,tEnd:a}}function ie(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)];let r=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(r)return[parseInt(r[1],16),parseInt(r[2],16),parseInt(r[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 ae(e,t,r){let n=ie(e),s=ie(t);return!n||!s?e:`rgb(${Math.round(n[0]+(s[0]-n[0])*r)},${Math.round(n[1]+(s[1]-n[1])*r)},${Math.round(n[2]+(s[2]-n[2])*r)})`}function ce(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t)}function Ae(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?ce("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&ce("Element has a fill \u2014 it may obscure the stroke animation.",e)}function ke(e,t,r){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 s(){let l=r==="x"?window.scrollX:window.scrollY,a=e-l,m=t-l,I=r==="x";n.innerHTML=`
2
+ <div style="position:absolute;${I?`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;${I?`left:${m}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${m}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",s,{passive:!0}),s(),n}function W(e,t={}){if(typeof window>"u")return{destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:n="path, polyline, line, polygon, rect, circle",speed:s=1,fade:l=!1,easing:a="linear",trigger:m={},stagger:I=0,direction:y="forward",once:U=!1,debug:ue=!1,axis:d="y",scrollContainer:G,autoReverse:Y=!1,delay:Z=0,strokeColor:w,strokeWidth:v,waypoints:V,onProgress:fe,onStart:pe,onComplete:ee}=t,te=typeof a=="function"?a:j[a]??j.linear,de=J(m.start??"top bottom"),me=J(m.end??"bottom top"),c=typeof G=="string"?document.querySelector(G):G??null,x=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="string"?w:null,g=Array.isArray(v)?v[0]:null,S=Array.isArray(v)?v[1]:typeof v=="number"?v:null,T=Array.from(e.querySelectorAll(n)),h=[],A=0,k=0,L=!1,N=!1,M=0,P=!1,C=-1,F=-1,R=null,q=new Set;function B(){return c?d==="x"?c.scrollLeft:c.scrollTop:d==="x"?window.scrollX:window.scrollY}function ge(){return c?d==="x"?c.clientWidth:c.clientHeight:d==="x"?window.innerWidth:window.innerHeight}function re(){let o=e.getBoundingClientRect(),i,D,b;if(c){let f=c.getBoundingClientRect();i=d==="x"?o.left-f.left+c.scrollLeft:o.top-f.top+c.scrollTop,D=d==="x"?o.width:o.height,b=B()}else i=d==="x"?o.left:o.top,D=d==="x"?o.width:o.height,b=B();let u=le({top:i,height:D},b,ge(),de,me);A=u.tStart,k=u.tEnd,ue&&process.env.NODE_ENV!=="production"&&(R?.remove(),R=ke(A,k,d))}function he(){T.forEach((o,i)=>{o.style.strokeDasharray=`${h[i]}`,o.style.strokeDashoffset=y==="reverse"?"0":`${h[i]}`,l?o.style.opacity=y==="reverse"?"1":"0":o.style.opacity="",x&&(o.style.stroke=x),g!==null&&(o.style.strokeWidth=`${g}`)})}if(T.forEach(o=>{Ae(o);let i=K(o);h.push(i),r?(o.style.strokeDasharray=`${i}`,o.style.strokeDashoffset=y==="reverse"?`${i}`:"0",l&&(o.style.opacity="1"),E&&(o.style.stroke=E),S!==null&&(o.style.strokeWidth=`${S}`)):(o.style.strokeDasharray=`${i}`,o.style.strokeDashoffset=y==="reverse"?"0":`${i}`,l?o.style.opacity=y==="reverse"?"1":"0":o.style.opacity="",x&&(o.style.stroke=x),g!==null&&(o.style.strokeWidth=`${g}`))}),r)return ee?.(),{destroy:()=>{},replay:()=>{}};re();function ne(){if(!P)return;let o=B(),i=Y?F===-1||o>=F?"forward":"reverse":y;F=o;let D=k-A,b=!0;if(T.forEach((u,f)=>{let $=f*I*D,p=te(z(o,A+$,k+$,s));U&&!Y&&(C=Math.max(C,p),p=C),u.style.strokeDashoffset=i==="reverse"?`${h[f]*p}`:`${h[f]*(1-p)}`,l&&(u.style.opacity=i==="reverse"?`${1-p}`:`${p}`),x&&E?u.style.stroke=ae(x,E,p):E&&(u.style.stroke=E),g!==null&&S!==null?u.style.strokeWidth=`${g+(S-g)*p}`:S!==null&&(u.style.strokeWidth=`${S}`),f===0&&fe?.(p),p<1&&(b=!1)}),V){let u=te(z(o,A,k,s));for(let f in V){let $=parseFloat(f);u>=$&&!q.has($)&&(q.add($),V[f]?.())}}!N&&z(o,A,k,s)>0&&(N=!0,pe?.()),b&&!L?(L=!0,ee?.()):!b&&!U&&(L=!1),M=requestAnimationFrame(ne)}let H=new IntersectionObserver(o=>{o.forEach(i=>{P=i.isIntersecting,P?M=requestAnimationFrame(ne):cancelAnimationFrame(M)})},{root:c??null}),X;function O(){clearTimeout(X),X=setTimeout(()=>{T.forEach((o,i)=>{h[i]=K(o),o.style.strokeDasharray=`${h[i]}`}),re()},150)}return window.addEventListener("resize",O),window.addEventListener("orientationchange",O),Z>0?setTimeout(()=>H.observe(e),Z):H.observe(e),{destroy(){cancelAnimationFrame(M),H.disconnect(),window.removeEventListener("resize",O),window.removeEventListener("orientationchange",O),clearTimeout(X),R?.remove()},replay(){C=-1,F=-1,N=!1,L=!1,q.clear(),he()}}}function $e(e,t){let r={destroy:()=>{},replay:()=>{}};if(typeof window>"u")return r;let n=typeof e=="string"?document.querySelector(e):e;return n?W(n,t):(console.warn("[svg-scroll-draw] Container not found:",e),r)}var Q=class extends HTMLElement{constructor(){super(...arguments);this.instance=null}connectedCallback(){let r={},n=this.getAttribute("speed"),s=this.getAttribute("easing"),l=this.getAttribute("stagger"),a=this.getAttribute("direction"),m=this.getAttribute("selector");n&&(r.speed=parseFloat(n)),s&&(r.easing=s),l&&(r.stagger=parseFloat(l)),a&&(r.direction=a),m&&(r.selector=m),this.hasAttribute("fade")&&(r.fade=this.getAttribute("fade")!=="false"),this.instance=W(this,r)}disconnectedCallback(){this.instance?.destroy(),this.instance=null}};typeof customElements<"u"&&!customElements.get("scroll-draw")&&customElements.define("scroll-draw",Q);return Ee(De);})();
package/dist/index.cjs CHANGED
@@ -1,8 +1,3 @@
1
- 'use strict';var I={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 M(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let r=t.split(/\s+/).filter(Boolean),[o="top",i="bottom"]=r;return {element:o,viewport:i}}function R(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function C(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function L(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ee(e,t,r){return Math.min(r,Math.max(t,e))}function O(e,t,r,o){return r===t?0:ee((e-t)/(r-t)*o,0,1)}function q(e,t,r,o,i){let u=R(e.top,e.height,t,o.element)-C(o.viewport,r),c=R(e.top,e.height,t,i.element)-C(i.viewport,r);return {tStart:u,tEnd:c}}function X(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function te(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?X("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&X("Element has a fill \u2014 it may obscure the stroke animation.",e);}function re(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let c=r==="x"?window.scrollX:window.scrollY,m=e-c,b=t-c,a=r==="x";o.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function B(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:u=false,easing:c="linear",trigger:m={},stagger:b=0,direction:a="forward",once:P=false,debug:_=false,axis:f="y",onProgress:W,onStart:j,onComplete:z}=t,H=typeof c=="function"?c:I[c]??I.linear,J=M(m.start??"top bottom"),K=M(m.end??"bottom top"),w=Array.from(e.querySelectorAll(o)),p=[],d=0,g=0,h=false,S=false,y=0,D=false,v=-1,$=null;function A(){return f==="x"?window.scrollX:window.scrollY}function Q(){return f==="x"?window.innerWidth:window.innerHeight}function U(n){return f==="x"?n.left:n.top}function Y(n){return f==="x"?n.width:n.height}function F(){let n=e.getBoundingClientRect(),s=q({top:U(n),height:Y(n)},A(),Q(),J,K);d=s.tStart,g=s.tEnd,_&&process.env.NODE_ENV!=="production"&&($?.remove(),$=re(d,g,f));}function Z(){w.forEach((n,s)=>{n.style.strokeDasharray=`${p[s]}`,n.style.strokeDashoffset=a==="reverse"?"0":`${p[s]}`,u?n.style.opacity=a==="reverse"?"1":"0":n.style.opacity="";});}if(w.forEach(n=>{te(n);let s=L(n);p.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?`${s}`:"0",u&&(n.style.opacity="1")):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?"0":`${s}`,u&&(n.style.opacity=a==="reverse"?"1":"0"));}),r)return z?.(),{destroy:()=>{},replay:()=>{}};F();function G(){if(!D)return;let n=g-d,s=true;w.forEach((k,E)=>{let N=E*b*n,l=H(O(A(),d+N,g+N,i));P&&(v=Math.max(v,l),l=v),k.style.strokeDashoffset=a==="reverse"?`${p[E]*l}`:`${p[E]*(1-l)}`,u&&(k.style.opacity=a==="reverse"?`${1-l}`:`${l}`),E===0&&W?.(l),l<1&&(s=false);}),S||O(A(),d,g,i)>0&&(S=true,j?.()),s&&!h?(h=true,z?.()):!s&&!P&&(h=false),y=requestAnimationFrame(G);}let V=new IntersectionObserver(n=>{n.forEach(s=>{D=s.isIntersecting,D?y=requestAnimationFrame(G):cancelAnimationFrame(y);});});V.observe(e);let T;function x(){clearTimeout(T),T=setTimeout(()=>{w.forEach((n,s)=>{p[s]=L(n),n.style.strokeDasharray=`${p[s]}`;}),F();},150);}return window.addEventListener("resize",x),window.addEventListener("orientationchange",x),{destroy(){cancelAnimationFrame(y),V.disconnect(),window.removeEventListener("resize",x),window.removeEventListener("orientationchange",x),clearTimeout(T),$?.remove();},replay(){v=-1,S=false,h=false,Z();}}}function ae(e,t){let r={destroy:()=>{},replay:()=>{}};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;return o?B(o,t):(console.warn("[svg-scroll-draw] Container not found:",e),r)}exports.scrollDraw=ae;
1
+ 'use strict';var _={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 H(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function te(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function re(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ye(e,t,r){return Math.min(r,Math.max(t,e))}function z(e,t,r,o){return r===t?0:ye((e-t)/(r-t)*o,0,1)}function oe(e,t,r,o,i){let f=te(e.top,e.height,t,o.element)-re(o.viewport,r),d=te(e.top,e.height,t,i.element)-re(i.viewport,r);return {tStart:f,tEnd:d}}function ne(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)];let r=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(r)return [parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16)];let o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function se(e,t,r){let o=ne(e),i=ne(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*r)},${Math.round(o[1]+(i[1]-o[1])*r)},${Math.round(o[2]+(i[2]-o[2])*r)})`}function ie(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function be(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?ie("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&ie("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ge(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let f=r==="x"?window.scrollX:window.scrollY,d=e-f,A=t-f,I=r==="x";o.innerHTML=`
2
+ <div style="position:absolute;${I?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${I?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function le(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:d="linear",trigger:A={},stagger:I=0,direction:g="forward",once:J=false,debug:ae=false,axis:p="y",scrollContainer:W,autoReverse:K=false,delay:Q=0,strokeColor:h,strokeWidth:w,waypoints:G,onProgress:ce,onStart:ue,onComplete:U}=t,Y=typeof d=="function"?d:_[d]??_.linear,fe=H(A.start??"top bottom"),pe=H(A.end??"bottom top"),l=typeof W=="string"?document.querySelector(W):W??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,T=Array.from(e.querySelectorAll(o)),y=[],$=0,S=0,L=false,V=false,M=0,N=false,C=-1,F=-1,P=null,R=new Set;function q(){return l?p==="x"?l.scrollLeft:l.scrollTop:p==="x"?window.scrollX:window.scrollY}function de(){return l?p==="x"?l.clientWidth:l.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function Z(){let n=e.getBoundingClientRect(),s,D,b;if(l){let c=l.getBoundingClientRect();s=p==="x"?n.left-c.left+l.scrollLeft:n.top-c.top+l.scrollTop,D=p==="x"?n.width:n.height,b=q();}else s=p==="x"?n.left:n.top,D=p==="x"?n.width:n.height,b=q();let a=oe({top:s,height:D},b,de(),fe,pe);$=a.tStart,S=a.tEnd,ae&&process.env.NODE_ENV!=="production"&&(P?.remove(),P=ge($,S,p));}function me(){T.forEach((n,s)=>{n.style.strokeDasharray=`${y[s]}`,n.style.strokeDashoffset=g==="reverse"?"0":`${y[s]}`,f?n.style.opacity=g==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`);});}if(T.forEach(n=>{be(n);let s=j(n);y.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=g==="reverse"?`${s}`:"0",f&&(n.style.opacity="1"),x&&(n.style.stroke=x),E!==null&&(n.style.strokeWidth=`${E}`)):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=g==="reverse"?"0":`${s}`,f?n.style.opacity=g==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`));}),r)return U?.(),{destroy:()=>{},replay:()=>{}};Z();function ee(){if(!N)return;let n=q(),s=K?F===-1||n>=F?"forward":"reverse":g;F=n;let D=S-$,b=true;if(T.forEach((a,c)=>{let k=c*I*D,u=Y(z(n,$+k,S+k,i));J&&!K&&(C=Math.max(C,u),u=C),a.style.strokeDashoffset=s==="reverse"?`${y[c]*u}`:`${y[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=se(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&ce?.(u),u<1&&(b=false);}),G){let a=Y(z(n,$,S,i));for(let c in G){let k=parseFloat(c);a>=k&&!R.has(k)&&(R.add(k),G[c]?.());}}!V&&z(n,$,S,i)>0&&(V=true,ue?.()),b&&!L?(L=true,U?.()):!b&&!J&&(L=false),M=requestAnimationFrame(ee);}let B=new IntersectionObserver(n=>{n.forEach(s=>{N=s.isIntersecting,N?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:l??null}),X;function O(){clearTimeout(X),X=setTimeout(()=>{T.forEach((n,s)=>{y[s]=j(n),n.style.strokeDasharray=`${y[s]}`;}),Z();},150);}return window.addEventListener("resize",O),window.addEventListener("orientationchange",O),Q>0?setTimeout(()=>B.observe(e),Q):B.observe(e),{destroy(){cancelAnimationFrame(M),B.disconnect(),window.removeEventListener("resize",O),window.removeEventListener("orientationchange",O),clearTimeout(X),P?.remove();},replay(){C=-1,F=-1,V=false,L=false,R.clear(),me();}}}function Ee(e,t){let r={destroy:()=>{},replay:()=>{}};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;return o?le(o,t):(console.warn("[svg-scroll-draw] Container not found:",e),r)}exports.scrollDraw=Ee;
package/dist/index.d.mts CHANGED
@@ -9,19 +9,25 @@ interface ScrollDrawOptions {
9
9
  fade?: boolean;
10
10
  easing?: EasingName | ((t: number) => number);
11
11
  trigger?: TriggerConfig;
12
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
13
12
  stagger?: number;
14
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
15
13
  direction?: 'forward' | 'reverse';
16
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
17
14
  once?: boolean;
18
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
19
15
  debug?: boolean;
20
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
21
17
  axis?: 'x' | 'y';
22
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
23
30
  onProgress?: (alpha: number) => void;
24
- /** Fires once on the first frame the animation begins drawing. */
25
31
  onStart?: () => void;
26
32
  onComplete?: () => void;
27
33
  }
package/dist/index.d.ts CHANGED
@@ -9,19 +9,25 @@ interface ScrollDrawOptions {
9
9
  fade?: boolean;
10
10
  easing?: EasingName | ((t: number) => number);
11
11
  trigger?: TriggerConfig;
12
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
13
12
  stagger?: number;
14
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
15
13
  direction?: 'forward' | 'reverse';
16
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
17
14
  once?: boolean;
18
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
19
15
  debug?: boolean;
20
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
21
17
  axis?: 'x' | 'y';
22
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
23
30
  onProgress?: (alpha: number) => void;
24
- /** Fires once on the first frame the animation begins drawing. */
25
31
  onStart?: () => void;
26
32
  onComplete?: () => void;
27
33
  }
package/dist/index.mjs CHANGED
@@ -1,8 +1,3 @@
1
- var I={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 M(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let r=t.split(/\s+/).filter(Boolean),[o="top",i="bottom"]=r;return {element:o,viewport:i}}function R(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function C(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function L(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ee(e,t,r){return Math.min(r,Math.max(t,e))}function O(e,t,r,o){return r===t?0:ee((e-t)/(r-t)*o,0,1)}function q(e,t,r,o,i){let u=R(e.top,e.height,t,o.element)-C(o.viewport,r),c=R(e.top,e.height,t,i.element)-C(i.viewport,r);return {tStart:u,tEnd:c}}function X(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function te(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?X("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&X("Element has a fill \u2014 it may obscure the stroke animation.",e);}function re(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let c=r==="x"?window.scrollX:window.scrollY,m=e-c,b=t-c,a=r==="x";o.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function B(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:u=false,easing:c="linear",trigger:m={},stagger:b=0,direction:a="forward",once:P=false,debug:_=false,axis:f="y",onProgress:W,onStart:j,onComplete:z}=t,H=typeof c=="function"?c:I[c]??I.linear,J=M(m.start??"top bottom"),K=M(m.end??"bottom top"),w=Array.from(e.querySelectorAll(o)),p=[],d=0,g=0,h=false,S=false,y=0,D=false,v=-1,$=null;function A(){return f==="x"?window.scrollX:window.scrollY}function Q(){return f==="x"?window.innerWidth:window.innerHeight}function U(n){return f==="x"?n.left:n.top}function Y(n){return f==="x"?n.width:n.height}function F(){let n=e.getBoundingClientRect(),s=q({top:U(n),height:Y(n)},A(),Q(),J,K);d=s.tStart,g=s.tEnd,_&&process.env.NODE_ENV!=="production"&&($?.remove(),$=re(d,g,f));}function Z(){w.forEach((n,s)=>{n.style.strokeDasharray=`${p[s]}`,n.style.strokeDashoffset=a==="reverse"?"0":`${p[s]}`,u?n.style.opacity=a==="reverse"?"1":"0":n.style.opacity="";});}if(w.forEach(n=>{te(n);let s=L(n);p.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?`${s}`:"0",u&&(n.style.opacity="1")):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?"0":`${s}`,u&&(n.style.opacity=a==="reverse"?"1":"0"));}),r)return z?.(),{destroy:()=>{},replay:()=>{}};F();function G(){if(!D)return;let n=g-d,s=true;w.forEach((k,E)=>{let N=E*b*n,l=H(O(A(),d+N,g+N,i));P&&(v=Math.max(v,l),l=v),k.style.strokeDashoffset=a==="reverse"?`${p[E]*l}`:`${p[E]*(1-l)}`,u&&(k.style.opacity=a==="reverse"?`${1-l}`:`${l}`),E===0&&W?.(l),l<1&&(s=false);}),S||O(A(),d,g,i)>0&&(S=true,j?.()),s&&!h?(h=true,z?.()):!s&&!P&&(h=false),y=requestAnimationFrame(G);}let V=new IntersectionObserver(n=>{n.forEach(s=>{D=s.isIntersecting,D?y=requestAnimationFrame(G):cancelAnimationFrame(y);});});V.observe(e);let T;function x(){clearTimeout(T),T=setTimeout(()=>{w.forEach((n,s)=>{p[s]=L(n),n.style.strokeDasharray=`${p[s]}`;}),F();},150);}return window.addEventListener("resize",x),window.addEventListener("orientationchange",x),{destroy(){cancelAnimationFrame(y),V.disconnect(),window.removeEventListener("resize",x),window.removeEventListener("orientationchange",x),clearTimeout(T),$?.remove();},replay(){v=-1,S=false,h=false,Z();}}}function ae(e,t){let r={destroy:()=>{},replay:()=>{}};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;return o?B(o,t):(console.warn("[svg-scroll-draw] Container not found:",e),r)}export{ae as scrollDraw};
1
+ var _={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 H(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function te(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function re(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ye(e,t,r){return Math.min(r,Math.max(t,e))}function z(e,t,r,o){return r===t?0:ye((e-t)/(r-t)*o,0,1)}function oe(e,t,r,o,i){let f=te(e.top,e.height,t,o.element)-re(o.viewport,r),d=te(e.top,e.height,t,i.element)-re(i.viewport,r);return {tStart:f,tEnd:d}}function ne(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)];let r=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(r)return [parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16)];let o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function se(e,t,r){let o=ne(e),i=ne(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*r)},${Math.round(o[1]+(i[1]-o[1])*r)},${Math.round(o[2]+(i[2]-o[2])*r)})`}function ie(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function be(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?ie("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&ie("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ge(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let f=r==="x"?window.scrollX:window.scrollY,d=e-f,A=t-f,I=r==="x";o.innerHTML=`
2
+ <div style="position:absolute;${I?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${I?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function le(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:d="linear",trigger:A={},stagger:I=0,direction:g="forward",once:J=false,debug:ae=false,axis:p="y",scrollContainer:W,autoReverse:K=false,delay:Q=0,strokeColor:h,strokeWidth:w,waypoints:G,onProgress:ce,onStart:ue,onComplete:U}=t,Y=typeof d=="function"?d:_[d]??_.linear,fe=H(A.start??"top bottom"),pe=H(A.end??"bottom top"),l=typeof W=="string"?document.querySelector(W):W??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,T=Array.from(e.querySelectorAll(o)),y=[],$=0,S=0,L=false,V=false,M=0,N=false,C=-1,F=-1,P=null,R=new Set;function q(){return l?p==="x"?l.scrollLeft:l.scrollTop:p==="x"?window.scrollX:window.scrollY}function de(){return l?p==="x"?l.clientWidth:l.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function Z(){let n=e.getBoundingClientRect(),s,D,b;if(l){let c=l.getBoundingClientRect();s=p==="x"?n.left-c.left+l.scrollLeft:n.top-c.top+l.scrollTop,D=p==="x"?n.width:n.height,b=q();}else s=p==="x"?n.left:n.top,D=p==="x"?n.width:n.height,b=q();let a=oe({top:s,height:D},b,de(),fe,pe);$=a.tStart,S=a.tEnd,ae&&process.env.NODE_ENV!=="production"&&(P?.remove(),P=ge($,S,p));}function me(){T.forEach((n,s)=>{n.style.strokeDasharray=`${y[s]}`,n.style.strokeDashoffset=g==="reverse"?"0":`${y[s]}`,f?n.style.opacity=g==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`);});}if(T.forEach(n=>{be(n);let s=j(n);y.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=g==="reverse"?`${s}`:"0",f&&(n.style.opacity="1"),x&&(n.style.stroke=x),E!==null&&(n.style.strokeWidth=`${E}`)):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=g==="reverse"?"0":`${s}`,f?n.style.opacity=g==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`));}),r)return U?.(),{destroy:()=>{},replay:()=>{}};Z();function ee(){if(!N)return;let n=q(),s=K?F===-1||n>=F?"forward":"reverse":g;F=n;let D=S-$,b=true;if(T.forEach((a,c)=>{let k=c*I*D,u=Y(z(n,$+k,S+k,i));J&&!K&&(C=Math.max(C,u),u=C),a.style.strokeDashoffset=s==="reverse"?`${y[c]*u}`:`${y[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=se(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&ce?.(u),u<1&&(b=false);}),G){let a=Y(z(n,$,S,i));for(let c in G){let k=parseFloat(c);a>=k&&!R.has(k)&&(R.add(k),G[c]?.());}}!V&&z(n,$,S,i)>0&&(V=true,ue?.()),b&&!L?(L=true,U?.()):!b&&!J&&(L=false),M=requestAnimationFrame(ee);}let B=new IntersectionObserver(n=>{n.forEach(s=>{N=s.isIntersecting,N?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:l??null}),X;function O(){clearTimeout(X),X=setTimeout(()=>{T.forEach((n,s)=>{y[s]=j(n),n.style.strokeDasharray=`${y[s]}`;}),Z();},150);}return window.addEventListener("resize",O),window.addEventListener("orientationchange",O),Q>0?setTimeout(()=>B.observe(e),Q):B.observe(e),{destroy(){cancelAnimationFrame(M),B.disconnect(),window.removeEventListener("resize",O),window.removeEventListener("orientationchange",O),clearTimeout(X),P?.remove();},replay(){C=-1,F=-1,V=false,L=false,R.clear(),me();}}}function Ee(e,t){let r={destroy:()=>{},replay:()=>{}};if(typeof window>"u")return r;let o=typeof e=="string"?document.querySelector(e):e;return o?le(o,t):(console.warn("[svg-scroll-draw] Container not found:",e),r)}export{Ee as scrollDraw};
@@ -1,8 +1,3 @@
1
- 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var M={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 L(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let r=t.split(/\s+/).filter(Boolean),[o="top",i="bottom"]=r;return {element:o,viewport:i}}function V(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function C(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function P(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ee(e,t,r){return Math.min(r,Math.max(t,e))}function R(e,t,r,o){return r===t?0:ee((e-t)/(r-t)*o,0,1)}function q(e,t,r,o,i){let c=V(e.top,e.height,t,o.element)-C(o.viewport,r),l=V(e.top,e.height,t,i.element)-C(i.viewport,r);return {tStart:c,tEnd:l}}function X(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function te(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?X("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&X("Element has a fill \u2014 it may obscure the stroke animation.",e);}function re(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let l=r==="x"?window.scrollX:window.scrollY,m=e-l,b=t-l,a=r==="x";o.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function B(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:c=false,easing:l="linear",trigger:m={},stagger:b=0,direction:a="forward",once:O=false,debug:_=false,axis:f="y",onProgress:H,onStart:W,onComplete:N}=t,J=typeof l=="function"?l:M[l]??M.linear,K=L(m.start??"top bottom"),Q=L(m.end??"bottom top"),h=Array.from(e.querySelectorAll(o)),p=[],d=0,g=0,w=false,S=false,y=0,D=false,v=-1,$=null;function A(){return f==="x"?window.scrollX:window.scrollY}function U(){return f==="x"?window.innerWidth:window.innerHeight}function Y(n){return f==="x"?n.left:n.top}function Z(n){return f==="x"?n.width:n.height}function z(){let n=e.getBoundingClientRect(),s=q({top:Y(n),height:Z(n)},A(),U(),K,Q);d=s.tStart,g=s.tEnd,_&&process.env.NODE_ENV!=="production"&&($?.remove(),$=re(d,g,f));}function j(){h.forEach((n,s)=>{n.style.strokeDasharray=`${p[s]}`,n.style.strokeDashoffset=a==="reverse"?"0":`${p[s]}`,c?n.style.opacity=a==="reverse"?"1":"0":n.style.opacity="";});}if(h.forEach(n=>{te(n);let s=P(n);p.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?`${s}`:"0",c&&(n.style.opacity="1")):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?"0":`${s}`,c&&(n.style.opacity=a==="reverse"?"1":"0"));}),r)return N?.(),{destroy:()=>{},replay:()=>{}};z();function F(){if(!D)return;let n=g-d,s=true;h.forEach((k,x)=>{let G=x*b*n,u=J(R(A(),d+G,g+G,i));O&&(v=Math.max(v,u),u=v),k.style.strokeDashoffset=a==="reverse"?`${p[x]*u}`:`${p[x]*(1-u)}`,c&&(k.style.opacity=a==="reverse"?`${1-u}`:`${u}`),x===0&&H?.(u),u<1&&(s=false);}),S||R(A(),d,g,i)>0&&(S=true,W?.()),s&&!w?(w=true,N?.()):!s&&!O&&(w=false),y=requestAnimationFrame(F);}let I=new IntersectionObserver(n=>{n.forEach(s=>{D=s.isIntersecting,D?y=requestAnimationFrame(F):cancelAnimationFrame(y);});});I.observe(e);let T;function E(){clearTimeout(T),T=setTimeout(()=>{h.forEach((n,s)=>{p[s]=P(n),n.style.strokeDasharray=`${p[s]}`;}),z();},150);}return window.addEventListener("resize",E),window.addEventListener("orientationchange",E),{destroy(){cancelAnimationFrame(y),I.disconnect(),window.removeEventListener("resize",E),window.removeEventListener("orientationchange",E),clearTimeout(T),$?.remove();},replay(){v=-1,S=false,w=false,j();}}}function me({children:e,className:t,style:r,...o}){let i=react.useRef(null);return react.useEffect(()=>{if(!i.current)return;let c=B(i.current,o);return ()=>c.destroy()},[]),jsxRuntime.jsx("div",{ref:i,className:t,style:r,children:e})}exports.ScrollDraw=me;
1
+ 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[n="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:n,viewport:o}}function te(e,t,n,o){switch(o){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function re(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function J(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(n+o)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function ye(e,t,n){return Math.min(n,Math.max(t,e))}function N(e,t,n,o){return n===t?0:ye((e-t)/(n-t)*o,0,1)}function oe(e,t,n,o,i){let l=te(e.top,e.height,t,o.element)-re(o.viewport,n),d=te(e.top,e.height,t,i.element)-re(i.viewport,n);return {tStart:l,tEnd:d}}function ne(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[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 o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function se(e,t,n){let o=ne(e),i=ne(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*n)},${Math.round(o[1]+(i[1]-o[1])*n)},${Math.round(o[2]+(i[2]-o[2])*n)})`}function ie(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function ge(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?ie("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&ie("Element has a fill \u2014 it may obscure the stroke animation.",e);}function be(e,t,n){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let l=n==="x"?window.scrollX:window.scrollY,d=e-l,A=t-l,T=n==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function le(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:l=false,easing:d="linear",trigger:A={},stagger:T=0,direction:b="forward",once:K=false,debug:ae=false,axis:p="y",scrollContainer:P,autoReverse:Q=false,delay:U=0,strokeColor:h,strokeWidth:w,waypoints:z,onProgress:ce,onStart:ue,onComplete:Y}=t,Z=typeof d=="function"?d:X[d]??X.linear,fe=_(A.start??"top bottom"),pe=_(A.end??"bottom top"),a=typeof P=="string"?document.querySelector(P):P??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),y=[],$=0,k=0,L=false,O=false,M=0,W=false,C=-1,F=-1,G=null,V=new Set;function q(){return a?p==="x"?a.scrollLeft:a.scrollTop:p==="x"?window.scrollX:window.scrollY}function de(){return a?p==="x"?a.clientWidth:a.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function j(){let r=e.getBoundingClientRect(),s,D,g;if(a){let u=a.getBoundingClientRect();s=p==="x"?r.left-u.left+a.scrollLeft:r.top-u.top+a.scrollTop,D=p==="x"?r.width:r.height,g=q();}else s=p==="x"?r.left:r.top,D=p==="x"?r.width:r.height,g=q();let c=oe({top:s,height:D},g,de(),fe,pe);$=c.tStart,k=c.tEnd,ae&&process.env.NODE_ENV!=="production"&&(G?.remove(),G=be($,k,p));}function me(){I.forEach((r,s)=>{r.style.strokeDasharray=`${y[s]}`,r.style.strokeDashoffset=b==="reverse"?"0":`${y[s]}`,l?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`);});}if(I.forEach(r=>{ge(r);let s=J(r);y.push(s),n?(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?`${s}`:"0",l&&(r.style.opacity="1"),x&&(r.style.stroke=x),E!==null&&(r.style.strokeWidth=`${E}`)):(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?"0":`${s}`,l?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`));}),n)return Y?.(),{destroy:()=>{},replay:()=>{}};j();function ee(){if(!W)return;let r=q(),s=Q?F===-1||r>=F?"forward":"reverse":b;F=r;let D=k-$,g=true;if(I.forEach((c,u)=>{let S=u*T*D,f=Z(N(r,$+S,k+S,i));K&&!Q&&(C=Math.max(C,f),f=C),c.style.strokeDashoffset=s==="reverse"?`${y[u]*f}`:`${y[u]*(1-f)}`,l&&(c.style.opacity=s==="reverse"?`${1-f}`:`${f}`),v&&x?c.style.stroke=se(v,x,f):x&&(c.style.stroke=x),m!==null&&E!==null?c.style.strokeWidth=`${m+(E-m)*f}`:E!==null&&(c.style.strokeWidth=`${E}`),u===0&&ce?.(f),f<1&&(g=false);}),z){let c=Z(N(r,$,k,i));for(let u in z){let S=parseFloat(u);c>=S&&!V.has(S)&&(V.add(S),z[u]?.());}}!O&&N(r,$,k,i)>0&&(O=true,ue?.()),g&&!L?(L=true,Y?.()):!g&&!K&&(L=false),M=requestAnimationFrame(ee);}let B=new IntersectionObserver(r=>{r.forEach(s=>{W=s.isIntersecting,W?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:a??null}),H;function R(){clearTimeout(H),H=setTimeout(()=>{I.forEach((r,s)=>{y[s]=J(r),r.style.strokeDasharray=`${y[s]}`;}),j();},150);}return window.addEventListener("resize",R),window.addEventListener("orientationchange",R),U>0?setTimeout(()=>B.observe(e),U):B.observe(e),{destroy(){cancelAnimationFrame(M),B.disconnect(),window.removeEventListener("resize",R),window.removeEventListener("orientationchange",R),clearTimeout(H),G?.remove();},replay(){C=-1,F=-1,O=false,L=false,V.clear(),me();}}}function De({children:e,className:t,style:n,...o}){let i=react.useRef(null);return react.useEffect(()=>{if(!i.current)return;let l=le(i.current,o);return ()=>l.destroy()},[]),jsxRuntime.jsx("div",{ref:i,className:t,style:n,children:e})}exports.ScrollDraw=De;
@@ -12,19 +12,25 @@ interface ScrollDrawOptions {
12
12
  fade?: boolean;
13
13
  easing?: EasingName | ((t: number) => number);
14
14
  trigger?: TriggerConfig;
15
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
16
15
  stagger?: number;
17
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
18
16
  direction?: 'forward' | 'reverse';
19
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
20
17
  once?: boolean;
21
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
22
18
  debug?: boolean;
23
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
19
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
24
20
  axis?: 'x' | 'y';
25
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
21
+ /** CSS selector or Element for a custom scroll container (default: window). */
22
+ scrollContainer?: string | Element;
23
+ /** Automatically reverse the animation when the user scrolls back up. */
24
+ autoReverse?: boolean;
25
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
26
+ delay?: number;
27
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
28
+ strokeColor?: string | [string, string];
29
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
30
+ strokeWidth?: number | [number, number];
31
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
32
+ waypoints?: Record<number, () => void>;
26
33
  onProgress?: (alpha: number) => void;
27
- /** Fires once on the first frame the animation begins drawing. */
28
34
  onStart?: () => void;
29
35
  onComplete?: () => void;
30
36
  }
@@ -12,19 +12,25 @@ interface ScrollDrawOptions {
12
12
  fade?: boolean;
13
13
  easing?: EasingName | ((t: number) => number);
14
14
  trigger?: TriggerConfig;
15
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
16
15
  stagger?: number;
17
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
18
16
  direction?: 'forward' | 'reverse';
19
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
20
17
  once?: boolean;
21
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
22
18
  debug?: boolean;
23
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
19
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
24
20
  axis?: 'x' | 'y';
25
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
21
+ /** CSS selector or Element for a custom scroll container (default: window). */
22
+ scrollContainer?: string | Element;
23
+ /** Automatically reverse the animation when the user scrolls back up. */
24
+ autoReverse?: boolean;
25
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
26
+ delay?: number;
27
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
28
+ strokeColor?: string | [string, string];
29
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
30
+ strokeWidth?: number | [number, number];
31
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
32
+ waypoints?: Record<number, () => void>;
26
33
  onProgress?: (alpha: number) => void;
27
- /** Fires once on the first frame the animation begins drawing. */
28
34
  onStart?: () => void;
29
35
  onComplete?: () => void;
30
36
  }
@@ -1,8 +1,3 @@
1
- import {useRef,useEffect}from'react';import {jsx}from'react/jsx-runtime';var M={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 L(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let r=t.split(/\s+/).filter(Boolean),[o="top",i="bottom"]=r;return {element:o,viewport:i}}function V(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function C(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function P(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ee(e,t,r){return Math.min(r,Math.max(t,e))}function R(e,t,r,o){return r===t?0:ee((e-t)/(r-t)*o,0,1)}function q(e,t,r,o,i){let c=V(e.top,e.height,t,o.element)-C(o.viewport,r),l=V(e.top,e.height,t,i.element)-C(i.viewport,r);return {tStart:c,tEnd:l}}function X(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function te(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?X("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&X("Element has a fill \u2014 it may obscure the stroke animation.",e);}function re(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let l=r==="x"?window.scrollX:window.scrollY,m=e-l,b=t-l,a=r==="x";o.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function B(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:c=false,easing:l="linear",trigger:m={},stagger:b=0,direction:a="forward",once:O=false,debug:_=false,axis:f="y",onProgress:H,onStart:W,onComplete:N}=t,J=typeof l=="function"?l:M[l]??M.linear,K=L(m.start??"top bottom"),Q=L(m.end??"bottom top"),h=Array.from(e.querySelectorAll(o)),p=[],d=0,g=0,w=false,S=false,y=0,D=false,v=-1,$=null;function A(){return f==="x"?window.scrollX:window.scrollY}function U(){return f==="x"?window.innerWidth:window.innerHeight}function Y(n){return f==="x"?n.left:n.top}function Z(n){return f==="x"?n.width:n.height}function z(){let n=e.getBoundingClientRect(),s=q({top:Y(n),height:Z(n)},A(),U(),K,Q);d=s.tStart,g=s.tEnd,_&&process.env.NODE_ENV!=="production"&&($?.remove(),$=re(d,g,f));}function j(){h.forEach((n,s)=>{n.style.strokeDasharray=`${p[s]}`,n.style.strokeDashoffset=a==="reverse"?"0":`${p[s]}`,c?n.style.opacity=a==="reverse"?"1":"0":n.style.opacity="";});}if(h.forEach(n=>{te(n);let s=P(n);p.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?`${s}`:"0",c&&(n.style.opacity="1")):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?"0":`${s}`,c&&(n.style.opacity=a==="reverse"?"1":"0"));}),r)return N?.(),{destroy:()=>{},replay:()=>{}};z();function F(){if(!D)return;let n=g-d,s=true;h.forEach((k,x)=>{let G=x*b*n,u=J(R(A(),d+G,g+G,i));O&&(v=Math.max(v,u),u=v),k.style.strokeDashoffset=a==="reverse"?`${p[x]*u}`:`${p[x]*(1-u)}`,c&&(k.style.opacity=a==="reverse"?`${1-u}`:`${u}`),x===0&&H?.(u),u<1&&(s=false);}),S||R(A(),d,g,i)>0&&(S=true,W?.()),s&&!w?(w=true,N?.()):!s&&!O&&(w=false),y=requestAnimationFrame(F);}let I=new IntersectionObserver(n=>{n.forEach(s=>{D=s.isIntersecting,D?y=requestAnimationFrame(F):cancelAnimationFrame(y);});});I.observe(e);let T;function E(){clearTimeout(T),T=setTimeout(()=>{h.forEach((n,s)=>{p[s]=P(n),n.style.strokeDasharray=`${p[s]}`;}),z();},150);}return window.addEventListener("resize",E),window.addEventListener("orientationchange",E),{destroy(){cancelAnimationFrame(y),I.disconnect(),window.removeEventListener("resize",E),window.removeEventListener("orientationchange",E),clearTimeout(T),$?.remove();},replay(){v=-1,S=false,w=false,j();}}}function me({children:e,className:t,style:r,...o}){let i=useRef(null);return useEffect(()=>{if(!i.current)return;let c=B(i.current,o);return ()=>c.destroy()},[]),jsx("div",{ref:i,className:t,style:r,children:e})}export{me as ScrollDraw};
1
+ import {useRef,useEffect}from'react';import {jsx}from'react/jsx-runtime';var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[n="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:n,viewport:o}}function te(e,t,n,o){switch(o){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function re(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function J(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(n+o)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function ye(e,t,n){return Math.min(n,Math.max(t,e))}function N(e,t,n,o){return n===t?0:ye((e-t)/(n-t)*o,0,1)}function oe(e,t,n,o,i){let l=te(e.top,e.height,t,o.element)-re(o.viewport,n),d=te(e.top,e.height,t,i.element)-re(i.viewport,n);return {tStart:l,tEnd:d}}function ne(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[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 o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function se(e,t,n){let o=ne(e),i=ne(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*n)},${Math.round(o[1]+(i[1]-o[1])*n)},${Math.round(o[2]+(i[2]-o[2])*n)})`}function ie(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function ge(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?ie("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&ie("Element has a fill \u2014 it may obscure the stroke animation.",e);}function be(e,t,n){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let l=n==="x"?window.scrollX:window.scrollY,d=e-l,A=t-l,T=n==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function le(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:l=false,easing:d="linear",trigger:A={},stagger:T=0,direction:b="forward",once:K=false,debug:ae=false,axis:p="y",scrollContainer:P,autoReverse:Q=false,delay:U=0,strokeColor:h,strokeWidth:w,waypoints:z,onProgress:ce,onStart:ue,onComplete:Y}=t,Z=typeof d=="function"?d:X[d]??X.linear,fe=_(A.start??"top bottom"),pe=_(A.end??"bottom top"),a=typeof P=="string"?document.querySelector(P):P??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),y=[],$=0,k=0,L=false,O=false,M=0,W=false,C=-1,F=-1,G=null,V=new Set;function q(){return a?p==="x"?a.scrollLeft:a.scrollTop:p==="x"?window.scrollX:window.scrollY}function de(){return a?p==="x"?a.clientWidth:a.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function j(){let r=e.getBoundingClientRect(),s,D,g;if(a){let u=a.getBoundingClientRect();s=p==="x"?r.left-u.left+a.scrollLeft:r.top-u.top+a.scrollTop,D=p==="x"?r.width:r.height,g=q();}else s=p==="x"?r.left:r.top,D=p==="x"?r.width:r.height,g=q();let c=oe({top:s,height:D},g,de(),fe,pe);$=c.tStart,k=c.tEnd,ae&&process.env.NODE_ENV!=="production"&&(G?.remove(),G=be($,k,p));}function me(){I.forEach((r,s)=>{r.style.strokeDasharray=`${y[s]}`,r.style.strokeDashoffset=b==="reverse"?"0":`${y[s]}`,l?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`);});}if(I.forEach(r=>{ge(r);let s=J(r);y.push(s),n?(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?`${s}`:"0",l&&(r.style.opacity="1"),x&&(r.style.stroke=x),E!==null&&(r.style.strokeWidth=`${E}`)):(r.style.strokeDasharray=`${s}`,r.style.strokeDashoffset=b==="reverse"?"0":`${s}`,l?r.style.opacity=b==="reverse"?"1":"0":r.style.opacity="",v&&(r.style.stroke=v),m!==null&&(r.style.strokeWidth=`${m}`));}),n)return Y?.(),{destroy:()=>{},replay:()=>{}};j();function ee(){if(!W)return;let r=q(),s=Q?F===-1||r>=F?"forward":"reverse":b;F=r;let D=k-$,g=true;if(I.forEach((c,u)=>{let S=u*T*D,f=Z(N(r,$+S,k+S,i));K&&!Q&&(C=Math.max(C,f),f=C),c.style.strokeDashoffset=s==="reverse"?`${y[u]*f}`:`${y[u]*(1-f)}`,l&&(c.style.opacity=s==="reverse"?`${1-f}`:`${f}`),v&&x?c.style.stroke=se(v,x,f):x&&(c.style.stroke=x),m!==null&&E!==null?c.style.strokeWidth=`${m+(E-m)*f}`:E!==null&&(c.style.strokeWidth=`${E}`),u===0&&ce?.(f),f<1&&(g=false);}),z){let c=Z(N(r,$,k,i));for(let u in z){let S=parseFloat(u);c>=S&&!V.has(S)&&(V.add(S),z[u]?.());}}!O&&N(r,$,k,i)>0&&(O=true,ue?.()),g&&!L?(L=true,Y?.()):!g&&!K&&(L=false),M=requestAnimationFrame(ee);}let B=new IntersectionObserver(r=>{r.forEach(s=>{W=s.isIntersecting,W?M=requestAnimationFrame(ee):cancelAnimationFrame(M);});},{root:a??null}),H;function R(){clearTimeout(H),H=setTimeout(()=>{I.forEach((r,s)=>{y[s]=J(r),r.style.strokeDasharray=`${y[s]}`;}),j();},150);}return window.addEventListener("resize",R),window.addEventListener("orientationchange",R),U>0?setTimeout(()=>B.observe(e),U):B.observe(e),{destroy(){cancelAnimationFrame(M),B.disconnect(),window.removeEventListener("resize",R),window.removeEventListener("orientationchange",R),clearTimeout(H),G?.remove();},replay(){C=-1,F=-1,O=false,L=false,V.clear(),me();}}}function De({children:e,className:t,style:n,...o}){let i=useRef(null);return useEffect(()=>{if(!i.current)return;let l=le(i.current,o);return ()=>l.destroy()},[]),jsx("div",{ref:i,className:t,style:n,children:e})}export{De as ScrollDraw};
@@ -0,0 +1,3 @@
1
+ 'use strict';var solidJs=require('solid-js');var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function re(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function ne(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function be(e,t,r){return Math.min(r,Math.max(t,e))}function z(e,t,r,o){return r===t?0:be((e-t)/(r-t)*o,0,1)}function se(e,t,r,o,i){let f=re(e.top,e.height,t,o.element)-ne(o.viewport,r),d=re(e.top,e.height,t,i.element)-ne(i.viewport,r);return {tStart:f,tEnd:d}}function oe(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)];let r=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(r)return [parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16)];let o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function ie(e,t,r){let o=oe(e),i=oe(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*r)},${Math.round(o[1]+(i[1]-o[1])*r)},${Math.round(o[2]+(i[2]-o[2])*r)})`}function le(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function he(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?le("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&le("Element has a fill \u2014 it may obscure the stroke animation.",e);}function we(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let f=r==="x"?window.scrollX:window.scrollY,d=e-f,A=t-f,T=r==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function J(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:d="linear",trigger:A={},stagger:T=0,direction:b="forward",once:K=false,debug:ue=false,axis:p="y",scrollContainer:W,autoReverse:Q=false,delay:U=0,strokeColor:h,strokeWidth:w,waypoints:G,onProgress:fe,onStart:pe,onComplete:Y}=t,Z=typeof d=="function"?d:X[d]??X.linear,de=_(A.start??"top bottom"),me=_(A.end??"bottom top"),l=typeof W=="string"?document.querySelector(W):W??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),g=[],S=0,$=0,M=false,V=false,L=0,N=false,C=-1,F=-1,P=null,R=new Set;function H(){return l?p==="x"?l.scrollLeft:l.scrollTop:p==="x"?window.scrollX:window.scrollY}function ge(){return l?p==="x"?l.clientWidth:l.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function ee(){let n=e.getBoundingClientRect(),s,D,y;if(l){let c=l.getBoundingClientRect();s=p==="x"?n.left-c.left+l.scrollLeft:n.top-c.top+l.scrollTop,D=p==="x"?n.width:n.height,y=H();}else s=p==="x"?n.left:n.top,D=p==="x"?n.width:n.height,y=H();let a=se({top:s,height:D},y,ge(),de,me);S=a.tStart,$=a.tEnd,ue&&process.env.NODE_ENV!=="production"&&(P?.remove(),P=we(S,$,p));}function ye(){I.forEach((n,s)=>{n.style.strokeDasharray=`${g[s]}`,n.style.strokeDashoffset=b==="reverse"?"0":`${g[s]}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`);});}if(I.forEach(n=>{he(n);let s=j(n);g.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?`${s}`:"0",f&&(n.style.opacity="1"),x&&(n.style.stroke=x),E!==null&&(n.style.strokeWidth=`${E}`)):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?"0":`${s}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`));}),r)return Y?.(),{destroy:()=>{},replay:()=>{}};ee();function te(){if(!N)return;let n=H(),s=Q?F===-1||n>=F?"forward":"reverse":b;F=n;let D=$-S,y=true;if(I.forEach((a,c)=>{let k=c*T*D,u=Z(z(n,S+k,$+k,i));K&&!Q&&(C=Math.max(C,u),u=C),a.style.strokeDashoffset=s==="reverse"?`${g[c]*u}`:`${g[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=ie(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&fe?.(u),u<1&&(y=false);}),G){let a=Z(z(n,S,$,i));for(let c in G){let k=parseFloat(c);a>=k&&!R.has(k)&&(R.add(k),G[c]?.());}}!V&&z(n,S,$,i)>0&&(V=true,pe?.()),y&&!M?(M=true,Y?.()):!y&&!K&&(M=false),L=requestAnimationFrame(te);}let q=new IntersectionObserver(n=>{n.forEach(s=>{N=s.isIntersecting,N?L=requestAnimationFrame(te):cancelAnimationFrame(L);});},{root:l??null}),B;function O(){clearTimeout(B),B=setTimeout(()=>{I.forEach((n,s)=>{g[s]=j(n),n.style.strokeDasharray=`${g[s]}`;}),ee();},150);}return window.addEventListener("resize",O),window.addEventListener("orientationchange",O),U>0?setTimeout(()=>q.observe(e),U):q.observe(e),{destroy(){cancelAnimationFrame(L),q.disconnect(),window.removeEventListener("resize",O),window.removeEventListener("orientationchange",O),clearTimeout(B),P?.remove();},replay(){C=-1,F=-1,V=false,M=false,R.clear(),ye();}}}function ke(e={}){let t,r;return solidJs.onMount(()=>{t&&(r=J(t,e));}),solidJs.onCleanup(()=>{r?.destroy();}),o=>{t=o;}}function Ae(e={}){let t,r;return solidJs.onMount(()=>{t&&(r=J(t,e));}),solidJs.onCleanup(()=>{r?.destroy(),r=void 0;}),{ref:o=>{t=o;},getInstance:()=>r}}exports.createScrollDraw=Ae;exports.useScrollDraw=ke;
@@ -0,0 +1,66 @@
1
+ type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
2
+ interface TriggerConfig {
3
+ start?: string;
4
+ end?: string;
5
+ }
6
+ interface ScrollDrawOptions {
7
+ selector?: string;
8
+ speed?: number;
9
+ fade?: boolean;
10
+ easing?: EasingName | ((t: number) => number);
11
+ trigger?: TriggerConfig;
12
+ stagger?: number;
13
+ direction?: 'forward' | 'reverse';
14
+ once?: boolean;
15
+ debug?: boolean;
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
17
+ axis?: 'x' | 'y';
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
30
+ onProgress?: (alpha: number) => void;
31
+ onStart?: () => void;
32
+ onComplete?: () => void;
33
+ }
34
+ interface ScrollDrawInstance {
35
+ destroy: () => void;
36
+ /** Reset and replay the animation from the beginning. */
37
+ replay: () => void;
38
+ }
39
+
40
+ /**
41
+ * SolidJS hook — returns a ref setter to attach to any container element.
42
+ *
43
+ * @example
44
+ * import { useScrollDraw } from 'svg-scroll-draw/solid';
45
+ *
46
+ * function Hero() {
47
+ * const ref = useScrollDraw({ easing: 'spring', fade: true });
48
+ * return <div ref={ref}><svg>...</svg></div>;
49
+ * }
50
+ */
51
+ declare function useScrollDraw(options?: ScrollDrawOptions): (node: HTMLElement) => void;
52
+ /**
53
+ * Returns both the ref setter and a getter for the live instance,
54
+ * so you can call instance.replay() from component logic.
55
+ *
56
+ * @example
57
+ * const { ref, getInstance } = createScrollDraw({ easing: 'ease-out' });
58
+ * <div ref={ref}><svg>...</svg></div>
59
+ * <button onClick={() => getInstance()?.replay()}>Replay</button>
60
+ */
61
+ declare function createScrollDraw(options?: ScrollDrawOptions): {
62
+ ref: (node: HTMLElement) => void;
63
+ getInstance: () => ScrollDrawInstance | undefined;
64
+ };
65
+
66
+ export { type ScrollDrawOptions, createScrollDraw, useScrollDraw };
@@ -0,0 +1,66 @@
1
+ type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
2
+ interface TriggerConfig {
3
+ start?: string;
4
+ end?: string;
5
+ }
6
+ interface ScrollDrawOptions {
7
+ selector?: string;
8
+ speed?: number;
9
+ fade?: boolean;
10
+ easing?: EasingName | ((t: number) => number);
11
+ trigger?: TriggerConfig;
12
+ stagger?: number;
13
+ direction?: 'forward' | 'reverse';
14
+ once?: boolean;
15
+ debug?: boolean;
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
17
+ axis?: 'x' | 'y';
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
30
+ onProgress?: (alpha: number) => void;
31
+ onStart?: () => void;
32
+ onComplete?: () => void;
33
+ }
34
+ interface ScrollDrawInstance {
35
+ destroy: () => void;
36
+ /** Reset and replay the animation from the beginning. */
37
+ replay: () => void;
38
+ }
39
+
40
+ /**
41
+ * SolidJS hook — returns a ref setter to attach to any container element.
42
+ *
43
+ * @example
44
+ * import { useScrollDraw } from 'svg-scroll-draw/solid';
45
+ *
46
+ * function Hero() {
47
+ * const ref = useScrollDraw({ easing: 'spring', fade: true });
48
+ * return <div ref={ref}><svg>...</svg></div>;
49
+ * }
50
+ */
51
+ declare function useScrollDraw(options?: ScrollDrawOptions): (node: HTMLElement) => void;
52
+ /**
53
+ * Returns both the ref setter and a getter for the live instance,
54
+ * so you can call instance.replay() from component logic.
55
+ *
56
+ * @example
57
+ * const { ref, getInstance } = createScrollDraw({ easing: 'ease-out' });
58
+ * <div ref={ref}><svg>...</svg></div>
59
+ * <button onClick={() => getInstance()?.replay()}>Replay</button>
60
+ */
61
+ declare function createScrollDraw(options?: ScrollDrawOptions): {
62
+ ref: (node: HTMLElement) => void;
63
+ getInstance: () => ScrollDrawInstance | undefined;
64
+ };
65
+
66
+ export { type ScrollDrawOptions, createScrollDraw, useScrollDraw };
@@ -0,0 +1,3 @@
1
+ import {onMount,onCleanup}from'solid-js';var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function re(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function ne(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function be(e,t,r){return Math.min(r,Math.max(t,e))}function z(e,t,r,o){return r===t?0:be((e-t)/(r-t)*o,0,1)}function se(e,t,r,o,i){let f=re(e.top,e.height,t,o.element)-ne(o.viewport,r),d=re(e.top,e.height,t,i.element)-ne(i.viewport,r);return {tStart:f,tEnd:d}}function oe(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)];let r=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(r)return [parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16)];let o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function ie(e,t,r){let o=oe(e),i=oe(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*r)},${Math.round(o[1]+(i[1]-o[1])*r)},${Math.round(o[2]+(i[2]-o[2])*r)})`}function le(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function he(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?le("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&le("Element has a fill \u2014 it may obscure the stroke animation.",e);}function we(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let f=r==="x"?window.scrollX:window.scrollY,d=e-f,A=t-f,T=r==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${A}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${A}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function J(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:d="linear",trigger:A={},stagger:T=0,direction:b="forward",once:K=false,debug:ue=false,axis:p="y",scrollContainer:W,autoReverse:Q=false,delay:U=0,strokeColor:h,strokeWidth:w,waypoints:G,onProgress:fe,onStart:pe,onComplete:Y}=t,Z=typeof d=="function"?d:X[d]??X.linear,de=_(A.start??"top bottom"),me=_(A.end??"bottom top"),l=typeof W=="string"?document.querySelector(W):W??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),g=[],S=0,$=0,M=false,V=false,L=0,N=false,C=-1,F=-1,P=null,R=new Set;function H(){return l?p==="x"?l.scrollLeft:l.scrollTop:p==="x"?window.scrollX:window.scrollY}function ge(){return l?p==="x"?l.clientWidth:l.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function ee(){let n=e.getBoundingClientRect(),s,D,y;if(l){let c=l.getBoundingClientRect();s=p==="x"?n.left-c.left+l.scrollLeft:n.top-c.top+l.scrollTop,D=p==="x"?n.width:n.height,y=H();}else s=p==="x"?n.left:n.top,D=p==="x"?n.width:n.height,y=H();let a=se({top:s,height:D},y,ge(),de,me);S=a.tStart,$=a.tEnd,ue&&process.env.NODE_ENV!=="production"&&(P?.remove(),P=we(S,$,p));}function ye(){I.forEach((n,s)=>{n.style.strokeDasharray=`${g[s]}`,n.style.strokeDashoffset=b==="reverse"?"0":`${g[s]}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`);});}if(I.forEach(n=>{he(n);let s=j(n);g.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?`${s}`:"0",f&&(n.style.opacity="1"),x&&(n.style.stroke=x),E!==null&&(n.style.strokeWidth=`${E}`)):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?"0":`${s}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`));}),r)return Y?.(),{destroy:()=>{},replay:()=>{}};ee();function te(){if(!N)return;let n=H(),s=Q?F===-1||n>=F?"forward":"reverse":b;F=n;let D=$-S,y=true;if(I.forEach((a,c)=>{let k=c*T*D,u=Z(z(n,S+k,$+k,i));K&&!Q&&(C=Math.max(C,u),u=C),a.style.strokeDashoffset=s==="reverse"?`${g[c]*u}`:`${g[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=ie(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&fe?.(u),u<1&&(y=false);}),G){let a=Z(z(n,S,$,i));for(let c in G){let k=parseFloat(c);a>=k&&!R.has(k)&&(R.add(k),G[c]?.());}}!V&&z(n,S,$,i)>0&&(V=true,pe?.()),y&&!M?(M=true,Y?.()):!y&&!K&&(M=false),L=requestAnimationFrame(te);}let q=new IntersectionObserver(n=>{n.forEach(s=>{N=s.isIntersecting,N?L=requestAnimationFrame(te):cancelAnimationFrame(L);});},{root:l??null}),B;function O(){clearTimeout(B),B=setTimeout(()=>{I.forEach((n,s)=>{g[s]=j(n),n.style.strokeDasharray=`${g[s]}`;}),ee();},150);}return window.addEventListener("resize",O),window.addEventListener("orientationchange",O),U>0?setTimeout(()=>q.observe(e),U):q.observe(e),{destroy(){cancelAnimationFrame(L),q.disconnect(),window.removeEventListener("resize",O),window.removeEventListener("orientationchange",O),clearTimeout(B),P?.remove();},replay(){C=-1,F=-1,V=false,M=false,R.clear(),ye();}}}function ke(e={}){let t,r;return onMount(()=>{t&&(r=J(t,e));}),onCleanup(()=>{r?.destroy();}),o=>{t=o;}}function Ae(e={}){let t,r;return onMount(()=>{t&&(r=J(t,e));}),onCleanup(()=>{r?.destroy(),r=void 0;}),{ref:o=>{t=o;},getInstance:()=>r}}export{Ae as createScrollDraw,ke as useScrollDraw};
@@ -1,8 +1,3 @@
1
- 'use strict';var L={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 O(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let r=t.split(/\s+/).filter(Boolean),[o="top",i="bottom"]=r;return {element:o,viewport:i}}function C(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function q(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function I(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ee(e,t,r){return Math.min(r,Math.max(t,e))}function P(e,t,r,o){return r===t?0:ee((e-t)/(r-t)*o,0,1)}function X(e,t,r,o,i){let u=C(e.top,e.height,t,o.element)-q(o.viewport,r),l=C(e.top,e.height,t,i.element)-q(i.viewport,r);return {tStart:u,tEnd:l}}function B(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function te(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?B("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&B("Element has a fill \u2014 it may obscure the stroke animation.",e);}function re(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let l=r==="x"?window.scrollX:window.scrollY,m=e-l,b=t-l,a=r==="x";o.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function D(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:u=false,easing:l="linear",trigger:m={},stagger:b=0,direction:a="forward",once:z=false,debug:H=false,axis:f="y",onProgress:_,onStart:W,onComplete:F}=t,j=typeof l=="function"?l:L[l]??L.linear,J=O(m.start??"top bottom"),K=O(m.end??"bottom top"),w=Array.from(e.querySelectorAll(o)),p=[],d=0,g=0,h=false,S=false,y=0,$=false,v=-1,A=null;function T(){return f==="x"?window.scrollX:window.scrollY}function Q(){return f==="x"?window.innerWidth:window.innerHeight}function U(n){return f==="x"?n.left:n.top}function Y(n){return f==="x"?n.width:n.height}function G(){let n=e.getBoundingClientRect(),s=X({top:U(n),height:Y(n)},T(),Q(),J,K);d=s.tStart,g=s.tEnd,H&&process.env.NODE_ENV!=="production"&&(A?.remove(),A=re(d,g,f));}function Z(){w.forEach((n,s)=>{n.style.strokeDasharray=`${p[s]}`,n.style.strokeDashoffset=a==="reverse"?"0":`${p[s]}`,u?n.style.opacity=a==="reverse"?"1":"0":n.style.opacity="";});}if(w.forEach(n=>{te(n);let s=I(n);p.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?`${s}`:"0",u&&(n.style.opacity="1")):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?"0":`${s}`,u&&(n.style.opacity=a==="reverse"?"1":"0"));}),r)return F?.(),{destroy:()=>{},replay:()=>{}};G();function V(){if(!$)return;let n=g-d,s=true;w.forEach((M,E)=>{let R=E*b*n,c=j(P(T(),d+R,g+R,i));z&&(v=Math.max(v,c),c=v),M.style.strokeDashoffset=a==="reverse"?`${p[E]*c}`:`${p[E]*(1-c)}`,u&&(M.style.opacity=a==="reverse"?`${1-c}`:`${c}`),E===0&&_?.(c),c<1&&(s=false);}),S||P(T(),d,g,i)>0&&(S=true,W?.()),s&&!h?(h=true,F?.()):!s&&!z&&(h=false),y=requestAnimationFrame(V);}let N=new IntersectionObserver(n=>{n.forEach(s=>{$=s.isIntersecting,$?y=requestAnimationFrame(V):cancelAnimationFrame(y);});});N.observe(e);let k;function x(){clearTimeout(k),k=setTimeout(()=>{w.forEach((n,s)=>{p[s]=I(n),n.style.strokeDasharray=`${p[s]}`;}),G();},150);}return window.addEventListener("resize",x),window.addEventListener("orientationchange",x),{destroy(){cancelAnimationFrame(y),N.disconnect(),window.removeEventListener("resize",x),window.removeEventListener("orientationchange",x),clearTimeout(k),A?.remove();},replay(){v=-1,S=false,h=false,Z();}}}function ae(e,t={}){let r=D(e,t);return {update(o){r.destroy(),r=D(e,o);},destroy(){r.destroy();}}}function le(e={}){let t=null;function r(o){return t=D(o,e),{destroy(){t?.destroy(),t=null;}}}return {action:r,getInstance:()=>t}}exports.createScrollDraw=le;exports.scrollDraw=ae;
1
+ 'use strict';var _={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 j(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function re(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function ne(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function J(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ye(e,t,r){return Math.min(r,Math.max(t,e))}function z(e,t,r,o){return r===t?0:ye((e-t)/(r-t)*o,0,1)}function se(e,t,r,o,i){let f=re(e.top,e.height,t,o.element)-ne(o.viewport,r),d=re(e.top,e.height,t,i.element)-ne(i.viewport,r);return {tStart:f,tEnd:d}}function oe(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)];let r=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(r)return [parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16)];let o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function ie(e,t,r){let o=oe(e),i=oe(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*r)},${Math.round(o[1]+(i[1]-o[1])*r)},${Math.round(o[2]+(i[2]-o[2])*r)})`}function le(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function ge(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?le("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&le("Element has a fill \u2014 it may obscure the stroke animation.",e);}function be(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let f=r==="x"?window.scrollX:window.scrollY,d=e-f,D=t-f,T=r==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${D}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${D}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function W(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:d="linear",trigger:D={},stagger:T=0,direction:b="forward",once:K=false,debug:ae=false,axis:p="y",scrollContainer:G,autoReverse:Q=false,delay:U=0,strokeColor:h,strokeWidth:w,waypoints:V,onProgress:ce,onStart:ue,onComplete:Y}=t,Z=typeof d=="function"?d:_[d]??_.linear,fe=j(D.start??"top bottom"),pe=j(D.end??"bottom top"),l=typeof G=="string"?document.querySelector(G):G??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),y=[],S=0,$=0,L=false,N=false,M=0,P=false,F=-1,O=-1,R=null,q=new Set;function B(){return l?p==="x"?l.scrollLeft:l.scrollTop:p==="x"?window.scrollX:window.scrollY}function de(){return l?p==="x"?l.clientWidth:l.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function ee(){let n=e.getBoundingClientRect(),s,A,g;if(l){let c=l.getBoundingClientRect();s=p==="x"?n.left-c.left+l.scrollLeft:n.top-c.top+l.scrollTop,A=p==="x"?n.width:n.height,g=B();}else s=p==="x"?n.left:n.top,A=p==="x"?n.width:n.height,g=B();let a=se({top:s,height:A},g,de(),fe,pe);S=a.tStart,$=a.tEnd,ae&&process.env.NODE_ENV!=="production"&&(R?.remove(),R=be(S,$,p));}function me(){I.forEach((n,s)=>{n.style.strokeDasharray=`${y[s]}`,n.style.strokeDashoffset=b==="reverse"?"0":`${y[s]}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`);});}if(I.forEach(n=>{ge(n);let s=J(n);y.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?`${s}`:"0",f&&(n.style.opacity="1"),x&&(n.style.stroke=x),E!==null&&(n.style.strokeWidth=`${E}`)):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?"0":`${s}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`));}),r)return Y?.(),{destroy:()=>{},replay:()=>{}};ee();function te(){if(!P)return;let n=B(),s=Q?O===-1||n>=O?"forward":"reverse":b;O=n;let A=$-S,g=true;if(I.forEach((a,c)=>{let k=c*T*A,u=Z(z(n,S+k,$+k,i));K&&!Q&&(F=Math.max(F,u),u=F),a.style.strokeDashoffset=s==="reverse"?`${y[c]*u}`:`${y[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=ie(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&ce?.(u),u<1&&(g=false);}),V){let a=Z(z(n,S,$,i));for(let c in V){let k=parseFloat(c);a>=k&&!q.has(k)&&(q.add(k),V[c]?.());}}!N&&z(n,S,$,i)>0&&(N=true,ue?.()),g&&!L?(L=true,Y?.()):!g&&!K&&(L=false),M=requestAnimationFrame(te);}let H=new IntersectionObserver(n=>{n.forEach(s=>{P=s.isIntersecting,P?M=requestAnimationFrame(te):cancelAnimationFrame(M);});},{root:l??null}),X;function C(){clearTimeout(X),X=setTimeout(()=>{I.forEach((n,s)=>{y[s]=J(n),n.style.strokeDasharray=`${y[s]}`;}),ee();},150);}return window.addEventListener("resize",C),window.addEventListener("orientationchange",C),U>0?setTimeout(()=>H.observe(e),U):H.observe(e),{destroy(){cancelAnimationFrame(M),H.disconnect(),window.removeEventListener("resize",C),window.removeEventListener("orientationchange",C),clearTimeout(X),R?.remove();},replay(){F=-1,O=-1,N=false,L=false,q.clear(),me();}}}function Ee(e,t={}){let r=W(e,t);return {update(o){r.destroy(),r=W(e,o);},destroy(){r.destroy();}}}function Se(e={}){let t=null;function r(o){return t=W(o,e),{destroy(){t?.destroy(),t=null;}}}return {action:r,getInstance:()=>t}}exports.createScrollDraw=Se;exports.scrollDraw=Ee;
@@ -9,19 +9,25 @@ interface ScrollDrawOptions {
9
9
  fade?: boolean;
10
10
  easing?: EasingName | ((t: number) => number);
11
11
  trigger?: TriggerConfig;
12
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
13
12
  stagger?: number;
14
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
15
13
  direction?: 'forward' | 'reverse';
16
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
17
14
  once?: boolean;
18
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
19
15
  debug?: boolean;
20
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
21
17
  axis?: 'x' | 'y';
22
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
23
30
  onProgress?: (alpha: number) => void;
24
- /** Fires once on the first frame the animation begins drawing. */
25
31
  onStart?: () => void;
26
32
  onComplete?: () => void;
27
33
  }
@@ -9,19 +9,25 @@ interface ScrollDrawOptions {
9
9
  fade?: boolean;
10
10
  easing?: EasingName | ((t: number) => number);
11
11
  trigger?: TriggerConfig;
12
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
13
12
  stagger?: number;
14
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
15
13
  direction?: 'forward' | 'reverse';
16
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
17
14
  once?: boolean;
18
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
19
15
  debug?: boolean;
20
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
16
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
21
17
  axis?: 'x' | 'y';
22
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
18
+ /** CSS selector or Element for a custom scroll container (default: window). */
19
+ scrollContainer?: string | Element;
20
+ /** Automatically reverse the animation when the user scrolls back up. */
21
+ autoReverse?: boolean;
22
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
23
+ delay?: number;
24
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
25
+ strokeColor?: string | [string, string];
26
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
27
+ strokeWidth?: number | [number, number];
28
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
29
+ waypoints?: Record<number, () => void>;
23
30
  onProgress?: (alpha: number) => void;
24
- /** Fires once on the first frame the animation begins drawing. */
25
31
  onStart?: () => void;
26
32
  onComplete?: () => void;
27
33
  }
@@ -1,8 +1,3 @@
1
- var L={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 O(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let r=t.split(/\s+/).filter(Boolean),[o="top",i="bottom"]=r;return {element:o,viewport:i}}function C(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function q(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function I(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ee(e,t,r){return Math.min(r,Math.max(t,e))}function P(e,t,r,o){return r===t?0:ee((e-t)/(r-t)*o,0,1)}function X(e,t,r,o,i){let u=C(e.top,e.height,t,o.element)-q(o.viewport,r),l=C(e.top,e.height,t,i.element)-q(i.viewport,r);return {tStart:u,tEnd:l}}function B(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function te(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?B("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&B("Element has a fill \u2014 it may obscure the stroke animation.",e);}function re(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let l=r==="x"?window.scrollX:window.scrollY,m=e-l,b=t-l,a=r==="x";o.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function D(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:u=false,easing:l="linear",trigger:m={},stagger:b=0,direction:a="forward",once:z=false,debug:H=false,axis:f="y",onProgress:_,onStart:W,onComplete:F}=t,j=typeof l=="function"?l:L[l]??L.linear,J=O(m.start??"top bottom"),K=O(m.end??"bottom top"),w=Array.from(e.querySelectorAll(o)),p=[],d=0,g=0,h=false,S=false,y=0,$=false,v=-1,A=null;function T(){return f==="x"?window.scrollX:window.scrollY}function Q(){return f==="x"?window.innerWidth:window.innerHeight}function U(n){return f==="x"?n.left:n.top}function Y(n){return f==="x"?n.width:n.height}function G(){let n=e.getBoundingClientRect(),s=X({top:U(n),height:Y(n)},T(),Q(),J,K);d=s.tStart,g=s.tEnd,H&&process.env.NODE_ENV!=="production"&&(A?.remove(),A=re(d,g,f));}function Z(){w.forEach((n,s)=>{n.style.strokeDasharray=`${p[s]}`,n.style.strokeDashoffset=a==="reverse"?"0":`${p[s]}`,u?n.style.opacity=a==="reverse"?"1":"0":n.style.opacity="";});}if(w.forEach(n=>{te(n);let s=I(n);p.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?`${s}`:"0",u&&(n.style.opacity="1")):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=a==="reverse"?"0":`${s}`,u&&(n.style.opacity=a==="reverse"?"1":"0"));}),r)return F?.(),{destroy:()=>{},replay:()=>{}};G();function V(){if(!$)return;let n=g-d,s=true;w.forEach((M,E)=>{let R=E*b*n,c=j(P(T(),d+R,g+R,i));z&&(v=Math.max(v,c),c=v),M.style.strokeDashoffset=a==="reverse"?`${p[E]*c}`:`${p[E]*(1-c)}`,u&&(M.style.opacity=a==="reverse"?`${1-c}`:`${c}`),E===0&&_?.(c),c<1&&(s=false);}),S||P(T(),d,g,i)>0&&(S=true,W?.()),s&&!h?(h=true,F?.()):!s&&!z&&(h=false),y=requestAnimationFrame(V);}let N=new IntersectionObserver(n=>{n.forEach(s=>{$=s.isIntersecting,$?y=requestAnimationFrame(V):cancelAnimationFrame(y);});});N.observe(e);let k;function x(){clearTimeout(k),k=setTimeout(()=>{w.forEach((n,s)=>{p[s]=I(n),n.style.strokeDasharray=`${p[s]}`;}),G();},150);}return window.addEventListener("resize",x),window.addEventListener("orientationchange",x),{destroy(){cancelAnimationFrame(y),N.disconnect(),window.removeEventListener("resize",x),window.removeEventListener("orientationchange",x),clearTimeout(k),A?.remove();},replay(){v=-1,S=false,h=false,Z();}}}function ae(e,t={}){let r=D(e,t);return {update(o){r.destroy(),r=D(e,o);},destroy(){r.destroy();}}}function le(e={}){let t=null;function r(o){return t=D(o,e),{destroy(){t?.destroy(),t=null;}}}return {action:r,getInstance:()=>t}}export{le as createScrollDraw,ae as scrollDraw};
1
+ var _={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 j(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[r="top",o="bottom"]=t.split(/\s+/).filter(Boolean);return {element:r,viewport:o}}function re(e,t,r,o){switch(o){case "top":return e+r;case "center":return e+r+t/2;case "bottom":return e+r+t;default:return e+r}}function ne(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function J(e){let t=e.tagName.toLowerCase();if(t==="rect"){let r=parseFloat(e.getAttribute("width")??"0"),o=parseFloat(e.getAttribute("height")??"0");return 2*(r+o)}if(t==="circle"){let r=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*r}return e.getTotalLength()}function ye(e,t,r){return Math.min(r,Math.max(t,e))}function z(e,t,r,o){return r===t?0:ye((e-t)/(r-t)*o,0,1)}function se(e,t,r,o,i){let f=re(e.top,e.height,t,o.element)-ne(o.viewport,r),d=re(e.top,e.height,t,i.element)-ne(i.viewport,r);return {tStart:f,tEnd:d}}function oe(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)];let r=/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);if(r)return [parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16)];let o=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return o?[parseInt(o[1]),parseInt(o[2]),parseInt(o[3])]:null}function ie(e,t,r){let o=oe(e),i=oe(t);return !o||!i?e:`rgb(${Math.round(o[0]+(i[0]-o[0])*r)},${Math.round(o[1]+(i[1]-o[1])*r)},${Math.round(o[2]+(i[2]-o[2])*r)})`}function le(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function ge(e){let t=e.getAttribute("stroke"),r=e.getAttribute("fill");!t||t==="none"?le("Element has no stroke \u2014 path will not be visible.",e):r&&r!=="none"&&r!=="transparent"&&le("Element has a fill \u2014 it may obscure the stroke animation.",e);}function be(e,t,r){let o=document.createElement("div");o.setAttribute("data-svg-scroll-draw-debug",""),o.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 i(){let f=r==="x"?window.scrollX:window.scrollY,d=e-f,D=t-f,T=r==="x";o.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${d}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${d}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;${T?`left:${D}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${D}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(o),window.addEventListener("scroll",i,{passive:true}),i(),o}function W(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let r=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:o="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:d="linear",trigger:D={},stagger:T=0,direction:b="forward",once:K=false,debug:ae=false,axis:p="y",scrollContainer:G,autoReverse:Q=false,delay:U=0,strokeColor:h,strokeWidth:w,waypoints:V,onProgress:ce,onStart:ue,onComplete:Y}=t,Z=typeof d=="function"?d:_[d]??_.linear,fe=j(D.start??"top bottom"),pe=j(D.end??"bottom top"),l=typeof G=="string"?document.querySelector(G):G??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,m=Array.isArray(w)?w[0]:null,E=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(o)),y=[],S=0,$=0,L=false,N=false,M=0,P=false,F=-1,O=-1,R=null,q=new Set;function B(){return l?p==="x"?l.scrollLeft:l.scrollTop:p==="x"?window.scrollX:window.scrollY}function de(){return l?p==="x"?l.clientWidth:l.clientHeight:p==="x"?window.innerWidth:window.innerHeight}function ee(){let n=e.getBoundingClientRect(),s,A,g;if(l){let c=l.getBoundingClientRect();s=p==="x"?n.left-c.left+l.scrollLeft:n.top-c.top+l.scrollTop,A=p==="x"?n.width:n.height,g=B();}else s=p==="x"?n.left:n.top,A=p==="x"?n.width:n.height,g=B();let a=se({top:s,height:A},g,de(),fe,pe);S=a.tStart,$=a.tEnd,ae&&process.env.NODE_ENV!=="production"&&(R?.remove(),R=be(S,$,p));}function me(){I.forEach((n,s)=>{n.style.strokeDasharray=`${y[s]}`,n.style.strokeDashoffset=b==="reverse"?"0":`${y[s]}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`);});}if(I.forEach(n=>{ge(n);let s=J(n);y.push(s),r?(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?`${s}`:"0",f&&(n.style.opacity="1"),x&&(n.style.stroke=x),E!==null&&(n.style.strokeWidth=`${E}`)):(n.style.strokeDasharray=`${s}`,n.style.strokeDashoffset=b==="reverse"?"0":`${s}`,f?n.style.opacity=b==="reverse"?"1":"0":n.style.opacity="",v&&(n.style.stroke=v),m!==null&&(n.style.strokeWidth=`${m}`));}),r)return Y?.(),{destroy:()=>{},replay:()=>{}};ee();function te(){if(!P)return;let n=B(),s=Q?O===-1||n>=O?"forward":"reverse":b;O=n;let A=$-S,g=true;if(I.forEach((a,c)=>{let k=c*T*A,u=Z(z(n,S+k,$+k,i));K&&!Q&&(F=Math.max(F,u),u=F),a.style.strokeDashoffset=s==="reverse"?`${y[c]*u}`:`${y[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=ie(v,x,u):x&&(a.style.stroke=x),m!==null&&E!==null?a.style.strokeWidth=`${m+(E-m)*u}`:E!==null&&(a.style.strokeWidth=`${E}`),c===0&&ce?.(u),u<1&&(g=false);}),V){let a=Z(z(n,S,$,i));for(let c in V){let k=parseFloat(c);a>=k&&!q.has(k)&&(q.add(k),V[c]?.());}}!N&&z(n,S,$,i)>0&&(N=true,ue?.()),g&&!L?(L=true,Y?.()):!g&&!K&&(L=false),M=requestAnimationFrame(te);}let H=new IntersectionObserver(n=>{n.forEach(s=>{P=s.isIntersecting,P?M=requestAnimationFrame(te):cancelAnimationFrame(M);});},{root:l??null}),X;function C(){clearTimeout(X),X=setTimeout(()=>{I.forEach((n,s)=>{y[s]=J(n),n.style.strokeDasharray=`${y[s]}`;}),ee();},150);}return window.addEventListener("resize",C),window.addEventListener("orientationchange",C),U>0?setTimeout(()=>H.observe(e),U):H.observe(e),{destroy(){cancelAnimationFrame(M),H.disconnect(),window.removeEventListener("resize",C),window.removeEventListener("orientationchange",C),clearTimeout(X),R?.remove();},replay(){F=-1,O=-1,N=false,L=false,q.clear(),me();}}}function Ee(e,t={}){let r=W(e,t);return {update(o){r.destroy(),r=W(e,o);},destroy(){r.destroy();}}}function Se(e={}){let t=null;function r(o){return t=W(o,e),{destroy(){t?.destroy(),t=null;}}}return {action:r,getInstance:()=>t}}export{Se as createScrollDraw,Ee as scrollDraw};
@@ -1,8 +1,3 @@
1
- 'use strict';var vue=require('vue');var M={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 k(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let n=t.split(/\s+/).filter(Boolean),[r="top",s="bottom"]=n;return {element:r,viewport:s}}function V(e,t,n,r){switch(r){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function B(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function P(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),r=parseFloat(e.getAttribute("height")??"0");return 2*(n+r)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function re(e,t,n){return Math.min(n,Math.max(t,e))}function L(e,t,n,r){return n===t?0:re((e-t)/(n-t)*r,0,1)}function q(e,t,n,r,s){let u=V(e.top,e.height,t,r.element)-B(r.viewport,n),l=V(e.top,e.height,t,s.element)-B(s.viewport,n);return {tStart:u,tEnd:l}}function X(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function oe(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?X("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&X("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ie(e,t,n){let r=document.createElement("div");r.setAttribute("data-svg-scroll-draw-debug",""),r.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 s(){let l=n==="x"?window.scrollX:window.scrollY,m=e-l,b=t-l,a=n==="x";r.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(r),window.addEventListener("scroll",s,{passive:true}),s(),r}function F(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:r="path, polyline, line, polygon, rect, circle",speed:s=1,fade:u=false,easing:l="linear",trigger:m={},stagger:b=0,direction:a="forward",once:C=false,debug:U=false,axis:d="y",onProgress:W,onStart:J,onComplete:z}=t,K=typeof l=="function"?l:M[l]??M.linear,Q=k(m.start??"top bottom"),Y=k(m.end??"bottom top"),w=Array.from(e.querySelectorAll(r)),f=[],p=0,g=0,y=false,E=false,h=0,D=false,v=-1,$=null;function A(){return d==="x"?window.scrollX:window.scrollY}function Z(){return d==="x"?window.innerWidth:window.innerHeight}function ee(o){return d==="x"?o.left:o.top}function te(o){return d==="x"?o.width:o.height}function I(){let o=e.getBoundingClientRect(),i=q({top:ee(o),height:te(o)},A(),Z(),Q,Y);p=i.tStart,g=i.tEnd,U&&process.env.NODE_ENV!=="production"&&($?.remove(),$=ie(p,g,d));}function ne(){w.forEach((o,i)=>{o.style.strokeDasharray=`${f[i]}`,o.style.strokeDashoffset=a==="reverse"?"0":`${f[i]}`,u?o.style.opacity=a==="reverse"?"1":"0":o.style.opacity="";});}if(w.forEach(o=>{oe(o);let i=P(o);f.push(i),n?(o.style.strokeDasharray=`${i}`,o.style.strokeDashoffset=a==="reverse"?`${i}`:"0",u&&(o.style.opacity="1")):(o.style.strokeDasharray=`${i}`,o.style.strokeDashoffset=a==="reverse"?"0":`${i}`,u&&(o.style.opacity=a==="reverse"?"1":"0"));}),n)return z?.(),{destroy:()=>{},replay:()=>{}};I();function N(){if(!D)return;let o=g-p,i=true;w.forEach((T,S)=>{let G=S*b*o,c=K(L(A(),p+G,g+G,s));C&&(v=Math.max(v,c),c=v),T.style.strokeDashoffset=a==="reverse"?`${f[S]*c}`:`${f[S]*(1-c)}`,u&&(T.style.opacity=a==="reverse"?`${1-c}`:`${c}`),S===0&&W?.(c),c<1&&(i=false);}),E||L(A(),p,g,s)>0&&(E=true,J?.()),i&&!y?(y=true,z?.()):!i&&!C&&(y=false),h=requestAnimationFrame(N);}let R=new IntersectionObserver(o=>{o.forEach(i=>{D=i.isIntersecting,D?h=requestAnimationFrame(N):cancelAnimationFrame(h);});});R.observe(e);let O;function x(){clearTimeout(O),O=setTimeout(()=>{w.forEach((o,i)=>{f[i]=P(o),o.style.strokeDasharray=`${f[i]}`;}),I();},150);}return window.addEventListener("resize",x),window.addEventListener("orientationchange",x),{destroy(){cancelAnimationFrame(h),R.disconnect(),window.removeEventListener("resize",x),window.removeEventListener("orientationchange",x),clearTimeout(O),$?.remove();},replay(){v=-1,E=false,y=false,ne();}}}function de(e={}){let t=vue.ref(null);return vue.onMounted(()=>{if(!t.value)return;let n=F(t.value,e);vue.onUnmounted(()=>n.destroy());}),t}var pe=vue.defineComponent({name:"ScrollDraw",props:{selector:{type:String},speed:{type:Number},fade:{type:Boolean},stagger:{type:Number},easing:{type:[String,Function]},direction:{type:String},trigger:{type:Object},onProgress:{type:Function},onStart:{type:Function},onComplete:{type:Function},once:{type:Boolean},debug:{type:Boolean}},setup(e,{slots:t}){let n=vue.ref(null);return vue.onMounted(()=>{if(!n.value)return;let r={};e.selector!=null&&(r.selector=e.selector),e.speed!=null&&(r.speed=e.speed),e.fade!=null&&(r.fade=e.fade),e.stagger!=null&&(r.stagger=e.stagger),e.easing!=null&&(r.easing=e.easing),e.direction!=null&&(r.direction=e.direction),e.trigger!=null&&(r.trigger=e.trigger),e.once!=null&&(r.once=e.once),e.debug!=null&&(r.debug=e.debug),e.onProgress!=null&&(r.onProgress=e.onProgress),e.onStart!=null&&(r.onStart=e.onStart),e.onComplete!=null&&(r.onComplete=e.onComplete);let s=F(n.value,r);vue.onUnmounted(()=>s.destroy());}),()=>vue.h("div",{ref:n},t.default?.())}});exports.ScrollDraw=pe;exports.useScrollDraw=de;
1
+ 'use strict';var vue=require('vue');var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[n="top",r="bottom"]=t.split(/\s+/).filter(Boolean);return {element:n,viewport:r}}function re(e,t,n,r){switch(r){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function ne(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),r=parseFloat(e.getAttribute("height")??"0");return 2*(n+r)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function he(e,t,n){return Math.min(n,Math.max(t,e))}function P(e,t,n,r){return n===t?0:he((e-t)/(n-t)*r,0,1)}function se(e,t,n,r,i){let f=re(e.top,e.height,t,r.element)-ne(r.viewport,n),m=re(e.top,e.height,t,i.element)-ne(i.viewport,n);return {tStart:f,tEnd:m}}function oe(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[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 r=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return r?[parseInt(r[1]),parseInt(r[2]),parseInt(r[3])]:null}function ie(e,t,n){let r=oe(e),i=oe(t);return !r||!i?e:`rgb(${Math.round(r[0]+(i[0]-r[0])*n)},${Math.round(r[1]+(i[1]-r[1])*n)},${Math.round(r[2]+(i[2]-r[2])*n)})`}function le(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function we(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?le("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&le("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ve(e,t,n){let r=document.createElement("div");r.setAttribute("data-svg-scroll-draw-debug",""),r.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 i(){let f=n==="x"?window.scrollX:window.scrollY,m=e-f,D=t-f,T=n==="x";r.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}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;${T?`left:${D}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${D}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(r),window.addEventListener("scroll",i,{passive:true}),i(),r}function U(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:r="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:m="linear",trigger:D={},stagger:T=0,direction:b="forward",once:J=false,debug:fe=false,axis:d="y",scrollContainer:z,autoReverse:K=false,delay:Q=0,strokeColor:h,strokeWidth:w,waypoints:N,onProgress:de,onStart:me,onComplete:Y}=t,Z=typeof m=="function"?m:X[m]??X.linear,pe=_(D.start??"top bottom"),ge=_(D.end??"bottom top"),l=typeof z=="string"?document.querySelector(z):z??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,p=Array.isArray(w)?w[0]:null,S=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(r)),g=[],E=0,$=0,C=false,R=false,M=0,W=false,O=-1,F=-1,G=null,V=new Set;function B(){return l?d==="x"?l.scrollLeft:l.scrollTop:d==="x"?window.scrollX:window.scrollY}function ye(){return l?d==="x"?l.clientWidth:l.clientHeight:d==="x"?window.innerWidth:window.innerHeight}function ee(){let o=e.getBoundingClientRect(),s,A,y;if(l){let c=l.getBoundingClientRect();s=d==="x"?o.left-c.left+l.scrollLeft:o.top-c.top+l.scrollTop,A=d==="x"?o.width:o.height,y=B();}else s=d==="x"?o.left:o.top,A=d==="x"?o.width:o.height,y=B();let a=se({top:s,height:A},y,ye(),pe,ge);E=a.tStart,$=a.tEnd,fe&&process.env.NODE_ENV!=="production"&&(G?.remove(),G=ve(E,$,d));}function be(){I.forEach((o,s)=>{o.style.strokeDasharray=`${g[s]}`,o.style.strokeDashoffset=b==="reverse"?"0":`${g[s]}`,f?o.style.opacity=b==="reverse"?"1":"0":o.style.opacity="",v&&(o.style.stroke=v),p!==null&&(o.style.strokeWidth=`${p}`);});}if(I.forEach(o=>{we(o);let s=j(o);g.push(s),n?(o.style.strokeDasharray=`${s}`,o.style.strokeDashoffset=b==="reverse"?`${s}`:"0",f&&(o.style.opacity="1"),x&&(o.style.stroke=x),S!==null&&(o.style.strokeWidth=`${S}`)):(o.style.strokeDasharray=`${s}`,o.style.strokeDashoffset=b==="reverse"?"0":`${s}`,f?o.style.opacity=b==="reverse"?"1":"0":o.style.opacity="",v&&(o.style.stroke=v),p!==null&&(o.style.strokeWidth=`${p}`));}),n)return Y?.(),{destroy:()=>{},replay:()=>{}};ee();function te(){if(!W)return;let o=B(),s=K?F===-1||o>=F?"forward":"reverse":b;F=o;let A=$-E,y=true;if(I.forEach((a,c)=>{let k=c*T*A,u=Z(P(o,E+k,$+k,i));J&&!K&&(O=Math.max(O,u),u=O),a.style.strokeDashoffset=s==="reverse"?`${g[c]*u}`:`${g[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=ie(v,x,u):x&&(a.style.stroke=x),p!==null&&S!==null?a.style.strokeWidth=`${p+(S-p)*u}`:S!==null&&(a.style.strokeWidth=`${S}`),c===0&&de?.(u),u<1&&(y=false);}),N){let a=Z(P(o,E,$,i));for(let c in N){let k=parseFloat(c);a>=k&&!V.has(k)&&(V.add(k),N[c]?.());}}!R&&P(o,E,$,i)>0&&(R=true,me?.()),y&&!C?(C=true,Y?.()):!y&&!J&&(C=false),M=requestAnimationFrame(te);}let q=new IntersectionObserver(o=>{o.forEach(s=>{W=s.isIntersecting,W?M=requestAnimationFrame(te):cancelAnimationFrame(M);});},{root:l??null}),H;function L(){clearTimeout(H),H=setTimeout(()=>{I.forEach((o,s)=>{g[s]=j(o),o.style.strokeDasharray=`${g[s]}`;}),ee();},150);}return window.addEventListener("resize",L),window.addEventListener("orientationchange",L),Q>0?setTimeout(()=>q.observe(e),Q):q.observe(e),{destroy(){cancelAnimationFrame(M),q.disconnect(),window.removeEventListener("resize",L),window.removeEventListener("orientationchange",L),clearTimeout(H),G?.remove();},replay(){O=-1,F=-1,R=false,C=false,V.clear(),be();}}}function Te(e={}){let t=vue.ref(null);return vue.onMounted(()=>{if(!t.value)return;let n=U(t.value,e);vue.onUnmounted(()=>n.destroy());}),t}var Ie=vue.defineComponent({name:"ScrollDraw",props:{selector:{type:String},speed:{type:Number},fade:{type:Boolean},stagger:{type:Number},easing:{type:[String,Function]},direction:{type:String},trigger:{type:Object},onProgress:{type:Function},onStart:{type:Function},onComplete:{type:Function},once:{type:Boolean},debug:{type:Boolean}},setup(e,{slots:t}){let n=vue.ref(null);return vue.onMounted(()=>{if(!n.value)return;let r={};e.selector!=null&&(r.selector=e.selector),e.speed!=null&&(r.speed=e.speed),e.fade!=null&&(r.fade=e.fade),e.stagger!=null&&(r.stagger=e.stagger),e.easing!=null&&(r.easing=e.easing),e.direction!=null&&(r.direction=e.direction),e.trigger!=null&&(r.trigger=e.trigger),e.once!=null&&(r.once=e.once),e.debug!=null&&(r.debug=e.debug),e.onProgress!=null&&(r.onProgress=e.onProgress),e.onStart!=null&&(r.onStart=e.onStart),e.onComplete!=null&&(r.onComplete=e.onComplete);let i=U(n.value,r);vue.onUnmounted(()=>i.destroy());}),()=>vue.h("div",{ref:n},t.default?.())}});exports.ScrollDraw=Ie;exports.useScrollDraw=Te;
@@ -11,19 +11,25 @@ interface ScrollDrawOptions {
11
11
  fade?: boolean;
12
12
  easing?: EasingName | ((t: number) => number);
13
13
  trigger?: TriggerConfig;
14
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
15
14
  stagger?: number;
16
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
17
15
  direction?: 'forward' | 'reverse';
18
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
19
16
  once?: boolean;
20
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
21
17
  debug?: boolean;
22
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
18
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
23
19
  axis?: 'x' | 'y';
24
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
20
+ /** CSS selector or Element for a custom scroll container (default: window). */
21
+ scrollContainer?: string | Element;
22
+ /** Automatically reverse the animation when the user scrolls back up. */
23
+ autoReverse?: boolean;
24
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
25
+ delay?: number;
26
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
27
+ strokeColor?: string | [string, string];
28
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
29
+ strokeWidth?: number | [number, number];
30
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
31
+ waypoints?: Record<number, () => void>;
25
32
  onProgress?: (alpha: number) => void;
26
- /** Fires once on the first frame the animation begins drawing. */
27
33
  onStart?: () => void;
28
34
  onComplete?: () => void;
29
35
  }
@@ -11,19 +11,25 @@ interface ScrollDrawOptions {
11
11
  fade?: boolean;
12
12
  easing?: EasingName | ((t: number) => number);
13
13
  trigger?: TriggerConfig;
14
- /** Normalized scroll-progress offset between each path starting (0–1). e.g. 0.15 → each path begins 15% of the scroll range after the previous. */
15
14
  stagger?: number;
16
- /** 'forward' draws the path in (default). 'reverse' erases — path starts fully drawn and disappears as you scroll. */
17
15
  direction?: 'forward' | 'reverse';
18
- /** Draw once and stay drawn — animation does not reverse when scrolling back up. */
19
16
  once?: boolean;
20
- /** Show trigger zone overlay for debugging. Dev-only — stripped in production. */
21
17
  debug?: boolean;
22
- /** Scroll axis to track. 'y' (default) for vertical scroll, 'x' for horizontal scroll containers. */
18
+ /** Scroll axis to track. 'y' (default) for vertical, 'x' for horizontal. */
23
19
  axis?: 'x' | 'y';
24
- /** Called every animation frame with the current draw progress (0–1) of the first path. */
20
+ /** CSS selector or Element for a custom scroll container (default: window). */
21
+ scrollContainer?: string | Element;
22
+ /** Automatically reverse the animation when the user scrolls back up. */
23
+ autoReverse?: boolean;
24
+ /** Delay in milliseconds before the engine starts observing (useful for page-load sequences). */
25
+ delay?: number;
26
+ /** Animate stroke color. Single string = static override. Tuple = interpolate from → to. */
27
+ strokeColor?: string | [string, string];
28
+ /** Animate stroke width. Single number = static override. Tuple = interpolate from → to. */
29
+ strokeWidth?: number | [number, number];
30
+ /** Fire callbacks at specific progress thresholds (0–1). Resets on replay(). */
31
+ waypoints?: Record<number, () => void>;
25
32
  onProgress?: (alpha: number) => void;
26
- /** Fires once on the first frame the animation begins drawing. */
27
33
  onStart?: () => void;
28
34
  onComplete?: () => void;
29
35
  }
@@ -1,8 +1,3 @@
1
- import {defineComponent,ref,onMounted,onUnmounted,h}from'vue';var M={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 k(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let n=t.split(/\s+/).filter(Boolean),[r="top",s="bottom"]=n;return {element:r,viewport:s}}function V(e,t,n,r){switch(r){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function B(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function P(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),r=parseFloat(e.getAttribute("height")??"0");return 2*(n+r)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function re(e,t,n){return Math.min(n,Math.max(t,e))}function L(e,t,n,r){return n===t?0:re((e-t)/(n-t)*r,0,1)}function q(e,t,n,r,s){let u=V(e.top,e.height,t,r.element)-B(r.viewport,n),l=V(e.top,e.height,t,s.element)-B(s.viewport,n);return {tStart:u,tEnd:l}}function X(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function oe(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?X("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&X("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ie(e,t,n){let r=document.createElement("div");r.setAttribute("data-svg-scroll-draw-debug",""),r.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 s(){let l=n==="x"?window.scrollX:window.scrollY,m=e-l,b=t-l,a=n==="x";r.innerHTML=`
2
- <div style="position:absolute;
3
- ${a?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}px;left:0;right:0;border-top:2px dashed #22c55e;`}
4
- padding:2px 6px;color:#22c55e;background:rgba(0,0,0,0.6);">\u25B6 start</div>
5
- <div style="position:absolute;
6
- ${a?`left:${b}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${b}px;left:0;right:0;border-top:2px dashed #ef4444;`}
7
- padding:2px 6px;color:#ef4444;background:rgba(0,0,0,0.6);">\u25A0 end</div>
8
- `;}return document.body.appendChild(r),window.addEventListener("scroll",s,{passive:true}),s(),r}function F(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:r="path, polyline, line, polygon, rect, circle",speed:s=1,fade:u=false,easing:l="linear",trigger:m={},stagger:b=0,direction:a="forward",once:C=false,debug:U=false,axis:d="y",onProgress:W,onStart:J,onComplete:z}=t,K=typeof l=="function"?l:M[l]??M.linear,Q=k(m.start??"top bottom"),Y=k(m.end??"bottom top"),w=Array.from(e.querySelectorAll(r)),f=[],p=0,g=0,y=false,E=false,h=0,D=false,v=-1,$=null;function A(){return d==="x"?window.scrollX:window.scrollY}function Z(){return d==="x"?window.innerWidth:window.innerHeight}function ee(o){return d==="x"?o.left:o.top}function te(o){return d==="x"?o.width:o.height}function I(){let o=e.getBoundingClientRect(),i=q({top:ee(o),height:te(o)},A(),Z(),Q,Y);p=i.tStart,g=i.tEnd,U&&process.env.NODE_ENV!=="production"&&($?.remove(),$=ie(p,g,d));}function ne(){w.forEach((o,i)=>{o.style.strokeDasharray=`${f[i]}`,o.style.strokeDashoffset=a==="reverse"?"0":`${f[i]}`,u?o.style.opacity=a==="reverse"?"1":"0":o.style.opacity="";});}if(w.forEach(o=>{oe(o);let i=P(o);f.push(i),n?(o.style.strokeDasharray=`${i}`,o.style.strokeDashoffset=a==="reverse"?`${i}`:"0",u&&(o.style.opacity="1")):(o.style.strokeDasharray=`${i}`,o.style.strokeDashoffset=a==="reverse"?"0":`${i}`,u&&(o.style.opacity=a==="reverse"?"1":"0"));}),n)return z?.(),{destroy:()=>{},replay:()=>{}};I();function N(){if(!D)return;let o=g-p,i=true;w.forEach((T,S)=>{let G=S*b*o,c=K(L(A(),p+G,g+G,s));C&&(v=Math.max(v,c),c=v),T.style.strokeDashoffset=a==="reverse"?`${f[S]*c}`:`${f[S]*(1-c)}`,u&&(T.style.opacity=a==="reverse"?`${1-c}`:`${c}`),S===0&&W?.(c),c<1&&(i=false);}),E||L(A(),p,g,s)>0&&(E=true,J?.()),i&&!y?(y=true,z?.()):!i&&!C&&(y=false),h=requestAnimationFrame(N);}let R=new IntersectionObserver(o=>{o.forEach(i=>{D=i.isIntersecting,D?h=requestAnimationFrame(N):cancelAnimationFrame(h);});});R.observe(e);let O;function x(){clearTimeout(O),O=setTimeout(()=>{w.forEach((o,i)=>{f[i]=P(o),o.style.strokeDasharray=`${f[i]}`;}),I();},150);}return window.addEventListener("resize",x),window.addEventListener("orientationchange",x),{destroy(){cancelAnimationFrame(h),R.disconnect(),window.removeEventListener("resize",x),window.removeEventListener("orientationchange",x),clearTimeout(O),$?.remove();},replay(){v=-1,E=false,y=false,ne();}}}function de(e={}){let t=ref(null);return onMounted(()=>{if(!t.value)return;let n=F(t.value,e);onUnmounted(()=>n.destroy());}),t}var pe=defineComponent({name:"ScrollDraw",props:{selector:{type:String},speed:{type:Number},fade:{type:Boolean},stagger:{type:Number},easing:{type:[String,Function]},direction:{type:String},trigger:{type:Object},onProgress:{type:Function},onStart:{type:Function},onComplete:{type:Function},once:{type:Boolean},debug:{type:Boolean}},setup(e,{slots:t}){let n=ref(null);return onMounted(()=>{if(!n.value)return;let r={};e.selector!=null&&(r.selector=e.selector),e.speed!=null&&(r.speed=e.speed),e.fade!=null&&(r.fade=e.fade),e.stagger!=null&&(r.stagger=e.stagger),e.easing!=null&&(r.easing=e.easing),e.direction!=null&&(r.direction=e.direction),e.trigger!=null&&(r.trigger=e.trigger),e.once!=null&&(r.once=e.once),e.debug!=null&&(r.debug=e.debug),e.onProgress!=null&&(r.onProgress=e.onProgress),e.onStart!=null&&(r.onStart=e.onStart),e.onComplete!=null&&(r.onComplete=e.onComplete);let s=F(n.value,r);onUnmounted(()=>s.destroy());}),()=>h("div",{ref:n},t.default?.())}});export{pe as ScrollDraw,de as useScrollDraw};
1
+ import {defineComponent,ref,onMounted,onUnmounted,h}from'vue';var X={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 _(e="top bottom"){let t=e.trim();if(/^\d+(\.\d+)?%$/.test(t))return {element:"top",viewport:t};let[n="top",r="bottom"]=t.split(/\s+/).filter(Boolean);return {element:n,viewport:r}}function re(e,t,n,r){switch(r){case "top":return e+n;case "center":return e+n+t/2;case "bottom":return e+n+t;default:return e+n}}function ne(e,t){if(/^\d+(\.\d+)?%$/.test(e))return t*(parseFloat(e)/100);switch(e){case "top":return 0;case "center":return t/2;case "bottom":return t;default:return t}}function j(e){let t=e.tagName.toLowerCase();if(t==="rect"){let n=parseFloat(e.getAttribute("width")??"0"),r=parseFloat(e.getAttribute("height")??"0");return 2*(n+r)}if(t==="circle"){let n=parseFloat(e.getAttribute("r")??"0");return 2*Math.PI*n}return e.getTotalLength()}function he(e,t,n){return Math.min(n,Math.max(t,e))}function P(e,t,n,r){return n===t?0:he((e-t)/(n-t)*r,0,1)}function se(e,t,n,r,i){let f=re(e.top,e.height,t,r.element)-ne(r.viewport,n),m=re(e.top,e.height,t,i.element)-ne(i.viewport,n);return {tStart:f,tEnd:m}}function oe(e){let t=/^#([a-f\d])([a-f\d])([a-f\d])$/i.exec(e);if(t)return [parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[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 r=/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i.exec(e);return r?[parseInt(r[1]),parseInt(r[2]),parseInt(r[3])]:null}function ie(e,t,n){let r=oe(e),i=oe(t);return !r||!i?e:`rgb(${Math.round(r[0]+(i[0]-r[0])*n)},${Math.round(r[1]+(i[1]-r[1])*n)},${Math.round(r[2]+(i[2]-r[2])*n)})`}function le(e,t){process.env.NODE_ENV!=="production"&&console.warn(`[svg-scroll-draw] ${e}`,t);}function we(e){let t=e.getAttribute("stroke"),n=e.getAttribute("fill");!t||t==="none"?le("Element has no stroke \u2014 path will not be visible.",e):n&&n!=="none"&&n!=="transparent"&&le("Element has a fill \u2014 it may obscure the stroke animation.",e);}function ve(e,t,n){let r=document.createElement("div");r.setAttribute("data-svg-scroll-draw-debug",""),r.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 i(){let f=n==="x"?window.scrollX:window.scrollY,m=e-f,D=t-f,T=n==="x";r.innerHTML=`
2
+ <div style="position:absolute;${T?`left:${m}px;top:0;bottom:0;border-left:2px dashed #22c55e;`:`top:${m}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;${T?`left:${D}px;top:0;bottom:0;border-left:2px dashed #ef4444;`:`top:${D}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(r),window.addEventListener("scroll",i,{passive:true}),i(),r}function U(e,t={}){if(typeof window>"u")return {destroy:()=>{},replay:()=>{}};let n=window.matchMedia("(prefers-reduced-motion: reduce)").matches,{selector:r="path, polyline, line, polygon, rect, circle",speed:i=1,fade:f=false,easing:m="linear",trigger:D={},stagger:T=0,direction:b="forward",once:J=false,debug:fe=false,axis:d="y",scrollContainer:z,autoReverse:K=false,delay:Q=0,strokeColor:h,strokeWidth:w,waypoints:N,onProgress:de,onStart:me,onComplete:Y}=t,Z=typeof m=="function"?m:X[m]??X.linear,pe=_(D.start??"top bottom"),ge=_(D.end??"bottom top"),l=typeof z=="string"?document.querySelector(z):z??null,v=Array.isArray(h)?h[0]:null,x=Array.isArray(h)?h[1]:typeof h=="string"?h:null,p=Array.isArray(w)?w[0]:null,S=Array.isArray(w)?w[1]:typeof w=="number"?w:null,I=Array.from(e.querySelectorAll(r)),g=[],E=0,$=0,C=false,R=false,M=0,W=false,O=-1,F=-1,G=null,V=new Set;function B(){return l?d==="x"?l.scrollLeft:l.scrollTop:d==="x"?window.scrollX:window.scrollY}function ye(){return l?d==="x"?l.clientWidth:l.clientHeight:d==="x"?window.innerWidth:window.innerHeight}function ee(){let o=e.getBoundingClientRect(),s,A,y;if(l){let c=l.getBoundingClientRect();s=d==="x"?o.left-c.left+l.scrollLeft:o.top-c.top+l.scrollTop,A=d==="x"?o.width:o.height,y=B();}else s=d==="x"?o.left:o.top,A=d==="x"?o.width:o.height,y=B();let a=se({top:s,height:A},y,ye(),pe,ge);E=a.tStart,$=a.tEnd,fe&&process.env.NODE_ENV!=="production"&&(G?.remove(),G=ve(E,$,d));}function be(){I.forEach((o,s)=>{o.style.strokeDasharray=`${g[s]}`,o.style.strokeDashoffset=b==="reverse"?"0":`${g[s]}`,f?o.style.opacity=b==="reverse"?"1":"0":o.style.opacity="",v&&(o.style.stroke=v),p!==null&&(o.style.strokeWidth=`${p}`);});}if(I.forEach(o=>{we(o);let s=j(o);g.push(s),n?(o.style.strokeDasharray=`${s}`,o.style.strokeDashoffset=b==="reverse"?`${s}`:"0",f&&(o.style.opacity="1"),x&&(o.style.stroke=x),S!==null&&(o.style.strokeWidth=`${S}`)):(o.style.strokeDasharray=`${s}`,o.style.strokeDashoffset=b==="reverse"?"0":`${s}`,f?o.style.opacity=b==="reverse"?"1":"0":o.style.opacity="",v&&(o.style.stroke=v),p!==null&&(o.style.strokeWidth=`${p}`));}),n)return Y?.(),{destroy:()=>{},replay:()=>{}};ee();function te(){if(!W)return;let o=B(),s=K?F===-1||o>=F?"forward":"reverse":b;F=o;let A=$-E,y=true;if(I.forEach((a,c)=>{let k=c*T*A,u=Z(P(o,E+k,$+k,i));J&&!K&&(O=Math.max(O,u),u=O),a.style.strokeDashoffset=s==="reverse"?`${g[c]*u}`:`${g[c]*(1-u)}`,f&&(a.style.opacity=s==="reverse"?`${1-u}`:`${u}`),v&&x?a.style.stroke=ie(v,x,u):x&&(a.style.stroke=x),p!==null&&S!==null?a.style.strokeWidth=`${p+(S-p)*u}`:S!==null&&(a.style.strokeWidth=`${S}`),c===0&&de?.(u),u<1&&(y=false);}),N){let a=Z(P(o,E,$,i));for(let c in N){let k=parseFloat(c);a>=k&&!V.has(k)&&(V.add(k),N[c]?.());}}!R&&P(o,E,$,i)>0&&(R=true,me?.()),y&&!C?(C=true,Y?.()):!y&&!J&&(C=false),M=requestAnimationFrame(te);}let q=new IntersectionObserver(o=>{o.forEach(s=>{W=s.isIntersecting,W?M=requestAnimationFrame(te):cancelAnimationFrame(M);});},{root:l??null}),H;function L(){clearTimeout(H),H=setTimeout(()=>{I.forEach((o,s)=>{g[s]=j(o),o.style.strokeDasharray=`${g[s]}`;}),ee();},150);}return window.addEventListener("resize",L),window.addEventListener("orientationchange",L),Q>0?setTimeout(()=>q.observe(e),Q):q.observe(e),{destroy(){cancelAnimationFrame(M),q.disconnect(),window.removeEventListener("resize",L),window.removeEventListener("orientationchange",L),clearTimeout(H),G?.remove();},replay(){O=-1,F=-1,R=false,C=false,V.clear(),be();}}}function Te(e={}){let t=ref(null);return onMounted(()=>{if(!t.value)return;let n=U(t.value,e);onUnmounted(()=>n.destroy());}),t}var Ie=defineComponent({name:"ScrollDraw",props:{selector:{type:String},speed:{type:Number},fade:{type:Boolean},stagger:{type:Number},easing:{type:[String,Function]},direction:{type:String},trigger:{type:Object},onProgress:{type:Function},onStart:{type:Function},onComplete:{type:Function},once:{type:Boolean},debug:{type:Boolean}},setup(e,{slots:t}){let n=ref(null);return onMounted(()=>{if(!n.value)return;let r={};e.selector!=null&&(r.selector=e.selector),e.speed!=null&&(r.speed=e.speed),e.fade!=null&&(r.fade=e.fade),e.stagger!=null&&(r.stagger=e.stagger),e.easing!=null&&(r.easing=e.easing),e.direction!=null&&(r.direction=e.direction),e.trigger!=null&&(r.trigger=e.trigger),e.once!=null&&(r.once=e.once),e.debug!=null&&(r.debug=e.debug),e.onProgress!=null&&(r.onProgress=e.onProgress),e.onStart!=null&&(r.onStart=e.onStart),e.onComplete!=null&&(r.onComplete=e.onComplete);let i=U(n.value,r);onUnmounted(()=>i.destroy());}),()=>h("div",{ref:n},t.default?.())}});export{Ie as ScrollDraw,Te as useScrollDraw};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svg-scroll-draw",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Scroll-driven SVG path drawing animation library — zero dependencies, under 3KB gzipped, works with React, Vue, and vanilla JS",
5
5
  "keywords": [
6
6
  "svg",
@@ -24,7 +24,12 @@
24
24
  "lightweight",
25
25
  "svelte",
26
26
  "svelte-action",
27
- "horizontal-scroll"
27
+ "solid",
28
+ "solidjs",
29
+ "angular",
30
+ "horizontal-scroll",
31
+ "color-animation",
32
+ "waypoints"
28
33
  ],
29
34
  "homepage": "https://ink-scroll.vercel.app",
30
35
  "repository": {
@@ -68,6 +73,16 @@
68
73
  "types": "./dist/svelte/index.d.ts",
69
74
  "import": "./dist/svelte/index.mjs",
70
75
  "require": "./dist/svelte/index.cjs"
76
+ },
77
+ "./solid": {
78
+ "types": "./dist/solid/index.d.ts",
79
+ "import": "./dist/solid/index.mjs",
80
+ "require": "./dist/solid/index.cjs"
81
+ },
82
+ "./angular": {
83
+ "types": "./dist/angular/index.d.ts",
84
+ "import": "./dist/angular/index.mjs",
85
+ "require": "./dist/angular/index.cjs"
71
86
  }
72
87
  },
73
88
  "scripts": {
@@ -82,6 +97,7 @@
82
97
  "@types/react": "^18.0.0",
83
98
  "@vitest/coverage-v8": "^2.0.0",
84
99
  "jsdom": "^25.0.0",
100
+ "solid-js": "^1.9.13",
85
101
  "tsup": "^8.0.0",
86
102
  "typescript": "^5.0.0",
87
103
  "vitest": "^2.0.0",
@@ -89,7 +105,8 @@
89
105
  },
90
106
  "peerDependencies": {
91
107
  "react": ">=17",
92
- "vue": ">=3"
108
+ "vue": ">=3",
109
+ "solid-js": ">=1"
93
110
  },
94
111
  "peerDependenciesMeta": {
95
112
  "react": {
@@ -97,6 +114,9 @@
97
114
  },
98
115
  "vue": {
99
116
  "optional": true
117
+ },
118
+ "solid-js": {
119
+ "optional": true
100
120
  }
101
121
  }
102
122
  }