torph 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Torph
2
2
 
3
- Animated text morphing component for React, Vue, and Svelte.
3
+ Dependency-free animated text morphing component for React, Vue, Svelte, and vanilla JavaScript.
4
4
 
5
5
  ## Installation
6
6
 
@@ -124,6 +124,31 @@ const morph = new TextMorph({
124
124
  morph.update("Hello World");
125
125
  ```
126
126
 
127
+ ## Spring Animations
128
+
129
+ Pass spring parameters to `ease` for physics-based easing. The duration is computed automatically from the spring physics.
130
+
131
+ ```tsx
132
+ import { TextMorph } from "torph/react";
133
+
134
+ function App() {
135
+ const [text, setText] = useState("Hello World");
136
+
137
+ return (
138
+ <TextMorph ease={{ stiffness: 200, damping: 20 }}>{text}</TextMorph>
139
+ );
140
+ }
141
+ ```
142
+
143
+ ### Spring Parameters
144
+
145
+ | Parameter | Type | Default | Description |
146
+ | ----------- | -------- | ------- | ----------------------------------------- |
147
+ | `stiffness` | `number` | `100` | Spring stiffness coefficient |
148
+ | `damping` | `number` | `10` | Damping coefficient |
149
+ | `mass` | `number` | `1` | Mass of the spring |
150
+ | `precision` | `number` | `0.001` | Threshold for determining settled position |
151
+
127
152
  ## API
128
153
 
129
154
  ### Options
@@ -131,17 +156,18 @@ morph.update("Hello World");
131
156
  All components accept the following props/options:
132
157
 
133
158
  - `text` / `children: string` - The text to display (required)
134
- - `duration?: number` - Animation duration in milliseconds (default: 400)
135
- - `ease?: string` - CSS easing function (default: "cubic-bezier(0.19, 1, 0.22, 1)")
136
- - `locale?: Intl.LocalesArgument` - Locale for text segmentation (default: "en")
159
+ - `duration?: number` - Animation duration in milliseconds (default: `400`)
160
+ - `ease?: string | SpringParams` - CSS easing function or spring parameters (default: `"cubic-bezier(0.19, 1, 0.22, 1)"`)
161
+ - `scale?: boolean` - Enable scale animation on exiting segments (default: `true`)
162
+ - `locale?: Intl.LocalesArgument` - Locale for text segmentation (default: `"en"`)
137
163
  - `debug?: boolean` - Enable debug mode with visual indicators
138
- - `disabled?: boolean` - Disable all morphing animations (default: false)
139
- - `respectReducedMotion?: boolean` - Respect user's prefers-reduced-motion setting (default: true)
164
+ - `disabled?: boolean` - Disable all morphing animations (default: `false`)
165
+ - `respectReducedMotion?: boolean` - Respect user's prefers-reduced-motion setting (default: `true`)
140
166
  - `onAnimationStart?: () => void` - Callback fired when animation begins
141
167
  - `onAnimationComplete?: () => void` - Callback fired when animation completes
142
168
  - `className?: string` - CSS class name (React/Vue: `class`)
143
169
  - `style?: object | string` - Inline styles
144
- - `as?: string` - HTML element type (default: "div")
170
+ - `as?: string` - HTML element type (default: `"span"`)
145
171
 
146
172
  ## Found this useful?
147
173
 
package/dist/index.d.mts CHANGED
@@ -1,16 +1,34 @@
1
+ interface SpringParams {
2
+ stiffness?: number;
3
+ damping?: number;
4
+ mass?: number;
5
+ precision?: number;
6
+ }
7
+
1
8
  interface TextMorphOptions {
2
9
  debug?: boolean;
3
10
  element: HTMLElement;
4
11
  locale?: Intl.LocalesArgument;
5
12
  scale?: boolean;
6
13
  duration?: number;
7
- ease?: string;
14
+ ease?: string | SpringParams;
8
15
  disabled?: boolean;
9
16
  respectReducedMotion?: boolean;
10
17
  onAnimationStart?: () => void;
11
18
  onAnimationComplete?: () => void;
12
19
  }
13
20
 
21
+ declare class MorphController {
22
+ private instance;
23
+ private lastText;
24
+ private configKey;
25
+ attach(element: HTMLElement, options: Omit<TextMorphOptions, "element">): void;
26
+ update(text: string): void;
27
+ needsRecreate(options: Omit<TextMorphOptions, "element">): boolean;
28
+ destroy(): void;
29
+ static serializeConfig(options: Omit<TextMorphOptions, "element">): string;
30
+ }
31
+
14
32
  declare const DEFAULT_AS = "span";
15
33
  declare const DEFAULT_TEXT_MORPH_OPTIONS: {
16
34
  readonly debug: false;
@@ -28,22 +46,13 @@ declare class TextMorph {
28
46
  private currentMeasures;
29
47
  private prevMeasures;
30
48
  private isInitialRender;
31
- private prefersReducedMotion;
32
- private mediaQuery?;
33
- static styleEl: HTMLStyleElement;
49
+ private reducedMotion;
34
50
  constructor(options: TextMorphOptions);
35
51
  destroy(): void;
36
- private handleMediaQueryChange;
37
52
  private isDisabled;
38
53
  update(value: HTMLElement | string): void;
39
54
  private createTextGroup;
40
- private measure;
41
55
  private updateStyles;
42
- private addStyles;
43
- private removeStyles;
44
- private blocks;
45
- private blocksFallback;
46
- private log;
47
56
  }
48
57
 
49
- export { DEFAULT_AS, DEFAULT_TEXT_MORPH_OPTIONS, TextMorph, type TextMorphOptions };
58
+ export { DEFAULT_AS, DEFAULT_TEXT_MORPH_OPTIONS, MorphController, type SpringParams, TextMorph, type TextMorphOptions };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,34 @@
1
+ interface SpringParams {
2
+ stiffness?: number;
3
+ damping?: number;
4
+ mass?: number;
5
+ precision?: number;
6
+ }
7
+
1
8
  interface TextMorphOptions {
2
9
  debug?: boolean;
3
10
  element: HTMLElement;
4
11
  locale?: Intl.LocalesArgument;
5
12
  scale?: boolean;
6
13
  duration?: number;
7
- ease?: string;
14
+ ease?: string | SpringParams;
8
15
  disabled?: boolean;
9
16
  respectReducedMotion?: boolean;
10
17
  onAnimationStart?: () => void;
11
18
  onAnimationComplete?: () => void;
12
19
  }
13
20
 
21
+ declare class MorphController {
22
+ private instance;
23
+ private lastText;
24
+ private configKey;
25
+ attach(element: HTMLElement, options: Omit<TextMorphOptions, "element">): void;
26
+ update(text: string): void;
27
+ needsRecreate(options: Omit<TextMorphOptions, "element">): boolean;
28
+ destroy(): void;
29
+ static serializeConfig(options: Omit<TextMorphOptions, "element">): string;
30
+ }
31
+
14
32
  declare const DEFAULT_AS = "span";
15
33
  declare const DEFAULT_TEXT_MORPH_OPTIONS: {
16
34
  readonly debug: false;
@@ -28,22 +46,13 @@ declare class TextMorph {
28
46
  private currentMeasures;
29
47
  private prevMeasures;
30
48
  private isInitialRender;
31
- private prefersReducedMotion;
32
- private mediaQuery?;
33
- static styleEl: HTMLStyleElement;
49
+ private reducedMotion;
34
50
  constructor(options: TextMorphOptions);
35
51
  destroy(): void;
36
- private handleMediaQueryChange;
37
52
  private isDisabled;
38
53
  update(value: HTMLElement | string): void;
39
54
  private createTextGroup;
40
- private measure;
41
55
  private updateStyles;
42
- private addStyles;
43
- private removeStyles;
44
- private blocks;
45
- private blocksFallback;
46
- private log;
47
56
  }
48
57
 
49
- export { DEFAULT_AS, DEFAULT_TEXT_MORPH_OPTIONS, TextMorph, type TextMorphOptions };
58
+ export { DEFAULT_AS, DEFAULT_TEXT_MORPH_OPTIONS, MorphController, type SpringParams, TextMorph, type TextMorphOptions };
package/dist/index.js CHANGED
@@ -1,25 +1,23 @@
1
- 'use strict';var T="span",A={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},b=class g{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;prefersReducedMotion=false;mediaQuery;static styleEl;constructor(e){this.options={...A,...e},this.element=e.element,typeof window<"u"&&this.options.respectReducedMotion&&(this.mediaQuery=window.matchMedia("(prefers-reduced-motion: reduce)"),this.prefersReducedMotion=this.mediaQuery.matches,this.mediaQuery.addEventListener("change",this.handleMediaQueryChange)),this.isDisabled()||(this.element.setAttribute("torph-root",""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,e.debug&&this.element.setAttribute("torph-debug","")),this.data="",this.isDisabled()||this.addStyles();}destroy(){this.mediaQuery&&this.mediaQuery.removeEventListener("change",this.handleMediaQueryChange),this.element.getAnimations().forEach(e=>e.cancel()),this.element.removeAttribute("torph-root"),this.element.removeAttribute("torph-debug"),this.removeStyles();}handleMediaQueryChange=e=>{this.prefersReducedMotion=e.matches;};isDisabled(){return !!(this.options.disabled||this.options.respectReducedMotion&&this.prefersReducedMotion)}update(e){if(e!==this.data){if(this.data=e,this.isDisabled()){typeof e=="string"&&(this.element.textContent=e);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(e,s){let h=s.offsetWidth,i=s.offsetHeight,a=e.includes(" "),p;if(typeof Intl.Segmenter<"u"){let r=new Intl.Segmenter(this.options.locale,{granularity:a?"word":"grapheme"}).segment(e)[Symbol.iterator]();p=this.blocks(r);}else p=this.blocksFallback(e,a);this.prevMeasures=this.measure();let l=Array.from(s.children),d=new Set(p.map(t=>t.id)),c=l.filter(t=>!d.has(t.getAttribute("torph-id"))&&!t.hasAttribute("torph-exiting")),m=new Set(c),y=new Map;for(let t=0;t<l.length;t++){let r=l[t];if(!m.has(r))continue;let o=null;for(let n=t+1;n<l.length;n++){let u=l[n].getAttribute("torph-id");if(d.has(u)&&!m.has(l[n])){o=u;break}}if(!o)for(let n=t-1;n>=0;n--){let u=l[n].getAttribute("torph-id");if(d.has(u)&&!m.has(l[n])){o=u;break}}y.set(r,o);}let x=c.map(t=>(t.getAnimations().forEach(r=>r.cancel()),{left:t.offsetLeft,top:t.offsetTop,width:t.offsetWidth,height:t.offsetHeight}));if(c.forEach((t,r)=>{let o=x[r];t.setAttribute("torph-exiting",""),t.style.position="absolute",t.style.pointerEvents="none",t.style.left=`${o.left}px`,t.style.top=`${o.top}px`,t.style.width=`${o.width}px`,t.style.height=`${o.height}px`;}),l.forEach(t=>{let r=t.getAttribute("torph-id");d.has(r)&&t.remove();}),Array.from(s.childNodes).forEach(t=>{t.nodeType===Node.TEXT_NODE&&t.remove();}),p.forEach(t=>{let r=document.createElement("span");r.setAttribute("torph-item",""),r.setAttribute("torph-id",t.id),r.textContent=t.string,s.appendChild(r);}),this.currentMeasures=this.measure(),this.updateStyles(p),c.forEach(t=>{if(this.isInitialRender){t.remove();return}let r=y.get(t),o=0,n=0;if(r&&this.prevMeasures[r]&&this.currentMeasures[r]){let E=this.prevMeasures[r],v=this.currentMeasures[r];o=v.x-E.x,n=v.y-E.y;}t.animate({transform:this.options.scale?`translate(${o}px, ${n}px) scale(0.95)`:`translate(${o}px, ${n}px)`,offset:1},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let u=t.animate({opacity:0,offset:1},{duration:this.options.duration*.25,easing:"linear",fill:"both"});u.onfinish=()=>t.remove();}),this.isInitialRender){this.isInitialRender=false,s.style.width="auto",s.style.height="auto";return}if(h===0||i===0)return;s.style.width="auto",s.style.height="auto",s.offsetWidth;let f=s.offsetWidth,M=s.offsetHeight;s.style.width=`${h}px`,s.style.height=`${i}px`,s.offsetWidth,s.style.width=`${f}px`,s.style.height=`${M}px`,setTimeout(()=>{s.style.width="auto",s.style.height="auto",this.options.onAnimationComplete&&this.options.onAnimationComplete();},this.options.duration);}measure(){let e=Array.from(this.element.children),s={};return e.forEach((h,i)=>{if(h.hasAttribute("torph-exiting"))return;let a=h.getAttribute("torph-id")||`child-${i}`;s[a]={x:h.offsetLeft,y:h.offsetTop};}),s}updateStyles(e){if(this.isInitialRender)return;let s=Array.from(this.element.children),h=new Set(e.map(i=>i.id).filter(i=>this.prevMeasures[i]));s.forEach((i,a)=>{if(i.hasAttribute("torph-exiting"))return;let p=i.getAttribute("torph-id")||`child-${a}`,l=this.prevMeasures[p],d=this.currentMeasures[p],c=d?.x||0,m=d?.y||0,y=l?l.x-c:0,x=l?l.y-m:0,f=!l;if(f){let r=e.findIndex(n=>n.id===p),o=null;for(let n=r-1;n>=0;n--)if(h.has(e[n].id)){o=e[n].id;break}if(!o){for(let n=r+1;n<e.length;n++)if(h.has(e[n].id)){o=e[n].id;break}}if(o){let n=this.prevMeasures[o],u=this.currentMeasures[o];y=n.x-u.x,x=n.y-u.y;}}i.getAnimations().forEach(r=>r.cancel()),i.animate({transform:`translate(${y}px, ${x}px) scale(${f?.95:1})`,offset:0},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let M=f?this.options.duration*.25:0,t=f?this.options.duration*.25:0;i.animate({opacity:f?0:1,offset:0},{duration:M,delay:t,easing:"linear",fill:"both"});});}addStyles(){if(g.styleEl)return;let e=document.createElement("style");e.dataset.torph="true",e.innerHTML=`
2
- [torph-root] {
3
- display: inline-flex;
1
+ 'use strict';function $(e,t,n){if(n<1){let u=t*Math.sqrt(1-n*n);return 1-Math.exp(-n*t*e)*(Math.cos(u*e)+n*t/u*Math.sin(u*e))}let o=Math.sqrt(n*n-1),r=-t*(n+o),i=-t*(n-o),s=-r/(i-r);return 1-(1-s)*Math.exp(r*e)-s*Math.exp(i*e)}function j(e,t,n){let i=0;for(let s=0;s<10;s+=.001)if(Math.abs($(s,e,t)-1)>n)i=0;else if(i+=.001,i>.1)return Math.ceil((s-i+.001)*1e3);return Math.ceil(10*1e3)}var O=new Map;function D(e){let{stiffness:t=100,damping:n=10,mass:o=1,precision:r=.001}=e??{},i=`${t}:${n}:${o}:${r}`,s=O.get(i);if(s)return s;let a=Math.sqrt(t/o),u=n/(2*Math.sqrt(t*o)),c=j(a,u,r),l=Math.min(100,Math.max(32,Math.round(c/15))),d=[];for(let g=0;g<l;g++){let A=g/(l-1)*(c/1e3),S=g===l-1?1:$(A,a,u);d.push(Math.round(S*1e4)/1e4+"");}for(;d.length>2&&d[d.length-2]==="1";)d.splice(d.length-2,1);let p={easing:`linear(${d.join(", ")})`,duration:c};return O.set(i,p),p}function H(e,t){let n=e.includes(" ");if(typeof Intl.Segmenter<"u"){let r=new Intl.Segmenter(t,{granularity:n?"word":"grapheme"}).segment(e)[Symbol.iterator]();return q(r)}return Y(e,n)}function q(e){return Array.from(e).reduce((t,n)=>n.segment===" "?[...t,{id:`space-${n.index}`,string:"\xA0"}]:t.find(r=>r.string===n.segment)?[...t,{id:`${n.segment}-${n.index}`,string:n.segment}]:[...t,{id:n.segment,string:n.segment}],[])}function K(e,t,n){let o=e.find(r=>r.string===t);e.push(o?{id:`${t}-${n}`,string:t}:{id:t,string:t});}function Y(e,t){let n=t?e.split(" "):e.split(""),o=[];return n.forEach((r,i)=>{t&&i>0&&o.push({id:`space-${i}`,string:"\xA0"}),K(o,r,i);}),o}var y="torph-root",T="torph-item",m="torph-id",f="torph-exiting",M="torph-debug";function R(e){let t=Array.from(e.children),n={},o=e.getBoundingClientRect();return t.forEach((r,i)=>{if(r.hasAttribute(f))return;let s=r.getAttribute(m)||`child-${i}`,a=r.getBoundingClientRect();n[s]={x:a.left-o.left,y:a.top-o.top};}),n}function w(e,t,n){let o=e[n],r=t[n];return !o||!r?{dx:0,dy:0}:{dx:o.x-r.x,dy:o.y-r.y}}function v(e,t,n,o="backward-first"){let[r,i]=o==="backward-first"?["backward","forward"]:["forward","backward"],s=a=>{if(a==="backward"){for(let u=e-1;u>=0;u--)if(n.has(t[u]))return t[u]}else for(let u=e+1;u<t.length;u++)if(n.has(t[u]))return t[u];return null};return s(r)??s(i)}function _(e,t,n,o){let r=new Set(n.filter((s,a)=>o.has(s)&&!t.has(e[a]))),i=new Map;for(let s=0;s<e.length;s++){let a=e[s];t.has(a)&&i.set(a,v(s,n,r,"forward-first"));}return i}function C(e,t){return Math.min(e*t,150)}function L(e){let t=getComputedStyle(e).transform;if(!t||t==="none")return {tx:0,ty:0};let n=t.match(/matrix\(([^)]+)\)/);if(!n)return {tx:0,ty:0};let o=n[1].split(",").map(Number);return {tx:o[4]||0,ty:o[5]||0}}function Q(e){let{tx:t,ty:n}=L(e),o=Number(getComputedStyle(e).opacity)||1;return e.getAnimations().forEach(r=>r.cancel()),{tx:t,ty:n,opacity:o}}function N(e,t){let{dx:n,dy:o,duration:r,ease:i,scale:s}=t;e.animate({transform:s?`translate(${n}px, ${o}px) scale(0.95)`:`translate(${n}px, ${o}px)`,offset:1},{duration:r,easing:i,fill:"both"});let a=e.animate({opacity:0,offset:1},{duration:C(r,.25),easing:"linear",fill:"both"});a.onfinish=()=>e.remove();}function k(e,t){let{deltaX:n,deltaY:o,isNew:r,duration:i,ease:s}=t,a=Q(e),u=n+a.tx,c=o+a.ty;e.animate({transform:`translate(${u}px, ${c}px) scale(${r?.95:1})`,offset:0},{duration:i,easing:s,fill:"both"});let l=r&&a.opacity>=1?0:a.opacity;l<1&&e.animate([{opacity:l},{opacity:1}],{duration:C(i,r?.5:.25),easing:"linear",fill:"both"});}var x=null;function F(e,t,n,o,r){if(x&&(x(),x=null),t===0||n===0)return;e.style.width="auto",e.style.height="auto",e.offsetWidth;let i=e.offsetWidth,s=e.offsetHeight;e.style.width=`${t}px`,e.style.height=`${n}px`,e.offsetWidth,e.style.width=`${i}px`,e.style.height=`${s}px`;function a(){e.removeEventListener("transitionend",u),clearTimeout(c),x=null,e.style.width="auto",e.style.height="auto",r?.();}function u(l){l.target===e&&(l.propertyName!=="width"&&l.propertyName!=="height"||a());}e.addEventListener("transitionend",u);let c=setTimeout(a,o+50);x=()=>{e.removeEventListener("transitionend",u),clearTimeout(c),x=null;};}function P(e){let n=e[0]?.parentElement?.getBoundingClientRect(),o=e.map(r=>{let{tx:i,ty:s}=L(r),a=Number(getComputedStyle(r).opacity)||1;r.getAnimations().forEach(c=>c.cancel());let u=r.getBoundingClientRect();return {left:(n?u.left-n.left:u.left)+i,top:(n?u.top-n.top:u.top)+s,width:u.width,height:u.height,opacity:a}});e.forEach((r,i)=>{let s=o[i];r.setAttribute(f,""),r.style.position="absolute",r.style.pointerEvents="none",r.style.left=`${s.left}px`,r.style.top=`${s.top}px`,r.style.width=`${s.width}px`,r.style.height=`${s.height}px`,r.style.opacity=String(s.opacity);});}function X(e,t,n,o){let r=new Map;t.forEach(i=>{let s=i.getAttribute(m);n.has(s)&&!i.hasAttribute(f)&&(r.set(s,i),i.remove());}),Array.from(e.childNodes).forEach(i=>{i.nodeType===Node.TEXT_NODE&&i.remove();}),o.forEach(i=>{let s=r.get(i.id);if(s)s.textContent=i.string,e.appendChild(s);else {let a=document.createElement("span");a.setAttribute(T,""),a.setAttribute(m,i.id),a.textContent=i.string,e.appendChild(a);}});}var J=`
2
+ [${y}] {
3
+ display: inline-block;
4
4
  position: relative;
5
5
  will-change: width, height;
6
6
  transition-property: width, height;
7
7
  white-space: nowrap;
8
8
  }
9
9
 
10
- [torph-item] {
10
+ [${T}] {
11
11
  display: inline-block;
12
12
  will-change: opacity, transform;
13
13
  transform: none;
14
14
  opacity: 1;
15
15
  }
16
16
 
17
- [torph-root][torph-debug] {
18
- outline:2px solid magenta;
19
- [torph-item] {
20
- outline:2px solid cyan;
17
+ [${y}][${M}] {
18
+ outline: 2px solid magenta;
19
+ [${T}] {
20
+ outline: 2px solid cyan;
21
21
  outline-offset: -4px;
22
22
  }
23
- }
24
- `,document.head.appendChild(e),g.styleEl=e;}removeStyles(){g.styleEl&&(g.styleEl.remove(),g.styleEl=void 0);}blocks(e){return Array.from(e).reduce((h,i)=>i.segment===" "?[...h,{id:`space-${i.index}`,string:"\xA0"}]:h.find(p=>p.string===i.segment)?[...h,{id:`${i.segment}-${i.index}`,string:i.segment}]:[...h,{id:i.segment,string:i.segment}],[])}blocksFallback(e,s){let h=s?e.split(" "):e.split(""),i=[];return s?h.forEach((a,p)=>{p>0&&i.push({id:`space-${p}`,string:"\xA0"}),i.find(d=>d.string===a)?i.push({id:`${a}-${p}`,string:a}):i.push({id:a,string:a});}):h.forEach((a,p)=>{i.find(d=>d.string===a)?i.push({id:`${a}-${p}`,string:a}):i.push({id:a,string:a});}),i}log(...e){this.options.debug&&console.log("[TextMorph]",...e);}};exports.DEFAULT_AS=T;exports.DEFAULT_TEXT_MORPH_OPTIONS=A;exports.TextMorph=b;//# sourceMappingURL=index.js.map
25
- //# sourceMappingURL=index.js.map
23
+ }`,h=null,I=0;function B(){I++,!h&&(h=document.createElement("style"),h.dataset.torph="true",h.textContent=J,document.head.appendChild(h));}function G(){I--,!(I>0||!h)&&(h.remove(),h=null);}function U(){if(typeof window>"u")return {prefersReducedMotion:false,destroy:()=>{}};let e=window.matchMedia("(prefers-reduced-motion: reduce)"),t={prefersReducedMotion:e.matches,destroy:o};function n(r){t.prefersReducedMotion=r.matches;}function o(){e.removeEventListener("change",n);}return e.addEventListener("change",n),t}var E=class e{instance=null;lastText="";configKey="";attach(t,n){this.instance?.destroy(),this.instance=new b({element:t,...n}),this.configKey=e.serializeConfig(n),this.lastText&&this.instance.update(this.lastText);}update(t){this.lastText=t,this.instance?.update(t);}needsRecreate(t){return e.serializeConfig(t)!==this.configKey}destroy(){this.instance?.destroy(),this.instance=null;}static serializeConfig(t){return JSON.stringify({ease:t.ease,duration:t.duration,locale:t.locale,scale:t.scale,debug:t.debug,disabled:t.disabled,respectReducedMotion:t.respectReducedMotion})}};var V="span",W={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},b=class{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;reducedMotion=null;constructor(t){let{ease:n,...o}={...W,...t},r,i;if(typeof n=="object"){let s=D(n);r=s.easing,i=s.duration;}else r=n,i=o.duration;this.options={...o,ease:r,duration:i},this.element=t.element,this.options.respectReducedMotion&&(this.reducedMotion=U()),this.isDisabled()||(this.element.setAttribute(y,""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,t.debug&&this.element.setAttribute(M,"")),this.data="",this.isDisabled()||B();}destroy(){this.reducedMotion?.destroy(),this.element.getAnimations().forEach(t=>t.cancel()),this.element.removeAttribute(y),this.element.removeAttribute(M),G();}isDisabled(){return !!(this.options.disabled||this.reducedMotion?.prefersReducedMotion)}update(t){if(t!==this.data){if(this.data=t,this.isDisabled()){typeof t=="string"&&(this.element.textContent=t);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(t,n){let o=n.offsetWidth,r=n.offsetHeight,i=H(t,this.options.locale);this.prevMeasures=R(this.element);let s=Array.from(n.children),a=new Set(i.map(p=>p.id)),u=s.filter(p=>!a.has(p.getAttribute(m))&&!p.hasAttribute(f)),c=new Set(u),l=s.map(p=>p.getAttribute(m)),d=_(s,c,l,a);if(P(u),X(n,s,a,i),this.currentMeasures=R(this.element),this.updateStyles(i),u.forEach(p=>{if(this.isInitialRender){p.remove();return}let g=d.get(p),{dx:A,dy:S}=g?w(this.currentMeasures,this.prevMeasures,g):{dx:0,dy:0};N(p,{dx:A,dy:S,duration:this.options.duration,ease:this.options.ease,scale:this.options.scale});}),this.isInitialRender){this.isInitialRender=false,n.style.width="auto",n.style.height="auto";return}F(n,o,r,this.options.duration,this.options.onAnimationComplete);}updateStyles(t){if(this.isInitialRender)return;let n=Array.from(this.element.children),o=t.map(i=>i.id),r=new Set(o.filter(i=>this.prevMeasures[i]));n.forEach((i,s)=>{if(i.hasAttribute(f))return;let a=i.getAttribute(m)||`child-${s}`,u=!this.prevMeasures[a],c=u?v(t.findIndex(p=>p.id===a),o,r):a,{dx:l,dy:d}=c?w(this.prevMeasures,this.currentMeasures,c):{dx:0,dy:0};k(i,{deltaX:l,deltaY:d,isNew:u,duration:this.options.duration,ease:this.options.ease});});}};exports.DEFAULT_AS=V;exports.DEFAULT_TEXT_MORPH_OPTIONS=W;exports.MorphController=E;exports.TextMorph=b;
package/dist/index.mjs CHANGED
@@ -1,25 +1,23 @@
1
- var T="span",A={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},b=class g{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;prefersReducedMotion=false;mediaQuery;static styleEl;constructor(e){this.options={...A,...e},this.element=e.element,typeof window<"u"&&this.options.respectReducedMotion&&(this.mediaQuery=window.matchMedia("(prefers-reduced-motion: reduce)"),this.prefersReducedMotion=this.mediaQuery.matches,this.mediaQuery.addEventListener("change",this.handleMediaQueryChange)),this.isDisabled()||(this.element.setAttribute("torph-root",""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,e.debug&&this.element.setAttribute("torph-debug","")),this.data="",this.isDisabled()||this.addStyles();}destroy(){this.mediaQuery&&this.mediaQuery.removeEventListener("change",this.handleMediaQueryChange),this.element.getAnimations().forEach(e=>e.cancel()),this.element.removeAttribute("torph-root"),this.element.removeAttribute("torph-debug"),this.removeStyles();}handleMediaQueryChange=e=>{this.prefersReducedMotion=e.matches;};isDisabled(){return !!(this.options.disabled||this.options.respectReducedMotion&&this.prefersReducedMotion)}update(e){if(e!==this.data){if(this.data=e,this.isDisabled()){typeof e=="string"&&(this.element.textContent=e);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(e,s){let h=s.offsetWidth,i=s.offsetHeight,a=e.includes(" "),p;if(typeof Intl.Segmenter<"u"){let r=new Intl.Segmenter(this.options.locale,{granularity:a?"word":"grapheme"}).segment(e)[Symbol.iterator]();p=this.blocks(r);}else p=this.blocksFallback(e,a);this.prevMeasures=this.measure();let l=Array.from(s.children),d=new Set(p.map(t=>t.id)),c=l.filter(t=>!d.has(t.getAttribute("torph-id"))&&!t.hasAttribute("torph-exiting")),m=new Set(c),y=new Map;for(let t=0;t<l.length;t++){let r=l[t];if(!m.has(r))continue;let o=null;for(let n=t+1;n<l.length;n++){let u=l[n].getAttribute("torph-id");if(d.has(u)&&!m.has(l[n])){o=u;break}}if(!o)for(let n=t-1;n>=0;n--){let u=l[n].getAttribute("torph-id");if(d.has(u)&&!m.has(l[n])){o=u;break}}y.set(r,o);}let x=c.map(t=>(t.getAnimations().forEach(r=>r.cancel()),{left:t.offsetLeft,top:t.offsetTop,width:t.offsetWidth,height:t.offsetHeight}));if(c.forEach((t,r)=>{let o=x[r];t.setAttribute("torph-exiting",""),t.style.position="absolute",t.style.pointerEvents="none",t.style.left=`${o.left}px`,t.style.top=`${o.top}px`,t.style.width=`${o.width}px`,t.style.height=`${o.height}px`;}),l.forEach(t=>{let r=t.getAttribute("torph-id");d.has(r)&&t.remove();}),Array.from(s.childNodes).forEach(t=>{t.nodeType===Node.TEXT_NODE&&t.remove();}),p.forEach(t=>{let r=document.createElement("span");r.setAttribute("torph-item",""),r.setAttribute("torph-id",t.id),r.textContent=t.string,s.appendChild(r);}),this.currentMeasures=this.measure(),this.updateStyles(p),c.forEach(t=>{if(this.isInitialRender){t.remove();return}let r=y.get(t),o=0,n=0;if(r&&this.prevMeasures[r]&&this.currentMeasures[r]){let E=this.prevMeasures[r],v=this.currentMeasures[r];o=v.x-E.x,n=v.y-E.y;}t.animate({transform:this.options.scale?`translate(${o}px, ${n}px) scale(0.95)`:`translate(${o}px, ${n}px)`,offset:1},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let u=t.animate({opacity:0,offset:1},{duration:this.options.duration*.25,easing:"linear",fill:"both"});u.onfinish=()=>t.remove();}),this.isInitialRender){this.isInitialRender=false,s.style.width="auto",s.style.height="auto";return}if(h===0||i===0)return;s.style.width="auto",s.style.height="auto",s.offsetWidth;let f=s.offsetWidth,M=s.offsetHeight;s.style.width=`${h}px`,s.style.height=`${i}px`,s.offsetWidth,s.style.width=`${f}px`,s.style.height=`${M}px`,setTimeout(()=>{s.style.width="auto",s.style.height="auto",this.options.onAnimationComplete&&this.options.onAnimationComplete();},this.options.duration);}measure(){let e=Array.from(this.element.children),s={};return e.forEach((h,i)=>{if(h.hasAttribute("torph-exiting"))return;let a=h.getAttribute("torph-id")||`child-${i}`;s[a]={x:h.offsetLeft,y:h.offsetTop};}),s}updateStyles(e){if(this.isInitialRender)return;let s=Array.from(this.element.children),h=new Set(e.map(i=>i.id).filter(i=>this.prevMeasures[i]));s.forEach((i,a)=>{if(i.hasAttribute("torph-exiting"))return;let p=i.getAttribute("torph-id")||`child-${a}`,l=this.prevMeasures[p],d=this.currentMeasures[p],c=d?.x||0,m=d?.y||0,y=l?l.x-c:0,x=l?l.y-m:0,f=!l;if(f){let r=e.findIndex(n=>n.id===p),o=null;for(let n=r-1;n>=0;n--)if(h.has(e[n].id)){o=e[n].id;break}if(!o){for(let n=r+1;n<e.length;n++)if(h.has(e[n].id)){o=e[n].id;break}}if(o){let n=this.prevMeasures[o],u=this.currentMeasures[o];y=n.x-u.x,x=n.y-u.y;}}i.getAnimations().forEach(r=>r.cancel()),i.animate({transform:`translate(${y}px, ${x}px) scale(${f?.95:1})`,offset:0},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let M=f?this.options.duration*.25:0,t=f?this.options.duration*.25:0;i.animate({opacity:f?0:1,offset:0},{duration:M,delay:t,easing:"linear",fill:"both"});});}addStyles(){if(g.styleEl)return;let e=document.createElement("style");e.dataset.torph="true",e.innerHTML=`
2
- [torph-root] {
3
- display: inline-flex;
1
+ function $(e,t,n){if(n<1){let u=t*Math.sqrt(1-n*n);return 1-Math.exp(-n*t*e)*(Math.cos(u*e)+n*t/u*Math.sin(u*e))}let o=Math.sqrt(n*n-1),r=-t*(n+o),i=-t*(n-o),s=-r/(i-r);return 1-(1-s)*Math.exp(r*e)-s*Math.exp(i*e)}function j(e,t,n){let i=0;for(let s=0;s<10;s+=.001)if(Math.abs($(s,e,t)-1)>n)i=0;else if(i+=.001,i>.1)return Math.ceil((s-i+.001)*1e3);return Math.ceil(10*1e3)}var O=new Map;function D(e){let{stiffness:t=100,damping:n=10,mass:o=1,precision:r=.001}=e??{},i=`${t}:${n}:${o}:${r}`,s=O.get(i);if(s)return s;let a=Math.sqrt(t/o),u=n/(2*Math.sqrt(t*o)),c=j(a,u,r),l=Math.min(100,Math.max(32,Math.round(c/15))),d=[];for(let g=0;g<l;g++){let A=g/(l-1)*(c/1e3),S=g===l-1?1:$(A,a,u);d.push(Math.round(S*1e4)/1e4+"");}for(;d.length>2&&d[d.length-2]==="1";)d.splice(d.length-2,1);let p={easing:`linear(${d.join(", ")})`,duration:c};return O.set(i,p),p}function H(e,t){let n=e.includes(" ");if(typeof Intl.Segmenter<"u"){let r=new Intl.Segmenter(t,{granularity:n?"word":"grapheme"}).segment(e)[Symbol.iterator]();return q(r)}return Y(e,n)}function q(e){return Array.from(e).reduce((t,n)=>n.segment===" "?[...t,{id:`space-${n.index}`,string:"\xA0"}]:t.find(r=>r.string===n.segment)?[...t,{id:`${n.segment}-${n.index}`,string:n.segment}]:[...t,{id:n.segment,string:n.segment}],[])}function K(e,t,n){let o=e.find(r=>r.string===t);e.push(o?{id:`${t}-${n}`,string:t}:{id:t,string:t});}function Y(e,t){let n=t?e.split(" "):e.split(""),o=[];return n.forEach((r,i)=>{t&&i>0&&o.push({id:`space-${i}`,string:"\xA0"}),K(o,r,i);}),o}var y="torph-root",T="torph-item",m="torph-id",f="torph-exiting",M="torph-debug";function R(e){let t=Array.from(e.children),n={},o=e.getBoundingClientRect();return t.forEach((r,i)=>{if(r.hasAttribute(f))return;let s=r.getAttribute(m)||`child-${i}`,a=r.getBoundingClientRect();n[s]={x:a.left-o.left,y:a.top-o.top};}),n}function w(e,t,n){let o=e[n],r=t[n];return !o||!r?{dx:0,dy:0}:{dx:o.x-r.x,dy:o.y-r.y}}function v(e,t,n,o="backward-first"){let[r,i]=o==="backward-first"?["backward","forward"]:["forward","backward"],s=a=>{if(a==="backward"){for(let u=e-1;u>=0;u--)if(n.has(t[u]))return t[u]}else for(let u=e+1;u<t.length;u++)if(n.has(t[u]))return t[u];return null};return s(r)??s(i)}function _(e,t,n,o){let r=new Set(n.filter((s,a)=>o.has(s)&&!t.has(e[a]))),i=new Map;for(let s=0;s<e.length;s++){let a=e[s];t.has(a)&&i.set(a,v(s,n,r,"forward-first"));}return i}function C(e,t){return Math.min(e*t,150)}function L(e){let t=getComputedStyle(e).transform;if(!t||t==="none")return {tx:0,ty:0};let n=t.match(/matrix\(([^)]+)\)/);if(!n)return {tx:0,ty:0};let o=n[1].split(",").map(Number);return {tx:o[4]||0,ty:o[5]||0}}function Q(e){let{tx:t,ty:n}=L(e),o=Number(getComputedStyle(e).opacity)||1;return e.getAnimations().forEach(r=>r.cancel()),{tx:t,ty:n,opacity:o}}function N(e,t){let{dx:n,dy:o,duration:r,ease:i,scale:s}=t;e.animate({transform:s?`translate(${n}px, ${o}px) scale(0.95)`:`translate(${n}px, ${o}px)`,offset:1},{duration:r,easing:i,fill:"both"});let a=e.animate({opacity:0,offset:1},{duration:C(r,.25),easing:"linear",fill:"both"});a.onfinish=()=>e.remove();}function k(e,t){let{deltaX:n,deltaY:o,isNew:r,duration:i,ease:s}=t,a=Q(e),u=n+a.tx,c=o+a.ty;e.animate({transform:`translate(${u}px, ${c}px) scale(${r?.95:1})`,offset:0},{duration:i,easing:s,fill:"both"});let l=r&&a.opacity>=1?0:a.opacity;l<1&&e.animate([{opacity:l},{opacity:1}],{duration:C(i,r?.5:.25),easing:"linear",fill:"both"});}var x=null;function F(e,t,n,o,r){if(x&&(x(),x=null),t===0||n===0)return;e.style.width="auto",e.style.height="auto",e.offsetWidth;let i=e.offsetWidth,s=e.offsetHeight;e.style.width=`${t}px`,e.style.height=`${n}px`,e.offsetWidth,e.style.width=`${i}px`,e.style.height=`${s}px`;function a(){e.removeEventListener("transitionend",u),clearTimeout(c),x=null,e.style.width="auto",e.style.height="auto",r?.();}function u(l){l.target===e&&(l.propertyName!=="width"&&l.propertyName!=="height"||a());}e.addEventListener("transitionend",u);let c=setTimeout(a,o+50);x=()=>{e.removeEventListener("transitionend",u),clearTimeout(c),x=null;};}function P(e){let n=e[0]?.parentElement?.getBoundingClientRect(),o=e.map(r=>{let{tx:i,ty:s}=L(r),a=Number(getComputedStyle(r).opacity)||1;r.getAnimations().forEach(c=>c.cancel());let u=r.getBoundingClientRect();return {left:(n?u.left-n.left:u.left)+i,top:(n?u.top-n.top:u.top)+s,width:u.width,height:u.height,opacity:a}});e.forEach((r,i)=>{let s=o[i];r.setAttribute(f,""),r.style.position="absolute",r.style.pointerEvents="none",r.style.left=`${s.left}px`,r.style.top=`${s.top}px`,r.style.width=`${s.width}px`,r.style.height=`${s.height}px`,r.style.opacity=String(s.opacity);});}function X(e,t,n,o){let r=new Map;t.forEach(i=>{let s=i.getAttribute(m);n.has(s)&&!i.hasAttribute(f)&&(r.set(s,i),i.remove());}),Array.from(e.childNodes).forEach(i=>{i.nodeType===Node.TEXT_NODE&&i.remove();}),o.forEach(i=>{let s=r.get(i.id);if(s)s.textContent=i.string,e.appendChild(s);else {let a=document.createElement("span");a.setAttribute(T,""),a.setAttribute(m,i.id),a.textContent=i.string,e.appendChild(a);}});}var J=`
2
+ [${y}] {
3
+ display: inline-block;
4
4
  position: relative;
5
5
  will-change: width, height;
6
6
  transition-property: width, height;
7
7
  white-space: nowrap;
8
8
  }
9
9
 
10
- [torph-item] {
10
+ [${T}] {
11
11
  display: inline-block;
12
12
  will-change: opacity, transform;
13
13
  transform: none;
14
14
  opacity: 1;
15
15
  }
16
16
 
17
- [torph-root][torph-debug] {
18
- outline:2px solid magenta;
19
- [torph-item] {
20
- outline:2px solid cyan;
17
+ [${y}][${M}] {
18
+ outline: 2px solid magenta;
19
+ [${T}] {
20
+ outline: 2px solid cyan;
21
21
  outline-offset: -4px;
22
22
  }
23
- }
24
- `,document.head.appendChild(e),g.styleEl=e;}removeStyles(){g.styleEl&&(g.styleEl.remove(),g.styleEl=void 0);}blocks(e){return Array.from(e).reduce((h,i)=>i.segment===" "?[...h,{id:`space-${i.index}`,string:"\xA0"}]:h.find(p=>p.string===i.segment)?[...h,{id:`${i.segment}-${i.index}`,string:i.segment}]:[...h,{id:i.segment,string:i.segment}],[])}blocksFallback(e,s){let h=s?e.split(" "):e.split(""),i=[];return s?h.forEach((a,p)=>{p>0&&i.push({id:`space-${p}`,string:"\xA0"}),i.find(d=>d.string===a)?i.push({id:`${a}-${p}`,string:a}):i.push({id:a,string:a});}):h.forEach((a,p)=>{i.find(d=>d.string===a)?i.push({id:`${a}-${p}`,string:a}):i.push({id:a,string:a});}),i}log(...e){this.options.debug&&console.log("[TextMorph]",...e);}};export{T as DEFAULT_AS,A as DEFAULT_TEXT_MORPH_OPTIONS,b as TextMorph};//# sourceMappingURL=index.mjs.map
25
- //# sourceMappingURL=index.mjs.map
23
+ }`,h=null,I=0;function B(){I++,!h&&(h=document.createElement("style"),h.dataset.torph="true",h.textContent=J,document.head.appendChild(h));}function G(){I--,!(I>0||!h)&&(h.remove(),h=null);}function U(){if(typeof window>"u")return {prefersReducedMotion:false,destroy:()=>{}};let e=window.matchMedia("(prefers-reduced-motion: reduce)"),t={prefersReducedMotion:e.matches,destroy:o};function n(r){t.prefersReducedMotion=r.matches;}function o(){e.removeEventListener("change",n);}return e.addEventListener("change",n),t}var E=class e{instance=null;lastText="";configKey="";attach(t,n){this.instance?.destroy(),this.instance=new b({element:t,...n}),this.configKey=e.serializeConfig(n),this.lastText&&this.instance.update(this.lastText);}update(t){this.lastText=t,this.instance?.update(t);}needsRecreate(t){return e.serializeConfig(t)!==this.configKey}destroy(){this.instance?.destroy(),this.instance=null;}static serializeConfig(t){return JSON.stringify({ease:t.ease,duration:t.duration,locale:t.locale,scale:t.scale,debug:t.debug,disabled:t.disabled,respectReducedMotion:t.respectReducedMotion})}};var V="span",W={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},b=class{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;reducedMotion=null;constructor(t){let{ease:n,...o}={...W,...t},r,i;if(typeof n=="object"){let s=D(n);r=s.easing,i=s.duration;}else r=n,i=o.duration;this.options={...o,ease:r,duration:i},this.element=t.element,this.options.respectReducedMotion&&(this.reducedMotion=U()),this.isDisabled()||(this.element.setAttribute(y,""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,t.debug&&this.element.setAttribute(M,"")),this.data="",this.isDisabled()||B();}destroy(){this.reducedMotion?.destroy(),this.element.getAnimations().forEach(t=>t.cancel()),this.element.removeAttribute(y),this.element.removeAttribute(M),G();}isDisabled(){return !!(this.options.disabled||this.reducedMotion?.prefersReducedMotion)}update(t){if(t!==this.data){if(this.data=t,this.isDisabled()){typeof t=="string"&&(this.element.textContent=t);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(t,n){let o=n.offsetWidth,r=n.offsetHeight,i=H(t,this.options.locale);this.prevMeasures=R(this.element);let s=Array.from(n.children),a=new Set(i.map(p=>p.id)),u=s.filter(p=>!a.has(p.getAttribute(m))&&!p.hasAttribute(f)),c=new Set(u),l=s.map(p=>p.getAttribute(m)),d=_(s,c,l,a);if(P(u),X(n,s,a,i),this.currentMeasures=R(this.element),this.updateStyles(i),u.forEach(p=>{if(this.isInitialRender){p.remove();return}let g=d.get(p),{dx:A,dy:S}=g?w(this.currentMeasures,this.prevMeasures,g):{dx:0,dy:0};N(p,{dx:A,dy:S,duration:this.options.duration,ease:this.options.ease,scale:this.options.scale});}),this.isInitialRender){this.isInitialRender=false,n.style.width="auto",n.style.height="auto";return}F(n,o,r,this.options.duration,this.options.onAnimationComplete);}updateStyles(t){if(this.isInitialRender)return;let n=Array.from(this.element.children),o=t.map(i=>i.id),r=new Set(o.filter(i=>this.prevMeasures[i]));n.forEach((i,s)=>{if(i.hasAttribute(f))return;let a=i.getAttribute(m)||`child-${s}`,u=!this.prevMeasures[a],c=u?v(t.findIndex(p=>p.id===a),o,r):a,{dx:l,dy:d}=c?w(this.prevMeasures,this.currentMeasures,c):{dx:0,dy:0};k(i,{deltaX:l,deltaY:d,isNew:u,duration:this.options.duration,ease:this.options.ease});});}};export{V as DEFAULT_AS,W as DEFAULT_TEXT_MORPH_OPTIONS,E as MorphController,b as TextMorph};
@@ -1,12 +1,19 @@
1
1
  import React from 'react';
2
2
 
3
+ interface SpringParams {
4
+ stiffness?: number;
5
+ damping?: number;
6
+ mass?: number;
7
+ precision?: number;
8
+ }
9
+
3
10
  interface TextMorphOptions {
4
11
  debug?: boolean;
5
12
  element: HTMLElement;
6
13
  locale?: Intl.LocalesArgument;
7
14
  scale?: boolean;
8
15
  duration?: number;
9
- ease?: string;
16
+ ease?: string | SpringParams;
10
17
  disabled?: boolean;
11
18
  respectReducedMotion?: boolean;
12
19
  onAnimationStart?: () => void;
@@ -21,7 +28,7 @@ type TextMorphProps = Omit<TextMorphOptions, "element"> & {
21
28
  };
22
29
  declare const TextMorph: ({ children, className, style, as, ...props }: TextMorphProps) => React.JSX.Element;
23
30
  declare function useTextMorph(props: Omit<TextMorphOptions, "element">): {
24
- ref: React.MutableRefObject<HTMLDivElement | null>;
31
+ ref: React.MutableRefObject<HTMLElement | null>;
25
32
  update: (text: string) => void;
26
33
  };
27
34
 
@@ -1,12 +1,19 @@
1
1
  import React from 'react';
2
2
 
3
+ interface SpringParams {
4
+ stiffness?: number;
5
+ damping?: number;
6
+ mass?: number;
7
+ precision?: number;
8
+ }
9
+
3
10
  interface TextMorphOptions {
4
11
  debug?: boolean;
5
12
  element: HTMLElement;
6
13
  locale?: Intl.LocalesArgument;
7
14
  scale?: boolean;
8
15
  duration?: number;
9
- ease?: string;
16
+ ease?: string | SpringParams;
10
17
  disabled?: boolean;
11
18
  respectReducedMotion?: boolean;
12
19
  onAnimationStart?: () => void;
@@ -21,7 +28,7 @@ type TextMorphProps = Omit<TextMorphOptions, "element"> & {
21
28
  };
22
29
  declare const TextMorph: ({ children, className, style, as, ...props }: TextMorphProps) => React.JSX.Element;
23
30
  declare function useTextMorph(props: Omit<TextMorphOptions, "element">): {
24
- ref: React.MutableRefObject<HTMLDivElement | null>;
31
+ ref: React.MutableRefObject<HTMLElement | null>;
25
32
  update: (text: string) => void;
26
33
  };
27
34
 
@@ -1,25 +1,23 @@
1
- 'use strict';var c=require('react');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var c__default=/*#__PURE__*/_interopDefault(c);var A="span",$={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},b=class h{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;prefersReducedMotion=false;mediaQuery;static styleEl;constructor(t){this.options={...$,...t},this.element=t.element,typeof window<"u"&&this.options.respectReducedMotion&&(this.mediaQuery=window.matchMedia("(prefers-reduced-motion: reduce)"),this.prefersReducedMotion=this.mediaQuery.matches,this.mediaQuery.addEventListener("change",this.handleMediaQueryChange)),this.isDisabled()||(this.element.setAttribute("torph-root",""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,t.debug&&this.element.setAttribute("torph-debug","")),this.data="",this.isDisabled()||this.addStyles();}destroy(){this.mediaQuery&&this.mediaQuery.removeEventListener("change",this.handleMediaQueryChange),this.element.getAnimations().forEach(t=>t.cancel()),this.element.removeAttribute("torph-root"),this.element.removeAttribute("torph-debug"),this.removeStyles();}handleMediaQueryChange=t=>{this.prefersReducedMotion=t.matches;};isDisabled(){return !!(this.options.disabled||this.options.respectReducedMotion&&this.prefersReducedMotion)}update(t){if(t!==this.data){if(this.data=t,this.isDisabled()){typeof t=="string"&&(this.element.textContent=t);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(t,s){let o=s.offsetWidth,i=s.offsetHeight,a=t.includes(" "),l;if(typeof Intl.Segmenter<"u"){let n=new Intl.Segmenter(this.options.locale,{granularity:a?"word":"grapheme"}).segment(t)[Symbol.iterator]();l=this.blocks(n);}else l=this.blocksFallback(t,a);this.prevMeasures=this.measure();let p=Array.from(s.children),d=new Set(l.map(e=>e.id)),m=p.filter(e=>!d.has(e.getAttribute("torph-id"))&&!e.hasAttribute("torph-exiting")),y=new Set(m),x=new Map;for(let e=0;e<p.length;e++){let n=p[e];if(!y.has(n))continue;let u=null;for(let r=e+1;r<p.length;r++){let f=p[r].getAttribute("torph-id");if(d.has(f)&&!y.has(p[r])){u=f;break}}if(!u)for(let r=e-1;r>=0;r--){let f=p[r].getAttribute("torph-id");if(d.has(f)&&!y.has(p[r])){u=f;break}}x.set(n,u);}let M=m.map(e=>(e.getAnimations().forEach(n=>n.cancel()),{left:e.offsetLeft,top:e.offsetTop,width:e.offsetWidth,height:e.offsetHeight}));if(m.forEach((e,n)=>{let u=M[n];e.setAttribute("torph-exiting",""),e.style.position="absolute",e.style.pointerEvents="none",e.style.left=`${u.left}px`,e.style.top=`${u.top}px`,e.style.width=`${u.width}px`,e.style.height=`${u.height}px`;}),p.forEach(e=>{let n=e.getAttribute("torph-id");d.has(n)&&e.remove();}),Array.from(s.childNodes).forEach(e=>{e.nodeType===Node.TEXT_NODE&&e.remove();}),l.forEach(e=>{let n=document.createElement("span");n.setAttribute("torph-item",""),n.setAttribute("torph-id",e.id),n.textContent=e.string,s.appendChild(n);}),this.currentMeasures=this.measure(),this.updateStyles(l),m.forEach(e=>{if(this.isInitialRender){e.remove();return}let n=x.get(e),u=0,r=0;if(n&&this.prevMeasures[n]&&this.currentMeasures[n]){let E=this.prevMeasures[n],v=this.currentMeasures[n];u=v.x-E.x,r=v.y-E.y;}e.animate({transform:this.options.scale?`translate(${u}px, ${r}px) scale(0.95)`:`translate(${u}px, ${r}px)`,offset:1},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let f=e.animate({opacity:0,offset:1},{duration:this.options.duration*.25,easing:"linear",fill:"both"});f.onfinish=()=>e.remove();}),this.isInitialRender){this.isInitialRender=false,s.style.width="auto",s.style.height="auto";return}if(o===0||i===0)return;s.style.width="auto",s.style.height="auto",s.offsetWidth;let g=s.offsetWidth,T=s.offsetHeight;s.style.width=`${o}px`,s.style.height=`${i}px`,s.offsetWidth,s.style.width=`${g}px`,s.style.height=`${T}px`,setTimeout(()=>{s.style.width="auto",s.style.height="auto",this.options.onAnimationComplete&&this.options.onAnimationComplete();},this.options.duration);}measure(){let t=Array.from(this.element.children),s={};return t.forEach((o,i)=>{if(o.hasAttribute("torph-exiting"))return;let a=o.getAttribute("torph-id")||`child-${i}`;s[a]={x:o.offsetLeft,y:o.offsetTop};}),s}updateStyles(t){if(this.isInitialRender)return;let s=Array.from(this.element.children),o=new Set(t.map(i=>i.id).filter(i=>this.prevMeasures[i]));s.forEach((i,a)=>{if(i.hasAttribute("torph-exiting"))return;let l=i.getAttribute("torph-id")||`child-${a}`,p=this.prevMeasures[l],d=this.currentMeasures[l],m=d?.x||0,y=d?.y||0,x=p?p.x-m:0,M=p?p.y-y:0,g=!p;if(g){let n=t.findIndex(r=>r.id===l),u=null;for(let r=n-1;r>=0;r--)if(o.has(t[r].id)){u=t[r].id;break}if(!u){for(let r=n+1;r<t.length;r++)if(o.has(t[r].id)){u=t[r].id;break}}if(u){let r=this.prevMeasures[u],f=this.currentMeasures[u];x=r.x-f.x,M=r.y-f.y;}}i.getAnimations().forEach(n=>n.cancel()),i.animate({transform:`translate(${x}px, ${M}px) scale(${g?.95:1})`,offset:0},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let T=g?this.options.duration*.25:0,e=g?this.options.duration*.25:0;i.animate({opacity:g?0:1,offset:0},{duration:T,delay:e,easing:"linear",fill:"both"});});}addStyles(){if(h.styleEl)return;let t=document.createElement("style");t.dataset.torph="true",t.innerHTML=`
2
- [torph-root] {
3
- display: inline-flex;
1
+ 'use strict';var g=require('react');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var g__default=/*#__PURE__*/_interopDefault(g);function H(t,e,n){if(n<1){let c=e*Math.sqrt(1-n*n);return 1-Math.exp(-n*e*t)*(Math.cos(c*t)+n*e/c*Math.sin(c*t))}let s=Math.sqrt(n*n-1),r=-e*(n+s),i=-e*(n-s),o=-r/(i-r);return 1-(1-o)*Math.exp(r*t)-o*Math.exp(i*t)}function Y(t,e,n){let i=0;for(let o=0;o<10;o+=.001)if(Math.abs(H(o,t,e)-1)>n)i=0;else if(i+=.001,i>.1)return Math.ceil((o-i+.001)*1e3);return Math.ceil(10*1e3)}var $=new Map;function C(t){let{stiffness:e=100,damping:n=10,mass:s=1,precision:r=.001}=t??{},i=`${e}:${n}:${s}:${r}`,o=$.get(i);if(o)return o;let a=Math.sqrt(e/s),c=n/(2*Math.sqrt(e*s)),u=Y(a,c,r),l=Math.min(100,Math.max(32,Math.round(u/15))),m=[];for(let y=0;y<l;y++){let R=y/(l-1)*(u/1e3),S=y===l-1?1:H(R,a,c);m.push(Math.round(S*1e4)/1e4+"");}for(;m.length>2&&m[m.length-2]==="1";)m.splice(m.length-2,1);let p={easing:`linear(${m.join(", ")})`,duration:u};return $.set(i,p),p}function D(t,e){let n=t.includes(" ");if(typeof Intl.Segmenter<"u"){let r=new Intl.Segmenter(e,{granularity:n?"word":"grapheme"}).segment(t)[Symbol.iterator]();return Q(r)}return V(t,n)}function Q(t){return Array.from(t).reduce((e,n)=>n.segment===" "?[...e,{id:`space-${n.index}`,string:"\xA0"}]:e.find(r=>r.string===n.segment)?[...e,{id:`${n.segment}-${n.index}`,string:n.segment}]:[...e,{id:n.segment,string:n.segment}],[])}function J(t,e,n){let s=t.find(r=>r.string===e);t.push(s?{id:`${e}-${n}`,string:e}:{id:e,string:e});}function V(t,e){let n=e?t.split(" "):t.split(""),s=[];return n.forEach((r,i)=>{e&&i>0&&s.push({id:`space-${i}`,string:"\xA0"}),J(s,r,i);}),s}var x="torph-root",M="torph-item",d="torph-id",f="torph-exiting",b="torph-debug";function w(t){let e=Array.from(t.children),n={},s=t.getBoundingClientRect();return e.forEach((r,i)=>{if(r.hasAttribute(f))return;let o=r.getAttribute(d)||`child-${i}`,a=r.getBoundingClientRect();n[o]={x:a.left-s.left,y:a.top-s.top};}),n}function v(t,e,n){let s=t[n],r=e[n];return !s||!r?{dx:0,dy:0}:{dx:s.x-r.x,dy:s.y-r.y}}function L(t,e,n,s="backward-first"){let[r,i]=s==="backward-first"?["backward","forward"]:["forward","backward"],o=a=>{if(a==="backward"){for(let c=t-1;c>=0;c--)if(n.has(e[c]))return e[c]}else for(let c=t+1;c<e.length;c++)if(n.has(e[c]))return e[c];return null};return o(r)??o(i)}function _(t,e,n,s){let r=new Set(n.filter((o,a)=>s.has(o)&&!e.has(t[a]))),i=new Map;for(let o=0;o<t.length;o++){let a=t[o];e.has(a)&&i.set(a,L(o,n,r,"forward-first"));}return i}function N(t,e){return Math.min(t*e,150)}function I(t){let e=getComputedStyle(t).transform;if(!e||e==="none")return {tx:0,ty:0};let n=e.match(/matrix\(([^)]+)\)/);if(!n)return {tx:0,ty:0};let s=n[1].split(",").map(Number);return {tx:s[4]||0,ty:s[5]||0}}function z(t){let{tx:e,ty:n}=I(t),s=Number(getComputedStyle(t).opacity)||1;return t.getAnimations().forEach(r=>r.cancel()),{tx:e,ty:n,opacity:s}}function k(t,e){let{dx:n,dy:s,duration:r,ease:i,scale:o}=e;t.animate({transform:o?`translate(${n}px, ${s}px) scale(0.95)`:`translate(${n}px, ${s}px)`,offset:1},{duration:r,easing:i,fill:"both"});let a=t.animate({opacity:0,offset:1},{duration:N(r,.25),easing:"linear",fill:"both"});a.onfinish=()=>t.remove();}function P(t,e){let{deltaX:n,deltaY:s,isNew:r,duration:i,ease:o}=e,a=z(t),c=n+a.tx,u=s+a.ty;t.animate({transform:`translate(${c}px, ${u}px) scale(${r?.95:1})`,offset:0},{duration:i,easing:o,fill:"both"});let l=r&&a.opacity>=1?0:a.opacity;l<1&&t.animate([{opacity:l},{opacity:1}],{duration:N(i,r?.5:.25),easing:"linear",fill:"both"});}var T=null;function F(t,e,n,s,r){if(T&&(T(),T=null),e===0||n===0)return;t.style.width="auto",t.style.height="auto",t.offsetWidth;let i=t.offsetWidth,o=t.offsetHeight;t.style.width=`${e}px`,t.style.height=`${n}px`,t.offsetWidth,t.style.width=`${i}px`,t.style.height=`${o}px`;function a(){t.removeEventListener("transitionend",c),clearTimeout(u),T=null,t.style.width="auto",t.style.height="auto",r?.();}function c(l){l.target===t&&(l.propertyName!=="width"&&l.propertyName!=="height"||a());}t.addEventListener("transitionend",c);let u=setTimeout(a,s+50);T=()=>{t.removeEventListener("transitionend",c),clearTimeout(u),T=null;};}function X(t){let n=t[0]?.parentElement?.getBoundingClientRect(),s=t.map(r=>{let{tx:i,ty:o}=I(r),a=Number(getComputedStyle(r).opacity)||1;r.getAnimations().forEach(u=>u.cancel());let c=r.getBoundingClientRect();return {left:(n?c.left-n.left:c.left)+i,top:(n?c.top-n.top:c.top)+o,width:c.width,height:c.height,opacity:a}});t.forEach((r,i)=>{let o=s[i];r.setAttribute(f,""),r.style.position="absolute",r.style.pointerEvents="none",r.style.left=`${o.left}px`,r.style.top=`${o.top}px`,r.style.width=`${o.width}px`,r.style.height=`${o.height}px`,r.style.opacity=String(o.opacity);});}function B(t,e,n,s){let r=new Map;e.forEach(i=>{let o=i.getAttribute(d);n.has(o)&&!i.hasAttribute(f)&&(r.set(o,i),i.remove());}),Array.from(t.childNodes).forEach(i=>{i.nodeType===Node.TEXT_NODE&&i.remove();}),s.forEach(i=>{let o=r.get(i.id);if(o)o.textContent=i.string,t.appendChild(o);else {let a=document.createElement("span");a.setAttribute(M,""),a.setAttribute(d,i.id),a.textContent=i.string,t.appendChild(a);}});}var Z=`
2
+ [${x}] {
3
+ display: inline-block;
4
4
  position: relative;
5
5
  will-change: width, height;
6
6
  transition-property: width, height;
7
7
  white-space: nowrap;
8
8
  }
9
9
 
10
- [torph-item] {
10
+ [${M}] {
11
11
  display: inline-block;
12
12
  will-change: opacity, transform;
13
13
  transform: none;
14
14
  opacity: 1;
15
15
  }
16
16
 
17
- [torph-root][torph-debug] {
18
- outline:2px solid magenta;
19
- [torph-item] {
20
- outline:2px solid cyan;
17
+ [${x}][${b}] {
18
+ outline: 2px solid magenta;
19
+ [${M}] {
20
+ outline: 2px solid cyan;
21
21
  outline-offset: -4px;
22
22
  }
23
- }
24
- `,document.head.appendChild(t),h.styleEl=t;}removeStyles(){h.styleEl&&(h.styleEl.remove(),h.styleEl=void 0);}blocks(t){return Array.from(t).reduce((o,i)=>i.segment===" "?[...o,{id:`space-${i.index}`,string:"\xA0"}]:o.find(l=>l.string===i.segment)?[...o,{id:`${i.segment}-${i.index}`,string:i.segment}]:[...o,{id:i.segment,string:i.segment}],[])}blocksFallback(t,s){let o=s?t.split(" "):t.split(""),i=[];return s?o.forEach((a,l)=>{l>0&&i.push({id:`space-${l}`,string:"\xA0"}),i.find(d=>d.string===a)?i.push({id:`${a}-${l}`,string:a}):i.push({id:a,string:a});}):o.forEach((a,l)=>{i.find(d=>d.string===a)?i.push({id:`${a}-${l}`,string:a}):i.push({id:a,string:a});}),i}log(...t){this.options.debug&&console.log("[TextMorph]",...t);}};function w(h){if(typeof h=="string")return h;if(typeof h=="number")return String(h);if(!h||typeof h=="boolean")return "";if(Array.isArray(h))return h.map(w).join("");throw c__default.default.isValidElement(h)?new Error("TextMorph only accepts text content. Found a React element \u2014 use strings, numbers, or expressions instead."):new Error(`TextMorph received an unsupported child of type "${typeof h}".`)}var R=({children:h,className:t,style:s,as:o=A,...i})=>{let{ref:a,update:l}=S(i),p=w(h),d=c__default.default.useRef({__html:p});return c__default.default.useEffect(()=>{l(p);},[p,l]),c__default.default.createElement(o,{ref:a,className:t,style:s,dangerouslySetInnerHTML:d.current})};function S(h){let t=c__default.default.useRef(null),s=c__default.default.useRef(null);c__default.default.useEffect(()=>(t.current&&(s.current=new b({element:t.current,...h})),()=>{s.current?.destroy();}),[]);let o=c__default.default.useCallback(i=>{s.current?.update(i);},[]);return {ref:t,update:o}}exports.TextMorph=R;exports.useTextMorph=S;//# sourceMappingURL=index.js.map
25
- //# sourceMappingURL=index.js.map
23
+ }`,h=null,O=0;function G(){O++,!h&&(h=document.createElement("style"),h.dataset.torph="true",h.textContent=Z,document.head.appendChild(h));}function U(){O--,!(O>0||!h)&&(h.remove(),h=null);}function j(){if(typeof window>"u")return {prefersReducedMotion:false,destroy:()=>{}};let t=window.matchMedia("(prefers-reduced-motion: reduce)"),e={prefersReducedMotion:t.matches,destroy:s};function n(r){e.prefersReducedMotion=r.matches;}function s(){t.removeEventListener("change",n);}return t.addEventListener("change",n),e}var E=class t{instance=null;lastText="";configKey="";attach(e,n){this.instance?.destroy(),this.instance=new A({element:e,...n}),this.configKey=t.serializeConfig(n),this.lastText&&this.instance.update(this.lastText);}update(e){this.lastText=e,this.instance?.update(e);}needsRecreate(e){return t.serializeConfig(e)!==this.configKey}destroy(){this.instance?.destroy(),this.instance=null;}static serializeConfig(e){return JSON.stringify({ease:e.ease,duration:e.duration,locale:e.locale,scale:e.scale,debug:e.debug,disabled:e.disabled,respectReducedMotion:e.respectReducedMotion})}};var K="span",tt={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},A=class{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;reducedMotion=null;constructor(e){let{ease:n,...s}={...tt,...e},r,i;if(typeof n=="object"){let o=C(n);r=o.easing,i=o.duration;}else r=n,i=s.duration;this.options={...s,ease:r,duration:i},this.element=e.element,this.options.respectReducedMotion&&(this.reducedMotion=j()),this.isDisabled()||(this.element.setAttribute(x,""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,e.debug&&this.element.setAttribute(b,"")),this.data="",this.isDisabled()||G();}destroy(){this.reducedMotion?.destroy(),this.element.getAnimations().forEach(e=>e.cancel()),this.element.removeAttribute(x),this.element.removeAttribute(b),U();}isDisabled(){return !!(this.options.disabled||this.reducedMotion?.prefersReducedMotion)}update(e){if(e!==this.data){if(this.data=e,this.isDisabled()){typeof e=="string"&&(this.element.textContent=e);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(e,n){let s=n.offsetWidth,r=n.offsetHeight,i=D(e,this.options.locale);this.prevMeasures=w(this.element);let o=Array.from(n.children),a=new Set(i.map(p=>p.id)),c=o.filter(p=>!a.has(p.getAttribute(d))&&!p.hasAttribute(f)),u=new Set(c),l=o.map(p=>p.getAttribute(d)),m=_(o,u,l,a);if(X(c),B(n,o,a,i),this.currentMeasures=w(this.element),this.updateStyles(i),c.forEach(p=>{if(this.isInitialRender){p.remove();return}let y=m.get(p),{dx:R,dy:S}=y?v(this.currentMeasures,this.prevMeasures,y):{dx:0,dy:0};k(p,{dx:R,dy:S,duration:this.options.duration,ease:this.options.ease,scale:this.options.scale});}),this.isInitialRender){this.isInitialRender=false,n.style.width="auto",n.style.height="auto";return}F(n,s,r,this.options.duration,this.options.onAnimationComplete);}updateStyles(e){if(this.isInitialRender)return;let n=Array.from(this.element.children),s=e.map(i=>i.id),r=new Set(s.filter(i=>this.prevMeasures[i]));n.forEach((i,o)=>{if(i.hasAttribute(f))return;let a=i.getAttribute(d)||`child-${o}`,c=!this.prevMeasures[a],u=c?L(e.findIndex(p=>p.id===a),s,r):a,{dx:l,dy:m}=u?v(this.prevMeasures,this.currentMeasures,u):{dx:0,dy:0};P(i,{deltaX:l,deltaY:m,isNew:c,duration:this.options.duration,ease:this.options.ease});});}};function W(t){if(typeof t=="string")return t;if(typeof t=="number")return String(t);if(!t||typeof t=="boolean")return "";if(Array.isArray(t))return t.map(W).join("");throw g__default.default.isValidElement(t)?new Error("TextMorph only accepts text content. Found a React element \u2014 use strings, numbers, or expressions instead."):new Error(`TextMorph received an unsupported child of type "${typeof t}".`)}var et=({children:t,className:e,style:n,as:s=K,...r})=>{let{ref:i,update:o}=q(r),a=W(t),c=g__default.default.useRef({__html:a});return g__default.default.useEffect(()=>{o(a);},[a,o]),g__default.default.createElement(s,{ref:i,className:e,style:n,dangerouslySetInnerHTML:c.current})};function q(t){let e=g__default.default.useRef(null),n=g__default.default.useRef(new E),s=E.serializeConfig(t);g__default.default.useEffect(()=>(e.current&&n.current.attach(e.current,t),()=>{n.current.destroy();}),[s]);let r=g__default.default.useCallback(i=>{n.current.update(i);},[]);return {ref:e,update:r}}exports.TextMorph=et;exports.useTextMorph=q;
@@ -1,25 +1,23 @@
1
- import c from'react';var A="span",$={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},b=class h{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;prefersReducedMotion=false;mediaQuery;static styleEl;constructor(t){this.options={...$,...t},this.element=t.element,typeof window<"u"&&this.options.respectReducedMotion&&(this.mediaQuery=window.matchMedia("(prefers-reduced-motion: reduce)"),this.prefersReducedMotion=this.mediaQuery.matches,this.mediaQuery.addEventListener("change",this.handleMediaQueryChange)),this.isDisabled()||(this.element.setAttribute("torph-root",""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,t.debug&&this.element.setAttribute("torph-debug","")),this.data="",this.isDisabled()||this.addStyles();}destroy(){this.mediaQuery&&this.mediaQuery.removeEventListener("change",this.handleMediaQueryChange),this.element.getAnimations().forEach(t=>t.cancel()),this.element.removeAttribute("torph-root"),this.element.removeAttribute("torph-debug"),this.removeStyles();}handleMediaQueryChange=t=>{this.prefersReducedMotion=t.matches;};isDisabled(){return !!(this.options.disabled||this.options.respectReducedMotion&&this.prefersReducedMotion)}update(t){if(t!==this.data){if(this.data=t,this.isDisabled()){typeof t=="string"&&(this.element.textContent=t);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(t,s){let o=s.offsetWidth,i=s.offsetHeight,a=t.includes(" "),l;if(typeof Intl.Segmenter<"u"){let n=new Intl.Segmenter(this.options.locale,{granularity:a?"word":"grapheme"}).segment(t)[Symbol.iterator]();l=this.blocks(n);}else l=this.blocksFallback(t,a);this.prevMeasures=this.measure();let p=Array.from(s.children),d=new Set(l.map(e=>e.id)),m=p.filter(e=>!d.has(e.getAttribute("torph-id"))&&!e.hasAttribute("torph-exiting")),y=new Set(m),x=new Map;for(let e=0;e<p.length;e++){let n=p[e];if(!y.has(n))continue;let u=null;for(let r=e+1;r<p.length;r++){let f=p[r].getAttribute("torph-id");if(d.has(f)&&!y.has(p[r])){u=f;break}}if(!u)for(let r=e-1;r>=0;r--){let f=p[r].getAttribute("torph-id");if(d.has(f)&&!y.has(p[r])){u=f;break}}x.set(n,u);}let M=m.map(e=>(e.getAnimations().forEach(n=>n.cancel()),{left:e.offsetLeft,top:e.offsetTop,width:e.offsetWidth,height:e.offsetHeight}));if(m.forEach((e,n)=>{let u=M[n];e.setAttribute("torph-exiting",""),e.style.position="absolute",e.style.pointerEvents="none",e.style.left=`${u.left}px`,e.style.top=`${u.top}px`,e.style.width=`${u.width}px`,e.style.height=`${u.height}px`;}),p.forEach(e=>{let n=e.getAttribute("torph-id");d.has(n)&&e.remove();}),Array.from(s.childNodes).forEach(e=>{e.nodeType===Node.TEXT_NODE&&e.remove();}),l.forEach(e=>{let n=document.createElement("span");n.setAttribute("torph-item",""),n.setAttribute("torph-id",e.id),n.textContent=e.string,s.appendChild(n);}),this.currentMeasures=this.measure(),this.updateStyles(l),m.forEach(e=>{if(this.isInitialRender){e.remove();return}let n=x.get(e),u=0,r=0;if(n&&this.prevMeasures[n]&&this.currentMeasures[n]){let E=this.prevMeasures[n],v=this.currentMeasures[n];u=v.x-E.x,r=v.y-E.y;}e.animate({transform:this.options.scale?`translate(${u}px, ${r}px) scale(0.95)`:`translate(${u}px, ${r}px)`,offset:1},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let f=e.animate({opacity:0,offset:1},{duration:this.options.duration*.25,easing:"linear",fill:"both"});f.onfinish=()=>e.remove();}),this.isInitialRender){this.isInitialRender=false,s.style.width="auto",s.style.height="auto";return}if(o===0||i===0)return;s.style.width="auto",s.style.height="auto",s.offsetWidth;let g=s.offsetWidth,T=s.offsetHeight;s.style.width=`${o}px`,s.style.height=`${i}px`,s.offsetWidth,s.style.width=`${g}px`,s.style.height=`${T}px`,setTimeout(()=>{s.style.width="auto",s.style.height="auto",this.options.onAnimationComplete&&this.options.onAnimationComplete();},this.options.duration);}measure(){let t=Array.from(this.element.children),s={};return t.forEach((o,i)=>{if(o.hasAttribute("torph-exiting"))return;let a=o.getAttribute("torph-id")||`child-${i}`;s[a]={x:o.offsetLeft,y:o.offsetTop};}),s}updateStyles(t){if(this.isInitialRender)return;let s=Array.from(this.element.children),o=new Set(t.map(i=>i.id).filter(i=>this.prevMeasures[i]));s.forEach((i,a)=>{if(i.hasAttribute("torph-exiting"))return;let l=i.getAttribute("torph-id")||`child-${a}`,p=this.prevMeasures[l],d=this.currentMeasures[l],m=d?.x||0,y=d?.y||0,x=p?p.x-m:0,M=p?p.y-y:0,g=!p;if(g){let n=t.findIndex(r=>r.id===l),u=null;for(let r=n-1;r>=0;r--)if(o.has(t[r].id)){u=t[r].id;break}if(!u){for(let r=n+1;r<t.length;r++)if(o.has(t[r].id)){u=t[r].id;break}}if(u){let r=this.prevMeasures[u],f=this.currentMeasures[u];x=r.x-f.x,M=r.y-f.y;}}i.getAnimations().forEach(n=>n.cancel()),i.animate({transform:`translate(${x}px, ${M}px) scale(${g?.95:1})`,offset:0},{duration:this.options.duration,easing:this.options.ease,fill:"both"});let T=g?this.options.duration*.25:0,e=g?this.options.duration*.25:0;i.animate({opacity:g?0:1,offset:0},{duration:T,delay:e,easing:"linear",fill:"both"});});}addStyles(){if(h.styleEl)return;let t=document.createElement("style");t.dataset.torph="true",t.innerHTML=`
2
- [torph-root] {
3
- display: inline-flex;
1
+ import g from'react';function H(t,e,n){if(n<1){let c=e*Math.sqrt(1-n*n);return 1-Math.exp(-n*e*t)*(Math.cos(c*t)+n*e/c*Math.sin(c*t))}let s=Math.sqrt(n*n-1),r=-e*(n+s),i=-e*(n-s),o=-r/(i-r);return 1-(1-o)*Math.exp(r*t)-o*Math.exp(i*t)}function Y(t,e,n){let i=0;for(let o=0;o<10;o+=.001)if(Math.abs(H(o,t,e)-1)>n)i=0;else if(i+=.001,i>.1)return Math.ceil((o-i+.001)*1e3);return Math.ceil(10*1e3)}var $=new Map;function C(t){let{stiffness:e=100,damping:n=10,mass:s=1,precision:r=.001}=t??{},i=`${e}:${n}:${s}:${r}`,o=$.get(i);if(o)return o;let a=Math.sqrt(e/s),c=n/(2*Math.sqrt(e*s)),u=Y(a,c,r),l=Math.min(100,Math.max(32,Math.round(u/15))),m=[];for(let y=0;y<l;y++){let R=y/(l-1)*(u/1e3),S=y===l-1?1:H(R,a,c);m.push(Math.round(S*1e4)/1e4+"");}for(;m.length>2&&m[m.length-2]==="1";)m.splice(m.length-2,1);let p={easing:`linear(${m.join(", ")})`,duration:u};return $.set(i,p),p}function D(t,e){let n=t.includes(" ");if(typeof Intl.Segmenter<"u"){let r=new Intl.Segmenter(e,{granularity:n?"word":"grapheme"}).segment(t)[Symbol.iterator]();return Q(r)}return V(t,n)}function Q(t){return Array.from(t).reduce((e,n)=>n.segment===" "?[...e,{id:`space-${n.index}`,string:"\xA0"}]:e.find(r=>r.string===n.segment)?[...e,{id:`${n.segment}-${n.index}`,string:n.segment}]:[...e,{id:n.segment,string:n.segment}],[])}function J(t,e,n){let s=t.find(r=>r.string===e);t.push(s?{id:`${e}-${n}`,string:e}:{id:e,string:e});}function V(t,e){let n=e?t.split(" "):t.split(""),s=[];return n.forEach((r,i)=>{e&&i>0&&s.push({id:`space-${i}`,string:"\xA0"}),J(s,r,i);}),s}var x="torph-root",M="torph-item",d="torph-id",f="torph-exiting",b="torph-debug";function w(t){let e=Array.from(t.children),n={},s=t.getBoundingClientRect();return e.forEach((r,i)=>{if(r.hasAttribute(f))return;let o=r.getAttribute(d)||`child-${i}`,a=r.getBoundingClientRect();n[o]={x:a.left-s.left,y:a.top-s.top};}),n}function v(t,e,n){let s=t[n],r=e[n];return !s||!r?{dx:0,dy:0}:{dx:s.x-r.x,dy:s.y-r.y}}function L(t,e,n,s="backward-first"){let[r,i]=s==="backward-first"?["backward","forward"]:["forward","backward"],o=a=>{if(a==="backward"){for(let c=t-1;c>=0;c--)if(n.has(e[c]))return e[c]}else for(let c=t+1;c<e.length;c++)if(n.has(e[c]))return e[c];return null};return o(r)??o(i)}function _(t,e,n,s){let r=new Set(n.filter((o,a)=>s.has(o)&&!e.has(t[a]))),i=new Map;for(let o=0;o<t.length;o++){let a=t[o];e.has(a)&&i.set(a,L(o,n,r,"forward-first"));}return i}function N(t,e){return Math.min(t*e,150)}function I(t){let e=getComputedStyle(t).transform;if(!e||e==="none")return {tx:0,ty:0};let n=e.match(/matrix\(([^)]+)\)/);if(!n)return {tx:0,ty:0};let s=n[1].split(",").map(Number);return {tx:s[4]||0,ty:s[5]||0}}function z(t){let{tx:e,ty:n}=I(t),s=Number(getComputedStyle(t).opacity)||1;return t.getAnimations().forEach(r=>r.cancel()),{tx:e,ty:n,opacity:s}}function k(t,e){let{dx:n,dy:s,duration:r,ease:i,scale:o}=e;t.animate({transform:o?`translate(${n}px, ${s}px) scale(0.95)`:`translate(${n}px, ${s}px)`,offset:1},{duration:r,easing:i,fill:"both"});let a=t.animate({opacity:0,offset:1},{duration:N(r,.25),easing:"linear",fill:"both"});a.onfinish=()=>t.remove();}function P(t,e){let{deltaX:n,deltaY:s,isNew:r,duration:i,ease:o}=e,a=z(t),c=n+a.tx,u=s+a.ty;t.animate({transform:`translate(${c}px, ${u}px) scale(${r?.95:1})`,offset:0},{duration:i,easing:o,fill:"both"});let l=r&&a.opacity>=1?0:a.opacity;l<1&&t.animate([{opacity:l},{opacity:1}],{duration:N(i,r?.5:.25),easing:"linear",fill:"both"});}var T=null;function F(t,e,n,s,r){if(T&&(T(),T=null),e===0||n===0)return;t.style.width="auto",t.style.height="auto",t.offsetWidth;let i=t.offsetWidth,o=t.offsetHeight;t.style.width=`${e}px`,t.style.height=`${n}px`,t.offsetWidth,t.style.width=`${i}px`,t.style.height=`${o}px`;function a(){t.removeEventListener("transitionend",c),clearTimeout(u),T=null,t.style.width="auto",t.style.height="auto",r?.();}function c(l){l.target===t&&(l.propertyName!=="width"&&l.propertyName!=="height"||a());}t.addEventListener("transitionend",c);let u=setTimeout(a,s+50);T=()=>{t.removeEventListener("transitionend",c),clearTimeout(u),T=null;};}function X(t){let n=t[0]?.parentElement?.getBoundingClientRect(),s=t.map(r=>{let{tx:i,ty:o}=I(r),a=Number(getComputedStyle(r).opacity)||1;r.getAnimations().forEach(u=>u.cancel());let c=r.getBoundingClientRect();return {left:(n?c.left-n.left:c.left)+i,top:(n?c.top-n.top:c.top)+o,width:c.width,height:c.height,opacity:a}});t.forEach((r,i)=>{let o=s[i];r.setAttribute(f,""),r.style.position="absolute",r.style.pointerEvents="none",r.style.left=`${o.left}px`,r.style.top=`${o.top}px`,r.style.width=`${o.width}px`,r.style.height=`${o.height}px`,r.style.opacity=String(o.opacity);});}function B(t,e,n,s){let r=new Map;e.forEach(i=>{let o=i.getAttribute(d);n.has(o)&&!i.hasAttribute(f)&&(r.set(o,i),i.remove());}),Array.from(t.childNodes).forEach(i=>{i.nodeType===Node.TEXT_NODE&&i.remove();}),s.forEach(i=>{let o=r.get(i.id);if(o)o.textContent=i.string,t.appendChild(o);else {let a=document.createElement("span");a.setAttribute(M,""),a.setAttribute(d,i.id),a.textContent=i.string,t.appendChild(a);}});}var Z=`
2
+ [${x}] {
3
+ display: inline-block;
4
4
  position: relative;
5
5
  will-change: width, height;
6
6
  transition-property: width, height;
7
7
  white-space: nowrap;
8
8
  }
9
9
 
10
- [torph-item] {
10
+ [${M}] {
11
11
  display: inline-block;
12
12
  will-change: opacity, transform;
13
13
  transform: none;
14
14
  opacity: 1;
15
15
  }
16
16
 
17
- [torph-root][torph-debug] {
18
- outline:2px solid magenta;
19
- [torph-item] {
20
- outline:2px solid cyan;
17
+ [${x}][${b}] {
18
+ outline: 2px solid magenta;
19
+ [${M}] {
20
+ outline: 2px solid cyan;
21
21
  outline-offset: -4px;
22
22
  }
23
- }
24
- `,document.head.appendChild(t),h.styleEl=t;}removeStyles(){h.styleEl&&(h.styleEl.remove(),h.styleEl=void 0);}blocks(t){return Array.from(t).reduce((o,i)=>i.segment===" "?[...o,{id:`space-${i.index}`,string:"\xA0"}]:o.find(l=>l.string===i.segment)?[...o,{id:`${i.segment}-${i.index}`,string:i.segment}]:[...o,{id:i.segment,string:i.segment}],[])}blocksFallback(t,s){let o=s?t.split(" "):t.split(""),i=[];return s?o.forEach((a,l)=>{l>0&&i.push({id:`space-${l}`,string:"\xA0"}),i.find(d=>d.string===a)?i.push({id:`${a}-${l}`,string:a}):i.push({id:a,string:a});}):o.forEach((a,l)=>{i.find(d=>d.string===a)?i.push({id:`${a}-${l}`,string:a}):i.push({id:a,string:a});}),i}log(...t){this.options.debug&&console.log("[TextMorph]",...t);}};function w(h){if(typeof h=="string")return h;if(typeof h=="number")return String(h);if(!h||typeof h=="boolean")return "";if(Array.isArray(h))return h.map(w).join("");throw c.isValidElement(h)?new Error("TextMorph only accepts text content. Found a React element \u2014 use strings, numbers, or expressions instead."):new Error(`TextMorph received an unsupported child of type "${typeof h}".`)}var R=({children:h,className:t,style:s,as:o=A,...i})=>{let{ref:a,update:l}=S(i),p=w(h),d=c.useRef({__html:p});return c.useEffect(()=>{l(p);},[p,l]),c.createElement(o,{ref:a,className:t,style:s,dangerouslySetInnerHTML:d.current})};function S(h){let t=c.useRef(null),s=c.useRef(null);c.useEffect(()=>(t.current&&(s.current=new b({element:t.current,...h})),()=>{s.current?.destroy();}),[]);let o=c.useCallback(i=>{s.current?.update(i);},[]);return {ref:t,update:o}}export{R as TextMorph,S as useTextMorph};//# sourceMappingURL=index.mjs.map
25
- //# sourceMappingURL=index.mjs.map
23
+ }`,h=null,O=0;function G(){O++,!h&&(h=document.createElement("style"),h.dataset.torph="true",h.textContent=Z,document.head.appendChild(h));}function U(){O--,!(O>0||!h)&&(h.remove(),h=null);}function j(){if(typeof window>"u")return {prefersReducedMotion:false,destroy:()=>{}};let t=window.matchMedia("(prefers-reduced-motion: reduce)"),e={prefersReducedMotion:t.matches,destroy:s};function n(r){e.prefersReducedMotion=r.matches;}function s(){t.removeEventListener("change",n);}return t.addEventListener("change",n),e}var E=class t{instance=null;lastText="";configKey="";attach(e,n){this.instance?.destroy(),this.instance=new A({element:e,...n}),this.configKey=t.serializeConfig(n),this.lastText&&this.instance.update(this.lastText);}update(e){this.lastText=e,this.instance?.update(e);}needsRecreate(e){return t.serializeConfig(e)!==this.configKey}destroy(){this.instance?.destroy(),this.instance=null;}static serializeConfig(e){return JSON.stringify({ease:e.ease,duration:e.duration,locale:e.locale,scale:e.scale,debug:e.debug,disabled:e.disabled,respectReducedMotion:e.respectReducedMotion})}};var K="span",tt={debug:false,locale:"en",duration:400,scale:true,ease:"cubic-bezier(0.19, 1, 0.22, 1)",disabled:false,respectReducedMotion:true},A=class{element;options={};data;currentMeasures={};prevMeasures={};isInitialRender=true;reducedMotion=null;constructor(e){let{ease:n,...s}={...tt,...e},r,i;if(typeof n=="object"){let o=C(n);r=o.easing,i=o.duration;}else r=n,i=s.duration;this.options={...s,ease:r,duration:i},this.element=e.element,this.options.respectReducedMotion&&(this.reducedMotion=j()),this.isDisabled()||(this.element.setAttribute(x,""),this.element.style.transitionDuration=`${this.options.duration}ms`,this.element.style.transitionTimingFunction=this.options.ease,e.debug&&this.element.setAttribute(b,"")),this.data="",this.isDisabled()||G();}destroy(){this.reducedMotion?.destroy(),this.element.getAnimations().forEach(e=>e.cancel()),this.element.removeAttribute(x),this.element.removeAttribute(b),U();}isDisabled(){return !!(this.options.disabled||this.reducedMotion?.prefersReducedMotion)}update(e){if(e!==this.data){if(this.data=e,this.isDisabled()){typeof e=="string"&&(this.element.textContent=e);return}if(this.data instanceof HTMLElement)throw new Error("HTMLElement not yet supported");this.options.onAnimationStart&&!this.isInitialRender&&this.options.onAnimationStart(),this.createTextGroup(this.data,this.element);}}createTextGroup(e,n){let s=n.offsetWidth,r=n.offsetHeight,i=D(e,this.options.locale);this.prevMeasures=w(this.element);let o=Array.from(n.children),a=new Set(i.map(p=>p.id)),c=o.filter(p=>!a.has(p.getAttribute(d))&&!p.hasAttribute(f)),u=new Set(c),l=o.map(p=>p.getAttribute(d)),m=_(o,u,l,a);if(X(c),B(n,o,a,i),this.currentMeasures=w(this.element),this.updateStyles(i),c.forEach(p=>{if(this.isInitialRender){p.remove();return}let y=m.get(p),{dx:R,dy:S}=y?v(this.currentMeasures,this.prevMeasures,y):{dx:0,dy:0};k(p,{dx:R,dy:S,duration:this.options.duration,ease:this.options.ease,scale:this.options.scale});}),this.isInitialRender){this.isInitialRender=false,n.style.width="auto",n.style.height="auto";return}F(n,s,r,this.options.duration,this.options.onAnimationComplete);}updateStyles(e){if(this.isInitialRender)return;let n=Array.from(this.element.children),s=e.map(i=>i.id),r=new Set(s.filter(i=>this.prevMeasures[i]));n.forEach((i,o)=>{if(i.hasAttribute(f))return;let a=i.getAttribute(d)||`child-${o}`,c=!this.prevMeasures[a],u=c?L(e.findIndex(p=>p.id===a),s,r):a,{dx:l,dy:m}=u?v(this.prevMeasures,this.currentMeasures,u):{dx:0,dy:0};P(i,{deltaX:l,deltaY:m,isNew:c,duration:this.options.duration,ease:this.options.ease});});}};function W(t){if(typeof t=="string")return t;if(typeof t=="number")return String(t);if(!t||typeof t=="boolean")return "";if(Array.isArray(t))return t.map(W).join("");throw g.isValidElement(t)?new Error("TextMorph only accepts text content. Found a React element \u2014 use strings, numbers, or expressions instead."):new Error(`TextMorph received an unsupported child of type "${typeof t}".`)}var et=({children:t,className:e,style:n,as:s=K,...r})=>{let{ref:i,update:o}=q(r),a=W(t),c=g.useRef({__html:a});return g.useEffect(()=>{o(a);},[a,o]),g.createElement(s,{ref:i,className:e,style:n,dangerouslySetInnerHTML:c.current})};function q(t){let e=g.useRef(null),n=g.useRef(new E),s=E.serializeConfig(t);g.useEffect(()=>(e.current&&n.current.attach(e.current,t),()=>{n.current.destroy();}),[s]);let r=g.useCallback(i=>{n.current.update(i);},[]);return {ref:e,update:r}}export{et as TextMorph,q as useTextMorph};