@liiift-studio/threadtext 0.1.0 → 0.2.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 +20 -13
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +462 -374
- package/dist/threadtext.webflow.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
**Render any text as photorealistic, procedural satin-stitch embroidery — in real time, in the browser, from the font's actual glyph geometry.**
|
|
4
4
|
|
|
5
|
-
> Status: **
|
|
6
|
-
> hook
|
|
7
|
-
>
|
|
8
|
-
> The original reference renderer lives in
|
|
9
|
-
>
|
|
10
|
-
>
|
|
5
|
+
> Status: **shipped.** Published to npm (`@liiift-studio/threadtext`) with a framework-agnostic
|
|
6
|
+
> core (`createThreadText`), a React hook + component, Framer and Webflow ports, tests, and a
|
|
7
|
+
> live landing site at [threadtext.com](https://threadtext.com) (demo font: the OFL Fraunces
|
|
8
|
+
> variable). The original single-file reference renderer lives in
|
|
9
|
+
> [`demo/index.html`](./demo/index.html) as the visual oracle; tool-build conventions are in the
|
|
10
|
+
> monorepo [`../GUIDE.md`](../GUIDE.md).
|
|
11
11
|
|
|
12
12
|
Homepage: [threadtext.com](https://threadtext.com) · npm: `@liiift-studio/threadtext`
|
|
13
13
|
|
|
@@ -58,10 +58,12 @@ const thread = createThreadText(document.getElementById('host'), {
|
|
|
58
58
|
weight: 680,
|
|
59
59
|
})
|
|
60
60
|
|
|
61
|
-
thread.setText('Threads')
|
|
62
|
-
thread.
|
|
63
|
-
thread.
|
|
64
|
-
thread.
|
|
61
|
+
thread.setText('Threads') // re-fit to width and redraw instantly (no sew-in)
|
|
62
|
+
thread.update({ threadColor: '#e6c200', fill: 0.8 }) // live changes — instant, no re-sew
|
|
63
|
+
thread.replay() // re-run the sew-in animation
|
|
64
|
+
thread.resize() // re-fit to the container
|
|
65
|
+
thread.focus() // focus the surface for typing (editable mode)
|
|
66
|
+
thread.destroy() // cancel rAF, remove listeners, free canvases
|
|
65
67
|
```
|
|
66
68
|
|
|
67
69
|
React:
|
|
@@ -73,14 +75,19 @@ import { ThreadText } from '@liiift-studio/threadtext'
|
|
|
73
75
|
```
|
|
74
76
|
|
|
75
77
|
Thread colour, `fill` (size — the word re-fits to the container width on load/resize),
|
|
76
|
-
`weight`, `font`, `
|
|
77
|
-
|
|
78
|
+
`weight`, `font`, `sewStyle` (`'machine'` satin rows or `'hand'` — a single thread that
|
|
79
|
+
wanders stitch by stitch), `sewRate`, `sheen`, `animate`, and `editable` (type straight on
|
|
80
|
+
the artwork — backed by a real input, so touch keyboards and IME work) with an `onTextChange`
|
|
81
|
+
callback are all options — see `ThreadTextOptions`. Change any of them live with
|
|
78
82
|
`instance.update(...)` — it redraws instantly, never re-running the sew-in. `react`/`react-dom`
|
|
79
83
|
are optional peers; the core is framework-free.
|
|
80
84
|
|
|
81
85
|
## What's next
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
Now shipped. Remaining ideas (see `HANDOFF.md`): region-limit or move the per-keystroke geometry
|
|
88
|
+
rebuild to a Web Worker/WASM (it currently re-runs the full distance-transform pipeline on every
|
|
89
|
+
edit); real variable-font axis control (`opsz`/`wght`) via path-based glyph rendering, since canvas
|
|
90
|
+
`fillText` can't set `font-variation-settings`; and additional stitch modes (chain, cross, running).
|
|
84
91
|
|
|
85
92
|
---
|
|
86
93
|
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const X=require("react"),xe=require("react/jsx-runtime"),pt={bg:"tt-bg",fx:"tt-fx",caret:"tt-caret"};function Q(m,e){let o=Math.imul(m|0,374761393)+Math.imul(e|0,668265263)|0;return o=Math.imul(o^o>>>13,1274126177),((o^o>>>16)>>>0)/4294967295}function Qt(m,e){const o=Math.floor(m),r=Math.floor(e),i=m-o,a=e-r,f=i*i*(3-2*i),A=a*a*(3-2*a),E=Q(o,r),C=Q(o+1,r),c=Q(o,r+1),d=Q(o+1,r+1);return E+(C-E)*f+(c-E)*A+(E-C-c+d)*f*A}const Mt=1e20;function Zt(m,e,o,r,i){let a=0;r[0]=0,i[0]=-Mt,i[1]=Mt;for(let f=1;f<e;f++){let A=(m[f]+f*f-(m[r[a]]+r[a]*r[a]))/(2*f-2*r[a]);for(;A<=i[a];)a--,A=(m[f]+f*f-(m[r[a]]+r[a]*r[a]))/(2*f-2*r[a]);a++,r[a]=f,i[a]=A,i[a+1]=Mt}a=0;for(let f=0;f<e;f++){for(;i[a+1]<f;)a++;o[f]=(f-r[a])*(f-r[a])+m[r[a]]}}function ge(m,e,o){const r=new Float64Array(e*o);for(let c=0;c<e*o;c++)r[c]=m[c]?Mt:0;const i=Math.max(e,o),a=new Float64Array(i),f=new Float64Array(i),A=new Int32Array(i),E=new Float64Array(i+1);for(let c=0;c<e;c++){for(let d=0;d<o;d++)a[d]=r[d*e+c];Zt(a,o,f,A,E);for(let d=0;d<o;d++)r[d*e+c]=f[d]}for(let c=0;c<o;c++){for(let d=0;d<e;d++)a[d]=r[c*e+d];Zt(a,e,f,A,E);for(let d=0;d<e;d++)r[c*e+d]=f[d]}const C=new Float32Array(e*o);for(let c=0;c<e*o;c++)C[c]=Math.sqrt(r[c]);return C}function Ht(m,e,o,r,i){let a=Float32Array.from(m);const f=new Float32Array(e*o),A=1/(2*r+1),E=(C,c)=>C<0?0:C>c?c:C;for(let C=0;C<i;C++){for(let c=0;c<o;c++){const d=c*e;let $=0;for(let B=-r;B<=r;B++)$+=a[d+E(B,e-1)];for(let B=0;B<e;B++)f[d+B]=$*A,$+=a[d+E(B+r+1,e-1)]-a[d+E(B-r,e-1)]}for(let c=0;c<e;c++){let d=0;for(let $=-r;$<=r;$++)d+=f[E($,o-1)*e+c];for(let $=0;$<o;$++)a[$*e+c]=d*A,d+=f[E($+r+1,o-1)*e+c]-f[E($-r,o-1)*e+c]}}return a}function Wt(m,e){if(!m)return e;const o=m.trim();if(o[0]==="#"){let i=o.slice(1);if(i.length===3&&(i=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]),i.length>=6){const a=parseInt(i.slice(0,2),16),f=parseInt(i.slice(2,4),16),A=parseInt(i.slice(4,6),16);if(!Number.isNaN(a)&&!Number.isNaN(f)&&!Number.isNaN(A))return[a,f,A]}return e}const r=o.match(/rgba?\(([^)]+)\)/i);if(r){const i=r[1].split(",").map(a=>parseFloat(a));if(i.length>=3&&i.slice(0,3).every(a=>!Number.isNaN(a)))return[Math.round(i[0]),Math.round(i[1]),Math.round(i[2])]}return e}function K(m){return m<0?0:m>255?255:Math.round(m)}function te(m){return(m.split(",")[0]||"serif").trim().replace(/^["']|["']$/g,"")}function ee(m,e){if(typeof window>"u"||typeof document>"u"||!m)return{setText(){},replay(){},resize(){},update(){},focus(){},destroy(){},get text(){return e.text??""}};let o=e.text??"",r=e.font??"Georgia, serif",i=e.weight??680,a=e.fill??.9,f=e.sewRate??110,A=e.sheen??!0,E=e.animate??!0,C=e.editable??!1,c=e.pitch,d=e.onTextChange,$=te(r);const B=e.reducedMotion??!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches);let D=Wt(e.threadColor??"#fffbf3",[255,251,243]),tt=[0,0,0],N=[0,0,0];function et(t){D=Wt(t,[255,251,243]),tt=[D[0]*.585,D[1]*.585,D[2]*.585],N=[D[0]*.47,D[1]*.47,D[2]*.47]}et(e.threadColor??"#fffbf3");const G=[];let P,g;m instanceof HTMLCanvasElement?(P=m,g=m.parentElement??m):(g=m,P=document.createElement("canvas"),G.push(P),g.appendChild(P)),P.classList.add(pt.bg);const O=document.createElement("canvas");G.push(O),O.classList.add(pt.fx),g.appendChild(O),getComputedStyle(g).position==="static"&&(g.style.position="relative"),P.style.display="block",P.style.width="100%",Object.assign(O.style,{position:"absolute",inset:"0",width:"100%",pointerEvents:"none",mixBlendMode:"screen"});let S=null,Z=!1,s=0,h=0,H=0,bt=0,ft=4,nt=[],ot=0,rt=0,Ct=new Uint8Array(0),Tt=new Float32Array(0),ut=new Float32Array(0),dt=new Float32Array(0),U=null,it=null,ht=null,mt=[],yt=3;const L={rows:[],idx:0,acc:0,rate:0,on:!1},Y={x:0,y:0,set:!1};let W=!0,vt=0,Bt=!1,xt=0,q=!1,J=!1;function re(){const t=g.getBoundingClientRect(),n=Math.max(1,Math.round(t.width||Math.min(window.innerWidth*.95,1240))),l=o||"Ag",y=P.getContext("2d");let T=100;y&&(y.font=`${i} 100px ${r}`,T=y.measureText(l).width||100);let b=Math.max(8,100*(n*a)/T),v=b*.7,R=b*.3,I=n*a;if(y){y.font=`${i} ${b}px ${r}`;const p=y.measureText(l);I=p.width||I,p.actualBoundingBoxAscent>0&&(v=p.actualBoundingBoxAscent),p.actualBoundingBoxDescent>0&&(R=p.actualBoundingBoxDescent)}const w=Math.max(1,Math.round(2*Math.max(v,R)*1.12));let u=Math.min(window.devicePixelRatio||1,1.7);for(;n*u*w*u>9e5&&u>.4;)u-=.1;s=Math.max(1,Math.round(n*u)),h=Math.max(1,Math.round(w*u)),H=Math.max(4,Math.round(b*u)),bt=Math.round(s/2-I*u/2);for(const p of[P,O])p.width=s,p.height=h,p.style.height=w+"px";g.style.height=w+"px",ft=c??Math.max(3,h*.0095)}function ie(){it=document.createElement("canvas"),it.width=s,it.height=h,ht=it.getContext("2d",{willReadFrequently:!0})}function Nt(){const t=Math.max(7,ft*2.5),n=Math.max(3.2,ft*1.3);ot=Math.ceil(t)+2,rt=Math.ceil(n)+2,nt=[];for(let l=0;l<20;l++){const y=.34+l/19*.82,T=document.createElement("canvas");T.width=ot,T.height=rt;const b=T.getContext("2d");if(!b){nt.push(T);continue}const v=ot/2,R=rt/2,I=b.createLinearGradient(0,R-n/2,0,R+n/2),w=(k,j)=>`rgba(${K(k[0]*y)},${K(k[1]*y)},${K(k[2]*y)},${j})`;I.addColorStop(0,w(N,0)),I.addColorStop(.16,w(tt,1)),I.addColorStop(.5,w(D,1)),I.addColorStop(.84,w(tt,1)),I.addColorStop(1,w(N,0)),b.fillStyle=I,b.beginPath();const u=n/2;b.moveTo(v-t/2+u,R-u),b.lineTo(v+t/2-u,R-u),b.arc(v+t/2-u,R,u,-Math.PI/2,Math.PI/2),b.lineTo(v-t/2+u,R+u),b.arc(v-t/2+u,R,u,Math.PI/2,-Math.PI/2),b.closePath(),b.fill(),b.globalCompositeOperation="destination-in";const p=b.createLinearGradient(v-t/2,0,v+t/2,0);p.addColorStop(0,"rgba(0,0,0,0)"),p.addColorStop(.22,"rgba(0,0,0,1)"),p.addColorStop(.78,"rgba(0,0,0,1)"),p.addColorStop(1,"rgba(0,0,0,0)"),b.fillStyle=p,b.fillRect(0,0,ot,rt),nt.push(T)}}function ae(){if(!ht)return;const t=ht;t.clearRect(0,0,s,h),t.fillStyle="#fff",t.textAlign="left",t.textBaseline="middle",t.font=`${i} ${H}px ${r}`,t.fillText(o,bt,h*.5);const n=t.getImageData(0,0,s,h).data,l=new Uint8Array(s*h);for(let x=0;x<h;x++)for(let M=0;M<s;M++){const F=x*s+M,_=n[F*4+3]/255,z=Qt(M*.5,x*.5)*.22+Qt(M*1.8,x*1.8)*.1;l[F]=_>.5+(z-.16)?1:0}Ct=l;const y=ge(l,s,h),T=new Float32Array(s*h);for(let x=1;x<h-1;x++)for(let M=1;M<s-1;M++){const F=x*s+M;T[F]=(y[F]*4+y[F-1]+y[F+1]+y[F-s]+y[F+s])/8}const b=new Float32Array(s*h),v=new Float32Array(s*h),R=new Float32Array(s*h),I=new Float32Array(s*h);for(let x=1;x<h-1;x++)for(let M=1;M<s-1;M++){const F=x*s+M;if(!l[F])continue;const _=(T[F+1]-T[F-1])*.5,z=(T[F+s]-T[F-s])*.5;R[F]=_,I[F]=z,b[F]=_*_-z*z,v[F]=2*_*z}const w=Math.max(7,Math.round(h*.05)),u=Ht(b,s,h,w,2),p=Ht(v,s,h,w,2);ut=new Float32Array(s*h),dt=new Float32Array(s*h);for(let x=0;x<s*h;x++){if(!l[x])continue;const M=.5*Math.atan2(p[x],u[x]);ut[x]=Math.cos(M),dt[x]=Math.sin(M)}const k=Math.max(9,h*.04),j=new Float32Array(s*h),ct=-.45,st=-.62,wt=.64;for(let x=1;x<h-1;x++)for(let M=1;M<s-1;M++){const F=x*s+M;if(!l[F])continue;let _=R[F],z=I[F];const Ut=Math.hypot(_,z)||1;_/=Ut,z/=Ut;const Vt=T[F],Yt=(1-Math.min(Vt/k,1))*1.25;let It=-_*Yt,Pt=-z*Yt;const Jt=1.5,Dt=Math.hypot(It,Pt,Jt);It/=Dt,Pt/=Dt;let kt=It*ct+Pt*st+Jt/Dt*wt;kt<0&&(kt=0);const ye=Math.min(1,.45+.55*Math.min(Vt/(k*.7),1));j[F]=Math.min(1.12,(.5+.75*kt)*ye)}Tt=j,U=document.createElement("canvas"),U.width=s,U.height=h;const V=U.getContext("2d");if(V){const x=V.createImageData(s,h);for(let M=0;M<s*h;M++)l[M]&&(x.data[M*4]=255,x.data[M*4+1]=255,x.data[M*4+2]=255,x.data[M*4+3]=255);V.putImageData(x,0,0)}}function le(){const t=Math.max(1.6,ft*.6);yt=t;const n=[];for(let l=0;l<h;l+=t)for(let y=0;y<s;y+=t){const T=(Q(Math.floor(y),Math.floor(l))-.5)*t*.9,b=(Q(Math.floor(l),Math.floor(y))-.5)*t*.9,v=Math.round(y+T),R=Math.round(l+b);if(v<1||R<1||v>=s-1||R>=h-1)continue;const I=R*s+v;if(!Ct[I])continue;const w=Math.atan2(dt[I],ut[I]),u=.86+Q(v*7,R*13)*.18;let p=Tt[I]*u;p=p<0?0:p>1.12?1.12:p,n.push({x:v,y:R,ang:w,idx:Math.min(19,Math.max(0,Math.round(p/1.12*19)))})}n.sort((l,y)=>l.x-y.x),mt=n}function Ot(t,n){t.save(),t.translate(n.x,n.y),t.rotate(n.ang),t.drawImage(nt[n.idx],-ot/2,-rt/2),t.restore()}function At(){const t=P.getContext("2d");if(t)for(const n of mt)Ot(t,n)}function Et(){const t=P.getContext("2d");t&&t.clearRect(0,0,s,h)}function ce(t){if(!t.length)return[];const n=Math.max(4,yt*1.5),l=new Map,y=(w,u)=>w+","+u;t.forEach((w,u)=>{const p=y(Math.floor(w.x/n),Math.floor(w.y/n));let k=l.get(p);k||l.set(p,k=[]),k.push(u)});const T=yt*1.8*(yt*1.8);function b(w){const u=t[w],p=Math.floor(u.x/n),k=Math.floor(u.y/n),j=[];for(let ct=-1;ct<=1;ct++)for(let st=-1;st<=1;st++){const wt=l.get(y(p+ct,k+st));if(wt)for(const V of wt){if(V===w)continue;const x=t[V].x-u.x,M=t[V].y-u.y;x*x+M*M<=T&&j.push(V)}}return j}const v=new Uint8Array(t.length),R=[],I=t.map((w,u)=>u).sort((w,u)=>t[w].x+t[w].y-(t[u].x+t[u].y));for(const w of I){if(v[w])continue;let u=[w];for(v[w]=1;u.length;){R.push(u.map(k=>t[k]));const p=[];for(const k of u)for(const j of b(k))v[j]||(v[j]=1,p.push(j));u=p}}return R}function se(){if(Et(),B||!E){At(),L.on=!1;return}L.rows=ce(mt),L.idx=0,L.acc=0,L.rate=f,L.on=L.rows.length>0}function fe(t){const n=P.getContext("2d");if(n)for(t>L.rows.length&&(t=L.rows.length);L.idx<t;){const l=L.rows[L.idx++];for(const y of l)Ot(n,y)}}function ue(t,n){const l=O.getContext("2d");if(!l||(l.clearRect(0,0,s,h),!A||!U))return;const y=s*.32,T=l.createRadialGradient(t,n,0,t,n,y);T.addColorStop(0,"rgba(255,250,238,0.18)"),T.addColorStop(.5,"rgba(255,250,238,0.055)"),T.addColorStop(1,"rgba(255,250,238,0)"),l.fillStyle=T,l.fillRect(0,0,s,h),l.globalCompositeOperation="destination-in",l.drawImage(U,0,0),l.globalCompositeOperation="source-over"}function de(){S||!C||(S=document.createElement("span"),S.className=pt.caret,S.setAttribute("aria-hidden","true"),Object.assign(S.style,{position:"absolute",pointerEvents:"none",borderRadius:"1px",opacity:"0",background:`rgb(${K(D[0])},${K(D[1])},${K(D[2])})`}),g.appendChild(S),G.push(S))}function St(){if(!C||!S)return;const t=P.getContext("2d");if(!t)return;t.font=`${i} ${H}px ${r}`;const n=t.measureText(o).width,l=(P.clientWidth||s)/s,y=H*.7;S.style.left=(bt+n+H*.05)*l+"px",S.style.top=.5*(P.clientHeight||h)-y*l/2+"px",S.style.height=y*l+"px",S.style.width=Math.max(2,Math.round(H*.02*l))+"px",S.style.background=`rgb(${K(D[0])},${K(D[1])},${K(D[2])})`}function jt(t){if(q)return;xt||(xt=t);const n=Math.min(.25,(t-xt)/1e3);xt=t,L.on&&(L.acc+=L.rate*n,fe(L.acc),L.idx>=L.rows.length&&(L.on=!1)),W&&U&&(ue(Y.set?Y.x:s*.5,Y.set?Y.y:h*.34),W=!1),S&&(S.style.opacity=C&&Z&&Math.floor(t/530)%2===0?"1":"0"),vt=requestAnimationFrame(jt)}function gt(t){const n=O.getBoundingClientRect();Y.x=(t.clientX-n.left)/(n.width||1)*s,Y.y=(t.clientY-n.top)/(n.height||1)*h,Y.set=!0,W=!0}function qt(t){if(!(!C||t.metaKey||t.ctrlKey||t.altKey)){if(t.key==="Backspace"){t.preventDefault(),Rt(o.slice(0,-1),!0);return}if(t.key==="Enter"){t.preventDefault(),$t.replay();return}[...t.key].length===1&&(t.preventDefault(),Rt(o+t.key,!0))}}function _t(){Z=!0}function zt(){Z=!1,S&&(S.style.opacity="0")}function Kt(){C&&g.focus()}function Ft(t){C=t,t?(g.tabIndex=0,g.setAttribute("role","textbox"),g.getAttribute("aria-label")||g.setAttribute("aria-label","Editable embroidered text — type to change it"),de(),g.addEventListener("keydown",qt),g.addEventListener("focus",_t),g.addEventListener("blur",zt),g.addEventListener("pointerdown",Kt),St()):(g.removeAttribute("tabindex"),g.removeAttribute("role"),g.removeEventListener("keydown",qt),g.removeEventListener("focus",_t),g.removeEventListener("blur",zt),g.removeEventListener("pointerdown",Kt),S&&(S.style.opacity="0"))}function he(t){if(t!==A)if(A=t,t)window.addEventListener("pointermove",gt,{passive:!0}),W=!0;else{window.removeEventListener("pointermove",gt);const n=O.getContext("2d");n&&n.clearRect(0,0,s,h)}}function at(t){re(),ie(),Nt(),ae(),le(),t?se():(Et(),At(),L.on=!1),St(),W=!0}function Rt(t,n){t=t??"",!(t===o&&J)&&(o=t,J&&(at(!1),n&&d&&d(o)))}let lt;function Xt(t,n,l){const y=`${n} 200px ${t}`;let T=!1;try{T=!!document.fonts&&document.fonts.check(y)}catch{T=!0}if(!document.fonts||T){l();return}let b=!1;const v=()=>{b||(b=!0,lt&&clearTimeout(lt),l())};document.fonts.load(y,o).then(()=>document.fonts.ready).then(v,v),lt=setTimeout(v,1500)}function me(){q||(at(!0),J=!0,Bt||(Bt=!0,vt=requestAnimationFrame(jt)))}C&&Ft(!0),A&&window.addEventListener("pointermove",gt,{passive:!0}),Xt($,i,me);let Lt;function Gt(){clearTimeout(Lt),Lt=setTimeout(()=>$t.resize(),200)}window.addEventListener("resize",Gt);const $t={get text(){return o},setText(t){if(!q){if(!J){o=t??"";return}Rt(t,!1)}},replay(){q||!J||at(!0)},resize(){q||!J||at(!1)},update(t){if(q)return;let n=!1,l=!1;t.font!==void 0&&t.font!==r&&(r=t.font,$=te(r),n=!0),t.weight!==void 0&&t.weight!==i&&(i=t.weight,n=!0),t.fill!==void 0&&t.fill!==a&&(a=t.fill,n=!0),t.pitch!==void 0&&t.pitch!==c&&(c=t.pitch,n=!0),t.threadColor!==void 0&&(et(t.threadColor),l=!0),t.sewRate!==void 0&&(f=t.sewRate),t.animate!==void 0&&(E=t.animate),t.onTextChange!==void 0&&(d=t.onTextChange),t.sheen!==void 0&&he(t.sheen),t.editable!==void 0&&t.editable!==C&&Ft(t.editable),J&&(n?Xt($,i,()=>{q||at(!1)}):l&&(Nt(),Et(),At(),St()),W=!0)},focus(){!q&&C&&g.focus()},destroy(){if(!q){q=!0,cancelAnimationFrame(vt),clearTimeout(Lt),lt&&clearTimeout(lt),window.removeEventListener("resize",Gt),window.removeEventListener("pointermove",gt),C&&Ft(!1);for(const t of G)t.remove();nt=[],mt=[],L.rows=[],Ct=new Uint8Array(0),Tt=new Float32Array(0),ut=new Float32Array(0),dt=new Float32Array(0),U=it=null,ht=null,S=null}}};return $t}function ne(m){const e=X.useRef(null),o=X.useRef(null),r=X.useRef(m);r.current=m;const i=X.useRef(m.onTextChange);i.current=m.onTextChange;const{text:a,font:f,weight:A,threadColor:E,pitch:C,fill:c,animate:d,sewRate:$,sheen:B,editable:D,reducedMotion:tt}=m;return X.useLayoutEffect(()=>{const N=e.current;if(!N)return;const et=ee(N,{...r.current,onTextChange:O=>{var S;return(S=i.current)==null?void 0:S.call(i,O)}});o.current=et;let G=0,P=0,g;return typeof ResizeObserver<"u"&&(g=new ResizeObserver(O=>{const S=Math.round(O[0].contentRect.width);S!==P&&(P=S,cancelAnimationFrame(G),G=requestAnimationFrame(()=>{var Z;return(Z=o.current)==null?void 0:Z.resize()}))}),g.observe(N)),()=>{g==null||g.disconnect(),cancelAnimationFrame(G),et.destroy(),o.current=null}},[tt]),X.useEffect(()=>{var N;(N=o.current)==null||N.update({font:f,weight:A,threadColor:E,pitch:C,fill:c,animate:d,sewRate:$,sheen:B,editable:D})},[f,A,E,C,c,d,$,B,D]),X.useEffect(()=>{var N;(N=o.current)==null||N.setText(a)},[a]),e}const oe=X.forwardRef(function({className:e,style:o,as:r="div","aria-label":i,role:a,"aria-describedby":f,...A},E){const C=ne(A),c=X.useCallback(d=>{C.current=d,typeof E=="function"?E(d):E&&(E.current=d)},[C,E]);return xe.jsx(r,{ref:c,className:e,style:o,role:a??"img","aria-label":i??A.text,"aria-describedby":f})});oe.displayName="ThreadText";exports.THREAD_TEXT_CLASSES=pt;exports.ThreadText=oe;exports.createThreadText=ee;exports.useThreadText=ne;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Q=require("react"),Fe=require("react/jsx-runtime"),Et={bg:"tt-bg",fx:"tt-fx",caret:"tt-caret"};function ot(y,o){let r=Math.imul(y|0,374761393)+Math.imul(o|0,668265263)|0;return r=Math.imul(r^r>>>13,1274126177),((r^r>>>16)>>>0)/4294967295}function ne(y,o){const r=Math.floor(y),l=Math.floor(o),c=y-r,s=o-l,h=c*c*(3-2*c),R=s*s*(3-2*s),E=ot(r,l),P=ot(r+1,l),f=ot(r,l+1),m=ot(r+1,l+1);return E+(P-E)*h+(f-E)*R+(E-P-f+m)*h*R}const At=1e20;function oe(y,o,r,l,c){let s=0;l[0]=0,c[0]=-At,c[1]=At;for(let h=1;h<o;h++){let R=(y[h]+h*h-(y[l[s]]+l[s]*l[s]))/(2*h-2*l[s]);for(;R<=c[s];)s--,R=(y[h]+h*h-(y[l[s]]+l[s]*l[s]))/(2*h-2*l[s]);s++,l[s]=h,c[s]=R,c[s+1]=At}s=0;for(let h=0;h<o;h++){for(;c[s+1]<h;)s++;r[h]=(h-l[s])*(h-l[s])+y[l[s]]}}function Re(y,o,r){const l=new Float64Array(o*r);for(let f=0;f<o*r;f++)l[f]=y[f]?At:0;const c=Math.max(o,r),s=new Float64Array(c),h=new Float64Array(c),R=new Int32Array(c),E=new Float64Array(c+1);for(let f=0;f<o;f++){for(let m=0;m<r;m++)s[m]=l[m*o+f];oe(s,r,h,R,E);for(let m=0;m<r;m++)l[m*o+f]=h[m]}for(let f=0;f<r;f++){for(let m=0;m<o;m++)s[m]=l[f*o+m];oe(s,o,h,R,E);for(let m=0;m<o;m++)l[f*o+m]=h[m]}const P=new Float32Array(o*r);for(let f=0;f<o*r;f++)P[f]=Math.sqrt(l[f]);return P}function re(y,o,r,l,c){let s=Float32Array.from(y);const h=new Float32Array(o*r),R=1/(2*l+1),E=(P,f)=>P<0?0:P>f?f:P;for(let P=0;P<c;P++){for(let f=0;f<r;f++){const m=f*o;let O=0;for(let z=-l;z<=l;z++)O+=s[m+E(z,o-1)];for(let z=0;z<o;z++)h[m+z]=O*R,O+=s[m+E(z+l+1,o-1)]-s[m+E(z-l,o-1)]}for(let f=0;f<o;f++){let m=0;for(let O=-l;O<=l;O++)m+=h[E(O,r-1)*o+f];for(let O=0;O<r;O++)s[O*o+f]=m*R,m+=h[E(O+l+1,r-1)*o+f]-h[E(O-l,r-1)*o+f]}}return s}function ie(y,o){if(!y)return o;const r=y.trim();if(r[0]==="#"){let c=r.slice(1);if(c.length===3&&(c=c[0]+c[0]+c[1]+c[1]+c[2]+c[2]),c.length>=6){const s=parseInt(c.slice(0,2),16),h=parseInt(c.slice(2,4),16),R=parseInt(c.slice(4,6),16);if(!Number.isNaN(s)&&!Number.isNaN(h)&&!Number.isNaN(R))return[s,h,R]}return o}const l=r.match(/rgba?\(([^)]+)\)/i);if(l){const c=l[1].split(",").map(s=>parseFloat(s));if(c.length>=3&&c.slice(0,3).every(s=>!Number.isNaN(s)))return[Math.round(c[0]),Math.round(c[1]),Math.round(c[2])]}return o}function J(y){return y<0?0:y>255?255:Math.round(y)}function St(y,o,r){return y<o?o:y>r?r:y}function ae(y){return(y.split(",")[0]||"serif").trim().replace(/^["']|["']$/g,"")}function le(y,o){if(typeof window>"u"||typeof document>"u"||!y)return{setText(){},replay(){},resize(){},update(){},focus(){},destroy(){},get text(){return o.text??""}};let r=o.text??"",l=o.font??"Georgia, serif",c=St(o.weight??680,1,1e3),s=St(o.fill??.9,.05,1),h=Math.max(1,o.sewRate??110),R=o.sewStyle==="hand"?"hand":"machine",E=o.sheen??!0,P=o.animate??!0,f=o.editable??!1,m=o.pitch,O=o.onTextChange,z=ae(l);const pt=o.reducedMotion??!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches);let B=ie(o.threadColor??"#fffbf3",[255,251,243]),ut=[0,0,0],G=[0,0,0];function dt(t){B=ie(t,[255,251,243]),ut=[B[0]*.585,B[1]*.585,B[2]*.585],G=[B[0]*.47,B[1]*.47,B[2]*.47]}dt(o.threadColor??"#fffbf3");const Y=[];let N,k;y instanceof HTMLCanvasElement?(N=y,k=y.parentElement??y):(k=y,N=document.createElement("canvas"),Y.push(N),k.appendChild(N)),N.classList.add(Et.bg);const U=document.createElement("canvas");Y.push(U),U.classList.add(Et.fx),k.appendChild(U),getComputedStyle(k).position==="static"&&(k.style.position="relative"),N.style.display="block",N.style.width="100%",Object.assign(U.style,{position:"absolute",inset:"0",width:"100%",pointerEvents:"none",mixBlendMode:"screen"});let w=null,F=null,tt=!1,u=0,g=0,rt=0,Ft=0,it=4,at=[],ht=0,mt=0,zt=-1,_t="",Xt=-1,Gt=-1,Rt=new Uint8Array(0),Lt=new Float32Array(0),wt=new Float32Array(0),Mt=new Float32Array(0),Z=null,lt=null,Ct=null,ct=[],et=3;const I={rows:[],idx:0,acc:0,rate:0,on:!1},H={x:0,y:0,set:!1};let nt=!0,It=0,xt=!1,yt=0,K=!1,W=!1;function fe(){const t=k.getBoundingClientRect(),e=Math.max(1,Math.round(t.width||Math.min(window.innerWidth*.95,1240))),i=r||"Ag",d=N.getContext("2d");d&&(d.textBaseline="middle");let b=100;d&&(d.font=`${c} 100px ${l}`,b=d.measureText(i).width||100);const C=Math.max(8,100*(e*s)/b);let T=C*.62,A=C*.62,S=e*s;if(d){d.font=`${c} ${C}px ${l}`;const a=d.measureText(i);S=a.width||S,a.actualBoundingBoxAscent>0&&(T=a.actualBoundingBoxAscent),a.actualBoundingBoxDescent>0&&(A=a.actualBoundingBoxDescent)}const M=Math.max(1,Math.round(2*Math.max(T,A)*1.1));let n=Math.min(window.devicePixelRatio||1,1.7);for(;e*n*M*n>9e5&&n>.4;)n-=.1;u=Math.max(1,Math.round(e*n)),g=Math.max(1,Math.round(M*n)),rt=Math.max(4,Math.round(C*n)),Ft=Math.round(u/2-S*n/2);for(const a of[N,U])a.width=u,a.height=g,a.style.height=M+"px";k.style.height=M+"px",it=m??Math.max(3,g*.0095)}function ue(){lt&&Xt===u&&Gt===g||(lt=document.createElement("canvas"),lt.width=u,lt.height=g,Ct=lt.getContext("2d",{willReadFrequently:!0}),Xt=u,Gt=g)}function Ut(){const t=Math.max(7,it*2.5),e=Math.max(3.2,it*1.3);ht=Math.ceil(t)+2,mt=Math.ceil(e)+2,at=[];for(let i=0;i<20;i++){const d=.34+i/19*.82,b=document.createElement("canvas");b.width=ht,b.height=mt;const C=b.getContext("2d");if(!C){at.push(b);continue}const T=ht/2,A=mt/2,S=C.createLinearGradient(0,A-e/2,0,A+e/2),M=(L,$)=>`rgba(${J(L[0]*d)},${J(L[1]*d)},${J(L[2]*d)},${$})`;S.addColorStop(0,M(G,0)),S.addColorStop(.16,M(ut,1)),S.addColorStop(.5,M(B,1)),S.addColorStop(.84,M(ut,1)),S.addColorStop(1,M(G,0)),C.fillStyle=S,C.beginPath();const n=e/2;C.moveTo(T-t/2+n,A-n),C.lineTo(T+t/2-n,A-n),C.arc(T+t/2-n,A,n,-Math.PI/2,Math.PI/2),C.lineTo(T-t/2+n,A+n),C.arc(T-t/2+n,A,n,Math.PI/2,-Math.PI/2),C.closePath(),C.fill(),C.globalCompositeOperation="destination-in";const a=C.createLinearGradient(T-t/2,0,T+t/2,0);a.addColorStop(0,"rgba(0,0,0,0)"),a.addColorStop(.22,"rgba(0,0,0,1)"),a.addColorStop(.78,"rgba(0,0,0,1)"),a.addColorStop(1,"rgba(0,0,0,0)"),C.fillStyle=a,C.fillRect(0,0,ht,mt),at.push(b)}zt=it,_t=B.join(",")}function de(){at.length&&zt===it&&_t===B.join(",")||Ut()}function he(){if(!Ct)return;const t=Ct;t.clearRect(0,0,u,g),t.fillStyle="#fff",t.textAlign="left",t.textBaseline="middle",t.font=`${c} ${rt}px ${l}`,t.fillText(r,Ft,g*.5);const e=t.getImageData(0,0,u,g).data,i=new Uint8Array(u*g);for(let x=0;x<g;x++)for(let p=0;p<u;p++){const v=x*u+p,_=e[v*4+3]/255,q=ne(p*.5,x*.5)*.22+ne(p*1.8,x*1.8)*.1;i[v]=_>.5+(q-.16)?1:0}Rt=i;const d=Re(i,u,g),b=new Float32Array(u*g);for(let x=1;x<g-1;x++)for(let p=1;p<u-1;p++){const v=x*u+p;b[v]=(d[v]*4+d[v-1]+d[v+1]+d[v-u]+d[v+u])/8}const C=new Float32Array(u*g),T=new Float32Array(u*g),A=new Float32Array(u*g),S=new Float32Array(u*g);for(let x=1;x<g-1;x++)for(let p=1;p<u-1;p++){const v=x*u+p;if(!i[v])continue;const _=(b[v+1]-b[v-1])*.5,q=(b[v+u]-b[v-u])*.5;A[v]=_,S[v]=q,C[v]=_*_-q*q,T[v]=2*_*q}const M=Math.max(7,Math.round(g*.05)),n=re(C,u,g,M,2),a=re(T,u,g,M,2);wt=new Float32Array(u*g),Mt=new Float32Array(u*g);for(let x=0;x<u*g;x++){if(!i[x])continue;const p=.5*Math.atan2(a[x],n[x]);wt[x]=Math.cos(p),Mt[x]=Math.sin(p)}const L=Math.max(9,g*.04),$=new Float32Array(u*g),X=-.45,V=-.62,D=.64;for(let x=1;x<g-1;x++)for(let p=1;p<u-1;p++){const v=x*u+p;if(!i[v])continue;let _=A[v],q=S[v];const gt=Math.hypot(_,q)||1;_/=gt,q/=gt;const Wt=b[v],te=(1-Math.min(Wt/L,1))*1.25;let Nt=-_*te,Dt=-q*te;const ee=1.5,jt=Math.hypot(Nt,Dt,ee);Nt/=jt,Dt/=jt;let qt=Nt*X+Dt*V+ee/jt*D;qt<0&&(qt=0);const Ae=Math.min(1,.45+.55*Math.min(Wt/(L*.7),1));$[v]=Math.min(1.12,(.5+.75*qt)*Ae)}Lt=$,Z=document.createElement("canvas"),Z.width=u,Z.height=g;const j=Z.getContext("2d");if(j){const x=j.createImageData(u,g);for(let p=0;p<u*g;p++)i[p]&&(x.data[p*4]=255,x.data[p*4+1]=255,x.data[p*4+2]=255,x.data[p*4+3]=255);j.putImageData(x,0,0)}}function me(){const t=Math.max(1.6,it*.6);et=t;const e=[];for(let i=0;i<g;i+=t)for(let d=0;d<u;d+=t){const b=(ot(Math.floor(d),Math.floor(i))-.5)*t*.9,C=(ot(Math.floor(i),Math.floor(d))-.5)*t*.9,T=Math.round(d+b),A=Math.round(i+C);if(T<1||A<1||T>=u-1||A>=g-1)continue;const S=A*u+T;if(!Rt[S])continue;const M=Math.atan2(Mt[S],wt[S]),n=.86+ot(T*7,A*13)*.18;let a=Lt[S]*n;a=a<0?0:a>1.12?1.12:a,e.push({x:T,y:A,ang:M,idx:Math.min(19,Math.max(0,Math.round(a/1.12*19)))})}ct=e}function Kt(t,e){t.save(),t.translate(e.x,e.y),t.rotate(e.ang),t.drawImage(at[e.idx],-ht/2,-mt/2),t.restore()}function $t(){const t=N.getContext("2d");if(t)for(const e of ct)Kt(t,e)}function kt(){const t=N.getContext("2d");t&&t.clearRect(0,0,u,g)}function xe(t){if(!t.length)return[];const e=Math.max(4,et*1.5),i=new Map,d=(M,n)=>M+","+n;t.forEach((M,n)=>{const a=d(Math.floor(M.x/e),Math.floor(M.y/e));let L=i.get(a);L||i.set(a,L=[]),L.push(n)});const b=et*1.8*(et*1.8);function C(M){const n=t[M],a=Math.floor(n.x/e),L=Math.floor(n.y/e),$=[];for(let X=-1;X<=1;X++)for(let V=-1;V<=1;V++){const D=i.get(d(a+X,L+V));if(D)for(const j of D){if(j===M)continue;const x=t[j].x-n.x,p=t[j].y-n.y;x*x+p*p<=b&&$.push(j)}}return $}const T=new Uint8Array(t.length),A=[],S=t.map((M,n)=>n).sort((M,n)=>t[M].x+t[M].y-(t[n].x+t[n].y));for(const M of S){if(T[M])continue;let n=[M];for(T[M]=1;n.length;){A.push(n.map(L=>t[L]));const a=[];for(const L of n)for(const $ of C(L))T[$]||(T[$]=1,a.push($));n=a}}return A}function ye(t){if(!t.length)return[];const e=Math.max(4,et*1.5),i=new Map,d=(n,a)=>n+","+a;t.forEach((n,a)=>{const L=d(Math.floor(n.x/e),Math.floor(n.y/e));let $=i.get(L);$||i.set(L,$=[]),$.push(a)});const b=et*1.8*(et*1.8),C=n=>{const a=t[n],L=d(Math.floor(a.x/e),Math.floor(a.y/e)),$=i.get(L);if(!$)return;const X=$.indexOf(n);X>=0&&$.splice(X,1),$.length||i.delete(L)};function T(n){const a=t[n],L=Math.floor(a.x/e),$=Math.floor(a.y/e);let X=-1,V=1/0;for(let D=-1;D<=1;D++)for(let j=-1;j<=1;j++){const x=i.get(d(L+D,$+j));if(x)for(const p of x){const v=t[p].x-a.x,_=t[p].y-a.y,q=v*v+_*_;q<=b&&q<V&&(V=q,X=p)}}return X}function A(n){const a=t[n],L=Math.floor(a.x/e),$=Math.floor(a.y/e);let X=-1,V=1/0;for(let D=1;D<512;D++){for(let j=-D;j<=D;j++)for(let x=-D;x<=D;x++){if(Math.max(Math.abs(j),Math.abs(x))!==D)continue;const p=i.get(d(L+j,$+x));if(p)for(const v of p){const _=t[v].x-a.x,q=t[v].y-a.y,gt=_*_+q*q;gt<V&&(V=gt,X=v)}}if(X>=0&&D>Math.ceil(Math.sqrt(V)/e)+1)break}return X}let S=0;for(let n=1;n<t.length;n++)t[n].x+t[n].y<t[S].x+t[S].y&&(S=n);const M=[t[S]];C(S);for(let n=1;n<t.length;n++){let a=T(S);if(a<0&&(a=A(S)),a<0)break;M.push(t[a]),C(a),S=a}return M}function ge(){if(kt(),pt||!P){$t(),I.on=!1;return}R==="hand"?(I.rows=ye(ct).map(t=>[t]),I.rate=Math.max(h,ct.length/3.2)):(I.rows=xe(ct),I.rate=h),I.idx=0,I.acc=0,I.on=I.rows.length>0}function pe(t){const e=N.getContext("2d");if(e)for(t>I.rows.length&&(t=I.rows.length);I.idx<t;){const i=I.rows[I.idx++];for(const d of i)Kt(e,d)}}function we(t,e){const i=U.getContext("2d");if(!i||(i.clearRect(0,0,u,g),!E||!Z))return;const d=u*.32,b=i.createRadialGradient(t,e,0,t,e,d);b.addColorStop(0,"rgba(255,250,238,0.18)"),b.addColorStop(.5,"rgba(255,250,238,0.055)"),b.addColorStop(1,"rgba(255,250,238,0)"),i.fillStyle=b,i.fillRect(0,0,u,g),i.globalCompositeOperation="destination-in",i.drawImage(Z,0,0),i.globalCompositeOperation="source-over"}function Me(){F||!f||(F=document.createElement("span"),F.className=Et.caret,F.setAttribute("aria-hidden","true"),Object.assign(F.style,{position:"absolute",pointerEvents:"none",borderRadius:"1px",opacity:"0",background:`rgb(${J(B[0])},${J(B[1])},${J(B[2])})`}),k.appendChild(F),Y.push(F))}function Pt(){if(!f||!F)return;const t=N.getContext("2d");if(!t)return;t.font=`${c} ${rt}px ${l}`;const e=t.measureText(r).width,i=(N.clientWidth||u)/u,d=rt*.7;F.style.left=(Ft+e+rt*.05)*i+"px",F.style.top=.5*(N.clientHeight||g)-d*i/2+"px",F.style.height=d*i+"px",F.style.width=Math.max(2,Math.round(rt*.02*i))+"px",F.style.background=`rgb(${J(B[0])},${J(B[1])},${J(B[2])})`}function st(){K||xt||(xt=!0,yt=0,It=requestAnimationFrame(Vt))}function Vt(t){if(K){xt=!1;return}yt||(yt=t);const e=Math.min(.25,(t-yt)/1e3);yt=t,I.on&&(I.acc+=I.rate*e,pe(I.acc),I.idx>=I.rows.length&&(I.on=!1)),nt&&Z&&(we(H.set?H.x:u*.5,H.set?H.y:g*.45),nt=!1);const i=f&&tt;if(F&&(F.style.opacity=i&&Math.floor(t/530)%2===0?"1":"0"),!I.on&&!nt&&!i){xt=!1;return}It=requestAnimationFrame(Vt)}function vt(t){const e=k.getBoundingClientRect();H.x=(t.clientX-e.left)/(e.width||1)*u,H.y=(t.clientY-e.top)/(e.height||1)*g,H.set=!0,nt=!0,st()}function Tt(){H.set=!1,nt=!0,st()}function Ce(){w&&Ht(w.value,!0)}function ve(t){t.key==="Enter"&&(t.preventDefault(),Bt.replay())}function Te(){tt=!0,st()}function be(){tt=!1,F&&(F.style.opacity="0")}function Yt(t){t===f&&w||(f=t,t?(w||(w=document.createElement("input"),w.type="text",w.value=r,w.maxLength=64,w.setAttribute("aria-label","Embroidered text — type to change it"),w.setAttribute("autocomplete","off"),w.setAttribute("autocapitalize","off"),w.spellcheck=!1,Object.assign(w.style,{position:"absolute",inset:"0",width:"100%",height:"100%",margin:"0",padding:"0",border:"0",outline:"none",background:"transparent",color:"transparent",caretColor:"transparent",font:"inherit",textAlign:"center",cursor:"text"}),w.addEventListener("input",Ce),w.addEventListener("keydown",ve),w.addEventListener("focus",Te),w.addEventListener("blur",be),k.appendChild(w),Y.push(w)),Me(),Pt()):(w&&(w.remove(),w=null),tt=!1,F&&(F.style.opacity="0")))}function Se(t){if(t!==E)if(E=t,t)k.addEventListener("pointermove",vt,{passive:!0}),k.addEventListener("pointerleave",Tt,{passive:!0}),H.set=!1,nt=!0,st();else{k.removeEventListener("pointermove",vt),k.removeEventListener("pointerleave",Tt);const e=U.getContext("2d");e&&e.clearRect(0,0,u,g)}}function ft(t){fe(),ue(),de(),he(),me(),t?ge():(kt(),$t(),I.on=!1),w&&w.value!==r&&(w.value=r),Pt(),nt=!0,st()}function Ht(t,e){t=t??"",!(t===r&&W)&&(r=t,W&&(ft(!1),e&&O&&O(r)))}const bt=new Set;function Jt(t,e,i){const d=`${e} 200px ${t}`;let b=!1;try{b=!!document.fonts&&document.fonts.check(d)}catch{b=!0}if(!document.fonts||b){i();return}let C=!1,T;const A=()=>{C||(C=!0,clearTimeout(T),bt.delete(T),K||i())};document.fonts.load(d,r).then(()=>document.fonts.ready).then(A,A),T=setTimeout(A,1500),bt.add(T)}function Ee(){K||(ft(!0),W=!0)}f&&(f=!1,Yt(!0)),E&&(k.addEventListener("pointermove",vt,{passive:!0}),k.addEventListener("pointerleave",Tt,{passive:!0})),Jt(z,c,Ee);let Ot,Qt=-1;function Zt(){clearTimeout(Ot),Ot=setTimeout(()=>{if(K||!W)return;const t=Math.round(k.getBoundingClientRect().width);t!==Qt&&(Qt=t,ft(!1))},200)}window.addEventListener("resize",Zt);const Bt={get text(){return r},setText(t){if(!K){if(!W){r=t??"",w&&(w.value=r);return}Ht(t,!1)}},replay(){K||!W||ft(!0)},resize(){K||!W||ft(!1)},update(t){if(K)return;t.text!==void 0&&Bt.setText(t.text);let e=!1,i=!1;if(t.font!==void 0&&t.font!==l&&(l=t.font,z=ae(l),e=!0),t.weight!==void 0){const d=St(t.weight,1,1e3);d!==c&&(c=d,e=!0)}if(t.fill!==void 0){const d=St(t.fill,.05,1);d!==s&&(s=d,e=!0)}t.pitch!==void 0&&t.pitch!==m&&(m=t.pitch,e=!0),t.threadColor!==void 0&&(dt(t.threadColor),i=!0),t.sewRate!==void 0&&(h=Math.max(1,t.sewRate)),t.sewStyle!==void 0&&(R=t.sewStyle==="hand"?"hand":"machine"),t.animate!==void 0&&(P=t.animate),t.onTextChange!==void 0&&(O=t.onTextChange),t.sheen!==void 0&&Se(t.sheen),t.editable!==void 0&&Yt(t.editable),W&&(e?Jt(z,c,()=>{K||ft(!1)}):i&&(Ut(),kt(),$t(),Pt(),st()))},focus(){!K&&f&&(w==null||w.focus())},destroy(){if(!K){K=!0,xt=!1,cancelAnimationFrame(It),clearTimeout(Ot);for(const t of bt)clearTimeout(t);bt.clear(),window.removeEventListener("resize",Zt),k.removeEventListener("pointermove",vt),k.removeEventListener("pointerleave",Tt);for(const t of Y)t.remove();at=[],ct=[],I.rows=[],Rt=new Uint8Array(0),Lt=new Float32Array(0),wt=new Float32Array(0),Mt=new Float32Array(0),Z=lt=null,Ct=null,F=null,w=null}}};return Bt}function ce(y){const o=Q.useRef(null),r=Q.useRef(null),l=Q.useRef(y);l.current=y;const c=Q.useRef(y.onTextChange);c.current=y.onTextChange;const{text:s,font:h,weight:R,threadColor:E,pitch:P,fill:f,animate:m,sewStyle:O,sewRate:z,sheen:pt,editable:B,reducedMotion:ut}=y;return Q.useLayoutEffect(()=>{const G=o.current;if(!G)return;const dt=le(G,{...l.current,onTextChange:w=>{var F;return(F=c.current)==null?void 0:F.call(c,w)}});r.current=dt;let Y=0,N=0,k=!0,U;return typeof ResizeObserver<"u"&&(U=new ResizeObserver(w=>{const F=Math.round(w[0].contentRect.width);if(k){k=!1,N=F;return}F!==N&&(N=F,cancelAnimationFrame(Y),Y=requestAnimationFrame(()=>{var tt;return(tt=r.current)==null?void 0:tt.resize()}))}),U.observe(G)),()=>{U==null||U.disconnect(),cancelAnimationFrame(Y),dt.destroy(),r.current=null}},[ut]),Q.useEffect(()=>{var G;(G=r.current)==null||G.update({font:h,weight:R,threadColor:E,pitch:P,fill:f,animate:m,sewStyle:O,sewRate:z,sheen:pt,editable:B})},[h,R,E,P,f,m,O,z,pt,B]),Q.useEffect(()=>{var G;(G=r.current)==null||G.setText(s)},[s]),o}const se=Q.forwardRef(function({className:o,style:r,as:l="div","aria-label":c,role:s,"aria-describedby":h,...R},E){const P=ce(R),f=Q.useCallback(m=>{P.current=m,typeof E=="function"?E(m):E&&(E.current=m)},[P,E]);return Fe.jsx(l,{ref:f,className:o,style:r,role:R.editable?s:s??"img","aria-label":R.editable?c:c??R.text,"aria-describedby":h})});se.displayName="ThreadText";exports.THREAD_TEXT_CLASSES=Et;exports.ThreadText=se;exports.createThreadText=le;exports.useThreadText=ce;
|
package/dist/index.d.ts
CHANGED
|
@@ -77,7 +77,15 @@ export declare interface ThreadTextOptions {
|
|
|
77
77
|
fill?: number;
|
|
78
78
|
/** Play the sew-in animation on mount and on `replay()`. (default: true) */
|
|
79
79
|
animate?: boolean;
|
|
80
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* How the word is sewn in:
|
|
82
|
+
* - **'machine'** (default) — satin cross-rows appear in parallel across each stroke, like
|
|
83
|
+
* machine embroidery (a BFS over the stitch graph).
|
|
84
|
+
* - **'hand'** — a single continuous thread wanders stitch by stitch along each stroke and
|
|
85
|
+
* carries to the next, laying one stitch at a time, like hand embroidery.
|
|
86
|
+
*/
|
|
87
|
+
sewStyle?: 'machine' | 'hand';
|
|
88
|
+
/** Satin cross-rows (machine) or stitches (hand) laid per second during the sew-in. (default: 110) */
|
|
81
89
|
sewRate?: number;
|
|
82
90
|
/** Enable the cursor-following radial sheen on the overlay canvas. (default: true) */
|
|
83
91
|
sheen?: boolean;
|