@mks2508/waapi-animation-primitives 0.1.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.
- package/README.md +164 -0
- package/dist/index.cjs +74 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +502 -0
- package/dist/index.d.ts +502 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# WAAPI Animation Primitives
|
|
2
|
+
|
|
3
|
+
React animation components using the Web Animations API. Zero dependencies beyond React.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @mks2508/waapi-animation-primitives
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Components
|
|
12
|
+
|
|
13
|
+
### SlidingNumber
|
|
14
|
+
|
|
15
|
+
Animates number changes with smooth transitions.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { SlidingNumber } from '@mks2508/waapi-animation-primitives';
|
|
19
|
+
|
|
20
|
+
<SlidingNumber
|
|
21
|
+
value={1234.56}
|
|
22
|
+
duration={300}
|
|
23
|
+
format={{ decimals: 2, separator: ',' }}
|
|
24
|
+
/>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Props:**
|
|
28
|
+
- `value` (number) - The number to display
|
|
29
|
+
- `duration` (number, optional) - Animation duration in ms (default: 200)
|
|
30
|
+
- `format` (object, optional) - Formatting options for decimals and separators
|
|
31
|
+
|
|
32
|
+
### SlidingText
|
|
33
|
+
|
|
34
|
+
Animates text changes character by character.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { SlidingText } from '@mks2508/waapi-animation-primitives';
|
|
38
|
+
|
|
39
|
+
<SlidingText
|
|
40
|
+
text="Hello World"
|
|
41
|
+
mode="character"
|
|
42
|
+
direction="vertical"
|
|
43
|
+
/>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Props:**
|
|
47
|
+
- `text` (string) - Text to display
|
|
48
|
+
- `mode` ('character' | 'word' | 'none') - Animation granularity
|
|
49
|
+
- `direction` ('vertical' | 'horizontal') - Animation direction
|
|
50
|
+
- `duration` (number, optional) - Animation duration in ms
|
|
51
|
+
- `staggerDelay` (number, optional) - Delay between character animations
|
|
52
|
+
|
|
53
|
+
### AnimatedTokens
|
|
54
|
+
|
|
55
|
+
Manages a list of animated tokens with enter/exit transitions.
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { AnimatedTokens } from '@mks2508/waapi-animation-primitives';
|
|
59
|
+
|
|
60
|
+
const tokens = [
|
|
61
|
+
{ id: '1', text: 'React' },
|
|
62
|
+
{ id: '2', text: 'TypeScript' },
|
|
63
|
+
{ id: '3', text: 'WAAPI' }
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
<AnimatedTokens
|
|
67
|
+
tokens={tokens}
|
|
68
|
+
maxVisible={5}
|
|
69
|
+
separator=", "
|
|
70
|
+
/>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Props:**
|
|
74
|
+
- `tokens` (Token[]) - Array of `{ id: string, text: string }`
|
|
75
|
+
- `maxVisible` (number, optional) - Maximum visible tokens before showing "+N more"
|
|
76
|
+
- `separator` (string, optional) - Separator between tokens (default: ", ")
|
|
77
|
+
- `textAnimationMode` ('character' | 'word' | 'none') - How text animates
|
|
78
|
+
- `enableWidthAnimation` (boolean, optional) - Animate width changes
|
|
79
|
+
|
|
80
|
+
## Utilities
|
|
81
|
+
|
|
82
|
+
### Animation Constants
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { TIMING, EASINGS, PRESETS } from '@mks2508/waapi-animation-primitives';
|
|
86
|
+
|
|
87
|
+
// Predefined timing values
|
|
88
|
+
TIMING.DURATION_ENTER // 200ms
|
|
89
|
+
TIMING.DURATION_EXIT // 180ms
|
|
90
|
+
|
|
91
|
+
// Easing functions
|
|
92
|
+
EASINGS.EASE_OUT_CUBIC
|
|
93
|
+
|
|
94
|
+
// Animation presets
|
|
95
|
+
PRESETS.slideUp
|
|
96
|
+
PRESETS.fadeIn
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Debug System
|
|
100
|
+
|
|
101
|
+
Development-only debugging tools. Automatically tree-shaken in production builds.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { DebugProvider, useDebug } from '@mks2508/waapi-animation-primitives';
|
|
105
|
+
|
|
106
|
+
// Wrap your app
|
|
107
|
+
<DebugProvider>
|
|
108
|
+
<YourApp />
|
|
109
|
+
</DebugProvider>
|
|
110
|
+
|
|
111
|
+
// Access debug tools
|
|
112
|
+
const { events, logEvent, exportToCSV } = useDebug();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Debug Features:**
|
|
116
|
+
- Event logging with timestamps
|
|
117
|
+
- Animation timing analysis
|
|
118
|
+
- Style and position capture
|
|
119
|
+
- CSV export for analysis
|
|
120
|
+
|
|
121
|
+
### Choreography Tracker
|
|
122
|
+
|
|
123
|
+
Track animation overlaps and timing.
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { choreographyTracker } from '@mks2508/waapi-animation-primitives';
|
|
127
|
+
|
|
128
|
+
choreographyTracker.startAnimation('anim-1', 'flip', 'element-1', 300);
|
|
129
|
+
choreographyTracker.endAnimation('anim-1');
|
|
130
|
+
|
|
131
|
+
const summary = choreographyTracker.getSummary();
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Build Variants
|
|
135
|
+
|
|
136
|
+
The package supports two build modes:
|
|
137
|
+
|
|
138
|
+
**Production** (default):
|
|
139
|
+
```bash
|
|
140
|
+
npm run build
|
|
141
|
+
```
|
|
142
|
+
- 24KB minified
|
|
143
|
+
- All debug code removed
|
|
144
|
+
- Optimized for production
|
|
145
|
+
|
|
146
|
+
**Debug**:
|
|
147
|
+
```bash
|
|
148
|
+
npm run build:debug
|
|
149
|
+
```
|
|
150
|
+
- 31KB minified
|
|
151
|
+
- Full debug instrumentation
|
|
152
|
+
- Event logging enabled
|
|
153
|
+
|
|
154
|
+
## Browser Support
|
|
155
|
+
|
|
156
|
+
Requires browsers with Web Animations API support:
|
|
157
|
+
- Chrome 84+
|
|
158
|
+
- Firefox 75+
|
|
159
|
+
- Safari 13.1+
|
|
160
|
+
- Edge 84+
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');function vt(n,t){let e=t?.locale||"en-US",r={style:t?.style||"decimal",minimumFractionDigits:t?.minimumFractionDigits,maximumFractionDigits:t?.maximumFractionDigits,useGrouping:t?.useGrouping??true};t?.style==="currency"&&t?.currency&&(r.currency=t.currency);let s=new Intl.NumberFormat(e,r).formatToParts(n),p=[],h=0;s.forEach(a=>{a.type==="integer"&&(h+=a.value.length);});let g=h,x=0,l=0;return s.forEach((a,d)=>{if(a.type==="integer")for(let f of a.value)p.push({char:f,key:`int-${g}`,isDigit:true,position:g}),g--;else if(a.type==="fraction")for(let f of a.value)x++,p.push({char:f,key:`frac-${x}`,isDigit:true,position:-x});else a.type==="decimal"?p.push({char:a.value,key:"decimal",isDigit:false,position:0}):a.type==="group"?(l++,p.push({char:a.value,key:`group-${l}`,isDigit:false,position:0})):a.type==="currency"?p.push({char:a.value,key:`currency-${d}`,isDigit:false,position:0}):a.type==="percentSign"?p.push({char:a.value,key:"percent",isDigit:false,position:0}):p.push({char:a.value,key:`symbol-${d}`,isDigit:false,position:0});}),p}function rt({value:n,duration:t=700,fontSize:e="3rem",fontWeight:r="700",color:o="#000",digitHeight:s=60,stagger:p=30,motionBlur:h=true,format:g,trend:x=0,animationConfig:l}){let a=react.useMemo(()=>{if(l){let{overshoot:i=1,stiffness:u=1,mass:y=1}=l,m=.34*u,T=1+.56*i,_=.64/y;return `cubic-bezier(${Math.min(m,1).toFixed(2)}, ${Math.min(T,2).toFixed(2)}, ${Math.min(_,1).toFixed(2)}, 1)`}return "cubic-bezier(0.34, 1.56, 0.64, 1)"},[l]),d=react.useMemo(()=>vt(n,g),[n,g]),f=react.useRef(new Set),c=react.useRef(true),A=react.useMemo(()=>{if(c.current)return new Set;let i=new Set;return d.forEach(u=>{f.current.has(u.key)||i.add(u.key);}),i},[d]);react.useEffect(()=>{c.current=false,f.current=new Set(d.map(i=>i.key));},[d]);let D=i=>(Math.abs(i)-1)*p;return jsxRuntime.jsx("div",{style:{display:"inline-flex",alignItems:"center",fontSize:e,fontWeight:r,color:o,fontVariantNumeric:"tabular-nums",fontFamily:"system-ui, -apple-system, sans-serif",overflow:"hidden"},children:d.map(i=>{let u=A.has(i.key);return i.isDigit?jsxRuntime.jsx(_t,{digit:Number.parseInt(i.char),duration:t,digitHeight:s,delay:D(i.position),motionBlur:h,easing:a,isEntering:u,trend:x},i.key):jsxRuntime.jsx(At,{char:i.char,isEntering:u,duration:t,easing:a},i.key)})})}function At({char:n,isEntering:t,duration:e,easing:r}){let o=react.useRef(null),s=react.useRef(false);return react.useLayoutEffect(()=>{!o.current||!t||s.current||(s.current=true,o.current.animate([{opacity:0,transform:"scale(0.8)"},{opacity:1,transform:"scale(1)"}],{duration:e*.3,easing:r,fill:"forwards"}));},[t,e,r]),jsxRuntime.jsx("span",{ref:o,style:{display:"inline-block",whiteSpace:"pre",opacity:t?0:1},children:n})}function _t({digit:n,duration:t,digitHeight:e,delay:r,motionBlur:o,easing:s,isEntering:p,trend:h}){let g=react.useRef(null),x=react.useRef(null),l=react.useRef(null),a=react.useRef(`blur-${Math.random().toString(36).slice(2,9)}`).current,d=react.useRef(null),f=react.useRef(n),c=react.useRef(false),A=react.useMemo(()=>{let i=[];for(let u=-1;u<=1;u++)for(let y=0;y<=9;y++)i.push(y);return i},[]);react.useLayoutEffect(()=>{if(!c.current){c.current=true;let i=-(n+10)*e;d.current=i,f.current=n,g.current&&(g.current.style.transform=`translateY(${i}px)`);}},[n,e]),react.useLayoutEffect(()=>{!x.current||!p||x.current.animate([{opacity:0,transform:"scale(0.5) translateY(-20px)"},{opacity:1,transform:"scale(1) translateY(0)"}],{duration:t*.4,easing:s,fill:"forwards"});},[p,t,s]),react.useEffect(()=>{if(f.current=n,!c.current)return;let i=d.current!==null?((Math.round(-d.current/e)-10)%10+10)%10:n;n===i&&d.current!==null||D(n);},[n,e]);let D=i=>{if(!g.current||!x.current)return;if(l.current){let w=getComputedStyle(g.current),B=new DOMMatrix(w.transform);d.current=B.m42,l.current.cancel(),l.current=null,g.current.style.transform=`translateY(${d.current}px)`;}let u=d.current!==null?-d.current/e:i+10,m=((Math.round(u)-10)%10+10)%10;if(i===m&&d.current!==null){let w=-(i+10)*e;if(g.current){let B=l.current;B&&B.cancel(),g.current.style.transform=`translateY(${w}px)`;}d.current=w;return}let T;h===1?T=i>=m?i-m:10-m+i:h===-1?T=i<=m?i-m:i-m-10:(T=i-m,T>5?T-=10:T<-5&&(T+=10));let _=d.current??-(m+10)*e,E=_-T*e,S=document.getElementById(a)?.querySelector("feGaussianBlur");if(o&&S){let w=Math.min(Math.abs(T)*1.2,6);S.setAttribute("stdDeviation",`0,${w}`),x.current.style.filter=`url(#${a})`;}let U=g.current.animate([{transform:`translateY(${_}px)`},{transform:`translateY(${E}px)`}],{duration:t,delay:r,easing:s,fill:"forwards"});l.current=U,U.onfinish=()=>{let w=-(i+10)*e;g.current&&(U.cancel(),g.current.style.transform=`translateY(${w}px)`),d.current=w,x.current&&(x.current.style.filter="none"),S&&S.setAttribute("stdDeviation","0,0"),l.current=null,f.current!==i&&requestAnimationFrame(()=>{D(f.current);});},U.oncancel=()=>{l.current=null;};};return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("svg",{style:{position:"absolute",width:0,height:0},"aria-hidden":"true",children:jsxRuntime.jsx("defs",{children:jsxRuntime.jsx("filter",{id:a,children:jsxRuntime.jsx("feGaussianBlur",{in:"SourceGraphic",stdDeviation:"0,0"})})})}),jsxRuntime.jsx("div",{ref:x,style:{position:"relative",height:`${e}px`,overflow:"hidden",width:"0.65em",textAlign:"center",opacity:p?0:1},children:jsxRuntime.jsx("div",{ref:g,style:{position:"absolute",left:0,right:0,willChange:"transform"},children:A.map((i,u)=>jsxRuntime.jsx("div",{style:{height:`${e}px`,display:"flex",alignItems:"center",justifyContent:"center"},children:i},u))})})]})}var q=n=>typeof window>"u"?n:window.matchMedia("(prefers-reduced-motion: reduce)").matches?0:window.innerWidth<768?Math.round(n*.6):n,ot=n=>typeof window>"u"?n:window.matchMedia("(prefers-reduced-motion: reduce)").matches?0:window.innerWidth<768?Math.round(n*.5):n,b={ENTER_DURATION:200,EXIT_DURATION:180,COLLAPSE_DURATION:200,FLIP_DURATION:300,ENTER_STAGGER:15,EXIT_STAGGER:0,COLLAPSE_DELAY:30,FLIP_DELAY_PERCENT:.25,MIN_DELTA_PX:1},F={OFFSET_Y_ENTER:8,OFFSET_Y_EXIT:-8,OFFSET_X:16,SCALE_EXIT:.95,ROTATE_EXIT:0},X={BLUR_ENTER:4,BLUR_EXIT:2},N={EASE_OUT_CUBIC:"cubic-bezier(0.33, 1, 0.68, 1)",EASE_IN_CUBIC:"cubic-bezier(0.32, 0, 0.67, 0)",EASE_IN_OUT:"cubic-bezier(0.42, 0, 0.58, 1)",EASE_OUT_EXPO:"cubic-bezier(0.16, 1, 0.3, 1)",EASE_FLIP:"cubic-bezier(0.2, 0, 0.2, 1)",SPRING_GENTLE:"linear(0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%, 0.938 16.7%, 1.017 19.4%, 1.067, 1.099 24.3%, 1.108 26%, 1.100, 1.078 30.1%, 1.049 32.5%, 0.994 37.3%, 0.981 40.2%, 0.974 43.4%, 0.975 50.2%, 0.997 62.5%, 1.001 74.7%, 1)",SPRING_SNAPPY:"linear(0, 0.006, 0.024 2%, 0.096 4.2%, 0.397 9.3%, 0.861 15.8%, 1.002 18.7%, 1.093 21.4%, 1.143 24%, 1.156, 1.149 28.3%, 1.115 31.5%, 1.022 40%, 0.988 47.1%, 0.984 55.1%, 0.998 72.3%, 1.001 85.4%, 1)"},Dt={tokenEnter:{get duration(){return q(b.ENTER_DURATION)},get stagger(){return ot(b.ENTER_STAGGER)},easing:N.EASE_OUT_CUBIC,blur:X.BLUR_ENTER,offsetY:F.OFFSET_Y_ENTER},tokenExit:{get duration(){return q(b.EXIT_DURATION)},get stagger(){return ot(b.EXIT_STAGGER)},easing:N.EASE_IN_CUBIC,blur:X.BLUR_EXIT,offsetY:F.OFFSET_Y_EXIT,scale:F.SCALE_EXIT},collapse:{get duration(){return q(b.COLLAPSE_DURATION)},delay:b.COLLAPSE_DELAY,easing:N.EASE_IN_OUT},flip:{get duration(){return q(b.FLIP_DURATION)},delayPercent:b.FLIP_DELAY_PERCENT,easing:N.SPRING_GENTLE}},I={DURATION_ENTER:b.ENTER_DURATION,DURATION_EXIT:b.EXIT_DURATION,DURATION_FLIP:b.FLIP_DURATION,STAGGER_DELAY:b.ENTER_STAGGER,OFFSET_VERTICAL:F.OFFSET_Y_ENTER,OFFSET_HORIZONTAL:F.OFFSET_X,BLUR_AMOUNT:X.BLUR_ENTER,EASING_ENTER:N.EASE_OUT_CUBIC,EASING_EXIT:N.EASE_IN_CUBIC,EASING_FLIP:N.SPRING_GENTLE,SPRING_EASING:N.SPRING_GENTLE},wt={tokenEnter:{duration:b.ENTER_DURATION,stagger:b.ENTER_STAGGER,easing:N.EASE_OUT_CUBIC,blur:X.BLUR_ENTER,offsetY:F.OFFSET_Y_ENTER},tokenExit:{duration:b.EXIT_DURATION,stagger:b.EXIT_STAGGER,easing:N.EASE_IN_CUBIC,blur:X.BLUR_EXIT,offsetY:F.OFFSET_Y_EXIT,scale:F.SCALE_EXIT},collapse:{duration:b.COLLAPSE_DURATION,delay:b.COLLAPSE_DELAY,easing:N.EASE_IN_OUT},flip:{duration:b.FLIP_DURATION,delayPercent:b.FLIP_DELAY_PERCENT,easing:N.SPRING_GENTLE}},z={newToken:{mode:"character",direction:"vertical",staggerDelay:15,blur:true,widthAnimation:true,duration:200,initial:"initial"},existingToken:{mode:"none",blur:false,widthAnimation:false,initial:false},placeholder:{mode:"word",direction:"vertical",blur:true,widthAnimation:false,duration:150},separator:{duration:100,widthAnimation:true}};var $={container:{"--duration-enter":"200ms","--duration-exit":"200ms","--easing-enter":"cubic-bezier(0.25, 0.46, 0.45, 0.94)","--easing-exit":"cubic-bezier(0.55, 0.06, 0.68, 0.19)","--offset-vertical":"8px","--offset-horizontal":"16px","--blur-amount":"4px",display:"inline-flex",overflow:"hidden",verticalAlign:"bottom",willChange:"width"},content:{display:"inline-flex",whiteSpace:"pre"},token:{display:"inline-block",willChange:"transform, opacity, filter",backfaceVisibility:"hidden",fontWeight:"500"},enterFrom:{opacity:0,filter:"blur(var(--blur-amount))"},enterTo:{opacity:1,transform:"translate(0, 0)",filter:"blur(0)"},exitActive:{opacity:0,filter:"blur(var(--blur-amount))"},verticalEnterFrom:{transform:"translateY(var(--offset-vertical))"},verticalExitActive:{transform:"translateY(calc(var(--offset-vertical) * -1))"},horizontalEnterFrom:{transform:"translateX(var(--offset-horizontal))"},horizontalExitActive:{transform:"translateX(calc(var(--offset-horizontal) * -1))"}},at=(n,t)=>{let e={...$.token};return n==="enter-from"?(Object.assign(e,$.enterFrom),t==="vertical"?Object.assign(e,$.verticalEnterFrom):Object.assign(e,$.horizontalEnterFrom)):n==="enter-to"?Object.assign(e,$.enterTo):n==="exit-active"&&(Object.assign(e,$.exitActive),t==="vertical"?Object.assign(e,$.verticalExitActive):Object.assign(e,$.horizontalExitActive)),e};var J=({text:n,mode:t="word",direction:e="vertical",staggerDelay:r=I.STAGGER_DELAY,duration:o=I.DURATION_ENTER,easing:s=I.EASING_ENTER,blur:p=true,widthAnimation:h=false,initial:g="initial",exit:x,className:l="",style:a})=>{let d=react.useRef(null),f=react.useRef(null),c=react.useRef(false),[A,D]=react.useState(g!=="initial");react.useEffect(()=>{g==="initial"&&!c.current&&(c.current=true,requestAnimationFrame(()=>{D(true);}));},[g]);let i=x==="exit"?"exit":A?"animate":"initial",u=t==="character"?n.split(""):[n];react.useLayoutEffect(()=>{if(!h||!d.current||!f.current)return;let m=d.current,T=f.current;if(i==="initial")m.style.width="0px";else if(i==="animate")if(CSS.supports("interpolate-size","allow-keywords"))m.style.width="auto",m.style.transition=`width ${o}ms ${s}`;else {let E=T.scrollWidth;m.style.width=`${E}px`,m.style.transition=`width ${o}ms ${s}`;let S=setTimeout(()=>{m.style.width="auto";},o);return ()=>clearTimeout(S)}else if(i==="exit"){let _=m.getBoundingClientRect().width;m.style.width=`${_}px`,m.getBoundingClientRect(),m.style.width="0px",m.style.transition=`width ${I.DURATION_EXIT}ms ${I.EASING_EXIT}`;}},[i,h,o,s,n]);let y=m=>{let T=m*r,_=i==="exit",E=_?I.DURATION_EXIT:o,S=_?I.EASING_EXIT:s;return {transition:`
|
|
2
|
+
opacity ${E}ms ${S} ${T}ms,
|
|
3
|
+
transform ${E}ms ${S} ${T}ms,
|
|
4
|
+
filter ${E}ms ${S} ${T}ms
|
|
5
|
+
`,"--blur-amount":p?`${I.BLUR_AMOUNT}px`:"0px","--offset":e==="vertical"?`${I.OFFSET_VERTICAL}px`:`${I.OFFSET_HORIZONTAL}px`}};return jsxRuntime.jsx("div",{ref:d,className:l,style:{...$.container,...a},children:jsxRuntime.jsx("div",{ref:f,style:$.content,children:u.map((m,T)=>jsxRuntime.jsx("span",{style:{...at(i==="initial"?"enter-from":i==="animate"?"enter-to":"exit-active",e),...y(T)},children:m},T))})})};var lt=n=>{let t=react.useRef(n);react.useEffect(()=>{t.current=n;},[n]);let e=react.useRef(new Map),r=react.useRef({animatingIds:new Set,positions:new Map}),o=react.useRef(new Map),s=react.useCallback((l,a)=>{a?e.current.set(l,a):e.current.delete(l);},[]),p=react.useCallback(l=>{let a=new Map;return e.current.forEach((d,f)=>{if(!l.has(f)){let c=d.getBoundingClientRect();c.width>0&&c.height>0&&a.set(f,c);}}),r.current.positions=a,a},[]),h=react.useCallback(l=>{let a=o.current.get(l);a&&(a.forEach(d=>d.cancel()),o.current.delete(l));},[]),g=react.useCallback(async l=>{let a=e.current.get(l);if(!a||r.current.animatingIds.has(l))return;r.current.animatingIds.add(l),p(new Set([l]));let f=t.current.exitDuration||b.EXIT_DURATION,c=t.current.exitEasing||N.EASE_IN_CUBIC,A=t.current.flipDuration||b.FLIP_DURATION,D=F.OFFSET_Y_EXIT,i=F.SCALE_EXIT,u=X.BLUR_EXIT,y=b.EXIT_STAGGER,m=a.getBoundingClientRect(),T=getComputedStyle(a),_=parseFloat(T.marginRight)||0,E=[],S=[],U=false,w=a.querySelectorAll(".sliding-text-token");if(w.length>0)w.forEach((C,v)=>{let M=v*y,O=C.animate([{opacity:1,transform:"translateY(0) scale(1)",filter:"blur(0px)"},{opacity:0,transform:`translateY(${D}px) scale(${i})`,filter:`blur(${u}px)`}],{duration:f,easing:c,delay:M,fill:"forwards"});E.push(O);});else {let C=a.animate([{opacity:1,transform:"translateY(0) scale(1)"},{opacity:0,transform:`translateY(${D}px) scale(${i})`}],{duration:f,easing:c,fill:"forwards"});E.push(C);}a.style.overflow="hidden";let B=a.animate([{width:`${m.width}px`,marginRight:`${_}px`},{width:"0px",marginRight:"0px"}],{duration:f,easing:c,fill:"forwards"});E.push(B),o.current.set(l,E);let R=f*b.FLIP_DELAY_PERCENT,Y=()=>{U||(U=true,a.style.position="absolute",a.style.opacity="0",a.style.pointerEvents="none",e.current.forEach((C,v)=>{if(v===l)return;let M=r.current.positions.get(v);if(!M)return;let O=C.getBoundingClientRect(),G=M.left-O.left,j=M.top-O.top;if(Math.abs(G)<1&&Math.abs(j)<1)return;let St=C.animate([{transform:`translate3d(${G}px, ${j}px, 0)`},{transform:"translate3d(0, 0, 0)"}],{duration:A,easing:N.SPRING_GENTLE});S.push(St);}));},P=setTimeout(Y,R);try{await Promise.all(E.map(C=>C.finished)),Y(),await Promise.all(S.map(C=>C.finished.catch(()=>{})));}catch{clearTimeout(P),r.current.animatingIds.delete(l);return}r.current.animatingIds.delete(l),o.current.delete(l),e.current.delete(l),t.current.onComplete(l);},[p]),x=react.useCallback(l=>l?r.current.animatingIds.has(l):r.current.animatingIds.size>0,[]);return react.useEffect(()=>()=>{o.current.forEach(l=>{l.forEach(a=>a.cancel());}),o.current.clear();},[]),{registerElement:s,startExit:g,isAnimating:x,cancelAnimations:h}};var H={container:{"--duration-enter":"200ms","--duration-exit":"180ms","--duration-collapse":"200ms","--duration-flip":"300ms","--stagger-enter":"15ms","--stagger-exit":"0ms","--offset-y-enter":"8px","--offset-y-exit":"-8px","--scale-exit":"0.95","--blur-enter":"4px","--blur-exit":"2px","--ease-enter":"cubic-bezier(0.33, 1, 0.68, 1)","--ease-exit":"cubic-bezier(0.32, 0, 0.67, 0)","--ease-collapse":"cubic-bezier(0.42, 0, 0.58, 1)","--ease-flip":"cubic-bezier(0.2, 0, 0.2, 1)",display:"flex",flexWrap:"wrap",alignItems:"center",gap:0},placeholder:{color:"var(--muted-foreground)",fontStyle:"italic"},tokenWrapper:{display:"inline-flex",alignItems:"center",marginRight:"4px"},tokenWrapperLast:{marginRight:0},tokenWrapperExitCompleted:{position:"absolute",opacity:0,pointerEvents:"none",marginRight:0},separator:{display:"inline",whiteSpace:"pre",opacity:1,transform:"translateY(0)",willChange:"transform, opacity",transition:`
|
|
6
|
+
opacity var(--duration-enter) var(--ease-enter),
|
|
7
|
+
transform var(--duration-enter) var(--ease-enter)
|
|
8
|
+
`},separatorExitActive:{opacity:0,transform:"translateY(-8px)",transition:`
|
|
9
|
+
opacity var(--duration-exit) var(--ease-exit),
|
|
10
|
+
transform var(--duration-exit) var(--ease-exit)
|
|
11
|
+
`},overflow:{display:"inline-flex",alignItems:"center",marginLeft:"4px",opacity:1,transform:"translateY(0)",willChange:"transform, opacity",transition:`
|
|
12
|
+
opacity var(--duration-enter) var(--ease-enter),
|
|
13
|
+
transform var(--duration-enter) var(--ease-enter)
|
|
14
|
+
`},overflowExiting:{opacity:0,transform:"translateY(-8px)",transition:`
|
|
15
|
+
opacity var(--duration-exit) var(--ease-exit),
|
|
16
|
+
transform var(--duration-exit) var(--ease-exit)
|
|
17
|
+
`}},ut=()=>{if(typeof window>"u")return H.container;let n=window.innerWidth<768,t=window.matchMedia("(prefers-reduced-motion: reduce)").matches,e=window.matchMedia("(prefers-contrast: high)").matches;return t?{...H.container,"--duration-enter":"0ms","--duration-exit":"0ms","--duration-collapse":"0ms","--duration-flip":"0ms","--stagger-enter":"0ms","--stagger-exit":"0ms","--blur-enter":"0px","--blur-exit":"0px","--offset-y-enter":"0px","--offset-y-exit":"0px","--scale-exit":"1"}:e?{...H.container,"--blur-enter":"0px","--blur-exit":"0px"}:n?{...H.container,"--duration-enter":"120ms","--duration-exit":"100ms","--duration-collapse":"120ms","--duration-flip":"180ms","--stagger-enter":"8ms","--blur-enter":"2px","--blur-exit":"1px","--offset-y-enter":"4px","--offset-y-exit":"-4px"}:H.container};var gt="waapi-animation-primitives-styles",Pt=`
|
|
18
|
+
/* AnimatedTokens critical animation styles */
|
|
19
|
+
.token-wrapper {
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
margin-right: 4px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.token-wrapper:last-child {
|
|
26
|
+
margin-right: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.token-wrapper.exit-completed {
|
|
30
|
+
position: absolute !important;
|
|
31
|
+
opacity: 0 !important;
|
|
32
|
+
pointer-events: none !important;
|
|
33
|
+
margin-right: 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.token-separator {
|
|
37
|
+
display: inline !important;
|
|
38
|
+
white-space: pre;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.token-separator.exit-completed {
|
|
42
|
+
opacity: 0;
|
|
43
|
+
position: absolute;
|
|
44
|
+
pointer-events: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.token-overflow {
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
margin-left: 4px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Reduced motion support */
|
|
54
|
+
@media (prefers-reduced-motion: reduce) {
|
|
55
|
+
.token-wrapper,
|
|
56
|
+
.token-overflow,
|
|
57
|
+
.sliding-text,
|
|
58
|
+
.sliding-number {
|
|
59
|
+
animation: none !important;
|
|
60
|
+
transition: none !important;
|
|
61
|
+
transform: none !important;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Mobile optimizations */
|
|
66
|
+
@media (max-width: 767px) {
|
|
67
|
+
.token-wrapper {
|
|
68
|
+
transform: translateZ(0);
|
|
69
|
+
backface-visibility: hidden;
|
|
70
|
+
perspective: 1000px;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
`;function ht(){if(typeof document>"u"||document.getElementById(gt))return;let n=document.createElement("style");n.id=gt,n.textContent=Pt,document.head.appendChild(n);}var $t=({tokens:n,placeholder:t="No tokens",maxVisible:e,textAnimationMode:r="character",textDirection:o="vertical",textStaggerDelay:s=15,separator:p=", ",enableWidthAnimation:h=false,className:g="",tokenClassName:x="",placeholderClassName:l="",separatorClassName:a=""})=>{let d=react.useRef(true);react.useEffect(()=>{ht();},[]),react.useEffect(()=>(d.current=true,()=>{d.current=false;}),[]);let[f,c]=react.useState(n),A=react.useRef(new Set),D=react.useCallback(R=>{d.current&&(A.current.delete(R),c(Y=>Y.filter(P=>P.id!==R)));},[]),{registerElement:i,startExit:u,isAnimating:y}=lt({onComplete:D}),m=react.useRef(u);react.useEffect(()=>{m.current=u;},[u]),react.useEffect(()=>{let R=new Set(n.map(v=>v.id)),Y=new Set(f.map(v=>v.id)),P=f.filter(v=>!R.has(v.id)&&!A.current.has(v.id)),C=n.filter(v=>!Y.has(v.id));if(!(P.length===0&&C.length===0)&&(P.forEach(v=>{let M=f.findIndex(G=>G.id===v.id);e!==void 0&&M>=e?c(G=>G.filter(j=>j.id!==v.id)):(A.current.add(v.id),m.current(v.id));}),C.length>0)){let v=f.filter(O=>!R.has(O.id)),M=[...n];v.forEach(O=>{let G=f.findIndex(j=>j.id===O.id);G!==-1&&G<=M.length&&M.splice(G,0,O);}),JSON.stringify(M.map(O=>O.id))!==JSON.stringify(f.map(O=>O.id))&&c(M);}},[n,f,e]);let T=f.filter(R=>!A.current.has(R.id)||!y(R.id)),_=e?f.slice(0,e):f,E=e?Math.max(0,T.length-e):0,S=react.useRef(0),U=E>0&&S.current===0,w=E===0&&S.current>0;react.useEffect(()=>{S.current=E;},[E]);let B=f.length===0&&!y()&&!!t;return jsxRuntime.jsxs("div",{style:ut(),className:g,children:[B&&jsxRuntime.jsx(J,{text:t,mode:z.placeholder.mode,direction:z.placeholder.direction,blur:z.placeholder.blur,duration:z.placeholder.duration,initial:"initial",animate:"animate",className:`token-placeholder ${l}`},"placeholder"),_.map((R,Y)=>{let P=A.current.has(R.id),C=!P&&Y<_.length-1;return jsxRuntime.jsxs("div",{className:`token-wrapper ${x} ${P?"exit-active":""}`,ref:v=>i(R.id,v),children:[jsxRuntime.jsx(J,{text:R.text,mode:P?"none":r,direction:o,staggerDelay:s,duration:I.DURATION_ENTER,blur:z.newToken.blur,widthAnimation:!P&&h,initial:P?false:"initial",animate:"animate"}),C&&jsxRuntime.jsx("span",{className:`token-separator ${a}`,children:p})]},R.id)}),(E>0||w)&&jsxRuntime.jsxs("div",{className:`token-overflow ${x} ${U?"entering":""} ${w?"exiting":""}`,ref:R=>i("overflow-counter",R),children:[jsxRuntime.jsx("span",{className:`token-separator ${a}`,children:"+"}),jsxRuntime.jsx(rt,{value:E,duration:I.DURATION_ENTER,fontSize:"inherit",fontWeight:"inherit",color:"inherit"}),jsxRuntime.jsx(J,{text:" more",mode:r,direction:o,staggerDelay:s,duration:w?I.DURATION_EXIT:I.DURATION_ENTER,blur:z.newToken.blur,initial:U?"initial":false,animate:"animate"})]})]})};var xt=react.createContext(null),Bt=()=>{let n=react.useContext(xt);if(!n)throw new Error("useDebug must be used within DebugProvider");return n},Yt=({children:n})=>{let[t,e]=react.useState([]),[r,o]=react.useState(true),s=react.useRef(r);s.current=r;let p=react.useCallback(c=>{},[]),h=react.useCallback(()=>{},[]),g=react.useCallback(()=>{},[]),x=react.useCallback(()=>{},[]),l=react.useCallback(()=>{},[]),a=react.useCallback(()=>"",[t]),d=react.useCallback(()=>"",[t]),f=react.useMemo(()=>({events:[],isEnabled:false,enableDebug:g,disableDebug:x,toggleDebug:l,logEvent:p,clearEvents:h,getEventLog:d,exportToCSV:a}),[t,r,g,x,l,p,h,d,a]);return jsxRuntime.jsx(xt.Provider,{value:f,children:n})};var nt=class{constructor(){this.activeAnimations=new Map;this.timeline=[];this.completedAnimations=[];this.sessionStartTime=0;}startSession(){}getRelativeTime(){return Math.round((performance.now()-this.sessionStartTime)*100)/100}startAnimation(t,e,r,o){}endAnimation(t){}detectOverlaps(t){let e=[];return this.activeAnimations.forEach((r,o)=>{o!==t&&e.push(`${r.type}:${r.elementId}`);}),e}getOverlaps(){return []}getTimeline(){return []}getActiveCount(){return 0}getActiveAnimations(){return []}getCompletedAnimations(){return []}getSummary(){return {totalAnimations:0,totalDuration:0,overlaps:[],timeline:[],activeAnimations:[]}}getTimelineForVisualization(){return []}},zt=new nt;function pt(n){let t=getComputedStyle(n);return {opacity:t.opacity,transform:t.transform,filter:t.filter,width:t.width,height:t.height,marginRight:t.marginRight,marginLeft:t.marginLeft,position:t.position,visibility:t.visibility,pointerEvents:t.pointerEvents}}function Wt(n){let t=pt(n);return {opacity:t.opacity,transform:t.transform==="none"?"none":t.transform,filter:t.filter==="none"?"none":t.filter,width:t.width,marginRight:t.marginRight,position:t.position}}function Tt(n){let t=n.getBoundingClientRect();return {x:Math.round(t.x*100)/100,y:Math.round(t.y*100)/100,width:Math.round(t.width*100)/100,height:Math.round(t.height*100)/100,top:Math.round(t.top*100)/100,left:Math.round(t.left*100)/100,right:Math.round(t.right*100)/100,bottom:Math.round(t.bottom*100)/100}}function jt(n){let t=Tt(n);return {x:t.x,y:t.y,w:t.width,h:t.height}}function Ht(n,t){return {deltaX:Math.round((n.left-t.left)*100)/100,deltaY:Math.round((n.top-t.top)*100)/100,deltaWidth:Math.round((n.width-t.width)*100)/100,deltaHeight:Math.round((n.height-t.height)*100)/100}}function Vt(n,t){let e=pt(t);return Object.entries(n).map(([r,o])=>{let s=e[r]||"",p=yt(r,o),h=yt(r,s);return {property:r,expected:o,actual:s,matches:p===h}})}function yt(n,t){if(!t)return "";if(n==="opacity")return parseFloat(t).toString();if(n==="transform"){if(t==="none")return "none";let e=t.match(/matrix\(([^)]+)\)/);if(e&&e[1]){let r=e[1].split(",").map(p=>parseFloat(p.trim())),o=r[4],s=r[5];if(o!==void 0&&s!==void 0)return `translate(${Math.round(o)}px, ${Math.round(s)}px)`}return t}if(n==="width"||n==="height"||n.includes("margin")){let e=parseFloat(t);if(!isNaN(e))return `${Math.round(e)}px`}if(n==="filter"){if(t==="none")return "none";let e=t.match(/blur\(([^)]+)\)/);if(e&&e[1]){let r=parseFloat(e[1]);return `blur(${Math.round(r)}px)`}}return t}function qt(n){let t=performance.now();return {start:t,expectedDuration:n,end:()=>{let e=performance.now(),r=e-t,o=r-n;return {startTime:Math.round(t*100)/100,endTime:Math.round(e*100)/100,expectedDuration:n,actualDuration:Math.round(r*100)/100,deviation:Math.round(o*100)/100,deviationPercent:Math.round(o/n*1e4)/100}}}}function Jt(n){let t=n.deviation>=0?"+":"",e=Math.abs(n.deviation)<10?"\u2705":"\u26A0\uFE0F";return `Expected: ${n.expectedDuration}ms | Actual: ${n.actualDuration}ms | Deviation: ${t}${n.deviation}ms ${e}`}function bt(n){let t=n.effect?.getTiming?.();return {id:n.id,playState:n.playState,currentTime:n.currentTime,playbackRate:n.playbackRate,pending:n.pending,duration:t?.duration,easing:t?.easing,fill:t?.fill}}function Zt(n){return n.getAnimations().map(bt)}exports.ANIMATION_CONFIGS=wt;exports.ANIMATION_DEFAULTS=I;exports.AnimatedTokens=$t;exports.ChoreographyTrackerClass=nt;exports.DebugProvider=Yt;exports.EASINGS=N;exports.EFFECTS=X;exports.PRESETS=z;exports.RESPONSIVE_CONFIGS=Dt;exports.SlidingNumber=rt;exports.SlidingText=J;exports.TIMING=b;exports.TRANSFORMS=F;exports.animatedTokensStyles=H;exports.calculatePositionDelta=Ht;exports.captureAnimationInfo=bt;exports.captureComputedStyles=pt;exports.captureElementAnimations=Zt;exports.capturePosition=Tt;exports.capturePositionForLog=jt;exports.captureStylesForLog=Wt;exports.choreographyTracker=zt;exports.compareStyles=Vt;exports.createAnimationTimer=qt;exports.formatTimingResult=Jt;exports.getResponsiveAnimatedTokensStyle=ut;exports.getResponsiveDuration=q;exports.getResponsiveStagger=ot;exports.getSlidingTextTokenStyle=at;exports.slidingTextStyles=$;exports.useDebug=Bt;exports.useWAAPIAnimations=lt;//# sourceMappingURL=index.cjs.map
|
|
74
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/SlidingNumber.tsx","../src/utils/animationUtils.ts","../src/styles/slidingText.styles.ts","../src/components/SlidingText.tsx","../src/hooks/useWAAPIAnimations.ts","../src/styles/animatedTokens.styles.ts","../src/utils/injectStyles.ts","../src/components/AnimatedTokens.tsx","../src/contexts/DebugContext.tsx","../src/utils/choreographyTracker.ts","../src/utils/debugCapture.ts"],"names":["parseNumberToChars","value","format","locale","options","parts","result","integerDigitCount","part","integerIndex","fractionIndex","groupCount","partIdx","char","SlidingNumber","duration","fontSize","fontWeight","color","digitHeight","stagger","motionBlur","trend","animationConfig","computedEasing","useMemo","overshoot","stiffness","mass","p1","p2","p3","currentChars","prevKeysRef","useRef","isFirstRenderRef","enteringKeys","entering","c","useEffect","getDelay","position","jsx","item","isEntering","Digit","Symbol","easing","ref","hasAnimatedRef","useLayoutEffect","digit","delay","columnRef","containerRef","animationRef","filterId","currentOffsetRef","targetDigitRef","hasInitializedRef","sequence","seq","cycle","d","offset","currentDigit","animateToDigit","target","computedStyle","matrix","rawIndex","from","normalizedOffset","currentAnim","diff","startOffset","endOffset","blurEl","intensity","anim","jsxs","Fragment","i","getResponsiveDuration","baseDuration","getResponsiveStagger","baseDelay","TIMING","TRANSFORMS","EFFECTS","EASINGS","RESPONSIVE_CONFIGS","ANIMATION_DEFAULTS","ANIMATION_CONFIGS","PRESETS","slidingTextStyles","getSlidingTextTokenStyle","state","direction","base","SlidingText","text","mode","staggerDelay","blur","widthAnimation","initial","exit","className","style","contentRef","hasTriggeredEnterRef","showAnimate","setShowAnimate","useState","visualState","elements","container","content","targetWidth","timer","currentWidth","getTransitionStyle","index","isExit","currentDuration","currentEasing","useWAAPIAnimations","config","configRef","elementsRef","stateRef","activeAnimationsRef","registerElement","useCallback","id","el","capturePositions","excludeIds","positions","rect","cancelAnimations","animations","startExit","exitDuration","exitEasing","flipDuration","exitOffsetY","exitScale","exitBlur","exitStagger","wrapperRect","marginRight","exitAnimations","flipAnimations","flipStarted","tokens","token","widthAnim","flipDelay","startFlipAnimations","remainingEl","remainingId","prevRect","newRect","deltaX","deltaY","flipAnim","flipTimer","a","isAnimating","animatedTokensStyles","getResponsiveAnimatedTokensStyle","isMobile","prefersReducedMotion","prefersHighContrast","STYLE_ID","CSS_CONTENT","injectAnimationStyles","styleEl","AnimatedTokens","placeholder","maxVisible","textAnimationMode","textDirection","textStaggerDelay","separator","enableWidthAnimation","tokenClassName","placeholderClassName","separatorClassName","isMountedRef","displayTokens","setDisplayTokens","animatingIdsRef","handleAnimationComplete","prev","t","startExitRef","currentIds","displayIds","removed","added","indexInDisplay","dt","exitingTokens","et","oldIdx","activeTokens","visibleTokens","overflowCount","prevOverflowCount","isOverflowEntering","isOverflowExiting","showPlaceholder","isExiting","showSeparator","DebugContext","createContext","useDebug","context","useContext","DebugProvider","children","events","setEvents","isEnabled","setIsEnabled","isEnabledRef","logEvent","event","clearEvents","enableDebug","disableDebug","toggleDebug","exportToCSV","getEventLog","contextValue","ChoreographyTrackerClass","type","elementId","expectedDuration","newAnimationId","overlaps","info","choreographyTracker","captureComputedStyles","computed","captureStylesForLog","styles","capturePosition","capturePositionForLog","pos","calculatePositionDelta","before","after","compareStyles","expected","actual","prop","expectedVal","actualVal","normalizedExpected","normalizeStyleValue","normalizedActual","property","match","values","v","tx","ty","num","blurMatch","blurValue","createAnimationTimer","startTime","endTime","actualDuration","deviation","formatTimingResult","timing","sign","status","captureAnimationInfo","animation","captureElementAnimations"],"mappings":"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","file":"index.cjs","sourcesContent":["\"use client\"\n\nimport { useEffect, useRef, useMemo, useLayoutEffect } from \"react\"\n\nexport interface FormatOptions {\n style?: \"decimal\" | \"currency\" | \"percent\"\n currency?: string\n locale?: string\n minimumFractionDigits?: number\n maximumFractionDigits?: number\n useGrouping?: boolean\n}\n\nexport interface SlidingNumberProps {\n value: number\n duration?: number\n fontSize?: string\n fontWeight?: string\n color?: string\n digitHeight?: number\n stagger?: number\n motionBlur?: boolean\n format?: FormatOptions\n trend?: -1 | 0 | 1\n animationConfig?: {\n overshoot?: number\n mass?: number\n stiffness?: number\n }\n}\n\ninterface CharItem {\n char: string\n key: string\n isDigit: boolean\n position: number\n}\n\nfunction parseNumberToChars(value: number, format?: FormatOptions): CharItem[] {\n const locale = format?.locale || \"en-US\"\n const options: Intl.NumberFormatOptions = {\n style: format?.style || \"decimal\",\n minimumFractionDigits: format?.minimumFractionDigits,\n maximumFractionDigits: format?.maximumFractionDigits,\n useGrouping: format?.useGrouping ?? true,\n }\n\n if (format?.style === \"currency\" && format?.currency) {\n options.currency = format.currency\n }\n\n const formatter = new Intl.NumberFormat(locale, options)\n const parts = formatter.formatToParts(value)\n\n const result: CharItem[] = []\n\n let integerDigitCount = 0\n parts.forEach((part) => {\n if (part.type === \"integer\") {\n integerDigitCount += part.value.length\n }\n })\n\n let integerIndex = integerDigitCount\n let fractionIndex = 0\n let groupCount = 0\n\n parts.forEach((part, partIdx) => {\n if (part.type === \"integer\") {\n for (const char of part.value) {\n result.push({\n char,\n key: `int-${integerIndex}`,\n isDigit: true,\n position: integerIndex,\n })\n integerIndex--\n }\n } else if (part.type === \"fraction\") {\n for (const char of part.value) {\n fractionIndex++\n result.push({\n char,\n key: `frac-${fractionIndex}`,\n isDigit: true,\n position: -fractionIndex,\n })\n }\n } else if (part.type === \"decimal\") {\n result.push({ char: part.value, key: \"decimal\", isDigit: false, position: 0 })\n } else if (part.type === \"group\") {\n groupCount++\n result.push({ char: part.value, key: `group-${groupCount}`, isDigit: false, position: 0 })\n } else if (part.type === \"currency\") {\n result.push({ char: part.value, key: `currency-${partIdx}`, isDigit: false, position: 0 })\n } else if (part.type === \"percentSign\") {\n result.push({ char: part.value, key: \"percent\", isDigit: false, position: 0 })\n } else {\n result.push({ char: part.value, key: `symbol-${partIdx}`, isDigit: false, position: 0 })\n }\n })\n\n return result\n}\n\nexport function SlidingNumber({\n value,\n duration = 700,\n fontSize = \"3rem\",\n fontWeight = \"700\",\n color = \"#000\",\n digitHeight = 60,\n stagger = 30,\n motionBlur = true,\n format,\n trend = 0,\n animationConfig,\n}: SlidingNumberProps) {\n const computedEasing = useMemo(() => {\n if (animationConfig) {\n const { overshoot = 1, stiffness = 1, mass = 1 } = animationConfig\n const p1 = 0.34 * stiffness\n const p2 = 1 + 0.56 * overshoot\n const p3 = 0.64 / mass\n return `cubic-bezier(${Math.min(p1, 1).toFixed(2)}, ${Math.min(p2, 2).toFixed(2)}, ${Math.min(p3, 1).toFixed(2)}, 1)`\n }\n return \"cubic-bezier(0.34, 1.56, 0.64, 1)\"\n }, [animationConfig])\n\n const currentChars = useMemo(() => parseNumberToChars(value, format), [value, format])\n const prevKeysRef = useRef<Set<string>>(new Set())\n const isFirstRenderRef = useRef(true)\n\n const enteringKeys = useMemo(() => {\n if (isFirstRenderRef.current) return new Set<string>()\n const entering = new Set<string>()\n currentChars.forEach((c) => {\n if (!prevKeysRef.current.has(c.key)) {\n entering.add(c.key)\n }\n })\n return entering\n }, [currentChars])\n\n useEffect(() => {\n isFirstRenderRef.current = false\n prevKeysRef.current = new Set(currentChars.map((c) => c.key))\n }, [currentChars])\n\n const getDelay = (position: number) => {\n const absPos = Math.abs(position)\n return (absPos - 1) * stagger\n }\n\n return (\n <div\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n fontSize,\n fontWeight,\n color,\n fontVariantNumeric: \"tabular-nums\",\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n overflow: \"hidden\",\n }}\n >\n {currentChars.map((item) => {\n const isEntering = enteringKeys.has(item.key)\n\n if (item.isDigit) {\n return (\n <Digit\n key={item.key}\n digit={Number.parseInt(item.char)}\n duration={duration}\n digitHeight={digitHeight}\n delay={getDelay(item.position)}\n motionBlur={motionBlur}\n easing={computedEasing}\n isEntering={isEntering}\n trend={trend}\n />\n )\n }\n\n return (\n <Symbol key={item.key} char={item.char} isEntering={isEntering} duration={duration} easing={computedEasing} />\n )\n })}\n </div>\n )\n}\n\nfunction Symbol({\n char,\n isEntering,\n duration,\n easing,\n}: { char: string; isEntering: boolean; duration: number; easing: string }) {\n const ref = useRef<HTMLSpanElement>(null)\n const hasAnimatedRef = useRef(false)\n\n useLayoutEffect(() => {\n if (!ref.current || !isEntering || hasAnimatedRef.current) return\n hasAnimatedRef.current = true\n\n ref.current.animate(\n [\n { opacity: 0, transform: \"scale(0.8)\" },\n { opacity: 1, transform: \"scale(1)\" },\n ],\n {\n duration: duration * 0.3,\n easing,\n fill: \"forwards\",\n },\n )\n }, [isEntering, duration, easing])\n\n return (\n <span\n ref={ref}\n style={{\n display: \"inline-block\",\n whiteSpace: \"pre\",\n opacity: isEntering ? 0 : 1,\n }}\n >\n {char}\n </span>\n )\n}\n\ninterface DigitProps {\n digit: number\n duration: number\n digitHeight: number\n delay: number\n motionBlur: boolean\n easing: string\n isEntering: boolean\n trend: -1 | 0 | 1\n}\n\nfunction Digit({ digit, duration, digitHeight, delay, motionBlur, easing, isEntering, trend }: DigitProps) {\n const columnRef = useRef<HTMLDivElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n const animationRef = useRef<Animation | null>(null)\n const filterId = useRef(`blur-${Math.random().toString(36).slice(2, 9)}`).current\n\n const currentOffsetRef = useRef<number | null>(null)\n const targetDigitRef = useRef(digit)\n const hasInitializedRef = useRef(false)\n\n const sequence = useMemo(() => {\n const seq: number[] = []\n for (let cycle = -1; cycle <= 1; cycle++) {\n for (let d = 0; d <= 9; d++) {\n seq.push(d)\n }\n }\n return seq\n }, [])\n\n useLayoutEffect(() => {\n if (!hasInitializedRef.current) {\n hasInitializedRef.current = true\n const offset = -(digit + 10) * digitHeight\n currentOffsetRef.current = offset\n targetDigitRef.current = digit\n\n if (columnRef.current) {\n columnRef.current.style.transform = `translateY(${offset}px)`\n }\n }\n }, [digit, digitHeight])\n\n useLayoutEffect(() => {\n if (!containerRef.current || !isEntering) return\n\n containerRef.current.animate(\n [\n { opacity: 0, transform: \"scale(0.5) translateY(-20px)\" },\n { opacity: 1, transform: \"scale(1) translateY(0)\" },\n ],\n {\n duration: duration * 0.4,\n easing,\n fill: \"forwards\",\n },\n )\n }, [isEntering, duration, easing])\n\n useEffect(() => {\n targetDigitRef.current = digit\n\n if (!hasInitializedRef.current) return\n\n const currentDigit =\n currentOffsetRef.current !== null\n ? (((Math.round(-currentOffsetRef.current / digitHeight) - 10) % 10) + 10) % 10\n : digit\n\n if (digit === currentDigit && currentOffsetRef.current !== null) {\n return\n }\n\n animateToDigit(digit)\n }, [digit, digitHeight])\n\n const animateToDigit = (target: number) => {\n if (!columnRef.current || !containerRef.current) return\n\n if (animationRef.current) {\n const computedStyle = getComputedStyle(columnRef.current)\n const matrix = new DOMMatrix(computedStyle.transform)\n currentOffsetRef.current = matrix.m42\n animationRef.current.cancel()\n animationRef.current = null\n columnRef.current.style.transform = `translateY(${currentOffsetRef.current}px)`\n }\n\n const rawIndex = currentOffsetRef.current !== null ? -currentOffsetRef.current / digitHeight : target + 10\n\n const currentDigitFromOffset = (((Math.round(rawIndex) - 10) % 10) + 10) % 10\n const from = currentDigitFromOffset\n\n if (target === from && currentOffsetRef.current !== null) {\n const normalizedOffset = -(target + 10) * digitHeight\n if (columnRef.current) {\n const currentAnim = animationRef.current as Animation | null\n if (currentAnim) {\n currentAnim.cancel()\n }\n columnRef.current.style.transform = `translateY(${normalizedOffset}px)`\n }\n currentOffsetRef.current = normalizedOffset\n return\n }\n\n let diff: number\n if (trend === 1) {\n diff = target >= from ? target - from : 10 - from + target\n } else if (trend === -1) {\n diff = target <= from ? target - from : target - from - 10\n } else {\n diff = target - from\n if (diff > 5) diff -= 10\n else if (diff < -5) diff += 10\n }\n\n const startOffset = currentOffsetRef.current ?? -(from + 10) * digitHeight\n const endOffset = startOffset - diff * digitHeight\n\n const blurEl = document.getElementById(filterId)?.querySelector(\"feGaussianBlur\")\n if (motionBlur && blurEl) {\n const intensity = Math.min(Math.abs(diff) * 1.2, 6)\n blurEl.setAttribute(\"stdDeviation\", `0,${intensity}`)\n containerRef.current.style.filter = `url(#${filterId})`\n }\n\n const anim = columnRef.current.animate(\n [{ transform: `translateY(${startOffset}px)` }, { transform: `translateY(${endOffset}px)` }],\n {\n duration,\n delay,\n easing,\n fill: \"forwards\",\n },\n )\n\n animationRef.current = anim\n\n anim.onfinish = () => {\n const normalizedOffset = -(target + 10) * digitHeight\n if (columnRef.current) {\n anim.cancel()\n columnRef.current.style.transform = `translateY(${normalizedOffset}px)`\n }\n currentOffsetRef.current = normalizedOffset\n\n if (containerRef.current) {\n containerRef.current.style.filter = \"none\"\n }\n if (blurEl) {\n blurEl.setAttribute(\"stdDeviation\", \"0,0\")\n }\n\n animationRef.current = null\n\n if (targetDigitRef.current !== target) {\n requestAnimationFrame(() => {\n animateToDigit(targetDigitRef.current)\n })\n }\n }\n\n anim.oncancel = () => {\n animationRef.current = null\n }\n }\n\n return (\n <>\n <svg style={{ position: \"absolute\", width: 0, height: 0 }} aria-hidden=\"true\">\n <defs>\n <filter id={filterId}>\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"0,0\" />\n </filter>\n </defs>\n </svg>\n\n <div\n ref={containerRef}\n style={{\n position: \"relative\",\n height: `${digitHeight}px`,\n overflow: \"hidden\",\n width: \"0.65em\",\n textAlign: \"center\",\n opacity: isEntering ? 0 : 1,\n }}\n >\n <div\n ref={columnRef}\n style={{\n position: \"absolute\",\n left: 0,\n right: 0,\n willChange: \"transform\",\n }}\n >\n {sequence.map((d, i) => (\n <div\n key={i}\n style={{\n height: `${digitHeight}px`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n {d}\n </div>\n ))}\n </div>\n </div>\n </>\n )\n}\n","// ============================================\n// ANIMATION CONFIGURATION\n// Sistema configurable para iteración rápida\n// Research-based values from:\n// - Material Design Motion\n// - CSS-Tricks FLIP Technique\n// - Josh W. Comeau Spring Animations\n// - Easings.net\n// ============================================\n\n// ============================================\n// RESPONSIVE & ACCESSIBILITY HELPERS\n// ============================================\n\n/**\n * Obtiene duración de animación responsiva para el dispositivo actual\n * @param baseDuration - Duración base en ms\n * @returns Duración ajustada para dispositivo actual\n */\nexport const getResponsiveDuration = (baseDuration: number): number => {\n if (typeof window === 'undefined') return baseDuration;\n\n // Verificar si el usuario prefiere reducir movimiento\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if (prefersReducedMotion) return 0;\n\n // Detectar dispositivo móvil y reducir duración para mejor performance\n const isMobile = window.innerWidth < 768; // md breakpoint\n if (isMobile) {\n return Math.round(baseDuration * 0.6); // 60% de la duración en móviles\n }\n\n return baseDuration;\n};\n\n/**\n * Obtiene stagger delay responsivo\n * @param baseDelay - Delay base en ms\n * @returns Delay ajustado para dispositivo actual\n */\nexport const getResponsiveStagger = (baseDelay: number): number => {\n if (typeof window === 'undefined') return baseDelay;\n\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if (prefersReducedMotion) return 0;\n\n const isMobile = window.innerWidth < 768;\n return isMobile ? Math.round(baseDelay * 0.5) : baseDelay;\n};\n\n// TIMING (ms)\nexport const TIMING = {\n // Durations\n ENTER_DURATION: 200,\n EXIT_DURATION: 180, // Faster to not block FLIP\n COLLAPSE_DURATION: 200,\n FLIP_DURATION: 300, // Longer for spring effect\n\n // Stagger between characters\n ENTER_STAGGER: 15,\n EXIT_STAGGER: 0, // No stagger on exit (cleaner)\n\n // Delays\n COLLAPSE_DELAY: 30, // Start collapse after fade begins\n FLIP_DELAY_PERCENT: 0.25, // Start FLIP at 25% of exit\n\n // Thresholds\n MIN_DELTA_PX: 1, // Ignore sub-pixel movements\n} as const;\n\n// TRANSFORMS (px/deg)\nexport const TRANSFORMS = {\n OFFSET_Y_ENTER: 8,\n OFFSET_Y_EXIT: -8,\n OFFSET_X: 16,\n SCALE_EXIT: 0.95, // Subtle scale down on exit\n ROTATE_EXIT: 0, // Optional: -2 for playful feel\n} as const;\n\n// EFFECTS\nexport const EFFECTS = {\n BLUR_ENTER: 4, // px\n BLUR_EXIT: 2, // Less blur on exit (faster)\n} as const;\n\n// EASINGS - Research-based\nexport const EASINGS = {\n // Standard (from easings.net)\n EASE_OUT_CUBIC: 'cubic-bezier(0.33, 1, 0.68, 1)',\n EASE_IN_CUBIC: 'cubic-bezier(0.32, 0, 0.67, 0)',\n EASE_IN_OUT: 'cubic-bezier(0.42, 0, 0.58, 1)',\n EASE_OUT_EXPO: 'cubic-bezier(0.16, 1, 0.3, 1)',\n\n // FLIP optimized (CSS-Tricks recommendation)\n EASE_FLIP: 'cubic-bezier(0.2, 0, 0.2, 1)',\n\n // Spring via linear() - Josh W. Comeau\n SPRING_GENTLE: `linear(0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%, 0.938 16.7%, 1.017 19.4%, 1.067, 1.099 24.3%, 1.108 26%, 1.100, 1.078 30.1%, 1.049 32.5%, 0.994 37.3%, 0.981 40.2%, 0.974 43.4%, 0.975 50.2%, 0.997 62.5%, 1.001 74.7%, 1)`,\n\n SPRING_SNAPPY: `linear(0, 0.006, 0.024 2%, 0.096 4.2%, 0.397 9.3%, 0.861 15.8%, 1.002 18.7%, 1.093 21.4%, 1.143 24%, 1.156, 1.149 28.3%, 1.115 31.5%, 1.022 40%, 0.988 47.1%, 0.984 55.1%, 0.998 72.3%, 1.001 85.4%, 1)`,\n} as const;\n\n/**\n * Configuración de animación responsiva con accessibility\n */\nexport const RESPONSIVE_CONFIGS = {\n tokenEnter: {\n get duration() { return getResponsiveDuration(TIMING.ENTER_DURATION); },\n get stagger() { return getResponsiveStagger(TIMING.ENTER_STAGGER); },\n easing: EASINGS.EASE_OUT_CUBIC,\n blur: EFFECTS.BLUR_ENTER,\n offsetY: TRANSFORMS.OFFSET_Y_ENTER,\n },\n tokenExit: {\n get duration() { return getResponsiveDuration(TIMING.EXIT_DURATION); },\n get stagger() { return getResponsiveStagger(TIMING.EXIT_STAGGER); },\n easing: EASINGS.EASE_IN_CUBIC,\n blur: EFFECTS.BLUR_EXIT,\n offsetY: TRANSFORMS.OFFSET_Y_EXIT,\n scale: TRANSFORMS.SCALE_EXIT,\n },\n collapse: {\n get duration() { return getResponsiveDuration(TIMING.COLLAPSE_DURATION); },\n delay: TIMING.COLLAPSE_DELAY,\n easing: EASINGS.EASE_IN_OUT,\n },\n flip: {\n get duration() { return getResponsiveDuration(TIMING.FLIP_DURATION); },\n delayPercent: TIMING.FLIP_DELAY_PERCENT,\n easing: EASINGS.SPRING_GENTLE,\n },\n} as const;\n\n// LEGACY DEFAULTS (for backward compatibility)\nexport const ANIMATION_DEFAULTS = {\n // Timing\n DURATION_ENTER: TIMING.ENTER_DURATION,\n DURATION_EXIT: TIMING.EXIT_DURATION,\n DURATION_FLIP: TIMING.FLIP_DURATION,\n STAGGER_DELAY: TIMING.ENTER_STAGGER,\n\n // Transform offsets\n OFFSET_VERTICAL: TRANSFORMS.OFFSET_Y_ENTER,\n OFFSET_HORIZONTAL: TRANSFORMS.OFFSET_X,\n\n // Blur\n BLUR_AMOUNT: EFFECTS.BLUR_ENTER,\n\n // Easing (updated to research-based values)\n EASING_ENTER: EASINGS.EASE_OUT_CUBIC,\n EASING_EXIT: EASINGS.EASE_IN_CUBIC,\n EASING_FLIP: EASINGS.SPRING_GENTLE,\n\n // Spring (para linear())\n SPRING_EASING: EASINGS.SPRING_GENTLE,\n};\n\n// ANIMATION CONFIGS (composite presets for specific use cases)\nexport const ANIMATION_CONFIGS = {\n tokenEnter: {\n duration: TIMING.ENTER_DURATION,\n stagger: TIMING.ENTER_STAGGER,\n easing: EASINGS.EASE_OUT_CUBIC,\n blur: EFFECTS.BLUR_ENTER,\n offsetY: TRANSFORMS.OFFSET_Y_ENTER,\n },\n tokenExit: {\n duration: TIMING.EXIT_DURATION,\n stagger: TIMING.EXIT_STAGGER,\n easing: EASINGS.EASE_IN_CUBIC,\n blur: EFFECTS.BLUR_EXIT,\n offsetY: TRANSFORMS.OFFSET_Y_EXIT,\n scale: TRANSFORMS.SCALE_EXIT,\n },\n collapse: {\n duration: TIMING.COLLAPSE_DURATION,\n delay: TIMING.COLLAPSE_DELAY,\n easing: EASINGS.EASE_IN_OUT,\n },\n flip: {\n duration: TIMING.FLIP_DURATION,\n delayPercent: TIMING.FLIP_DELAY_PERCENT,\n easing: EASINGS.SPRING_GENTLE,\n },\n} as const;\n\nexport const PRESETS = {\n newToken: {\n mode: 'character' as const,\n direction: 'vertical' as const,\n staggerDelay: 15,\n blur: true,\n widthAnimation: true,\n duration: 200,\n initial: 'initial' as const,\n },\n\n existingToken: {\n mode: 'none' as const,\n blur: false,\n widthAnimation: false,\n initial: false as const,\n },\n\n placeholder: {\n mode: 'word' as const,\n direction: 'vertical' as const,\n blur: true,\n widthAnimation: false,\n duration: 150,\n },\n\n separator: {\n duration: 100,\n widthAnimation: true,\n },\n};\n","import type React from 'react';\n\nexport const slidingTextStyles = {\n container: {\n '--duration-enter': '200ms',\n '--duration-exit': '200ms',\n '--easing-enter': 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',\n '--easing-exit': 'cubic-bezier(0.55, 0.06, 0.68, 0.19)',\n '--offset-vertical': '8px',\n '--offset-horizontal': '16px',\n '--blur-amount': '4px',\n display: 'inline-flex',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n willChange: 'width',\n } as React.CSSProperties,\n\n content: {\n display: 'inline-flex',\n whiteSpace: 'pre',\n } as React.CSSProperties,\n\n token: {\n display: 'inline-block',\n willChange: 'transform, opacity, filter',\n backfaceVisibility: 'hidden',\n fontWeight: '500',\n } as React.CSSProperties,\n\n enterFrom: {\n opacity: 0,\n filter: 'blur(var(--blur-amount))',\n } as React.CSSProperties,\n\n enterTo: {\n opacity: 1,\n transform: 'translate(0, 0)',\n filter: 'blur(0)',\n } as React.CSSProperties,\n\n exitActive: {\n opacity: 0,\n filter: 'blur(var(--blur-amount))',\n } as React.CSSProperties,\n\n verticalEnterFrom: {\n transform: 'translateY(var(--offset-vertical))',\n } as React.CSSProperties,\n\n verticalExitActive: {\n transform: 'translateY(calc(var(--offset-vertical) * -1))',\n } as React.CSSProperties,\n\n horizontalEnterFrom: {\n transform: 'translateX(var(--offset-horizontal))',\n } as React.CSSProperties,\n\n horizontalExitActive: {\n transform: 'translateX(calc(var(--offset-horizontal) * -1))',\n } as React.CSSProperties,\n} as const;\n\nexport const getSlidingTextTokenStyle = (\n state: 'enter-from' | 'enter-to' | 'exit-active',\n direction: 'vertical' | 'horizontal'\n): React.CSSProperties => {\n const base = { ...slidingTextStyles.token };\n\n if (state === 'enter-from') {\n Object.assign(base, slidingTextStyles.enterFrom);\n if (direction === 'vertical') {\n Object.assign(base, slidingTextStyles.verticalEnterFrom);\n } else {\n Object.assign(base, slidingTextStyles.horizontalEnterFrom);\n }\n } else if (state === 'enter-to') {\n Object.assign(base, slidingTextStyles.enterTo);\n } else if (state === 'exit-active') {\n Object.assign(base, slidingTextStyles.exitActive);\n if (direction === 'vertical') {\n Object.assign(base, slidingTextStyles.verticalExitActive);\n } else {\n Object.assign(base, slidingTextStyles.horizontalExitActive);\n }\n }\n\n return base;\n};\n","import React, { useRef, useState, useLayoutEffect, useEffect } from 'react';\nimport { ANIMATION_DEFAULTS } from '../utils/animationUtils';\nimport { slidingTextStyles, getSlidingTextTokenStyle } from '../styles/slidingText.styles';\n\nexport interface SlidingTextProps {\n text: string;\n mode?: 'word' | 'character' | 'none';\n direction?: 'vertical' | 'horizontal';\n staggerDelay?: number;\n duration?: number;\n easing?: string;\n blur?: boolean;\n widthAnimation?: boolean;\n initial?: 'initial' | false;\n animate?: 'animate';\n exit?: 'exit';\n onAnimationComplete?: () => void;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport const SlidingText: React.FC<SlidingTextProps> = ({\n text,\n mode = 'word',\n direction = 'vertical',\n staggerDelay = ANIMATION_DEFAULTS.STAGGER_DELAY,\n duration = ANIMATION_DEFAULTS.DURATION_ENTER,\n easing = ANIMATION_DEFAULTS.EASING_ENTER,\n blur = true,\n widthAnimation = false,\n initial = 'initial',\n exit,\n className = '',\n style,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n\n // Track if we've triggered the enter animation\n const hasTriggeredEnterRef = useRef(false);\n const [showAnimate, setShowAnimate] = useState(initial !== 'initial');\n\n // Trigger enter animation after mount\n useEffect(() => {\n if (initial === 'initial' && !hasTriggeredEnterRef.current) {\n hasTriggeredEnterRef.current = true;\n requestAnimationFrame(() => {\n setShowAnimate(true);\n });\n }\n }, [initial]);\n\n // Compute the actual visual state\n const visualState = exit === 'exit' ? 'exit' : (showAnimate ? 'animate' : 'initial');\n\n // Split text based on mode\n const elements = mode === 'character' ? text.split('') : [text];\n\n // Width Animation Logic\n useLayoutEffect(() => {\n if (!widthAnimation || !containerRef.current || !contentRef.current) return;\n\n const container = containerRef.current;\n const content = contentRef.current;\n\n if (visualState === 'initial') {\n container.style.width = '0px';\n } else if (visualState === 'animate') {\n const supportsInterpolateSize = CSS.supports('interpolate-size', 'allow-keywords');\n\n if (supportsInterpolateSize) {\n container.style.width = 'auto';\n container.style.transition = `width ${duration}ms ${easing}`;\n } else {\n const targetWidth = content.scrollWidth;\n container.style.width = `${targetWidth}px`;\n container.style.transition = `width ${duration}ms ${easing}`;\n\n const timer = setTimeout(() => {\n container.style.width = 'auto';\n }, duration);\n return () => clearTimeout(timer);\n }\n } else if (visualState === 'exit') {\n const currentWidth = container.getBoundingClientRect().width;\n container.style.width = `${currentWidth}px`;\n container.getBoundingClientRect(); // Force reflow\n container.style.width = '0px';\n container.style.transition = `width ${ANIMATION_DEFAULTS.DURATION_EXIT}ms ${ANIMATION_DEFAULTS.EASING_EXIT}`;\n }\n }, [visualState, widthAnimation, duration, easing, text]);\n\n const getTransitionStyle = (index: number): React.CSSProperties => {\n const delay = index * staggerDelay;\n const isExit = visualState === 'exit';\n const currentDuration = isExit ? ANIMATION_DEFAULTS.DURATION_EXIT : duration;\n const currentEasing = isExit ? ANIMATION_DEFAULTS.EASING_EXIT : easing;\n\n return {\n transition: `\n opacity ${currentDuration}ms ${currentEasing} ${delay}ms,\n transform ${currentDuration}ms ${currentEasing} ${delay}ms,\n filter ${currentDuration}ms ${currentEasing} ${delay}ms\n `,\n '--blur-amount': blur ? `${ANIMATION_DEFAULTS.BLUR_AMOUNT}px` : '0px',\n '--offset': direction === 'vertical' ? `${ANIMATION_DEFAULTS.OFFSET_VERTICAL}px` : `${ANIMATION_DEFAULTS.OFFSET_HORIZONTAL}px`\n } as React.CSSProperties;\n };\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={{\n ...slidingTextStyles.container,\n ...style,\n }}\n >\n <div ref={contentRef} style={slidingTextStyles.content}>\n {elements.map((char, index) => (\n <span\n key={index}\n style={{\n ...getSlidingTextTokenStyle(\n visualState === 'initial' ? 'enter-from' :\n visualState === 'animate' ? 'enter-to' :\n 'exit-active',\n direction\n ),\n ...getTransitionStyle(index),\n }}\n >\n {char}\n </span>\n ))}\n </div>\n </div>\n );\n};\n","import { useRef, useCallback, useEffect } from 'react';\nimport { TIMING, TRANSFORMS, EFFECTS, EASINGS } from '../utils/animationUtils';\n\ninterface AnimationConfig {\n onComplete: (id: string) => void;\n exitDuration?: number;\n flipDuration?: number;\n exitEasing?: string;\n flipEasing?: string;\n}\n\ninterface WapiState {\n animatingIds: Set<string>;\n positions: Map<string, DOMRect>;\n}\n\nexport const useWAAPIAnimations = (config: AnimationConfig) => {\n // Ref pattern para config - evita re-crear callbacks\n const configRef = useRef(config);\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n const elementsRef = useRef<Map<string, HTMLElement>>(new Map());\n const stateRef = useRef<WapiState>({\n animatingIds: new Set(),\n positions: new Map()\n });\n const activeAnimationsRef = useRef<Map<string, Animation[]>>(new Map());\n\n const registerElement = useCallback((id: string, el: HTMLElement | null) => {\n if (el) {\n elementsRef.current.set(id, el);\n } else {\n elementsRef.current.delete(id);\n }\n }, []);\n\n const capturePositions = useCallback((excludeIds: Set<string>) => {\n const positions = new Map<string, DOMRect>();\n elementsRef.current.forEach((el, id) => {\n if (!excludeIds.has(id)) {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n positions.set(id, rect);\n }\n }\n });\n stateRef.current.positions = positions;\n return positions;\n }, []);\n\n const cancelAnimations = useCallback((id: string) => {\n const animations = activeAnimationsRef.current.get(id);\n if (animations) {\n animations.forEach(anim => anim.cancel());\n activeAnimationsRef.current.delete(id);\n }\n }, []);\n\n const startExit = useCallback(async (id: string) => {\n const el = elementsRef.current.get(id);\n if (!el || stateRef.current.animatingIds.has(id)) return;\n\n stateRef.current.animatingIds.add(id);\n\n // 1. Capture positions of REMAINING tokens BEFORE any DOM changes\n const excludeIds = new Set([id]);\n capturePositions(excludeIds);\n\n // Use research-based timing values\n const exitDuration = configRef.current.exitDuration || TIMING.EXIT_DURATION;\n const exitEasing = configRef.current.exitEasing || EASINGS.EASE_IN_CUBIC;\n const flipDuration = configRef.current.flipDuration || TIMING.FLIP_DURATION;\n\n // Use research-based transform/effect values (declared early for logging)\n const exitOffsetY = TRANSFORMS.OFFSET_Y_EXIT;\n const exitScale = TRANSFORMS.SCALE_EXIT;\n const exitBlur = EFFECTS.BLUR_EXIT;\n const exitStagger = TIMING.EXIT_STAGGER;\n\n // Get wrapper dimensions for width collapse\n const wrapperRect = el.getBoundingClientRect();\n const computedStyle = getComputedStyle(el);\n const marginRight = parseFloat(computedStyle.marginRight) || 0;\n\n const exitAnimations: Animation[] = [];\n const flipAnimations: Animation[] = [];\n let flipStarted = false;\n\n // 2. Run exit animations SIMULTANEOUSLY:\n // - Character fade out (staggered)\n // - Width collapse\n // - Margin collapse\n\n const tokens = el.querySelectorAll('.sliding-text-token');\n\n if (tokens.length > 0) {\n // Animate each character - no stagger on exit for cleaner feel\n tokens.forEach((token, index) => {\n const delay = index * exitStagger;\n const anim = (token as HTMLElement).animate([\n { opacity: 1, transform: 'translateY(0) scale(1)', filter: 'blur(0px)' },\n { opacity: 0, transform: `translateY(${exitOffsetY}px) scale(${exitScale})`, filter: `blur(${exitBlur}px)` }\n ], {\n duration: exitDuration,\n easing: exitEasing,\n delay,\n fill: 'forwards'\n });\n exitAnimations.push(anim);\n });\n } else {\n // Fallback: animate the whole element with scale\n const anim = el.animate([\n { opacity: 1, transform: 'translateY(0) scale(1)' },\n { opacity: 0, transform: `translateY(${exitOffsetY}px) scale(${exitScale})` }\n ], {\n duration: exitDuration,\n easing: exitEasing,\n fill: 'forwards'\n });\n exitAnimations.push(anim);\n }\n\n // Width + margin collapse animation (simultaneous with fade)\n el.style.overflow = 'hidden';\n const widthAnim = el.animate([\n { width: `${wrapperRect.width}px`, marginRight: `${marginRight}px` },\n { width: '0px', marginRight: '0px' }\n ], {\n duration: exitDuration,\n easing: exitEasing,\n fill: 'forwards'\n });\n exitAnimations.push(widthAnim);\n\n activeAnimationsRef.current.set(id, exitAnimations);\n\n // 3. Start FLIP animations at 25% of exit (research-based overlap)\n const flipDelay = exitDuration * TIMING.FLIP_DELAY_PERCENT;\n\n const startFlipAnimations = () => {\n if (flipStarted) return;\n flipStarted = true;\n\n // Remove from layout flow\n el.style.position = 'absolute';\n el.style.opacity = '0';\n el.style.pointerEvents = 'none';\n\n elementsRef.current.forEach((remainingEl, remainingId) => {\n if (remainingId === id) return;\n\n const prevRect = stateRef.current.positions.get(remainingId);\n if (!prevRect) return;\n\n const newRect = remainingEl.getBoundingClientRect();\n const deltaX = prevRect.left - newRect.left;\n const deltaY = prevRect.top - newRect.top;\n\n // Ignore sub-pixel movements\n if (Math.abs(deltaX) < 1 && Math.abs(deltaY) < 1) return;\n\n // Use spring easing for natural FLIP feel\n const flipAnim = remainingEl.animate([\n { transform: `translate3d(${deltaX}px, ${deltaY}px, 0)` },\n { transform: 'translate3d(0, 0, 0)' }\n ], {\n duration: flipDuration,\n easing: EASINGS.SPRING_GENTLE // Spring for natural overshoot\n });\n\n flipAnimations.push(flipAnim);\n });\n };\n\n // Schedule FLIP to start during exit animation (overlap)\n const flipTimer = setTimeout(startFlipAnimations, flipDelay);\n\n // 4. Wait for ALL animations to complete\n try {\n await Promise.all(exitAnimations.map(a => a.finished));\n\n // Ensure FLIP started if exit finished early\n startFlipAnimations();\n await Promise.all(flipAnimations.map(a => a.finished.catch(() => {})));\n } catch {\n // Animation was cancelled\n clearTimeout(flipTimer);\n stateRef.current.animatingIds.delete(id);\n return;\n }\n\n // 5. Cleanup and notify completion\n stateRef.current.animatingIds.delete(id);\n activeAnimationsRef.current.delete(id);\n elementsRef.current.delete(id);\n\n configRef.current.onComplete(id);\n }, [capturePositions]); // Removed config - using configRef\n\n const isAnimating = useCallback((id?: string) => {\n if (id) return stateRef.current.animatingIds.has(id);\n return stateRef.current.animatingIds.size > 0;\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n activeAnimationsRef.current.forEach((animations) => {\n animations.forEach(anim => anim.cancel());\n });\n activeAnimationsRef.current.clear();\n };\n }, []);\n\n return {\n registerElement,\n startExit,\n isAnimating,\n cancelAnimations\n };\n};\n","import type React from 'react';\n\nexport const animatedTokensStyles = {\n container: {\n '--duration-enter': '200ms',\n '--duration-exit': '180ms',\n '--duration-collapse': '200ms',\n '--duration-flip': '300ms',\n '--stagger-enter': '15ms',\n '--stagger-exit': '0ms',\n '--offset-y-enter': '8px',\n '--offset-y-exit': '-8px',\n '--scale-exit': '0.95',\n '--blur-enter': '4px',\n '--blur-exit': '2px',\n '--ease-enter': 'cubic-bezier(0.33, 1, 0.68, 1)',\n '--ease-exit': 'cubic-bezier(0.32, 0, 0.67, 0)',\n '--ease-collapse': 'cubic-bezier(0.42, 0, 0.58, 1)',\n '--ease-flip': 'cubic-bezier(0.2, 0, 0.2, 1)',\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 0,\n } as React.CSSProperties,\n\n placeholder: {\n color: 'var(--muted-foreground)',\n fontStyle: 'italic',\n } as React.CSSProperties,\n\n tokenWrapper: {\n display: 'inline-flex',\n alignItems: 'center',\n marginRight: '4px',\n } as React.CSSProperties,\n\n tokenWrapperLast: {\n marginRight: 0,\n } as React.CSSProperties,\n\n tokenWrapperExitCompleted: {\n position: 'absolute',\n opacity: 0,\n pointerEvents: 'none',\n marginRight: 0,\n } as React.CSSProperties,\n\n separator: {\n display: 'inline',\n whiteSpace: 'pre',\n opacity: 1,\n transform: 'translateY(0)',\n willChange: 'transform, opacity',\n transition: `\n opacity var(--duration-enter) var(--ease-enter),\n transform var(--duration-enter) var(--ease-enter)\n `,\n } as React.CSSProperties,\n\n separatorExitActive: {\n opacity: 0,\n transform: 'translateY(-8px)',\n transition: `\n opacity var(--duration-exit) var(--ease-exit),\n transform var(--duration-exit) var(--ease-exit)\n `,\n } as React.CSSProperties,\n\n overflow: {\n display: 'inline-flex',\n alignItems: 'center',\n marginLeft: '4px',\n opacity: 1,\n transform: 'translateY(0)',\n willChange: 'transform, opacity',\n transition: `\n opacity var(--duration-enter) var(--ease-enter),\n transform var(--duration-enter) var(--ease-enter)\n `,\n } as React.CSSProperties,\n\n overflowExiting: {\n opacity: 0,\n transform: 'translateY(-8px)',\n transition: `\n opacity var(--duration-exit) var(--ease-exit),\n transform var(--duration-exit) var(--ease-exit)\n `,\n } as React.CSSProperties,\n} as const;\n\nexport const getResponsiveAnimatedTokensStyle = (): React.CSSProperties => {\n if (typeof window === 'undefined') return animatedTokensStyles.container;\n\n const isMobile = window.innerWidth < 768;\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n const prefersHighContrast = window.matchMedia('(prefers-contrast: high)').matches;\n\n if (prefersReducedMotion) {\n return {\n ...animatedTokensStyles.container,\n '--duration-enter': '0ms',\n '--duration-exit': '0ms',\n '--duration-collapse': '0ms',\n '--duration-flip': '0ms',\n '--stagger-enter': '0ms',\n '--stagger-exit': '0ms',\n '--blur-enter': '0px',\n '--blur-exit': '0px',\n '--offset-y-enter': '0px',\n '--offset-y-exit': '0px',\n '--scale-exit': '1',\n } as React.CSSProperties;\n }\n\n if (prefersHighContrast) {\n return {\n ...animatedTokensStyles.container,\n '--blur-enter': '0px',\n '--blur-exit': '0px',\n } as React.CSSProperties;\n }\n\n if (isMobile) {\n return {\n ...animatedTokensStyles.container,\n '--duration-enter': '120ms',\n '--duration-exit': '100ms',\n '--duration-collapse': '120ms',\n '--duration-flip': '180ms',\n '--stagger-enter': '8ms',\n '--blur-enter': '2px',\n '--blur-exit': '1px',\n '--offset-y-enter': '4px',\n '--offset-y-exit': '-4px',\n } as React.CSSProperties;\n }\n\n return animatedTokensStyles.container;\n};\n","/**\n * Injects critical CSS styles for animations into the document head\n * This is needed for dynamic classes that can't be done with inline styles\n */\n\nconst STYLE_ID = 'waapi-animation-primitives-styles';\n\nconst CSS_CONTENT = `\n/* AnimatedTokens critical animation styles */\n.token-wrapper {\n display: inline-flex;\n align-items: center;\n margin-right: 4px;\n}\n\n.token-wrapper:last-child {\n margin-right: 0;\n}\n\n.token-wrapper.exit-completed {\n position: absolute !important;\n opacity: 0 !important;\n pointer-events: none !important;\n margin-right: 0;\n}\n\n.token-separator {\n display: inline !important;\n white-space: pre;\n}\n\n.token-separator.exit-completed {\n opacity: 0;\n position: absolute;\n pointer-events: none;\n}\n\n.token-overflow {\n display: inline-flex;\n align-items: center;\n margin-left: 4px;\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .token-wrapper,\n .token-overflow,\n .sliding-text,\n .sliding-number {\n animation: none !important;\n transition: none !important;\n transform: none !important;\n }\n}\n\n/* Mobile optimizations */\n@media (max-width: 767px) {\n .token-wrapper {\n transform: translateZ(0);\n backface-visibility: hidden;\n perspective: 1000px;\n }\n}\n`;\n\nexport function injectAnimationStyles(): void {\n // Only run in browser environment\n if (typeof document === 'undefined') return;\n\n // Check if styles are already injected\n if (document.getElementById(STYLE_ID)) return;\n\n // Create and inject style element\n const styleEl = document.createElement('style');\n styleEl.id = STYLE_ID;\n styleEl.textContent = CSS_CONTENT;\n document.head.appendChild(styleEl);\n}\n","import React, { useEffect, useState, useRef, useCallback } from 'react';\nimport { SlidingText } from './SlidingText';\nimport { SlidingNumber } from './SlidingNumber';\nimport { useWAAPIAnimations } from '../hooks/useWAAPIAnimations';\nimport { PRESETS, ANIMATION_DEFAULTS } from '../utils/animationUtils';\nimport { getResponsiveAnimatedTokensStyle } from '../styles/animatedTokens.styles';\nimport { injectAnimationStyles } from '../utils/injectStyles';\n\nexport interface Token {\n id: string;\n text: string;\n}\n\nexport interface AnimatedTokensProps {\n tokens: Token[];\n placeholder?: string;\n maxVisible?: number;\n textAnimationMode?: 'character' | 'word';\n textDirection?: 'vertical' | 'horizontal';\n textStaggerDelay?: number;\n separator?: string;\n enableWidthAnimation?: boolean;\n className?: string;\n tokenClassName?: string;\n placeholderClassName?: string;\n separatorClassName?: string;\n}\n\nexport const AnimatedTokens: React.FC<AnimatedTokensProps> = ({\n tokens,\n placeholder = 'No tokens',\n maxVisible,\n textAnimationMode = 'character',\n textDirection = 'vertical',\n textStaggerDelay = 15,\n separator = ', ',\n enableWidthAnimation = false,\n className = '',\n tokenClassName = '',\n placeholderClassName = '',\n separatorClassName = '',\n}) => {\n const isMountedRef = useRef(true);\n\n // Inject critical CSS styles on mount\n useEffect(() => {\n injectAnimationStyles();\n }, []);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n // Single state: displayTokens (includes tokens being animated out)\n const [displayTokens, setDisplayTokens] = useState<Token[]>(tokens);\n\n // Track which tokens are currently animating (via ref, not state)\n const animatingIdsRef = useRef<Set<string>>(new Set());\n\n // Stable callback for onComplete\n const handleAnimationComplete = useCallback((id: string) => {\n if (!isMountedRef.current) return;\n\n animatingIdsRef.current.delete(id);\n setDisplayTokens(prev => prev.filter(t => t.id !== id));\n }, []);\n\n // WAAPI-centric hook - all animation logic handled internally\n const { registerElement, startExit, isAnimating } = useWAAPIAnimations({\n onComplete: handleAnimationComplete\n });\n\n // Store startExit in ref to avoid dependency issues\n const startExitRef = useRef(startExit);\n useEffect(() => {\n startExitRef.current = startExit;\n }, [startExit]);\n\n // Detect removals and additions - ONE useEffect, no RAF nesting\n useEffect(() => {\n const currentIds = new Set(tokens.map(t => t.id));\n const displayIds = new Set(displayTokens.map(t => t.id));\n\n // Detect removals\n const removed = displayTokens.filter(t =>\n !currentIds.has(t.id) && !animatingIdsRef.current.has(t.id)\n );\n\n // Detect additions\n const added = tokens.filter(t => !displayIds.has(t.id));\n\n // Skip if no changes\n if (removed.length === 0 && added.length === 0) return;\n\n // Handle removals - check if in overflow (no animation needed)\n removed.forEach(token => {\n const indexInDisplay = displayTokens.findIndex(dt => dt.id === token.id);\n const isInOverflow = maxVisible !== undefined && indexInDisplay >= maxVisible;\n\n if (isInOverflow) {\n setDisplayTokens(prev => prev.filter(t => t.id !== token.id));\n } else {\n animatingIdsRef.current.add(token.id);\n startExitRef.current(token.id);\n }\n });\n\n // Handle additions\n if (added.length > 0) {\n // Merge added tokens while preserving order from tokens prop\n const exitingTokens = displayTokens.filter(t => !currentIds.has(t.id));\n let result = [...tokens];\n\n // Insert exiting tokens at their original positions\n exitingTokens.forEach(et => {\n const oldIdx = displayTokens.findIndex(t => t.id === et.id);\n if (oldIdx !== -1 && oldIdx <= result.length) {\n result.splice(oldIdx, 0, et);\n }\n });\n\n if (JSON.stringify(result.map(t => t.id)) !== JSON.stringify(displayTokens.map(t => t.id))) {\n setDisplayTokens(result);\n }\n }\n }, [tokens, displayTokens, maxVisible]);\n\n // Calculate visible tokens and overflow\n const activeTokens = displayTokens.filter(t => !animatingIdsRef.current.has(t.id) || !isAnimating(t.id));\n const visibleTokens = maxVisible ? displayTokens.slice(0, maxVisible) : displayTokens;\n const overflowCount = maxVisible ? Math.max(0, activeTokens.length - maxVisible) : 0;\n\n // Overflow state tracking for enter/exit animations\n const prevOverflowCount = useRef(0);\n const isOverflowEntering = overflowCount > 0 && prevOverflowCount.current === 0;\n const isOverflowExiting = overflowCount === 0 && prevOverflowCount.current > 0;\n\n useEffect(() => {\n prevOverflowCount.current = overflowCount;\n }, [overflowCount]);\n\n const showPlaceholder = displayTokens.length === 0 && !isAnimating() && !!placeholder;\n\n return (\n <div style={getResponsiveAnimatedTokensStyle()} className={className}>\n {showPlaceholder && (\n <SlidingText\n key=\"placeholder\"\n text={placeholder}\n mode={PRESETS.placeholder.mode}\n direction={PRESETS.placeholder.direction}\n blur={PRESETS.placeholder.blur}\n duration={PRESETS.placeholder.duration}\n initial=\"initial\"\n animate=\"animate\"\n className={`token-placeholder ${placeholderClassName}`}\n />\n )}\n\n {visibleTokens.map((token, index) => {\n const isExiting = animatingIdsRef.current.has(token.id);\n const showSeparator = !isExiting && index < visibleTokens.length - 1;\n\n return (\n <div\n key={token.id}\n className={`token-wrapper ${tokenClassName} ${isExiting ? 'exit-active' : ''}`}\n ref={el => registerElement(token.id, el as HTMLElement)}\n >\n <SlidingText\n text={token.text}\n mode={isExiting ? 'none' : textAnimationMode}\n direction={textDirection}\n staggerDelay={textStaggerDelay}\n duration={ANIMATION_DEFAULTS.DURATION_ENTER}\n blur={PRESETS.newToken.blur}\n widthAnimation={!isExiting && enableWidthAnimation}\n initial={isExiting ? false : 'initial'}\n animate=\"animate\"\n />\n {showSeparator && (\n <span className={`token-separator ${separatorClassName}`}>\n {separator}\n </span>\n )}\n </div>\n );\n })}\n\n {(overflowCount > 0 || isOverflowExiting) && (\n <div\n className={`token-overflow ${tokenClassName} ${isOverflowEntering ? 'entering' : ''} ${isOverflowExiting ? 'exiting' : ''}`}\n ref={el => registerElement('overflow-counter', el as HTMLElement)}\n >\n <span className={`token-separator ${separatorClassName}`}>+</span>\n <SlidingNumber\n value={overflowCount}\n duration={ANIMATION_DEFAULTS.DURATION_ENTER}\n fontSize=\"inherit\"\n fontWeight=\"inherit\"\n color=\"inherit\"\n />\n <SlidingText\n text=\" more\"\n mode={textAnimationMode}\n direction={textDirection}\n staggerDelay={textStaggerDelay}\n duration={isOverflowExiting ? ANIMATION_DEFAULTS.DURATION_EXIT : ANIMATION_DEFAULTS.DURATION_ENTER}\n blur={PRESETS.newToken.blur}\n initial={isOverflowEntering ? 'initial' : false}\n animate=\"animate\"\n />\n </div>\n )}\n </div>\n );\n};\n","import React, { createContext, useContext, useState, useCallback, useRef, useMemo } from 'react';\n\n// ============================================\n// ENHANCED DEBUG EVENT TYPES\n// ============================================\n\n// Timing data for measuring actual vs expected animation duration\nexport interface TimingData {\n startTime: number;\n endTime?: number;\n expectedDuration: number;\n actualDuration?: number;\n deviation?: number;\n deviationPercent?: number;\n}\n\n// Style comparison data\nexport interface StyleData {\n property: string;\n expected: string;\n actual: string;\n matches: boolean;\n}\n\n// Position data with full DOMRect info\nexport interface PositionData {\n element: string;\n x: number;\n y: number;\n width: number;\n height: number;\n delta?: { x: number; y: number };\n}\n\n// Animation metadata\nexport interface AnimationData {\n name: string;\n phase: 'start' | 'running' | 'complete' | 'cancelled';\n progress?: number;\n easing?: string;\n fill?: string;\n}\n\n// All event types\nexport type DebugEventType =\n // Token events\n | 'token-add'\n | 'token-remove'\n | 'token-reorder'\n | 'token-exit-start'\n | 'token-exit-complete'\n | 'token-dom-remove'\n | 'overflow-token-remove'\n // FLIP events\n | 'flip-animation'\n | 'flip-animation-complete'\n | 'flip-all-animations-complete'\n | 'flip-executing-callback'\n | 'flip-measure-start'\n | 'flip-position-measured'\n | 'flip-invalid-rect'\n | 'flip-invalid-delta'\n | 'flip-manual-trigger'\n | 'flip-capture-positions'\n | 'flip-position-captured'\n // WAAPI events\n | 'waapi-exit-start'\n | 'waapi-exit-complete'\n | 'waapi-flip-animation'\n // Separated timing events\n | 'exit-fade-complete'\n | 'orchestration-complete'\n // Enhanced quantitative events\n | 'animation-start-detailed'\n | 'animation-complete-detailed'\n | 'animation-timing'\n | 'style-capture'\n | 'style-mismatch'\n | 'position-capture'\n | 'position-delta'\n | 'choreography-overlap'\n | 'choreography-sequence'\n // Enter animation events\n | 'text-enter-start'\n | 'text-enter-complete'\n // Legacy events\n | 'triggering-flip-before-absolute'\n | 'state-change'\n | 'render'\n | 'animation-complete-called'\n | 'scheduling-raf'\n | 'raf-executed'\n | 'component-unmounted'\n | 'token-removing-from-layout'\n | 'exit-completed-ids-updated'\n | 'exit-completed-change'\n | 'registering-callback'\n | 'callback-fired';\n\nexport interface DebugEvent {\n timestamp: number;\n type: DebugEventType;\n source: string;\n message: string;\n\n // Enhanced quantitative data (optional)\n timing?: TimingData;\n styles?: StyleData[];\n position?: PositionData;\n animation?: AnimationData;\n\n // Generic data field (existing)\n data?: Record<string, unknown>;\n}\n\ninterface DebugContextValue {\n events: DebugEvent[];\n isEnabled: boolean;\n enableDebug: () => void;\n disableDebug: () => void;\n toggleDebug: () => void;\n logEvent: (event: Omit<DebugEvent, 'timestamp'>) => void;\n clearEvents: () => void;\n getEventLog: () => string;\n exportToCSV: () => string;\n}\n\nconst DebugContext = createContext<DebugContextValue | null>(null);\n\nexport const useDebug = () => {\n const context = useContext(DebugContext);\n if (!context) {\n throw new Error('useDebug must be used within DebugProvider');\n }\n return context;\n};\n\nexport const DebugProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n const [events, setEvents] = useState<DebugEvent[]>([]);\n const [isEnabled, setIsEnabled] = useState(true);\n const isEnabledRef = useRef(isEnabled);\n\n // Keep ref in sync with state\n isEnabledRef.current = isEnabled;\n\n const logEvent = useCallback((event: Omit<DebugEvent, 'timestamp'>) => {\n if (!__DEBUG__) return; // Guard: skip entirely in production\n\n // Use ref to check if enabled to avoid dependency on isEnabled state\n if (!isEnabledRef.current) return;\n\n const fullEvent: DebugEvent = {\n ...event,\n timestamp: Date.now(),\n };\n\n // Use functional update to avoid dependency on events\n setEvents(prev => [...prev, fullEvent]);\n\n // Console logging with color coding\n const colors: Record<string, string> = {\n // Token events\n 'token-add': '#22c55e',\n 'token-remove': '#ef4444',\n 'token-reorder': '#f59e0b',\n 'token-exit-start': '#f97316',\n 'token-exit-complete': '#8b5cf6',\n 'token-dom-remove': '#dc2626',\n // FLIP events\n 'flip-animation': '#3b82f6',\n 'flip-animation-complete': '#06b6d4',\n 'flip-all-animations-complete': '#10b981',\n 'flip-executing-callback': '#14b8a6',\n 'flip-measure-start': '#0ea5e9',\n 'flip-position-measured': '#3b82f6',\n 'flip-invalid-rect': '#f59e0b',\n 'flip-invalid-delta': '#ef4444',\n 'flip-manual-trigger': '#06b6d4',\n 'flip-capture-positions': '#8b5cf6',\n 'flip-position-captured': '#a78bfa',\n // WAAPI events\n 'waapi-exit-start': '#f97316',\n 'waapi-exit-complete': '#22c55e',\n 'waapi-flip-animation': '#3b82f6',\n // Separated timing events\n 'exit-fade-complete': '#f97316',\n 'orchestration-complete': '#10b981',\n // Enhanced quantitative events\n 'animation-start-detailed': '#f97316',\n 'animation-complete-detailed': '#22c55e',\n 'animation-timing': '#06b6d4',\n 'style-capture': '#8b5cf6',\n 'style-mismatch': '#ef4444',\n 'position-capture': '#3b82f6',\n 'position-delta': '#0ea5e9',\n 'choreography-overlap': '#f59e0b',\n 'choreography-sequence': '#14b8a6',\n // Enter animation events\n 'text-enter-start': '#22c55e',\n 'text-enter-complete': '#10b981',\n // Legacy events\n 'triggering-flip-before-absolute': '#f97316',\n 'state-change': '#06b6d4',\n 'render': '#6b7280',\n 'animation-complete-called': '#8b5cf6',\n 'scheduling-raf': '#a855f7',\n 'raf-executed': '#c084fc',\n 'component-unmounted': '#ef4444',\n 'token-removing-from-layout': '#f97316',\n 'exit-completed-ids-updated': '#fb923c',\n 'exit-completed-change': '#f59e0b',\n 'registering-callback': '#34d399',\n 'callback-fired': '#10b981',\n };\n\n console.log(\n `%c[${event.type}] %c${event.source}%c: ${event.message}`,\n `color: ${colors[event.type] || '#6b7280'}; font-weight: bold`,\n 'color: #9ca3af',\n 'color: inherit',\n event.data || ''\n );\n }, []); // Empty deps - stable reference\n\n const clearEvents = useCallback(() => {\n if (!__DEBUG__) return;\n setEvents([]);\n }, []);\n\n const enableDebug = useCallback(() => {\n if (!__DEBUG__) return;\n setIsEnabled(true);\n }, []);\n\n const disableDebug = useCallback(() => {\n if (!__DEBUG__) return;\n setIsEnabled(false);\n }, []);\n\n const toggleDebug = useCallback(() => {\n if (!__DEBUG__) return;\n setIsEnabled(prev => !prev);\n }, []);\n\n const exportToCSV = useCallback(() => {\n if (!__DEBUG__) return '';\n\n // CSV Header - includes all quantitative data\n const headers = [\n 'Index', 'Timestamp', 'Time', 'Type', 'Source', 'Message',\n 'Expected_Duration', 'Actual_Duration', 'Deviation', 'Deviation_Percent',\n 'Animation_Name', 'Animation_Phase', 'Animation_Easing',\n 'Element', 'Pos_X', 'Pos_Y', 'Width', 'Height', 'Delta_X', 'Delta_Y',\n 'Style_Checks', 'Style_Matches', 'Style_Mismatches',\n 'Data'\n ];\n\n // CSV Rows - includes all captured data\n const rows = events.map((e, i) => {\n const time = new Date(e.timestamp).toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit'\n });\n\n // Flatten data object into key=value pairs\n const dataStr = e.data\n ? Object.entries(e.data)\n .map(([key, val]) => {\n if (Array.isArray(val)) {\n return `${key}=[${val.join(',')}]`;\n } else if (typeof val === 'object' && val !== null) {\n return `${key}=${JSON.stringify(val)}`;\n }\n return `${key}=${val}`;\n })\n .join('; ')\n : '';\n\n // Style analysis\n const styleMatches = e.styles?.filter(s => s.matches).length ?? '';\n const styleMismatches = e.styles?.filter(s => !s.matches).length ?? '';\n\n return [\n i + 1,\n e.timestamp,\n time,\n e.type,\n e.source,\n e.message,\n e.timing?.expectedDuration ?? '',\n e.timing?.actualDuration?.toFixed(2) ?? '',\n e.timing?.deviation?.toFixed(2) ?? '',\n e.timing?.deviationPercent?.toFixed(2) ?? '',\n e.animation?.name ?? '',\n e.animation?.phase ?? '',\n e.animation?.easing ?? '',\n e.position?.element ?? '',\n e.position?.x?.toFixed(2) ?? '',\n e.position?.y?.toFixed(2) ?? '',\n e.position?.width?.toFixed(2) ?? '',\n e.position?.height?.toFixed(2) ?? '',\n e.position?.delta?.x?.toFixed(2) ?? '',\n e.position?.delta?.y?.toFixed(2) ?? '',\n e.styles?.length ?? '',\n styleMatches,\n styleMismatches,\n dataStr\n ];\n });\n\n // Convert to CSV format\n const csvContent = [\n headers.join(','),\n ...rows.map(row =>\n row.map(cell => {\n const cellStr = String(cell);\n if (cellStr.includes(',') || cellStr.includes('\"') || cellStr.includes('\\n')) {\n return `\"${cellStr.replace(/\"/g, '\"\"')}\"`;\n }\n return cellStr;\n }).join(',')\n )\n ].join('\\n');\n\n return csvContent;\n }, [events]);\n\n const getEventLog = useCallback(() => {\n if (!__DEBUG__) return '';\n\n return events.map((e, i) => {\n const time = new Date(e.timestamp).toLocaleTimeString();\n const parts: string[] = [\n `[${i + 1}] ${time} [${e.type}] ${e.source}: ${e.message}`\n ];\n\n if (e.timing) {\n const t = e.timing;\n parts.push(` Timing: ${t.expectedDuration}ms expected → ${t.actualDuration?.toFixed(1) ?? '?'}ms actual (${t.deviation && t.deviation >= 0 ? '+' : ''}${t.deviation?.toFixed(1) ?? '?'}ms)`);\n }\n\n if (e.animation) {\n parts.push(` Animation: ${e.animation.name} [${e.animation.phase}] easing=${e.animation.easing || 'default'}`);\n }\n\n if (e.position) {\n const p = e.position;\n let posStr = ` Position: ${p.element} @ (${p.x.toFixed(0)}, ${p.y.toFixed(0)}) ${p.width.toFixed(0)}x${p.height.toFixed(0)}`;\n if (p.delta) {\n posStr += ` Δ(${p.delta.x.toFixed(1)}, ${p.delta.y.toFixed(1)})`;\n }\n parts.push(posStr);\n }\n\n if (e.styles && e.styles.length > 0) {\n const matches = e.styles.filter(s => s.matches).length;\n const mismatches = e.styles.filter(s => !s.matches).length;\n parts.push(` Styles: ${e.styles.length} checks (${matches} match, ${mismatches} mismatch)`);\n e.styles.filter(s => !s.matches).forEach(s => {\n parts.push(` ✗ ${s.property}: expected \"${s.expected}\" got \"${s.actual}\"`);\n });\n }\n\n if (e.data && Object.keys(e.data).length > 0) {\n parts.push(` Data: ${JSON.stringify(e.data, null, 2).split('\\n').join('\\n ')}`);\n }\n\n return parts.join('\\n');\n }).join('\\n\\n');\n }, [events]);\n\n const contextValue = useMemo(() => ({\n events: __DEBUG__ ? events : [],\n isEnabled: __DEBUG__ ? isEnabled : false,\n enableDebug,\n disableDebug,\n toggleDebug,\n logEvent,\n clearEvents,\n getEventLog,\n exportToCSV,\n }), [events, isEnabled, enableDebug, disableDebug, toggleDebug, logEvent, clearEvents, getEventLog, exportToCSV]);\n\n return (\n <DebugContext.Provider value={contextValue}>\n {children}\n </DebugContext.Provider>\n );\n};\n","// ============================================\n// CHOREOGRAPHY TRACKER\n// Track animation timeline and detect overlaps\n// ============================================\n\nexport interface AnimationInfo {\n id: string;\n type: 'exit-fade' | 'exit-collapse' | 'flip' | 'enter' | 'width-collapse';\n elementId: string;\n startTime: number;\n expectedDuration: number;\n endTime?: number;\n actualDuration?: number;\n}\n\nexport interface TimelineEvent {\n time: number;\n event: 'animation-start' | 'animation-end' | 'overlap-detected';\n animationId: string;\n type?: string;\n overlappingWith?: string[];\n expectedDuration?: number;\n actualDuration?: number;\n deviation?: number;\n}\n\nexport interface OverlapInfo {\n animation1: string;\n animation2: string;\n overlapStart: number;\n overlapDuration: number;\n}\n\nexport interface ChoreographySummary {\n totalAnimations: number;\n totalDuration: number;\n overlaps: OverlapInfo[];\n timeline: TimelineEvent[];\n activeAnimations: AnimationInfo[];\n}\n\n/**\n * ChoreographyTracker - Singleton for tracking animation choreography\n * Detects overlaps, generates timeline, measures actual vs expected timing\n */\nclass ChoreographyTrackerClass {\n private activeAnimations: Map<string, AnimationInfo> = new Map();\n private timeline: TimelineEvent[] = [];\n private completedAnimations: AnimationInfo[] = [];\n private sessionStartTime: number = 0;\n\n /**\n * Start a new tracking session (call when debug panel is cleared)\n */\n startSession(): void {\n if (!__DEBUG__) return;\n\n this.activeAnimations.clear();\n this.timeline = [];\n this.completedAnimations = [];\n this.sessionStartTime = performance.now();\n }\n\n /**\n * Get relative time since session start\n */\n private getRelativeTime(): number {\n return Math.round((performance.now() - this.sessionStartTime) * 100) / 100;\n }\n\n /**\n * Start tracking an animation\n */\n startAnimation(\n id: string,\n type: AnimationInfo['type'],\n elementId: string,\n expectedDuration: number\n ): void {\n if (!__DEBUG__) return;\n\n const startTime = this.getRelativeTime();\n\n const info: AnimationInfo = {\n id,\n type,\n elementId,\n startTime,\n expectedDuration,\n };\n\n this.activeAnimations.set(id, info);\n\n // Detect overlaps with currently running animations\n const overlaps = this.detectOverlaps(id);\n\n // Log start event\n this.timeline.push({\n time: startTime,\n event: 'animation-start',\n animationId: id,\n type,\n expectedDuration,\n overlappingWith: overlaps.length > 0 ? overlaps : undefined,\n });\n\n // Log overlap event if detected\n if (overlaps.length > 0) {\n this.timeline.push({\n time: startTime,\n event: 'overlap-detected',\n animationId: id,\n overlappingWith: overlaps,\n });\n }\n }\n\n /**\n * End tracking an animation\n */\n endAnimation(id: string): AnimationInfo | undefined {\n if (!__DEBUG__) return undefined;\n\n const info = this.activeAnimations.get(id);\n if (!info) return undefined;\n\n const endTime = this.getRelativeTime();\n const actualDuration = endTime - info.startTime;\n\n info.endTime = endTime;\n info.actualDuration = Math.round(actualDuration * 100) / 100;\n\n this.timeline.push({\n time: endTime,\n event: 'animation-end',\n animationId: id,\n type: info.type,\n expectedDuration: info.expectedDuration,\n actualDuration: info.actualDuration,\n deviation: Math.round((info.actualDuration - info.expectedDuration) * 100) / 100,\n });\n\n this.completedAnimations.push(info);\n this.activeAnimations.delete(id);\n\n return info;\n }\n\n /**\n * Detect which animations are overlapping with the given animation\n */\n private detectOverlaps(newAnimationId: string): string[] {\n const overlaps: string[] = [];\n\n this.activeAnimations.forEach((info, id) => {\n if (id !== newAnimationId) {\n overlaps.push(`${info.type}:${info.elementId}`);\n }\n });\n\n return overlaps;\n }\n\n /**\n * Get all overlap pairs with duration\n */\n getOverlaps(): OverlapInfo[] {\n if (!__DEBUG__) return [];\n\n const overlaps: OverlapInfo[] = [];\n const allAnimations = [...this.completedAnimations];\n\n // Also include active animations with estimated end time\n this.activeAnimations.forEach(info => {\n allAnimations.push({\n ...info,\n endTime: info.startTime + info.expectedDuration,\n actualDuration: info.expectedDuration,\n });\n });\n\n // Find overlapping pairs\n for (let i = 0; i < allAnimations.length; i++) {\n for (let j = i + 1; j < allAnimations.length; j++) {\n const a = allAnimations[i];\n const b = allAnimations[j];\n\n // Skip if either is undefined (TypeScript safety)\n if (!a || !b) continue;\n\n const aEnd = a.endTime || (a.startTime + a.expectedDuration);\n const bEnd = b.endTime || (b.startTime + b.expectedDuration);\n\n // Check if they overlap\n if (a.startTime < bEnd && aEnd > b.startTime) {\n const overlapStart = Math.max(a.startTime, b.startTime);\n const overlapEnd = Math.min(aEnd, bEnd);\n const overlapDuration = overlapEnd - overlapStart;\n\n if (overlapDuration > 0) {\n overlaps.push({\n animation1: `${a.type}:${a.elementId}`,\n animation2: `${b.type}:${b.elementId}`,\n overlapStart: Math.round(overlapStart * 100) / 100,\n overlapDuration: Math.round(overlapDuration * 100) / 100,\n });\n }\n }\n }\n }\n\n return overlaps;\n }\n\n /**\n * Get current timeline\n */\n getTimeline(): TimelineEvent[] {\n if (!__DEBUG__) return [];\n return [...this.timeline];\n }\n\n /**\n * Get active animation count\n */\n getActiveCount(): number {\n if (!__DEBUG__) return 0;\n return this.activeAnimations.size;\n }\n\n /**\n * Get active animations\n */\n getActiveAnimations(): AnimationInfo[] {\n if (!__DEBUG__) return [];\n return Array.from(this.activeAnimations.values());\n }\n\n /**\n * Get completed animations\n */\n getCompletedAnimations(): AnimationInfo[] {\n if (!__DEBUG__) return [];\n return [...this.completedAnimations];\n }\n\n /**\n * Get full choreography summary\n */\n getSummary(): ChoreographySummary {\n if (!__DEBUG__) {\n return {\n totalAnimations: 0,\n totalDuration: 0,\n overlaps: [],\n timeline: [],\n activeAnimations: [],\n };\n }\n\n const allAnimations = [...this.completedAnimations, ...this.getActiveAnimations()];\n\n let totalDuration = 0;\n if (allAnimations.length > 0) {\n const minStart = Math.min(...allAnimations.map(a => a.startTime));\n const maxEnd = Math.max(\n ...allAnimations.map(a => a.endTime || (a.startTime + a.expectedDuration))\n );\n totalDuration = maxEnd - minStart;\n }\n\n return {\n totalAnimations: allAnimations.length,\n totalDuration: Math.round(totalDuration * 100) / 100,\n overlaps: this.getOverlaps(),\n timeline: this.getTimeline(),\n activeAnimations: this.getActiveAnimations(),\n };\n }\n\n /**\n * Get timeline for visualization (normalized to 0-100%)\n */\n getTimelineForVisualization(): Array<{\n id: string;\n type: string;\n elementId: string;\n startPercent: number;\n widthPercent: number;\n duration: number;\n isActive: boolean;\n }> {\n if (!__DEBUG__) return [];\n\n const summary = this.getSummary();\n if (summary.totalDuration === 0) return [];\n\n const allAnimations = [...this.completedAnimations, ...this.getActiveAnimations()];\n const minStart = Math.min(...allAnimations.map(a => a.startTime));\n\n return allAnimations.map(anim => {\n const duration = anim.actualDuration || anim.expectedDuration;\n const startPercent = ((anim.startTime - minStart) / summary.totalDuration) * 100;\n const widthPercent = (duration / summary.totalDuration) * 100;\n\n return {\n id: anim.id,\n type: anim.type,\n elementId: anim.elementId,\n startPercent: Math.round(startPercent * 100) / 100,\n widthPercent: Math.round(widthPercent * 100) / 100,\n duration: Math.round(duration * 100) / 100,\n isActive: this.activeAnimations.has(anim.id),\n };\n });\n }\n}\n\n// Export singleton instance\nexport const choreographyTracker = new ChoreographyTrackerClass();\n\n// Export class for testing\nexport { ChoreographyTrackerClass };\n","// ============================================\n// DEBUG CAPTURE UTILITIES\n// Functions for capturing quantitative animation data\n// ============================================\n\n// Types\nexport interface StyleCapture {\n opacity: string;\n transform: string;\n filter: string;\n width: string;\n height: string;\n marginRight: string;\n marginLeft: string;\n position: string;\n visibility: string;\n pointerEvents: string;\n}\n\nexport interface PositionCapture {\n x: number;\n y: number;\n width: number;\n height: number;\n top: number;\n left: number;\n right: number;\n bottom: number;\n}\n\nexport interface StyleComparison {\n property: string;\n expected: string;\n actual: string;\n matches: boolean;\n}\n\nexport interface TimingResult {\n startTime: number;\n endTime: number;\n expectedDuration: number;\n actualDuration: number;\n deviation: number;\n deviationPercent: number;\n}\n\nexport interface AnimationTimer {\n start: number;\n expectedDuration: number;\n end: () => TimingResult;\n}\n\n// ============================================\n// STYLE CAPTURE\n// ============================================\n\n/**\n * Capture relevant computed styles from an element\n * These are the styles we animate and need to verify\n */\nexport function captureComputedStyles(el: HTMLElement): StyleCapture {\n const computed = getComputedStyle(el);\n return {\n opacity: computed.opacity,\n transform: computed.transform,\n filter: computed.filter,\n width: computed.width,\n height: computed.height,\n marginRight: computed.marginRight,\n marginLeft: computed.marginLeft,\n position: computed.position,\n visibility: computed.visibility,\n pointerEvents: computed.pointerEvents,\n };\n}\n\n/**\n * Capture styles as a simple key-value object for logging\n */\nexport function captureStylesForLog(el: HTMLElement): Record<string, string> {\n const styles = captureComputedStyles(el);\n return {\n opacity: styles.opacity,\n transform: styles.transform === 'none' ? 'none' : styles.transform,\n filter: styles.filter === 'none' ? 'none' : styles.filter,\n width: styles.width,\n marginRight: styles.marginRight,\n position: styles.position,\n };\n}\n\n// ============================================\n// POSITION CAPTURE\n// ============================================\n\n/**\n * Capture complete position information from DOMRect\n */\nexport function capturePosition(el: HTMLElement): PositionCapture {\n const rect = el.getBoundingClientRect();\n return {\n x: Math.round(rect.x * 100) / 100,\n y: Math.round(rect.y * 100) / 100,\n width: Math.round(rect.width * 100) / 100,\n height: Math.round(rect.height * 100) / 100,\n top: Math.round(rect.top * 100) / 100,\n left: Math.round(rect.left * 100) / 100,\n right: Math.round(rect.right * 100) / 100,\n bottom: Math.round(rect.bottom * 100) / 100,\n };\n}\n\n/**\n * Capture position as simple object for logging\n */\nexport function capturePositionForLog(el: HTMLElement): Record<string, number> {\n const pos = capturePosition(el);\n return {\n x: pos.x,\n y: pos.y,\n w: pos.width,\n h: pos.height,\n };\n}\n\n/**\n * Calculate delta between two positions\n */\nexport function calculatePositionDelta(\n before: PositionCapture,\n after: PositionCapture\n): { deltaX: number; deltaY: number; deltaWidth: number; deltaHeight: number } {\n return {\n deltaX: Math.round((before.left - after.left) * 100) / 100,\n deltaY: Math.round((before.top - after.top) * 100) / 100,\n deltaWidth: Math.round((before.width - after.width) * 100) / 100,\n deltaHeight: Math.round((before.height - after.height) * 100) / 100,\n };\n}\n\n// ============================================\n// STYLE COMPARISON\n// ============================================\n\n/**\n * Compare expected styles vs actual computed styles\n * Used to verify animations applied correctly\n */\nexport function compareStyles(\n expected: Record<string, string>,\n el: HTMLElement\n): StyleComparison[] {\n const actual = captureComputedStyles(el);\n\n return Object.entries(expected).map(([prop, expectedVal]) => {\n const actualVal = actual[prop as keyof StyleCapture] || '';\n\n // Normalize values for comparison\n const normalizedExpected = normalizeStyleValue(prop, expectedVal);\n const normalizedActual = normalizeStyleValue(prop, actualVal);\n\n return {\n property: prop,\n expected: expectedVal,\n actual: actualVal,\n matches: normalizedExpected === normalizedActual,\n };\n });\n}\n\n/**\n * Normalize style values for comparison\n * Handles browser quirks and formatting differences\n */\nfunction normalizeStyleValue(property: string, value: string): string {\n if (!value) return '';\n\n // Normalize opacity (some browsers return \"1\" vs \"1.0\")\n if (property === 'opacity') {\n return parseFloat(value).toString();\n }\n\n // Normalize transform (handle matrix vs translate)\n if (property === 'transform') {\n if (value === 'none') return 'none';\n // Extract translation values if present\n const match = value.match(/matrix\\(([^)]+)\\)/);\n if (match && match[1]) {\n const values = match[1].split(',').map(v => parseFloat(v.trim()));\n // matrix(a, b, c, d, tx, ty) - tx is values[4], ty is values[5]\n const tx = values[4];\n const ty = values[5];\n if (tx !== undefined && ty !== undefined) {\n return `translate(${Math.round(tx)}px, ${Math.round(ty)}px)`;\n }\n }\n return value;\n }\n\n // Normalize width/height (round to nearest pixel)\n if (property === 'width' || property === 'height' || property.includes('margin')) {\n const num = parseFloat(value);\n if (!isNaN(num)) {\n return `${Math.round(num)}px`;\n }\n }\n\n // Normalize filter blur\n if (property === 'filter') {\n if (value === 'none') return 'none';\n const blurMatch = value.match(/blur\\(([^)]+)\\)/);\n if (blurMatch && blurMatch[1]) {\n const blurValue = parseFloat(blurMatch[1]);\n return `blur(${Math.round(blurValue)}px)`;\n }\n }\n\n return value;\n}\n\n// ============================================\n// TIMING\n// ============================================\n\n/**\n * Create a timer for measuring actual animation duration\n * Uses performance.now() for high precision\n */\nexport function createAnimationTimer(expectedDuration: number): AnimationTimer {\n const startTime = performance.now();\n\n return {\n start: startTime,\n expectedDuration,\n end: () => {\n const endTime = performance.now();\n const actualDuration = endTime - startTime;\n const deviation = actualDuration - expectedDuration;\n\n return {\n startTime: Math.round(startTime * 100) / 100,\n endTime: Math.round(endTime * 100) / 100,\n expectedDuration,\n actualDuration: Math.round(actualDuration * 100) / 100,\n deviation: Math.round(deviation * 100) / 100,\n deviationPercent: Math.round((deviation / expectedDuration) * 10000) / 100,\n };\n },\n };\n}\n\n/**\n * Format timing result for display\n */\nexport function formatTimingResult(timing: TimingResult): string {\n const sign = timing.deviation >= 0 ? '+' : '';\n const status = Math.abs(timing.deviation) < 10 ? '✅' : '⚠️';\n return `Expected: ${timing.expectedDuration}ms | Actual: ${timing.actualDuration}ms | Deviation: ${sign}${timing.deviation}ms ${status}`;\n}\n\n// ============================================\n// ANIMATION INFO HELPERS\n// ============================================\n\n/**\n * Extract animation info from WAAPI Animation object\n */\nexport function captureAnimationInfo(animation: Animation): Record<string, unknown> {\n const timing = animation.effect?.getTiming?.();\n return {\n id: animation.id,\n playState: animation.playState,\n currentTime: animation.currentTime,\n playbackRate: animation.playbackRate,\n pending: animation.pending,\n duration: timing?.duration,\n easing: timing?.easing,\n fill: timing?.fill,\n };\n}\n\n/**\n * Capture all active animations on an element\n */\nexport function captureElementAnimations(el: HTMLElement): Record<string, unknown>[] {\n const animations = el.getAnimations();\n return animations.map(captureAnimationInfo);\n}\n"]}
|