@liiift-studio/magnettype 1.1.3 → 1.1.4
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 +80 -30
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +16 -6
- package/dist/index.js +304 -244
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@liiift-studio/magnettype) [](https://opensource.org/licenses/MIT) [](https://github.com/Liiift-Studio/type-tools)
|
|
4
4
|
|
|
5
|
-
CSS `font-variation-settings` applies a single value to the whole element — there is no native way to drive axis values per word from cursor proximity,
|
|
5
|
+
CSS `font-variation-settings` applies a single value to the whole element — there is no native way to drive axis values per word from cursor proximity, to selectively widen visually confusable characters for legibility, or to vary weight per-character across a block element. magnetType adds all three.
|
|
6
6
|
|
|
7
7
|
**[magnettype.com](https://magnettype.com)** · [npm](https://www.npmjs.com/package/@liiift-studio/magnettype) · [GitHub](https://github.com/Liiift-Studio/MagnetType)
|
|
8
8
|
|
|
@@ -16,15 +16,15 @@ TypeScript · Zero dependencies · React + Vanilla JS
|
|
|
16
16
|
npm install @liiift-studio/magnettype
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
> **Variable font required:** magnetType sets `font-variation-settings` per word or per character. The target font must support the axes you specify (e.g. a font with a `wght` axis for weight-based effects, or a `wdth` axis for legibility mode). The effect is invisible with non-variable fonts.
|
|
20
|
+
|
|
19
21
|
---
|
|
20
22
|
|
|
21
23
|
## Usage
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
> **Variable font required:** magnetType sets `font-variation-settings` per word or per character. The target font must support the axes you specify (e.g. a font with a `wght` axis for weight-based field effects, or a `wdth` axis for legibility mode). The effect is invisible with fonts that do not have variable axis support.
|
|
25
|
+
### React — field mode (`MagnetTypeText`)
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Per-word cursor-proximity weight variation driven by a continuous rAF loop.
|
|
28
28
|
|
|
29
29
|
```tsx
|
|
30
30
|
import { MagnetTypeText } from '@liiift-studio/magnettype'
|
|
@@ -40,19 +40,67 @@ import { MagnetTypeText } from '@liiift-studio/magnettype'
|
|
|
40
40
|
</MagnetTypeText>
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
### React — block mode (`MagnetBlock`)
|
|
44
|
+
|
|
45
|
+
Per-character cursor-proximity weight variation. Works with mixed content (inline elements, links, `<code>`, etc.) inside any block element. Characters are wrapped as React elements — no DOM mutation.
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { MagnetBlock } from '@liiift-studio/magnettype'
|
|
49
|
+
|
|
50
|
+
// Per-character spread — each character responds to cursor distance
|
|
51
|
+
<MagnetBlock
|
|
52
|
+
spreadRadius={200}
|
|
53
|
+
minWeight={300}
|
|
54
|
+
maxWeight={700}
|
|
55
|
+
>
|
|
56
|
+
Typography that responds to presence.
|
|
57
|
+
</MagnetBlock>
|
|
58
|
+
|
|
59
|
+
// Whole-element gate — the effect only activates when the cursor is within proximityRadius of the element edge
|
|
60
|
+
<MagnetBlock
|
|
61
|
+
proximityRadius={120}
|
|
62
|
+
minWeight={300}
|
|
63
|
+
maxWeight={700}
|
|
64
|
+
>
|
|
65
|
+
Weight rises when the cursor enters.
|
|
66
|
+
</MagnetBlock>
|
|
67
|
+
|
|
68
|
+
// Both combined — proximity gates the spread effect
|
|
69
|
+
<MagnetBlock
|
|
70
|
+
proximityRadius={200}
|
|
71
|
+
spreadRadius={120}
|
|
72
|
+
minWeight={300}
|
|
73
|
+
maxWeight={700}
|
|
74
|
+
>
|
|
75
|
+
Only spreads when the cursor is close.
|
|
76
|
+
</MagnetBlock>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**`MagnetBlock` props:**
|
|
80
|
+
|
|
81
|
+
| Prop | Default | Description |
|
|
82
|
+
|------|---------|-------------|
|
|
83
|
+
| `as` | `'p'` | HTML element to render — `'h1'`, `'div'`, `'span'`, etc. |
|
|
84
|
+
| `minWeight` | `300` | `wght` axis value at rest (cursor beyond any radius) |
|
|
85
|
+
| `maxWeight` | `600` | `wght` axis value at peak (cursor directly over the character) |
|
|
86
|
+
| `spreadRadius` | — | Pixel distance from the cursor within which each **character's** weight rises to `maxWeight`. When omitted, per-character splitting is skipped |
|
|
87
|
+
| `proximityRadius` | — | Pixel distance from the element **edge** that gates the effect. Without `spreadRadius`, drives a whole-element weight ramp. With `spreadRadius`, acts as an outer gate — the spread only fires while the cursor is within this distance |
|
|
88
|
+
| `fixedAxes` | `{}` | Additional axis values to hold constant in every `font-variation-settings` string (e.g. `{ opsz: 144 }`) |
|
|
89
|
+
| `className` | — | Forwarded to the root element |
|
|
90
|
+
| `style` | — | Merged with the root element's style; `fontVariationSettings` at `minWeight` is set as the base |
|
|
91
|
+
|
|
43
92
|
### React hook — field mode
|
|
44
93
|
|
|
45
94
|
```tsx
|
|
46
95
|
import { useMagnetType } from '@liiift-studio/magnettype'
|
|
47
96
|
|
|
48
|
-
// Inside a React component:
|
|
49
97
|
const ref = useMagnetType({ mode: 'field', axes: { wght: [300, 700] }, radius: 150 })
|
|
50
98
|
return <p ref={ref}>{children}</p>
|
|
51
99
|
```
|
|
52
100
|
|
|
53
|
-
The hook starts the cursor-proximity rAF loop on mount and tears it down cleanly on unmount.
|
|
101
|
+
The hook starts the cursor-proximity rAF loop on mount and tears it down cleanly on unmount. After fonts load (`document.fonts.ready`), the hook re-runs to ensure measurements are taken on the loaded font.
|
|
54
102
|
|
|
55
|
-
### React
|
|
103
|
+
### React — legibility mode
|
|
56
104
|
|
|
57
105
|
```tsx
|
|
58
106
|
import { MagnetTypeText } from '@liiift-studio/magnettype'
|
|
@@ -112,7 +160,7 @@ ro.observe(el)
|
|
|
112
160
|
### TypeScript
|
|
113
161
|
|
|
114
162
|
```ts
|
|
115
|
-
import type { MagnetTypeOptions, FalloffType, MagnetModeType } from '@liiift-studio/magnettype'
|
|
163
|
+
import type { MagnetTypeOptions, FalloffType, MagnetModeType, MagnetBlockProps } from '@liiift-studio/magnettype'
|
|
116
164
|
|
|
117
165
|
const fieldOpts: MagnetTypeOptions = {
|
|
118
166
|
mode: 'field',
|
|
@@ -130,18 +178,18 @@ const legibilityOpts: MagnetTypeOptions = {
|
|
|
130
178
|
|
|
131
179
|
---
|
|
132
180
|
|
|
133
|
-
##
|
|
181
|
+
## Field mode options (`MagnetTypeText` / `useMagnetType` / vanilla JS)
|
|
134
182
|
|
|
135
183
|
| Option | Default | Description |
|
|
136
184
|
|--------|---------|-------------|
|
|
137
|
-
| `mode` | `'field'` | `'field'` — cursor proximity drives per-word `font-variation-settings` via a continuous rAF loop. `'legibility'` — static per-character `wdth` boost
|
|
138
|
-
| `axes` | `{ wght: [300, 500] }` | *(field mode
|
|
139
|
-
| `radius` | `120` | *(field mode
|
|
140
|
-
| `falloff` | `'quadratic'` | *(field mode
|
|
141
|
-
| `magnetMode` | `'attract'` | *(field mode
|
|
142
|
-
| `wdthBoost` | `6` | *(legibility mode
|
|
143
|
-
| `transitionMs` | `0` | Duration in
|
|
144
|
-
| `as` | `'p'` | HTML element to render
|
|
185
|
+
| `mode` | `'field'` | `'field'` — cursor proximity drives per-word `font-variation-settings` via a continuous rAF loop. `'legibility'` — static per-character `wdth` boost on visually confusable characters |
|
|
186
|
+
| `axes` | `{ wght: [300, 500] }` | *(field mode)* Map of axis tag → `[restValue, peakValue]` |
|
|
187
|
+
| `radius` | `120` | *(field mode)* Pixel radius over which the field effect fades from each word's centre |
|
|
188
|
+
| `falloff` | `'quadratic'` | *(field mode)* `'linear'` or `'quadratic'` falloff curve |
|
|
189
|
+
| `magnetMode` | `'attract'` | *(field mode)* `'attract'` — near words approach `peakValue`. `'repel'` — near words stay at `restValue`, far words approach `peakValue` |
|
|
190
|
+
| `wdthBoost` | `6` | *(legibility mode)* `wdth` units added to confusable characters, scaled by risk: `il1I` (risk 3) get the full boost; `r 0 O` (risk 2) get ⅔; `n m o b d p q c e` (risk 1) get ⅓ |
|
|
191
|
+
| `transitionMs` | `0` | Duration in ms for CSS transition back to rest when cursor leaves. `0` = instant snap. Cleared on the next `mousemove` so live tracking is not delayed |
|
|
192
|
+
| `as` | `'p'` | HTML element to render. *(React component only)* |
|
|
145
193
|
|
|
146
194
|
---
|
|
147
195
|
|
|
@@ -149,30 +197,32 @@ const legibilityOpts: MagnetTypeOptions = {
|
|
|
149
197
|
|
|
150
198
|
### Field mode
|
|
151
199
|
|
|
152
|
-
On activation, magnetType wraps each word in
|
|
200
|
+
On activation, magnetType wraps each word in an `mt-word` span. A `mousemove` listener records cursor coordinates, and a `requestAnimationFrame` loop runs while the cursor is inside the element. Each frame, the loop batch-reads every word span's `getBoundingClientRect`, computes Euclidean distance from cursor to word centre, and maps it through the falloff formula:
|
|
153
201
|
|
|
154
202
|
```
|
|
155
203
|
normalised = max(0, 1 − distance / radius)
|
|
156
204
|
strength = normalised² (quadratic) or normalised (linear)
|
|
157
205
|
```
|
|
158
206
|
|
|
159
|
-
Each word's `font-variation-settings`
|
|
207
|
+
Each word's `font-variation-settings` interpolates between `restValue` and `peakValue` at that strength. Reads are batched before writes on every frame to avoid layout thrashing. When the cursor leaves, one final frame resets all words to `restValue`.
|
|
208
|
+
|
|
209
|
+
### Block mode (`MagnetBlock`)
|
|
160
210
|
|
|
161
|
-
|
|
211
|
+
`MagnetBlock` splits string children into per-character `<span>` elements during the React render pass using `useMemo` — no DOM mutation. Callback refs collect each span element. On `mousemove` (and on `scroll`, using the stored last position), the component reads each span's `getBoundingClientRect`, computes cursor-to-character-centre distance, and sets `font-variation-settings` directly on the span's style. This is passive and batched per frame via the event handler.
|
|
212
|
+
|
|
213
|
+
`proximityRadius` measures cursor distance to the element **edge** (not its centre) — useful as an outer gate so the effect only fires when the cursor is actually near the block. `spreadRadius` measures cursor distance to each **character centre** — controls how wide the weight gradient spreads around the cursor within the block. Both are independent and combinable.
|
|
162
214
|
|
|
163
215
|
### Legibility mode
|
|
164
216
|
|
|
165
|
-
magnetType scans
|
|
217
|
+
magnetType scans text nodes recursively and checks each character against a built-in confusable character table. Confusable characters are wrapped in `mt-char` spans with a `wdth` boost proportional to risk level. Non-confusable characters pass through as plain text nodes.
|
|
166
218
|
|
|
167
219
|
### No layout shift
|
|
168
220
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
In legibility mode, the `wdth` axis boost widens individual confusable characters, which shifts surrounding characters slightly. This is intentional — the point is to make the characters physically wider and more distinct. The shift is small by default (`wdthBoost: 6`) and does not cause line breaks to change.
|
|
221
|
+
Field mode and block mode drive only `font-variation-settings` on per-word or per-character spans. If you use only a `wght` axis, advance widths are unaffected and no reflow occurs. If you include a `wdth` axis, character advance widths change and lines may reflow — consider constraining axis ranges or pairing with a `scaleX` transform.
|
|
172
222
|
|
|
173
223
|
### `prefers-reduced-motion`
|
|
174
224
|
|
|
175
|
-
Field mode respects `prefers-reduced-motion: reduce`. If the media query matches at
|
|
225
|
+
Field mode respects `prefers-reduced-motion: reduce`. If the media query matches at activation time, the function returns immediately without wrapping words or starting the rAF loop. Legibility mode and block mode are not affected.
|
|
176
226
|
|
|
177
227
|
---
|
|
178
228
|
|
|
@@ -188,10 +238,10 @@ The package itself has zero runtime dependencies. Do not remove this entry.
|
|
|
188
238
|
|
|
189
239
|
## Future improvements
|
|
190
240
|
|
|
191
|
-
- **Custom confusable table** — allow callers to pass their own `Record<string, number>` to override or extend the built-in character risk map
|
|
192
|
-
- **Axis clamping** — optional per-axis min/max clamp to prevent
|
|
193
|
-
- **SSR hydration** — pre-render legibility mode markup on the server so boosted characters are present from first paint
|
|
241
|
+
- **Custom confusable table** — allow callers to pass their own `Record<string, number>` to override or extend the built-in character risk map
|
|
242
|
+
- **Axis clamping** — optional per-axis min/max clamp to prevent values from exceeding a font's supported range
|
|
243
|
+
- **SSR hydration** — pre-render legibility mode markup on the server so boosted characters are present from first paint
|
|
194
244
|
|
|
195
245
|
---
|
|
196
246
|
|
|
197
|
-
Current version:
|
|
247
|
+
Current version: 1.1.3
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("react"),H=require("react/jsx-runtime"),G={i:3,l:3,1:3,I:3,r:2,n:1,m:1,0:2,O:2,o:1,b:1,d:1,p:1,q:1,c:1,e:1},R={word:"mt-word",char:"mt-char",probe:"mt-probe"},$={axes:{wght:[300,500]},radius:120,falloff:"quadratic",magnetMode:"attract",wdthBoost:6,scope:"document"};function D(t,n=[]){return t.nodeType===Node.TEXT_NODE?n.push(t):t.childNodes.forEach(o=>D(o,n)),n}function P(t,n,o){if(!t||t==="normal")return`"${n}" ${o}`;const u=new RegExp(`(["'])${n}\\1\\s+[\\d.eE+-]+`),c=`"${n}" ${o}`;return u.test(t)?t.replace(u,c):`${t}, ${c}`}function K(t,n){let o=t;for(const[u,c]of Object.entries(n))o=P(o,u,c);return o}function U(t,n,o){if(n.opacity!==void 0){const[u,c]=n.opacity;t.style.opacity=String(u+(c-u)*o)}n.italic===!0&&(t.style.fontStyle=o>.5?"italic":"")}function _(t,n){n.opacity!==void 0&&(t.style.opacity=String(n.opacity[0])),n.italic===!0&&(t.style.fontStyle="")}function z(t){const n=t.cloneNode(!0),o=n.querySelectorAll(`.${R.word}, .${R.char}`);return Array.from(o).reverse().forEach(c=>{const a=c.parentNode;if(a){for(;c.firstChild;)a.insertBefore(c.firstChild,c);a.removeChild(c)}}),n.innerHTML}function ot(t,n){t.innerHTML=n}function Q(t,n,o={}){if(typeof window>"u")return()=>{};if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return t.innerHTML=n,()=>{};const u=o.wdthBoost??$.wdthBoost,c=o.radius??$.radius,a=o.falloff??$.falloff,T=o.scope??$.scope,y=o.props,l=o.transitionMs??0,C=window.scrollY;t.innerHTML=n;const N=getComputedStyle(t).fontVariationSettings,F=N.match(/"wdth"\s+([\d.eE+-]+)/),g=F?parseFloat(F[1]):100,q=D(t),w=[];for(const r of q){const e=r.textContent??"";if(!e||!e.split("").some(m=>m in G))continue;const A=document.createDocumentFragment();for(const m of e){const k=G[m];if(k===void 0){const L=A.lastChild;L&&L.nodeType===Node.TEXT_NODE?L.textContent+=m:A.appendChild(document.createTextNode(m))}else{const L=document.createElement("span");L.className=R.char,L.style.fontVariationSettings=P(N,"wdth",g),L.textContent=m,A.appendChild(L),w.push({span:L,riskLevel:k})}}r.parentNode.replaceChild(A,r)}if(requestAnimationFrame(()=>{typeof window<"u"&&Math.abs(window.scrollY-C)>2&&window.scrollTo({top:C,behavior:"instant"})}),w.length===0)return()=>{};y&&w.forEach(({span:r})=>_(r,y));let h=-9999,V=-9999,E=!1,i=0,B=!0,S=null;function s(){if(!B)return;if(!E){w.forEach(({span:e})=>{l>0&&(e.style.transition=`font-variation-settings ${l}ms ease`),e.style.fontVariationSettings=P(N,"wdth",g),y&&_(e,y)}),l>0&&(S!==null&&clearTimeout(S),S=setTimeout(()=>{w.forEach(({span:e})=>{e.style.transition=""}),S=null},l)),i=0;return}const r=w.map(({span:e})=>e.getBoundingClientRect());w.forEach(({span:e,riskLevel:x},A)=>{e.style.transition="";const m=r[A],k=m.left+m.width/2,L=m.top+m.height/2,j=Math.sqrt((h-k)**2+(V-L)**2),O=Math.max(0,1-j/c),Y=a==="quadratic"?O*O:O,X=u*(x/3)*Y;e.style.fontVariationSettings=P(N,"wdth",g+X),y&&U(e,y,Y)}),i=requestAnimationFrame(s)}function M(r){h=r.clientX,V=r.clientY,E||(E=!0),i===0&&(i=requestAnimationFrame(s))}function v(){E=!1,i===0&&(i=requestAnimationFrame(s))}function f(r){r.touches.length!==0&&(h=r.touches[0].clientX,V=r.touches[0].clientY,E||(E=!0),i===0&&(i=requestAnimationFrame(s)))}function b(){E=!1,i===0&&(i=requestAnimationFrame(s))}const d=T==="document"?document:t;return d.addEventListener("mousemove",M),d.addEventListener("mouseleave",v),d.addEventListener("touchmove",f,{passive:!0}),d.addEventListener("touchend",b),()=>{B=!1,cancelAnimationFrame(i),S!==null&&clearTimeout(S),d.removeEventListener("mousemove",M),d.removeEventListener("mouseleave",v),d.removeEventListener("touchmove",f),d.removeEventListener("touchend",b),t.innerHTML=n}}function Z(t,n,o={}){if(typeof window>"u")return()=>{};if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return t.innerHTML=n,()=>{};const u=o.axes??$.axes,c=o.radius??$.radius,a=o.falloff??$.falloff,T=o.magnetMode??$.magnetMode,y=o.scope??$.scope,l=o.props,C=o.transitionMs??0,N=window.scrollY;t.innerHTML=n;const F=D(t),g=[];for(const r of F){const e=r.textContent??"";if(!e.trim())continue;const x=e.split(/(\S+)/),A=document.createDocumentFragment();for(let m=0;m<x.length;m+=2){const k=x[m],L=x[m+1];if(!L)continue;const O=x[m+3]===void 0?x[m+2]??"":"",Y=document.createElement("span");Y.className=R.word,Y.textContent=k+L+O,A.appendChild(Y),g.push(Y)}r.parentNode.replaceChild(A,r)}if(requestAnimationFrame(()=>{typeof window<"u"&&Math.abs(window.scrollY-N)>2&&window.scrollTo({top:N,behavior:"instant"})}),g.length===0)return()=>{};const q=getComputedStyle(t).fontVariationSettings,w=K(q,Object.fromEntries(Object.entries(u).map(([r,[e]])=>[r,e])));g.forEach(r=>{r.style.fontVariationSettings=w,l&&_(r,l)});let h=-9999,V=-9999,E=!1,i=0,B=!0,S=null;function s(){if(!B)return;if(!E){g.forEach(e=>{C>0&&(e.style.transition=`font-variation-settings ${C}ms ease`),e.style.fontVariationSettings=w,l&&_(e,l)}),C>0&&(S!==null&&clearTimeout(S),S=setTimeout(()=>{g.forEach(e=>{e.style.transition=""}),S=null},C)),i=0;return}const r=g.map(e=>e.getBoundingClientRect());g.forEach((e,x)=>{e.style.transition="";const A=r[x],m=A.left+A.width/2,k=A.top+A.height/2,L=Math.sqrt((h-m)**2+(V-k)**2),j=Math.max(0,1-L/c),O=a==="quadratic"?j*j:j,Y=T==="repel"?1-O:O,X={};for(const I of Object.keys(u)){const[J,nt]=u[I]??[300,500];X[I]=J+(nt-J)*Y}e.style.fontVariationSettings=K(q,X),l&&U(e,l,O)}),i=requestAnimationFrame(s)}function M(r){h=r.clientX,V=r.clientY,E||(E=!0),i===0&&(i=requestAnimationFrame(s))}function v(){E=!1,i===0&&(i=requestAnimationFrame(s))}function f(r){r.touches.length!==0&&(h=r.touches[0].clientX,V=r.touches[0].clientY,E||(E=!0),i===0&&(i=requestAnimationFrame(s)))}function b(){E=!1,i===0&&(i=requestAnimationFrame(s))}const d=y==="document"?document:t;return d.addEventListener("mousemove",M),d.addEventListener("mouseleave",v),d.addEventListener("touchmove",f,{passive:!0}),d.addEventListener("touchend",b),()=>{B=!1,cancelAnimationFrame(i),S!==null&&clearTimeout(S),d.removeEventListener("mousemove",M),d.removeEventListener("mouseleave",v),d.removeEventListener("touchmove",f),d.removeEventListener("touchend",b),t.innerHTML=n}}function W(t){const n=p.useRef(null),o=p.useRef(null),u=p.useRef(t);u.current=t;const c=p.useRef(null),a=t.mode??"field",{axes:T,radius:y,falloff:l,magnetMode:C,wdthBoost:N,scope:F}=t,g=T?JSON.stringify(T):void 0,q=t.props?JSON.stringify(t.props):void 0,w=p.useCallback(()=>{const h=n.current;if(!h)return;o.current===null&&(o.current=z(h)),c.current&&(c.current(),c.current=null),(u.current.mode??"field")==="field"?c.current=Z(h,o.current,u.current):c.current=Q(h,o.current,u.current)},[a,g,y,l,C,N,F,q]);return p.useLayoutEffect(()=>(w(),()=>{c.current&&(c.current(),c.current=null)}),[w]),p.useEffect(()=>{document.fonts.ready.then(w)},[w]),n}const tt=p.forwardRef(function({children:n,as:o="p",className:u,style:c,...a},T){const y=W(a),l=p.useCallback(C=>{y.current=C,typeof T=="function"?T(C):T&&(T.current=C)},[T]);return H.jsx(o,{ref:l,className:u,style:c,children:n})});tt.displayName="MagnetTypeText";const et=p.forwardRef(function({children:n,as:o="p",className:u,style:c,minWeight:a=300,maxWeight:T=600,proximityRadius:y,spreadRadius:l,fixedAxes:C={}},N){const F=p.useRef(null),g=p.useRef(null),q=p.useRef([]),w=p.useCallback(s=>{F.current=s,typeof N=="function"?N(s):N&&(N.current=s)},[N]);function h(s){const M=[`'wght' ${s.toFixed(0)}`];for(const[v,f]of Object.entries(C))M.push(`'${v}' ${f}`);return M.join(", ")}const V=p.useMemo(()=>{if(!l)return n;q.current=[];let s=0;function M(v){if(typeof v=="string")return[...v].map(f=>{if(/\s/.test(f))return f;const b=s++;return H.jsx("span",{ref:d=>{q.current[b]=d},style:{fontVariationSettings:h(a)},children:f},b)});if(Array.isArray(v))return v.map((f,b)=>H.jsx(p.Fragment,{children:M(f)},b));if(p.isValidElement(v)){const f=v;if(f.props.children!==void 0)return p.cloneElement(f,{},M(f.props.children))}return v}return M(n)},[n,l,a,JSON.stringify(C)]);function E(s,M){const v=F.current;if(!v)return;const f=v.getBoundingClientRect(),b=Math.max(f.left-s,0,s-f.right),d=Math.max(f.top-M,0,M-f.bottom),r=Math.sqrt(b*b+d*d);if(y!==void 0&&!l){const x=1-(1-Math.max(0,1-r/y))**2;v.style.fontVariationSettings=h(a+(T-a)*x);return}if(l){if(y!==void 0&&r>y){v.style.fontVariationSettings=h(a);for(const e of q.current)e&&(e.style.fontVariationSettings=h(a));return}for(const e of q.current){if(!e)continue;const x=e.getBoundingClientRect(),A=(x.left+x.right)/2,m=(x.top+x.bottom)/2,k=Math.sqrt((s-A)**2+(M-m)**2),j=1-(1-Math.max(0,1-k/l))**2;e.style.fontVariationSettings=h(a+(T-a)*j)}}}const i=p.useCallback(s=>{g.current={x:s.clientX,y:s.clientY},E(s.clientX,s.clientY)},[a,T,y,l]),B=p.useCallback(()=>{g.current&&E(g.current.x,g.current.y)},[a,T,y,l]),S=p.useCallback(()=>{g.current=null;const s=F.current;s&&(s.style.fontVariationSettings=h(a));for(const M of q.current)M&&(M.style.fontVariationSettings=h(a))},[a]);return p.useEffect(()=>(window.addEventListener("mousemove",i,{passive:!0}),window.addEventListener("scroll",B,{passive:!0,capture:!0}),document.documentElement.addEventListener("mouseleave",S),()=>{window.removeEventListener("mousemove",i),window.removeEventListener("scroll",B,{capture:!0}),document.documentElement.removeEventListener("mouseleave",S)}),[i,B,S]),H.jsx(o,{ref:w,className:u,style:{fontVariationSettings:h(a),...c},children:V})});et.displayName="MagnetBlock";exports.MAGNET_TYPE_CLASSES=R;exports.MagnetBlock=et;exports.MagnetTypeText=tt;exports.applyMagnetType=Q;exports.getCleanHTML=z;exports.removeMagnetType=ot;exports.startMagnetType=Z;exports.useMagnetType=W;
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react"),G=require("react/jsx-runtime"),tt={i:3,l:3,1:3,I:3,r:2,n:1,m:1,0:2,O:2,o:1,b:1,d:1,p:1,q:1,c:1,e:1},D={word:"mt-word",char:"mt-char",probe:"mt-probe"},j={axes:{wght:[300,500]},radius:120,falloff:"quadratic",magnetMode:"attract",wdthBoost:6,scope:"document"};function W(e,r=[]){return e.nodeType===Node.TEXT_NODE?r.push(e):e.childNodes.forEach(o=>W(o,r)),r}function K(e,r,o){if(!e||e==="normal")return`"${r}" ${o}`;const y=new RegExp(`(["'])${r}\\1\\s+[\\d.eE+-]+`),a=`"${r}" ${o}`;return y.test(e)?e.replace(y,a):`${e}, ${a}`}function et(e,r){let o=e;for(const[y,a]of Object.entries(r))o=K(o,y,a);return o}function nt(e,r,o){if(r.opacity!==void 0){const[y,a]=r.opacity;e.style.opacity=String(y+(a-y)*o)}r.italic===!0&&(e.style.fontStyle=o>.5?"italic":"")}function U(e,r){r.opacity!==void 0&&(e.style.opacity=String(r.opacity[0])),r.italic===!0&&(e.style.fontStyle="")}function rt(e){const r=e.cloneNode(!0),o=r.querySelectorAll(`.${D.word}, .${D.char}`);return Array.from(o).reverse().forEach(a=>{const l=a.parentNode;if(l){for(;a.firstChild;)l.insertBefore(a.firstChild,a);l.removeChild(a)}}),r.innerHTML}function lt(e,r){e.innerHTML=r}function ot(e,r,o={}){if(typeof window>"u")return()=>{};if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return e.innerHTML=r,()=>{};const y=o.wdthBoost??j.wdthBoost,a=o.radius??j.radius,l=o.falloff??j.falloff,x=o.scope??j.scope,E=o.props,f=o.transitionMs??0,w=window.scrollY;e.innerHTML=r;const L=getComputedStyle(e).fontVariationSettings,Y=L.match(/"wdth"\s+([\d.eE+-]+)/),T=Y?parseFloat(Y[1]):100,F=W(e),p=[];for(const s of F){const t=s.textContent??"";if(!t||!t.split("").some(n=>n in tt))continue;const c=document.createDocumentFragment();for(const n of t){const M=tt[n];if(M===void 0){const m=c.lastChild;m&&m.nodeType===Node.TEXT_NODE?m.textContent+=n:c.appendChild(document.createTextNode(n))}else{const m=document.createElement("span");m.className=D.char,m.style.fontVariationSettings=K(L,"wdth",T),m.textContent=n,c.appendChild(m),p.push({span:m,riskLevel:M})}}s.parentNode.replaceChild(c,s)}if(requestAnimationFrame(()=>{typeof window<"u"&&Math.abs(window.scrollY-w)>2&&window.scrollTo({top:w,behavior:"instant"})}),p.length===0)return()=>{};E&&p.forEach(({span:s})=>U(s,E));let g=-9999,V=-9999,S=!1,u=0,b=!0,N=null;function h(){if(!b)return;if(!S){p.forEach(({span:t})=>{f>0&&(t.style.transition=`font-variation-settings ${f}ms ease`),t.style.fontVariationSettings=K(L,"wdth",T),E&&U(t,E)}),f>0&&(N!==null&&clearTimeout(N),N=setTimeout(()=>{p.forEach(({span:t})=>{t.style.transition=""}),N=null},f)),u=0;return}const s=p.map(({span:t})=>t.getBoundingClientRect());p.forEach(({span:t,riskLevel:i},c)=>{t.style.transition="";const n=s[c],M=n.left+n.width/2,m=n.top+n.height/2,B=Math.sqrt((g-M)**2+(V-m)**2),A=Math.max(0,1-B/a),q=l==="quadratic"?A*A:A,H=y*(i/3)*q;t.style.fontVariationSettings=K(L,"wdth",T+H),E&&nt(t,E,q)}),u=requestAnimationFrame(h)}function X(s){g=s.clientX,V=s.clientY,S||(S=!0),u===0&&(u=requestAnimationFrame(h))}function R(){S=!1,u===0&&(u=requestAnimationFrame(h))}function k(s){s.touches.length!==0&&(g=s.touches[0].clientX,V=s.touches[0].clientY,S||(S=!0),u===0&&(u=requestAnimationFrame(h)))}function $(){S=!1,u===0&&(u=requestAnimationFrame(h))}const v=x==="document"?document:e;return v.addEventListener("mousemove",X),v.addEventListener("mouseleave",R),v.addEventListener("touchmove",k,{passive:!0}),v.addEventListener("touchend",$),()=>{b=!1,cancelAnimationFrame(u),N!==null&&clearTimeout(N),v.removeEventListener("mousemove",X),v.removeEventListener("mouseleave",R),v.removeEventListener("touchmove",k),v.removeEventListener("touchend",$),e.innerHTML=r}}function st(e,r,o={}){if(typeof window>"u")return()=>{};if(window.matchMedia("(prefers-reduced-motion: reduce)").matches)return e.innerHTML=r,()=>{};const y=o.axes??j.axes,a=o.radius??j.radius,l=o.falloff??j.falloff,x=o.magnetMode??j.magnetMode,E=o.scope??j.scope,f=o.props,w=o.transitionMs??0,L=window.scrollY;e.innerHTML=r;const Y=W(e),T=[];for(const s of Y){const t=s.textContent??"";if(!t.trim())continue;const i=t.split(/(\S+)/),c=document.createDocumentFragment();for(let n=0;n<i.length;n+=2){const M=i[n],m=i[n+1];if(!m)continue;const A=i[n+3]===void 0?i[n+2]??"":"",q=document.createElement("span");q.className=D.word,q.textContent=M+m+A,c.appendChild(q),T.push(q)}s.parentNode.replaceChild(c,s)}if(requestAnimationFrame(()=>{typeof window<"u"&&Math.abs(window.scrollY-L)>2&&window.scrollTo({top:L,behavior:"instant"})}),T.length===0)return()=>{};const F=getComputedStyle(e).fontVariationSettings,p=et(F,Object.fromEntries(Object.entries(y).map(([s,[t]])=>[s,t])));T.forEach(s=>{s.style.fontVariationSettings=p,f&&U(s,f)});let g=-9999,V=-9999,S=!1,u=0,b=!0,N=null;function h(){if(!b)return;if(!S){T.forEach(t=>{w>0&&(t.style.transition=`font-variation-settings ${w}ms ease`),t.style.fontVariationSettings=p,f&&U(t,f)}),w>0&&(N!==null&&clearTimeout(N),N=setTimeout(()=>{T.forEach(t=>{t.style.transition=""}),N=null},w)),u=0;return}const s=T.map(t=>t.getBoundingClientRect());T.forEach((t,i)=>{t.style.transition="";const c=s[i],n=c.left+c.width/2,M=c.top+c.height/2,m=Math.sqrt((g-n)**2+(V-M)**2),B=Math.max(0,1-m/a),A=l==="quadratic"?B*B:B,q=x==="repel"?1-A:A,H={};for(const _ of Object.keys(y)){const[J,O]=y[_]??[300,500];H[_]=J+(O-J)*q}t.style.fontVariationSettings=et(F,H),f&&nt(t,f,A)}),u=requestAnimationFrame(h)}function X(s){g=s.clientX,V=s.clientY,S||(S=!0),u===0&&(u=requestAnimationFrame(h))}function R(){S=!1,u===0&&(u=requestAnimationFrame(h))}function k(s){s.touches.length!==0&&(g=s.touches[0].clientX,V=s.touches[0].clientY,S||(S=!0),u===0&&(u=requestAnimationFrame(h)))}function $(){S=!1,u===0&&(u=requestAnimationFrame(h))}const v=E==="document"?document:e;return v.addEventListener("mousemove",X),v.addEventListener("mouseleave",R),v.addEventListener("touchmove",k,{passive:!0}),v.addEventListener("touchend",$),()=>{b=!1,cancelAnimationFrame(u),N!==null&&clearTimeout(N),v.removeEventListener("mousemove",X),v.removeEventListener("mouseleave",R),v.removeEventListener("touchmove",k),v.removeEventListener("touchend",$),e.innerHTML=r}}function ct(e){const r=d.useRef(null),o=d.useRef(null),y=d.useRef(e);y.current=e;const a=d.useRef(null),l=e.mode??"field",{axes:x,radius:E,falloff:f,magnetMode:w,wdthBoost:L,scope:Y}=e,T=x?JSON.stringify(x):void 0,F=e.props?JSON.stringify(e.props):void 0,p=d.useCallback(()=>{const g=r.current;if(!g)return;o.current===null&&(o.current=rt(g)),a.current&&(a.current(),a.current=null),(y.current.mode??"field")==="field"?a.current=st(g,o.current,y.current):a.current=ot(g,o.current,y.current)},[l,T,E,f,w,L,Y,F]);return d.useLayoutEffect(()=>(p(),()=>{a.current&&(a.current(),a.current=null)}),[p]),d.useEffect(()=>{document.fonts.ready.then(p)},[p]),r}const it=d.forwardRef(function({children:r,as:o="p",className:y,style:a,...l},x){const E=ct(l),f=d.useCallback(w=>{E.current=w,typeof x=="function"?x(w):x&&(x.current=w)},[x]);return G.jsx(o,{ref:f,className:y,style:a,children:r})});it.displayName="MagnetTypeText";const ut=d.forwardRef(function({children:r,as:o="p",className:y,style:a,minWeight:l=300,maxWeight:x=600,proximityRadius:E,spreadRadius:f,fixedAxes:w={},cachePositions:L=!0,rafThrottle:Y=!0},T){const F=d.useRef(null),p=d.useRef(null),g=d.useRef([]),V=d.useRef([]),S=d.useRef(null),u=d.useRef(!1),b=d.useRef(null),N=d.useCallback(t=>{F.current=t,typeof T=="function"?T(t):T&&(T.current=t)},[T]);function h(t){const i=[`'wght' ${t.toFixed(0)}`];for(const[c,n]of Object.entries(w))i.push(`'${c}' ${n}`);return i.join(", ")}function X(){const t=F.current;if(!t)return;const i=window.scrollX,c=window.scrollY,n=t.getBoundingClientRect();S.current={top:n.top+c,left:n.left+i,right:n.right+i,bottom:n.bottom+c},V.current=g.current.map(M=>{if(!M)return{cx:0,cy:0};const m=M.getBoundingClientRect();return{cx:(m.left+m.right)/2+i,cy:(m.top+m.bottom)/2+c}}),u.current=!0}function R(t,i){const c=F.current;if(!c)return;L&&!u.current&&X();let n,M,m,B,A,q;if(L&&S.current)A=t+window.scrollX,q=i+window.scrollY,{top:n,left:M,right:m,bottom:B}=S.current;else{const O=c.getBoundingClientRect();A=t,q=i,n=O.top,M=O.left,m=O.right,B=O.bottom}const H=Math.max(M-A,0,A-m),_=Math.max(n-q,0,q-B),J=Math.sqrt(H*H+_*_);if(E!==void 0&&!f){const C=1-(1-Math.max(0,1-J/E))**2;c.style.fontVariationSettings=h(l+(x-l)*C);return}if(f){if(E!==void 0&&J>E){c.style.fontVariationSettings=h(l);for(const C of g.current)C&&(C.style.fontVariationSettings=h(l));return}if(J>f){for(const C of g.current)C&&(C.style.fontVariationSettings=h(l));return}const O=g.current;if(L&&V.current.length===O.length)for(let C=0;C<O.length;C++){const I=O[C];if(!I)continue;const{cx:z,cy:P}=V.current[C],Q=Math.sqrt((A-z)**2+(q-P)**2),Z=1-(1-Math.max(0,1-Q/f))**2;I.style.fontVariationSettings=h(l+(x-l)*Z)}else for(const C of O){if(!C)continue;const I=C.getBoundingClientRect(),z=(I.left+I.right)/2,P=(I.top+I.bottom)/2,Q=Math.sqrt((t-z)**2+(i-P)**2),Z=1-(1-Math.max(0,1-Q/f))**2;C.style.fontVariationSettings=h(l+(x-l)*Z)}}}const k=d.useCallback(t=>{p.current={x:t.clientX,y:t.clientY},Y?b.current===null&&(b.current=requestAnimationFrame(()=>{b.current=null,p.current&&R(p.current.x,p.current.y)})):R(t.clientX,t.clientY)},[l,x,E,f,L,Y,JSON.stringify(w)]),$=d.useCallback(()=>{p.current&&R(p.current.x,p.current.y)},[l,x,E,f,L,JSON.stringify(w)]),v=d.useCallback(()=>{p.current=null,b.current!==null&&(cancelAnimationFrame(b.current),b.current=null);const t=F.current;t&&(t.style.fontVariationSettings=h(l));for(const i of g.current)i&&(i.style.fontVariationSettings=h(l))},[l,JSON.stringify(w)]);d.useEffect(()=>(window.addEventListener("mousemove",k,{passive:!0}),window.addEventListener("scroll",$,{passive:!0,capture:!0}),document.documentElement.addEventListener("mouseleave",v),()=>{window.removeEventListener("mousemove",k),window.removeEventListener("scroll",$,{capture:!0}),document.documentElement.removeEventListener("mouseleave",v),b.current!==null&&(cancelAnimationFrame(b.current),b.current=null)}),[k,$,v]),d.useEffect(()=>{if(!L||!f)return;u.current=!1;const t=F.current;if(!t)return;const i=new ResizeObserver(()=>{u.current=!1});return i.observe(t),document.fonts.ready.then(()=>{u.current=!1}),()=>i.disconnect()},[L,f]),d.useEffect(()=>{u.current=!1},[r,f]);const s=d.useMemo(()=>{if(!f)return r;g.current=[];let t=0;function i(c){if(typeof c=="string")return[...c].map(n=>{if(/\s/.test(n))return n;const M=t++;return G.jsx("span",{ref:m=>{g.current[M]=m},style:{fontVariationSettings:h(l)},children:n},M)});if(Array.isArray(c))return c.map((n,M)=>G.jsx(d.Fragment,{children:i(n)},M));if(d.isValidElement(c)){const n=c;if(n.props.children!==void 0)return d.cloneElement(n,{},i(n.props.children))}return c}return i(r)},[r,f,l,JSON.stringify(w)]);return G.jsx(o,{ref:N,className:y,style:{fontVariationSettings:h(l),...a},children:s})});ut.displayName="MagnetBlock";exports.MAGNET_TYPE_CLASSES=D;exports.MagnetBlock=ut;exports.MagnetTypeText=it;exports.applyMagnetType=ot;exports.getCleanHTML=rt;exports.removeMagnetType=lt;exports.startMagnetType=st;exports.useMagnetType=ct;
|
package/dist/index.d.ts
CHANGED
|
@@ -38,12 +38,6 @@ export declare const MAGNET_TYPE_CLASSES: {
|
|
|
38
38
|
readonly probe: "mt-probe";
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* Drop-in block element with cursor-proximity variable font weight variation.
|
|
43
|
-
* Accepts any ReactNode. When spreadRadius is set, string children are split into
|
|
44
|
-
* per-character spans rendered as React elements — no DOM manipulation required.
|
|
45
|
-
* Use proximityRadius for a whole-element gate, or combine both.
|
|
46
|
-
*/
|
|
47
41
|
export declare const MagnetBlock: default_2.ForwardRefExoticComponent<MagnetBlockProps & default_2.RefAttributes<HTMLElement>>;
|
|
48
42
|
|
|
49
43
|
export declare interface MagnetBlockProps {
|
|
@@ -59,6 +53,22 @@ export declare interface MagnetBlockProps {
|
|
|
59
53
|
/** Pixel distance from the cursor within which each character's weight rises to max */
|
|
60
54
|
spreadRadius?: number;
|
|
61
55
|
fixedAxes?: Record<string, number>;
|
|
56
|
+
/**
|
|
57
|
+
* Cache character centre positions in page-relative coordinates after first render,
|
|
58
|
+
* eliminating getBoundingClientRect calls on every mousemove. The cache is rebuilt on
|
|
59
|
+
* resize and after fonts load. Disable if the block lives inside a custom scroll
|
|
60
|
+
* container (overflow: scroll on a non-window element) — page coordinates are derived
|
|
61
|
+
* from window.scrollX/Y and will be incorrect when a nested element is the scroll parent.
|
|
62
|
+
* @default true
|
|
63
|
+
*/
|
|
64
|
+
cachePositions?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Throttle proximity updates to one per animation frame via requestAnimationFrame,
|
|
67
|
+
* capping the update rate at the display refresh rate. Disable if the ~16 ms rAF delay
|
|
68
|
+
* is perceptible — for example on 120 Hz displays or very tight, fast-moving effects.
|
|
69
|
+
* @default true
|
|
70
|
+
*/
|
|
71
|
+
rafThrottle?: boolean;
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
/** Whether cursor proximity attracts toward peak or repels toward rest */
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import
|
|
3
|
-
import { jsx as
|
|
4
|
-
const
|
|
2
|
+
import et, { useRef as O, useCallback as R, useLayoutEffect as ut, useEffect as K, forwardRef as ct, useMemo as at } from "react";
|
|
3
|
+
import { jsx as U } from "react/jsx-runtime";
|
|
4
|
+
const rt = {
|
|
5
5
|
i: 3,
|
|
6
6
|
l: 3,
|
|
7
7
|
1: 3,
|
|
@@ -23,14 +23,14 @@ const R = {
|
|
|
23
23
|
c: 1,
|
|
24
24
|
e: 1
|
|
25
25
|
// similar bowls
|
|
26
|
-
},
|
|
26
|
+
}, G = {
|
|
27
27
|
/** Applied to each word span in field mode */
|
|
28
28
|
word: "mt-word",
|
|
29
29
|
/** Applied to each character span in legibility mode */
|
|
30
30
|
char: "mt-char",
|
|
31
31
|
/** Applied to measurement probe spans (never in final output) */
|
|
32
32
|
probe: "mt-probe"
|
|
33
|
-
},
|
|
33
|
+
}, j = {
|
|
34
34
|
axes: { wght: [300, 500] },
|
|
35
35
|
radius: 120,
|
|
36
36
|
falloff: "quadratic",
|
|
@@ -38,329 +38,389 @@ const R = {
|
|
|
38
38
|
wdthBoost: 6,
|
|
39
39
|
scope: "document"
|
|
40
40
|
};
|
|
41
|
-
function
|
|
42
|
-
return
|
|
41
|
+
function nt(e, r = []) {
|
|
42
|
+
return e.nodeType === Node.TEXT_NODE ? r.push(e) : e.childNodes.forEach((o) => nt(o, r)), r;
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
if (!
|
|
46
|
-
const
|
|
47
|
-
return
|
|
44
|
+
function z(e, r, o) {
|
|
45
|
+
if (!e || e === "normal") return `"${r}" ${o}`;
|
|
46
|
+
const p = new RegExp(`(["'])${r}\\1\\s+[\\d.eE+-]+`), a = `"${r}" ${o}`;
|
|
47
|
+
return p.test(e) ? e.replace(p, a) : `${e}, ${a}`;
|
|
48
48
|
}
|
|
49
|
-
function
|
|
50
|
-
let o =
|
|
51
|
-
for (const [
|
|
52
|
-
o =
|
|
49
|
+
function ot(e, r) {
|
|
50
|
+
let o = e;
|
|
51
|
+
for (const [p, a] of Object.entries(r))
|
|
52
|
+
o = z(o, p, a);
|
|
53
53
|
return o;
|
|
54
54
|
}
|
|
55
|
-
function
|
|
56
|
-
if (
|
|
57
|
-
const [
|
|
58
|
-
|
|
55
|
+
function st(e, r, o) {
|
|
56
|
+
if (r.opacity !== void 0) {
|
|
57
|
+
const [p, a] = r.opacity;
|
|
58
|
+
e.style.opacity = String(p + (a - p) * o);
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
r.italic === !0 && (e.style.fontStyle = o > 0.5 ? "italic" : "");
|
|
61
61
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
62
|
+
function Q(e, r) {
|
|
63
|
+
r.opacity !== void 0 && (e.style.opacity = String(r.opacity[0])), r.italic === !0 && (e.style.fontStyle = "");
|
|
64
64
|
}
|
|
65
|
-
function
|
|
66
|
-
const
|
|
67
|
-
`.${
|
|
65
|
+
function lt(e) {
|
|
66
|
+
const r = e.cloneNode(!0), o = r.querySelectorAll(
|
|
67
|
+
`.${G.word}, .${G.char}`
|
|
68
68
|
);
|
|
69
|
-
return Array.from(o).reverse().forEach((
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
for (;
|
|
73
|
-
|
|
69
|
+
return Array.from(o).reverse().forEach((a) => {
|
|
70
|
+
const l = a.parentNode;
|
|
71
|
+
if (l) {
|
|
72
|
+
for (; a.firstChild; ) l.insertBefore(a.firstChild, a);
|
|
73
|
+
l.removeChild(a);
|
|
74
74
|
}
|
|
75
|
-
}),
|
|
75
|
+
}), r.innerHTML;
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
77
|
+
function gt(e, r) {
|
|
78
|
+
e.innerHTML = r;
|
|
79
79
|
}
|
|
80
|
-
function
|
|
80
|
+
function ft(e, r, o = {}) {
|
|
81
81
|
if (typeof window > "u") return () => {
|
|
82
82
|
};
|
|
83
83
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches)
|
|
84
|
-
return
|
|
84
|
+
return e.innerHTML = r, () => {
|
|
85
85
|
};
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
for (const
|
|
90
|
-
const
|
|
91
|
-
if (!
|
|
92
|
-
const
|
|
93
|
-
for (const
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
const
|
|
97
|
-
|
|
86
|
+
const p = o.wdthBoost ?? j.wdthBoost, a = o.radius ?? j.radius, l = o.falloff ?? j.falloff, S = o.scope ?? j.scope, w = o.props, f = o.transitionMs ?? 0, M = window.scrollY;
|
|
87
|
+
e.innerHTML = r;
|
|
88
|
+
const L = getComputedStyle(e).fontVariationSettings, Y = L.match(/"wdth"\s+([\d.eE+-]+)/), E = Y ? parseFloat(Y[1]) : 100, q = nt(e), m = [];
|
|
89
|
+
for (const c of q) {
|
|
90
|
+
const t = c.textContent ?? "";
|
|
91
|
+
if (!t || !t.split("").some((n) => n in rt)) continue;
|
|
92
|
+
const s = document.createDocumentFragment();
|
|
93
|
+
for (const n of t) {
|
|
94
|
+
const g = rt[n];
|
|
95
|
+
if (g === void 0) {
|
|
96
|
+
const d = s.lastChild;
|
|
97
|
+
d && d.nodeType === Node.TEXT_NODE ? d.textContent += n : s.appendChild(document.createTextNode(n));
|
|
98
98
|
} else {
|
|
99
|
-
const
|
|
100
|
-
|
|
99
|
+
const d = document.createElement("span");
|
|
100
|
+
d.className = G.char, d.style.fontVariationSettings = z(L, "wdth", E), d.textContent = n, s.appendChild(d), m.push({ span: d, riskLevel: g });
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
|
|
103
|
+
c.parentNode.replaceChild(s, c);
|
|
104
104
|
}
|
|
105
105
|
if (requestAnimationFrame(() => {
|
|
106
|
-
typeof window < "u" && Math.abs(window.scrollY -
|
|
107
|
-
}),
|
|
106
|
+
typeof window < "u" && Math.abs(window.scrollY - M) > 2 && window.scrollTo({ top: M, behavior: "instant" });
|
|
107
|
+
}), m.length === 0) return () => {
|
|
108
108
|
};
|
|
109
|
-
|
|
110
|
-
let
|
|
111
|
-
function
|
|
112
|
-
if (!
|
|
113
|
-
if (!
|
|
114
|
-
|
|
115
|
-
f > 0 && (
|
|
116
|
-
}), f > 0 && (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}),
|
|
120
|
-
}, f)),
|
|
109
|
+
w && m.forEach(({ span: c }) => Q(c, w));
|
|
110
|
+
let y = -9999, F = -9999, T = !1, u = 0, C = !0, N = null;
|
|
111
|
+
function h() {
|
|
112
|
+
if (!C) return;
|
|
113
|
+
if (!T) {
|
|
114
|
+
m.forEach(({ span: t }) => {
|
|
115
|
+
f > 0 && (t.style.transition = `font-variation-settings ${f}ms ease`), t.style.fontVariationSettings = z(L, "wdth", E), w && Q(t, w);
|
|
116
|
+
}), f > 0 && (N !== null && clearTimeout(N), N = setTimeout(() => {
|
|
117
|
+
m.forEach(({ span: t }) => {
|
|
118
|
+
t.style.transition = "";
|
|
119
|
+
}), N = null;
|
|
120
|
+
}, f)), u = 0;
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
}),
|
|
123
|
+
const c = m.map(({ span: t }) => t.getBoundingClientRect());
|
|
124
|
+
m.forEach(({ span: t, riskLevel: i }, s) => {
|
|
125
|
+
t.style.transition = "";
|
|
126
|
+
const n = c[s], g = n.left + n.width / 2, d = n.top + n.height / 2, B = Math.sqrt((y - g) ** 2 + (F - d) ** 2), b = Math.max(0, 1 - B / a), A = l === "quadratic" ? b * b : b, I = p * (i / 3) * A;
|
|
127
|
+
t.style.fontVariationSettings = z(L, "wdth", E + I), w && st(t, w, A);
|
|
128
|
+
}), u = requestAnimationFrame(h);
|
|
129
129
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
130
|
+
function H(c) {
|
|
131
|
+
y = c.clientX, F = c.clientY, T || (T = !0), u === 0 && (u = requestAnimationFrame(h));
|
|
132
132
|
}
|
|
133
|
-
function
|
|
134
|
-
|
|
133
|
+
function $() {
|
|
134
|
+
T = !1, u === 0 && (u = requestAnimationFrame(h));
|
|
135
135
|
}
|
|
136
|
-
function
|
|
137
|
-
|
|
136
|
+
function X(c) {
|
|
137
|
+
c.touches.length !== 0 && (y = c.touches[0].clientX, F = c.touches[0].clientY, T || (T = !0), u === 0 && (u = requestAnimationFrame(h)));
|
|
138
138
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
139
|
+
function k() {
|
|
140
|
+
T = !1, u === 0 && (u = requestAnimationFrame(h));
|
|
141
141
|
}
|
|
142
|
-
const
|
|
143
|
-
return
|
|
144
|
-
|
|
142
|
+
const v = S === "document" ? document : e;
|
|
143
|
+
return v.addEventListener("mousemove", H), v.addEventListener("mouseleave", $), v.addEventListener("touchmove", X, { passive: !0 }), v.addEventListener("touchend", k), () => {
|
|
144
|
+
C = !1, cancelAnimationFrame(u), N !== null && clearTimeout(N), v.removeEventListener("mousemove", H), v.removeEventListener("mouseleave", $), v.removeEventListener("touchmove", X), v.removeEventListener("touchend", k), e.innerHTML = r;
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
|
-
function
|
|
147
|
+
function dt(e, r, o = {}) {
|
|
148
148
|
if (typeof window > "u") return () => {
|
|
149
149
|
};
|
|
150
150
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches)
|
|
151
|
-
return
|
|
151
|
+
return e.innerHTML = r, () => {
|
|
152
152
|
};
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
for (const
|
|
157
|
-
const
|
|
158
|
-
if (!
|
|
159
|
-
const
|
|
160
|
-
for (let
|
|
161
|
-
const
|
|
162
|
-
if (!
|
|
163
|
-
const
|
|
164
|
-
|
|
153
|
+
const p = o.axes ?? j.axes, a = o.radius ?? j.radius, l = o.falloff ?? j.falloff, S = o.magnetMode ?? j.magnetMode, w = o.scope ?? j.scope, f = o.props, M = o.transitionMs ?? 0, L = window.scrollY;
|
|
154
|
+
e.innerHTML = r;
|
|
155
|
+
const Y = nt(e), E = [];
|
|
156
|
+
for (const c of Y) {
|
|
157
|
+
const t = c.textContent ?? "";
|
|
158
|
+
if (!t.trim()) continue;
|
|
159
|
+
const i = t.split(/(\S+)/), s = document.createDocumentFragment();
|
|
160
|
+
for (let n = 0; n < i.length; n += 2) {
|
|
161
|
+
const g = i[n], d = i[n + 1];
|
|
162
|
+
if (!d) continue;
|
|
163
|
+
const b = i[n + 3] === void 0 ? i[n + 2] ?? "" : "", A = document.createElement("span");
|
|
164
|
+
A.className = G.word, A.textContent = g + d + b, s.appendChild(A), E.push(A);
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
c.parentNode.replaceChild(s, c);
|
|
167
167
|
}
|
|
168
168
|
if (requestAnimationFrame(() => {
|
|
169
|
-
typeof window < "u" && Math.abs(window.scrollY -
|
|
170
|
-
}),
|
|
169
|
+
typeof window < "u" && Math.abs(window.scrollY - L) > 2 && window.scrollTo({ top: L, behavior: "instant" });
|
|
170
|
+
}), E.length === 0) return () => {
|
|
171
171
|
};
|
|
172
|
-
const q = getComputedStyle(
|
|
172
|
+
const q = getComputedStyle(e).fontVariationSettings, m = ot(
|
|
173
173
|
q,
|
|
174
|
-
Object.fromEntries(Object.entries(
|
|
174
|
+
Object.fromEntries(Object.entries(p).map(([c, [t]]) => [c, t]))
|
|
175
175
|
);
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
E.forEach((c) => {
|
|
177
|
+
c.style.fontVariationSettings = m, f && Q(c, f);
|
|
178
178
|
});
|
|
179
|
-
let
|
|
180
|
-
function
|
|
181
|
-
if (!
|
|
182
|
-
if (!
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}),
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}),
|
|
189
|
-
},
|
|
179
|
+
let y = -9999, F = -9999, T = !1, u = 0, C = !0, N = null;
|
|
180
|
+
function h() {
|
|
181
|
+
if (!C) return;
|
|
182
|
+
if (!T) {
|
|
183
|
+
E.forEach((t) => {
|
|
184
|
+
M > 0 && (t.style.transition = `font-variation-settings ${M}ms ease`), t.style.fontVariationSettings = m, f && Q(t, f);
|
|
185
|
+
}), M > 0 && (N !== null && clearTimeout(N), N = setTimeout(() => {
|
|
186
|
+
E.forEach((t) => {
|
|
187
|
+
t.style.transition = "";
|
|
188
|
+
}), N = null;
|
|
189
|
+
}, M)), u = 0;
|
|
190
190
|
return;
|
|
191
191
|
}
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
for (const
|
|
197
|
-
const [
|
|
198
|
-
|
|
192
|
+
const c = E.map((t) => t.getBoundingClientRect());
|
|
193
|
+
E.forEach((t, i) => {
|
|
194
|
+
t.style.transition = "";
|
|
195
|
+
const s = c[i], n = s.left + s.width / 2, g = s.top + s.height / 2, d = Math.sqrt((y - n) ** 2 + (F - g) ** 2), B = Math.max(0, 1 - d / a), b = l === "quadratic" ? B * B : B, A = S === "repel" ? 1 - b : b, I = {};
|
|
196
|
+
for (const _ of Object.keys(p)) {
|
|
197
|
+
const [D, V] = p[_] ?? [300, 500];
|
|
198
|
+
I[_] = D + (V - D) * A;
|
|
199
199
|
}
|
|
200
|
-
|
|
201
|
-
}),
|
|
200
|
+
t.style.fontVariationSettings = ot(q, I), f && st(t, f, b);
|
|
201
|
+
}), u = requestAnimationFrame(h);
|
|
202
202
|
}
|
|
203
|
-
function
|
|
204
|
-
|
|
203
|
+
function H(c) {
|
|
204
|
+
y = c.clientX, F = c.clientY, T || (T = !0), u === 0 && (u = requestAnimationFrame(h));
|
|
205
205
|
}
|
|
206
|
-
function
|
|
207
|
-
|
|
206
|
+
function $() {
|
|
207
|
+
T = !1, u === 0 && (u = requestAnimationFrame(h));
|
|
208
208
|
}
|
|
209
|
-
function
|
|
210
|
-
|
|
209
|
+
function X(c) {
|
|
210
|
+
c.touches.length !== 0 && (y = c.touches[0].clientX, F = c.touches[0].clientY, T || (T = !0), u === 0 && (u = requestAnimationFrame(h)));
|
|
211
211
|
}
|
|
212
|
-
function
|
|
213
|
-
|
|
212
|
+
function k() {
|
|
213
|
+
T = !1, u === 0 && (u = requestAnimationFrame(h));
|
|
214
214
|
}
|
|
215
|
-
const
|
|
216
|
-
return
|
|
217
|
-
|
|
215
|
+
const v = w === "document" ? document : e;
|
|
216
|
+
return v.addEventListener("mousemove", H), v.addEventListener("mouseleave", $), v.addEventListener("touchmove", X, { passive: !0 }), v.addEventListener("touchend", k), () => {
|
|
217
|
+
C = !1, cancelAnimationFrame(u), N !== null && clearTimeout(N), v.removeEventListener("mousemove", H), v.removeEventListener("mouseleave", $), v.removeEventListener("touchmove", X), v.removeEventListener("touchend", k), e.innerHTML = r;
|
|
218
218
|
};
|
|
219
219
|
}
|
|
220
|
-
function
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
if (!
|
|
226
|
-
o.current === null && (o.current =
|
|
227
|
-
}, [
|
|
228
|
-
return
|
|
229
|
-
|
|
230
|
-
}), [
|
|
231
|
-
document.fonts.ready.then(
|
|
232
|
-
}, [
|
|
220
|
+
function mt(e) {
|
|
221
|
+
const r = O(null), o = O(null), p = O(e);
|
|
222
|
+
p.current = e;
|
|
223
|
+
const a = O(null), l = e.mode ?? "field", { axes: S, radius: w, falloff: f, magnetMode: M, wdthBoost: L, scope: Y } = e, E = S ? JSON.stringify(S) : void 0, q = e.props ? JSON.stringify(e.props) : void 0, m = R(() => {
|
|
224
|
+
const y = r.current;
|
|
225
|
+
if (!y) return;
|
|
226
|
+
o.current === null && (o.current = lt(y)), a.current && (a.current(), a.current = null), (p.current.mode ?? "field") === "field" ? a.current = dt(y, o.current, p.current) : a.current = ft(y, o.current, p.current);
|
|
227
|
+
}, [l, E, w, f, M, L, Y, q]);
|
|
228
|
+
return ut(() => (m(), () => {
|
|
229
|
+
a.current && (a.current(), a.current = null);
|
|
230
|
+
}), [m]), K(() => {
|
|
231
|
+
document.fonts.ready.then(m);
|
|
232
|
+
}, [m]), r;
|
|
233
233
|
}
|
|
234
|
-
const
|
|
235
|
-
function({ children:
|
|
236
|
-
const
|
|
237
|
-
(
|
|
238
|
-
|
|
234
|
+
const pt = ct(
|
|
235
|
+
function({ children: r, as: o = "p", className: p, style: a, ...l }, S) {
|
|
236
|
+
const w = mt(l), f = R(
|
|
237
|
+
(M) => {
|
|
238
|
+
w.current = M, typeof S == "function" ? S(M) : S && (S.current = M);
|
|
239
239
|
},
|
|
240
240
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
241
|
-
[
|
|
241
|
+
[S]
|
|
242
242
|
);
|
|
243
|
-
return /* @__PURE__ */
|
|
243
|
+
return /* @__PURE__ */ U(o, { ref: f, className: p, style: a, children: r });
|
|
244
244
|
}
|
|
245
245
|
);
|
|
246
|
-
|
|
247
|
-
const
|
|
246
|
+
pt.displayName = "MagnetTypeText";
|
|
247
|
+
const ht = ct(
|
|
248
248
|
function({
|
|
249
|
-
children:
|
|
249
|
+
children: r,
|
|
250
250
|
as: o = "p",
|
|
251
|
-
className:
|
|
252
|
-
style:
|
|
253
|
-
minWeight:
|
|
254
|
-
maxWeight:
|
|
255
|
-
proximityRadius:
|
|
251
|
+
className: p,
|
|
252
|
+
style: a,
|
|
253
|
+
minWeight: l = 300,
|
|
254
|
+
maxWeight: S = 600,
|
|
255
|
+
proximityRadius: w,
|
|
256
256
|
spreadRadius: f,
|
|
257
|
-
fixedAxes:
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
fixedAxes: M = {},
|
|
258
|
+
cachePositions: L = !0,
|
|
259
|
+
rafThrottle: Y = !0
|
|
260
|
+
}, E) {
|
|
261
|
+
const q = O(null), m = O(null), y = O([]), F = O([]), T = O(null), u = O(!1), C = O(null), N = R(
|
|
262
|
+
(t) => {
|
|
263
|
+
q.current = t, typeof E == "function" ? E(t) : E && (E.current = t);
|
|
262
264
|
},
|
|
263
265
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
264
|
-
[
|
|
266
|
+
[E]
|
|
265
267
|
);
|
|
266
|
-
function
|
|
267
|
-
const
|
|
268
|
-
for (const [
|
|
269
|
-
return
|
|
268
|
+
function h(t) {
|
|
269
|
+
const i = [`'wght' ${t.toFixed(0)}`];
|
|
270
|
+
for (const [s, n] of Object.entries(M)) i.push(`'${s}' ${n}`);
|
|
271
|
+
return i.join(", ");
|
|
270
272
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
273
|
+
function H() {
|
|
274
|
+
const t = q.current;
|
|
275
|
+
if (!t) return;
|
|
276
|
+
const i = window.scrollX, s = window.scrollY, n = t.getBoundingClientRect();
|
|
277
|
+
T.current = {
|
|
278
|
+
top: n.top + s,
|
|
279
|
+
left: n.left + i,
|
|
280
|
+
right: n.right + i,
|
|
281
|
+
bottom: n.bottom + s
|
|
282
|
+
}, F.current = y.current.map((g) => {
|
|
283
|
+
if (!g) return { cx: 0, cy: 0 };
|
|
284
|
+
const d = g.getBoundingClientRect();
|
|
285
|
+
return {
|
|
286
|
+
cx: (d.left + d.right) / 2 + i,
|
|
287
|
+
cy: (d.top + d.bottom) / 2 + s
|
|
288
|
+
};
|
|
289
|
+
}), u.current = !0;
|
|
290
|
+
}
|
|
291
|
+
function $(t, i) {
|
|
292
|
+
const s = q.current;
|
|
293
|
+
if (!s) return;
|
|
294
|
+
L && !u.current && H();
|
|
295
|
+
let n, g, d, B, b, A;
|
|
296
|
+
if (L && T.current)
|
|
297
|
+
b = t + window.scrollX, A = i + window.scrollY, { top: n, left: g, right: d, bottom: B } = T.current;
|
|
298
|
+
else {
|
|
299
|
+
const V = s.getBoundingClientRect();
|
|
300
|
+
b = t, A = i, n = V.top, g = V.left, d = V.right, B = V.bottom;
|
|
299
301
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (!h) return;
|
|
305
|
-
const l = h.getBoundingClientRect(), A = Math.max(l.left - s, 0, s - l.right), d = Math.max(l.top - g, 0, g - l.bottom), r = Math.sqrt(A * A + d * d);
|
|
306
|
-
if (v !== void 0 && !f) {
|
|
307
|
-
const L = 1 - (1 - Math.max(0, 1 - r / v)) ** 2;
|
|
308
|
-
h.style.fontVariationSettings = p(a + (M - a) * L);
|
|
302
|
+
const I = Math.max(g - b, 0, b - d), _ = Math.max(n - A, 0, A - B), D = Math.sqrt(I * I + _ * _);
|
|
303
|
+
if (w !== void 0 && !f) {
|
|
304
|
+
const x = 1 - (1 - Math.max(0, 1 - D / w)) ** 2;
|
|
305
|
+
s.style.fontVariationSettings = h(l + (S - l) * x);
|
|
309
306
|
return;
|
|
310
307
|
}
|
|
311
308
|
if (f) {
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
for (const
|
|
309
|
+
if (w !== void 0 && D > w) {
|
|
310
|
+
s.style.fontVariationSettings = h(l);
|
|
311
|
+
for (const x of y.current) x && (x.style.fontVariationSettings = h(l));
|
|
315
312
|
return;
|
|
316
313
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
e.style.fontVariationSettings = p(a + (M - a) * k);
|
|
314
|
+
if (D > f) {
|
|
315
|
+
for (const x of y.current) x && (x.style.fontVariationSettings = h(l));
|
|
316
|
+
return;
|
|
321
317
|
}
|
|
318
|
+
const V = y.current;
|
|
319
|
+
if (L && F.current.length === V.length)
|
|
320
|
+
for (let x = 0; x < V.length; x++) {
|
|
321
|
+
const J = V[x];
|
|
322
|
+
if (!J) continue;
|
|
323
|
+
const { cx: Z, cy: P } = F.current[x], W = Math.sqrt((b - Z) ** 2 + (A - P) ** 2), tt = 1 - (1 - Math.max(0, 1 - W / f)) ** 2;
|
|
324
|
+
J.style.fontVariationSettings = h(l + (S - l) * tt);
|
|
325
|
+
}
|
|
326
|
+
else
|
|
327
|
+
for (const x of V) {
|
|
328
|
+
if (!x) continue;
|
|
329
|
+
const J = x.getBoundingClientRect(), Z = (J.left + J.right) / 2, P = (J.top + J.bottom) / 2, W = Math.sqrt((t - Z) ** 2 + (i - P) ** 2), tt = 1 - (1 - Math.max(0, 1 - W / f)) ** 2;
|
|
330
|
+
x.style.fontVariationSettings = h(l + (S - l) * tt);
|
|
331
|
+
}
|
|
322
332
|
}
|
|
323
333
|
}
|
|
324
|
-
const
|
|
325
|
-
(
|
|
326
|
-
|
|
334
|
+
const X = R(
|
|
335
|
+
(t) => {
|
|
336
|
+
m.current = { x: t.clientX, y: t.clientY }, Y ? C.current === null && (C.current = requestAnimationFrame(() => {
|
|
337
|
+
C.current = null, m.current && $(m.current.x, m.current.y);
|
|
338
|
+
})) : $(t.clientX, t.clientY);
|
|
327
339
|
},
|
|
328
|
-
|
|
329
|
-
|
|
340
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
341
|
+
[l, S, w, f, L, Y, JSON.stringify(M)]
|
|
342
|
+
), k = R(
|
|
330
343
|
() => {
|
|
331
|
-
|
|
344
|
+
m.current && $(m.current.x, m.current.y);
|
|
332
345
|
},
|
|
333
|
-
|
|
334
|
-
|
|
346
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
347
|
+
[l, S, w, f, L, JSON.stringify(M)]
|
|
348
|
+
), v = R(
|
|
335
349
|
() => {
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
for (const
|
|
350
|
+
m.current = null, C.current !== null && (cancelAnimationFrame(C.current), C.current = null);
|
|
351
|
+
const t = q.current;
|
|
352
|
+
t && (t.style.fontVariationSettings = h(l));
|
|
353
|
+
for (const i of y.current) i && (i.style.fontVariationSettings = h(l));
|
|
340
354
|
},
|
|
341
|
-
|
|
355
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
356
|
+
[l, JSON.stringify(M)]
|
|
342
357
|
);
|
|
343
|
-
|
|
344
|
-
window.removeEventListener("mousemove",
|
|
345
|
-
}), [
|
|
358
|
+
K(() => (window.addEventListener("mousemove", X, { passive: !0 }), window.addEventListener("scroll", k, { passive: !0, capture: !0 }), document.documentElement.addEventListener("mouseleave", v), () => {
|
|
359
|
+
window.removeEventListener("mousemove", X), window.removeEventListener("scroll", k, { capture: !0 }), document.documentElement.removeEventListener("mouseleave", v), C.current !== null && (cancelAnimationFrame(C.current), C.current = null);
|
|
360
|
+
}), [X, k, v]), K(() => {
|
|
361
|
+
if (!L || !f) return;
|
|
362
|
+
u.current = !1;
|
|
363
|
+
const t = q.current;
|
|
364
|
+
if (!t) return;
|
|
365
|
+
const i = new ResizeObserver(() => {
|
|
366
|
+
u.current = !1;
|
|
367
|
+
});
|
|
368
|
+
return i.observe(t), document.fonts.ready.then(() => {
|
|
369
|
+
u.current = !1;
|
|
370
|
+
}), () => i.disconnect();
|
|
371
|
+
}, [L, f]), K(() => {
|
|
372
|
+
u.current = !1;
|
|
373
|
+
}, [r, f]);
|
|
374
|
+
const c = at(() => {
|
|
375
|
+
if (!f) return r;
|
|
376
|
+
y.current = [];
|
|
377
|
+
let t = 0;
|
|
378
|
+
function i(s) {
|
|
379
|
+
if (typeof s == "string")
|
|
380
|
+
return [...s].map((n) => {
|
|
381
|
+
if (/\s/.test(n)) return n;
|
|
382
|
+
const g = t++;
|
|
383
|
+
return /* @__PURE__ */ U(
|
|
384
|
+
"span",
|
|
385
|
+
{
|
|
386
|
+
ref: (d) => {
|
|
387
|
+
y.current[g] = d;
|
|
388
|
+
},
|
|
389
|
+
style: { fontVariationSettings: h(l) },
|
|
390
|
+
children: n
|
|
391
|
+
},
|
|
392
|
+
g
|
|
393
|
+
);
|
|
394
|
+
});
|
|
395
|
+
if (Array.isArray(s)) return s.map((n, g) => /* @__PURE__ */ U(et.Fragment, { children: i(n) }, g));
|
|
396
|
+
if (et.isValidElement(s)) {
|
|
397
|
+
const n = s;
|
|
398
|
+
if (n.props.children !== void 0)
|
|
399
|
+
return et.cloneElement(n, {}, i(n.props.children));
|
|
400
|
+
}
|
|
401
|
+
return s;
|
|
402
|
+
}
|
|
403
|
+
return i(r);
|
|
404
|
+
}, [r, f, l, JSON.stringify(M)]);
|
|
405
|
+
return /* @__PURE__ */ U(
|
|
346
406
|
o,
|
|
347
407
|
{
|
|
348
|
-
ref:
|
|
349
|
-
className:
|
|
350
|
-
style: { fontVariationSettings:
|
|
351
|
-
children:
|
|
408
|
+
ref: N,
|
|
409
|
+
className: p,
|
|
410
|
+
style: { fontVariationSettings: h(l), ...a },
|
|
411
|
+
children: c
|
|
352
412
|
}
|
|
353
413
|
);
|
|
354
414
|
}
|
|
355
415
|
);
|
|
356
|
-
|
|
416
|
+
ht.displayName = "MagnetBlock";
|
|
357
417
|
export {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
418
|
+
G as MAGNET_TYPE_CLASSES,
|
|
419
|
+
ht as MagnetBlock,
|
|
420
|
+
pt as MagnetTypeText,
|
|
421
|
+
ft as applyMagnetType,
|
|
422
|
+
lt as getCleanHTML,
|
|
423
|
+
gt as removeMagnetType,
|
|
424
|
+
dt as startMagnetType,
|
|
425
|
+
mt as useMagnetType
|
|
366
426
|
};
|