@supermousejs/labs 2.3.0 → 2.3.1
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 +86 -15
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +134 -129
- package/dist/index.umd.js +2 -2
- package/package.json +9 -5
- package/CHANGELOG.md +0 -103
- package/meta.json +0 -148
- package/src/SmartIcon.ts +0 -200
- package/src/SmartRing.ts +0 -105
- package/src/Sparkles.ts +0 -168
- package/src/TextRing.ts +0 -159
- package/src/index.ts +0 -4
- package/tsconfig.json +0 -4
- package/vite.config.ts +0 -24
package/README.md
CHANGED
|
@@ -1,45 +1,116 @@
|
|
|
1
1
|
# @supermousejs/labs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Advanced state machine that morphs SVGs based on semantic context.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @supermousejs/labs
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## SmartIcon
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
Advanced state machine that morphs SVGs based on semantic context.
|
|
14
|
+
|
|
15
|
+
### Usage
|
|
10
16
|
|
|
11
17
|
```ts
|
|
12
|
-
import {
|
|
13
|
-
|
|
18
|
+
import { Supermouse } from "@supermousejs/core";
|
|
19
|
+
import { SmartIcon } from '@supermousejs/labs';
|
|
20
|
+
const app = new Supermouse();
|
|
21
|
+
app.use(SmartIcon({ icons: { ... } }));
|
|
14
22
|
```
|
|
15
23
|
|
|
16
|
-
###
|
|
24
|
+
### Options
|
|
25
|
+
|
|
26
|
+
| Name | Type | Default | Description |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| icons | Record<string, string> | {} | Map of state names to SVG strings. |
|
|
29
|
+
| defaultState | string | 'default' | Initial semantic state used before any hover interaction resolves. |
|
|
30
|
+
| useSemanticTags | boolean | true | Resolve smart states from semantic HTML tags such as links and buttons. |
|
|
31
|
+
| transitionDuration | number | 200 | Morph transition time in ms. |
|
|
32
|
+
| switchDelay | number | 80 | Minimum ms a state must be requested before committing to the next icon. |
|
|
33
|
+
| size | number | 24 | Size of the icon container. |
|
|
34
|
+
| color | string | 'black' | Icon fill color (currentColor). |
|
|
35
|
+
| offset | [number, number] | [0, 0] | Fixed offset. |
|
|
36
|
+
| anchor | string | 'center' | Alignment (center, top-left, etc). |
|
|
37
|
+
| followStrategy | 'smooth' | 'raw' | 'smooth' | Whether the icon should smoothly follow the pointer or snap to it. |
|
|
38
|
+
| rotateWithVelocity | boolean | false | Rotate the icon based on movement velocity. |
|
|
39
|
+
|
|
40
|
+
## SmartRing
|
|
17
41
|
|
|
18
42
|
A reactive ring that distorts with velocity and adapts to stuck elements.
|
|
19
43
|
|
|
44
|
+
### Usage
|
|
45
|
+
|
|
20
46
|
```ts
|
|
21
|
-
import {
|
|
22
|
-
|
|
47
|
+
import { Supermouse } from "@supermousejs/core";
|
|
48
|
+
import { SmartRing } from '@supermousejs/labs';
|
|
49
|
+
const app = new Supermouse();
|
|
50
|
+
app.use(SmartRing({ size: 24, color: '#f59e0b', enableSkew: true }));
|
|
23
51
|
```
|
|
24
52
|
|
|
25
|
-
###
|
|
53
|
+
### Options
|
|
54
|
+
|
|
55
|
+
| Name | Type | Default | Description |
|
|
56
|
+
| --- | --- | --- | --- |
|
|
57
|
+
| size | number | 20 | Base diameter. |
|
|
58
|
+
| hoverSize | number | 40 | Diameter on hover. |
|
|
59
|
+
| color | string | '#ffffff' | Border color used for the ring. |
|
|
60
|
+
| fill | string | 'transparent' | Background fill color applied to the ring. |
|
|
61
|
+
| borderWidth | number | 2 | Border thickness in pixels. |
|
|
62
|
+
| mixBlendMode | string | 'difference' | CSS mix-blend-mode applied to the ring element. |
|
|
63
|
+
| enableSkew | boolean | false | Distort shape based on velocity. |
|
|
64
|
+
|
|
65
|
+
## Sparkles
|
|
26
66
|
|
|
27
67
|
Emits particle trails based on movement velocity.
|
|
28
68
|
|
|
69
|
+
### Usage
|
|
70
|
+
|
|
29
71
|
```ts
|
|
30
|
-
import {
|
|
31
|
-
|
|
72
|
+
import { Supermouse } from "@supermousejs/core";
|
|
73
|
+
import { Sparkles } from '@supermousejs/labs';
|
|
74
|
+
const app = new Supermouse();
|
|
75
|
+
app.use(Sparkles({ color: '#f59e0b', frequency: 10 }));
|
|
32
76
|
```
|
|
33
77
|
|
|
34
|
-
###
|
|
78
|
+
### Options
|
|
79
|
+
|
|
80
|
+
| Name | Type | Default | Description |
|
|
81
|
+
| --- | --- | --- | --- |
|
|
82
|
+
| color | string | '#ff00ff' | Particle color. |
|
|
83
|
+
| count | number | 30 | Number of particles to keep in the pool. |
|
|
84
|
+
| frequency | number | 10 | Pixels per spawn. |
|
|
85
|
+
| decay | number | 0.05 | Fade rate. |
|
|
86
|
+
| scatter | number | 5 | Random position offset for particle spawning. |
|
|
87
|
+
|
|
88
|
+
## TextRing
|
|
35
89
|
|
|
36
90
|
Rotates text around the cursor position.
|
|
37
91
|
|
|
92
|
+
### Usage
|
|
93
|
+
|
|
38
94
|
```ts
|
|
39
|
-
import {
|
|
40
|
-
|
|
95
|
+
import { Supermouse } from "@supermousejs/core";
|
|
96
|
+
import { TextRing } from '@supermousejs/labs';
|
|
97
|
+
const app = new Supermouse();
|
|
98
|
+
app.use(TextRing({ text: 'LOADING • ', radius: 40 }));
|
|
41
99
|
```
|
|
42
100
|
|
|
101
|
+
### Options
|
|
102
|
+
|
|
103
|
+
| Name | Type | Default | Description |
|
|
104
|
+
| --- | --- | --- | --- |
|
|
105
|
+
| text | string | 'SUPERMOUSE • SUPERMOUSE • ' | Text content. |
|
|
106
|
+
| radius | number | 60 | Ring radius. |
|
|
107
|
+
| fontSize | number | 12 | Text size in pixels. |
|
|
108
|
+
| speed | number | 0.5 | Rotation speed deg/frame. |
|
|
109
|
+
| color | string | 'currentColor' | Text color used by the SVG ring. |
|
|
110
|
+
| opacity | number | 1 | Opacity of the rendered ring container. |
|
|
111
|
+
| className | string | '' | Optional CSS class added to the container. |
|
|
112
|
+
| spread | boolean | false | Stretch the text to fit around the full loop. |
|
|
113
|
+
|
|
43
114
|
## Documentation
|
|
44
115
|
|
|
45
116
|
Full documentation and interactive playground available at [supermouse](https://supermouse.js.org) or [check out the repo](https://github.com/Whitestar14/supermouse-js).
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export declare interface SmartIconOptions {
|
|
|
16
16
|
defaultState?: string;
|
|
17
17
|
useSemanticTags?: boolean;
|
|
18
18
|
transitionDuration?: number;
|
|
19
|
+
/** Minimum ms a state must be requested before committing. Default 80. */
|
|
20
|
+
switchDelay?: number;
|
|
19
21
|
size?: ValueOrGetter<number>;
|
|
20
22
|
color?: ValueOrGetter<string>;
|
|
21
23
|
offset?: [number, number];
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { normalize as p, definePlugin as
|
|
2
|
-
import { getCirclePath as
|
|
3
|
-
function
|
|
1
|
+
import { normalize as p, definePlugin as W, dom as l, math as b, Layers as D, effects as Y } from "@supermousejs/utils";
|
|
2
|
+
import { getCirclePath as j, getCircumference as U, formatLoopText as B } from "@supermousejs/zoetrope";
|
|
3
|
+
function q(t, a) {
|
|
4
4
|
const o = t.tagName.toLowerCase();
|
|
5
5
|
if (o === "input" || o === "textarea" || t.isContentEditable) {
|
|
6
6
|
const i = t.type;
|
|
@@ -12,16 +12,25 @@ function j(t, a) {
|
|
|
12
12
|
return "pointer";
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
15
|
-
const
|
|
16
|
-
let a, o = t.defaultState || "default", i = t.defaultState || "default",
|
|
17
|
-
const
|
|
18
|
-
|
|
15
|
+
const Q = (t) => {
|
|
16
|
+
let a, o = t.defaultState || "default", i = t.defaultState || "default", f = null, T = null, C = !1, h, u = null, m = 0;
|
|
17
|
+
const M = t.switchDelay ?? 80;
|
|
18
|
+
let e = 0, y = 0;
|
|
19
|
+
const x = p(t.size, 24), d = p(t.followStrategy, "smooth"), c = p(t.anchor, "center"), r = p(t.rotateWithVelocity, !1), R = t.useSemanticTags ?? !0, A = t.transitionDuration ?? 200, S = t.offset ? t.offset[0] : 0, n = t.offset ? t.offset[1] : 0;
|
|
20
|
+
function v(s) {
|
|
21
|
+
i = s, C = !0, clearTimeout(h), a.style.transform = "scale(0)", h = setTimeout(() => {
|
|
22
|
+
o = i, a.innerHTML = t.icons[o] || "", a.style.transform = "scale(1)", h = setTimeout(() => {
|
|
23
|
+
C = !1;
|
|
24
|
+
}, A / 2);
|
|
25
|
+
}, A / 2);
|
|
26
|
+
}
|
|
27
|
+
return W(
|
|
19
28
|
{
|
|
20
29
|
name: t.name || "smart-icon",
|
|
21
30
|
selector: "[data-supermouse-icon]",
|
|
22
31
|
create: () => {
|
|
23
|
-
const
|
|
24
|
-
return
|
|
32
|
+
const s = l.createActor("div");
|
|
33
|
+
return s.style.zIndex = D.CURSOR, a = l.createActor("div"), l.applyStyles(a, {
|
|
25
34
|
width: "100%",
|
|
26
35
|
height: "100%",
|
|
27
36
|
display: "flex",
|
|
@@ -29,8 +38,8 @@ const q = (t) => {
|
|
|
29
38
|
justifyContent: "center",
|
|
30
39
|
transformOrigin: "center center",
|
|
31
40
|
transform: "scale(1)",
|
|
32
|
-
transition: `transform ${
|
|
33
|
-
}), a.innerHTML = t.icons[o] || "",
|
|
41
|
+
transition: `transform ${A / 2}ms cubic-bezier(0.16, 1, 0.3, 1)`
|
|
42
|
+
}), a.innerHTML = t.icons[o] || "", l.injectStyles(
|
|
34
43
|
"supermouse-smart-icon-styles",
|
|
35
44
|
`
|
|
36
45
|
@keyframes sm {
|
|
@@ -41,107 +50,103 @@ const q = (t) => {
|
|
|
41
50
|
animation: sm 1s linear infinite;
|
|
42
51
|
}
|
|
43
52
|
`
|
|
44
|
-
),
|
|
53
|
+
), s.appendChild(a), s;
|
|
45
54
|
},
|
|
46
55
|
styles: {
|
|
47
56
|
color: "color"
|
|
48
57
|
},
|
|
49
|
-
update: (
|
|
50
|
-
const
|
|
51
|
-
let
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
58
|
+
update: (s, w, g) => {
|
|
59
|
+
const z = t.icons, L = s.state.hoverTarget;
|
|
60
|
+
let E = t.defaultState || "default";
|
|
61
|
+
if (L) {
|
|
62
|
+
L !== f && (f = L, T = R ? q(L, z) : null);
|
|
63
|
+
const N = s.state.interaction?.icon;
|
|
64
|
+
N && z[N] ? E = N : T && (E = T);
|
|
56
65
|
} else
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const P = o === "pointer" || o === "text";
|
|
69
|
-
if (v(l.state) && !P && !l.state.reducedMotion) {
|
|
70
|
-
const { x: L, y: I } = l.state.velocity;
|
|
71
|
-
w.dist(L, I) > 1 && (C = w.angle(L, I)), h = w.lerpAngle(h, C, 0.15);
|
|
66
|
+
f = null, T = null;
|
|
67
|
+
E !== o && !C ? !z[E] && E !== (t.defaultState || "default") ? (u = null, m = 0) : E !== u ? (u = E, m = 0) : (m += g, m >= M && (v(E), u = null, m = 0)) : E === o && (u = null, m = 0);
|
|
68
|
+
const k = x(s.state);
|
|
69
|
+
l.setStyle(w, "width", `${k}px`), l.setStyle(w, "height", `${k}px`);
|
|
70
|
+
let $ = 0, P = 0;
|
|
71
|
+
const I = k / 2, O = c(s.state);
|
|
72
|
+
O !== "center" && (O.includes("left") && ($ = I), O.includes("right") && ($ = -I), O.includes("top") && (P = I), O.includes("bottom") && (P = -I));
|
|
73
|
+
const X = o === "pointer" || o === "text";
|
|
74
|
+
if (r(s.state) && !X && !s.state.reducedMotion) {
|
|
75
|
+
const { x: N, y: H } = s.state.velocity;
|
|
76
|
+
b.dist(N, H) > 1 && (y = b.angle(N, H)), e = b.lerpAngle(e, y, 0.15);
|
|
72
77
|
} else
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
e = b.lerpAngle(e, 0, 0.15);
|
|
79
|
+
const F = d(s.state) === "raw" ? s.state.pointer : s.state.smooth;
|
|
80
|
+
l.setTransform(
|
|
81
|
+
w,
|
|
82
|
+
F.x + S + $,
|
|
83
|
+
F.y + n + P,
|
|
84
|
+
e
|
|
80
85
|
);
|
|
81
86
|
},
|
|
82
87
|
cleanup() {
|
|
83
|
-
clearTimeout(
|
|
88
|
+
clearTimeout(h);
|
|
84
89
|
}
|
|
85
90
|
},
|
|
86
91
|
t
|
|
87
92
|
);
|
|
88
|
-
},
|
|
89
|
-
const a = p(t.size, 20), o = p(t.hoverSize, 40), i = p(t.color, "#ffffff"),
|
|
90
|
-
let
|
|
91
|
-
return
|
|
93
|
+
}, Z = (t = {}) => {
|
|
94
|
+
const a = p(t.size, 20), o = p(t.hoverSize, 40), i = p(t.color, "#ffffff"), f = p(t.borderWidth, 2), T = p(t.fill, "transparent");
|
|
95
|
+
let C = 20, h = 20, u = 0, m = 1, M = 1;
|
|
96
|
+
return W(
|
|
92
97
|
{
|
|
93
98
|
name: t.name || "smart-ring",
|
|
94
99
|
selector: "[data-supermouse-color]",
|
|
95
|
-
create: (
|
|
96
|
-
const
|
|
97
|
-
return
|
|
98
|
-
zIndex:
|
|
100
|
+
create: (e) => {
|
|
101
|
+
const y = l.createCircle(a(e.state), T(e.state));
|
|
102
|
+
return l.applyStyles(y, {
|
|
103
|
+
zIndex: D.FOLLOWER,
|
|
99
104
|
mixBlendMode: t.mixBlendMode || "difference",
|
|
100
105
|
transition: "opacity 0.2s ease, border-radius 0.2s ease",
|
|
101
106
|
borderStyle: "solid"
|
|
102
|
-
}),
|
|
107
|
+
}), y;
|
|
103
108
|
},
|
|
104
|
-
update: (
|
|
105
|
-
const
|
|
106
|
-
let c =
|
|
107
|
-
|
|
108
|
-
let
|
|
109
|
-
if (!
|
|
110
|
-
const { velocity:
|
|
111
|
-
|
|
109
|
+
update: (e, y) => {
|
|
110
|
+
const x = a(e.state), d = e.state.shape;
|
|
111
|
+
let c = x, r = x, R = "50%", A = i(e.state);
|
|
112
|
+
d ? (c = d.width, r = d.height, R = `${d.borderRadius}px`) : (e.state.isHover && (c = o(e.state), r = o(e.state)), e.state.isDown && (c *= 0.9, r *= 0.9)), e.state.interaction.color && (A = e.state.interaction.color), C = b.lerp(C, c, 0.2), h = b.lerp(h, r, 0.2), l.setStyle(y, "width", `${C}px`), l.setStyle(y, "height", `${h}px`), l.setStyle(y, "borderRadius", R), l.setStyle(y, "borderColor", A), l.setStyle(y, "backgroundColor", T(e.state)), l.setStyle(y, "borderWidth", `${f(e.state)}px`);
|
|
113
|
+
let S = 0, n = 1, v = 1;
|
|
114
|
+
if (!d && t.enableSkew && !e.state.reducedMotion) {
|
|
115
|
+
const { velocity: g } = e.state, z = Y.getVelocityDistortion(g.x, g.y);
|
|
116
|
+
S = z.rotation, n = z.scaleX, v = z.scaleY, u = b.lerpAngle(u, S, 0.15);
|
|
112
117
|
} else
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const { x:
|
|
116
|
-
|
|
118
|
+
u = 0;
|
|
119
|
+
m = b.lerp(m, n, 0.15), M = b.lerp(M, v, 0.15);
|
|
120
|
+
const { x: s, y: w } = e.state.smooth;
|
|
121
|
+
l.setTransform(y, s, w, u, m, M);
|
|
117
122
|
}
|
|
118
123
|
},
|
|
119
124
|
t
|
|
120
125
|
);
|
|
121
|
-
},
|
|
122
|
-
const a = t.count || 30, o = t.decay || 0.05, i = t.frequency || 10,
|
|
123
|
-
let
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
if (!
|
|
127
|
-
|
|
128
|
-
const R =
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
126
|
+
}, _ = (t = {}) => {
|
|
127
|
+
const a = t.count || 30, o = t.decay || 0.05, i = t.frequency || 10, f = t.scatter || 5, C = p(t.color, "#ff00ff"), h = [];
|
|
128
|
+
let u = 0, m = 0, M = !1, e = 0;
|
|
129
|
+
const y = (x, d, c) => {
|
|
130
|
+
const r = h.find((n) => !n.isActive);
|
|
131
|
+
if (!r) return;
|
|
132
|
+
r.isActive = !0, r.life = 1, r.x = x + b.random(-f, f), r.y = d + b.random(-f, f);
|
|
133
|
+
const R = b.random(0, Math.PI * 2), A = b.random(0.5, 1.5);
|
|
134
|
+
r.vx = Math.cos(R) * A, r.vy = Math.sin(R) * A, r.scale = b.random(0.5, 1.2), r.color = c;
|
|
135
|
+
const S = b.random(2, 5);
|
|
136
|
+
l.setStyle(r.el, "width", `${S}px`), l.setStyle(r.el, "height", `${S}px`), l.setStyle(r.el, "backgroundColor", c), l.setStyle(r.el, "opacity", "1"), l.setTransform(r.el, r.x, r.y, 0, r.scale, r.scale);
|
|
132
137
|
};
|
|
133
|
-
return
|
|
138
|
+
return W(
|
|
134
139
|
{
|
|
135
140
|
name: t.name || "sparkles",
|
|
136
|
-
install(
|
|
137
|
-
for (let
|
|
138
|
-
const c =
|
|
139
|
-
|
|
140
|
-
zIndex:
|
|
141
|
+
install(x) {
|
|
142
|
+
for (let d = 0; d < a; d++) {
|
|
143
|
+
const c = l.createCircle(0, "transparent");
|
|
144
|
+
l.applyStyles(c, {
|
|
145
|
+
zIndex: D.TRACE,
|
|
141
146
|
opacity: "0",
|
|
142
147
|
willChange: "transform, opacity",
|
|
143
148
|
transition: "none"
|
|
144
|
-
}),
|
|
149
|
+
}), x.container.appendChild(c), h.push({
|
|
145
150
|
el: c,
|
|
146
151
|
isActive: !1,
|
|
147
152
|
x: 0,
|
|
@@ -154,51 +159,51 @@ const q = (t) => {
|
|
|
154
159
|
});
|
|
155
160
|
}
|
|
156
161
|
},
|
|
157
|
-
update(
|
|
158
|
-
const { x:
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
if (
|
|
162
|
-
const
|
|
163
|
-
for (let
|
|
164
|
-
const
|
|
165
|
-
|
|
162
|
+
update(x) {
|
|
163
|
+
const { x: d, y: c } = x.state.pointer;
|
|
164
|
+
M || (u = d, m = c, M = !0);
|
|
165
|
+
const r = d - u, R = c - m, A = Math.hypot(r, R);
|
|
166
|
+
if (e += A, e > i) {
|
|
167
|
+
const S = C(x.state), n = Math.floor(e / i);
|
|
168
|
+
for (let v = 0; v < n; v++) {
|
|
169
|
+
const s = v / n, w = u + r * s, g = m + R * s;
|
|
170
|
+
y(w, g, S);
|
|
166
171
|
}
|
|
167
|
-
|
|
172
|
+
e = e % i;
|
|
168
173
|
}
|
|
169
|
-
|
|
170
|
-
for (let
|
|
171
|
-
const
|
|
172
|
-
if (
|
|
173
|
-
if (
|
|
174
|
-
|
|
174
|
+
u = d, m = c;
|
|
175
|
+
for (let S = 0; S < a; S++) {
|
|
176
|
+
const n = h[S];
|
|
177
|
+
if (n.isActive)
|
|
178
|
+
if (n.x += n.vx, n.y += n.vy, n.life -= o, n.life <= 0)
|
|
179
|
+
n.isActive = !1, n.el.style.opacity = "0";
|
|
175
180
|
else {
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
|
|
181
|
+
n.el.style.opacity = String(n.life);
|
|
182
|
+
const v = n.scale * n.life;
|
|
183
|
+
l.setTransform(n.el, n.x, n.y, 0, v, v);
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
},
|
|
182
187
|
destroy() {
|
|
183
|
-
|
|
188
|
+
h.forEach((x) => x.el.remove()), h.length = 0;
|
|
184
189
|
}
|
|
185
190
|
},
|
|
186
191
|
t
|
|
187
192
|
);
|
|
188
193
|
};
|
|
189
|
-
let
|
|
190
|
-
const
|
|
191
|
-
let a, o, i,
|
|
192
|
-
const
|
|
193
|
-
let
|
|
194
|
-
return
|
|
194
|
+
let V = 0;
|
|
195
|
+
const tt = (t = {}) => {
|
|
196
|
+
let a, o, i, f, T;
|
|
197
|
+
const C = `supermouse-text-ring-path-${V++}`, h = "SUPERMOUSE • SUPERMOUSE • ", u = 60, m = 12, M = 0.5, e = t.className || "", y = t.spread ?? !1, x = p(t.text, h), d = p(t.radius, u), c = p(t.fontSize, m), r = p(t.speed, M), R = p(t.opacity, 1);
|
|
198
|
+
let A = 0, S = "", n = 0, v = 0;
|
|
199
|
+
return W(
|
|
195
200
|
{
|
|
196
201
|
name: "text-ring",
|
|
197
202
|
selector: "[data-supermouse-text-ring]",
|
|
198
|
-
create: (
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
zIndex:
|
|
203
|
+
create: (s) => {
|
|
204
|
+
const w = l.createActor("div");
|
|
205
|
+
l.applyStyles(w, {
|
|
206
|
+
zIndex: D.FOLLOWER,
|
|
202
207
|
transition: "opacity 0.2s ease",
|
|
203
208
|
opacity: "1",
|
|
204
209
|
width: "0px",
|
|
@@ -207,34 +212,34 @@ const J = (t = {}) => {
|
|
|
207
212
|
display: "flex",
|
|
208
213
|
alignItems: "center",
|
|
209
214
|
justifyContent: "center"
|
|
210
|
-
}),
|
|
211
|
-
const
|
|
212
|
-
return
|
|
215
|
+
}), e && w.classList.add(...e.split(" ").filter(Boolean)), a = document.createElementNS("http://www.w3.org/2000/svg", "svg"), a.style.overflow = "visible", a.style.position = "absolute", a.style.left = "0", a.style.top = "0", o = document.createElementNS("http://www.w3.org/2000/svg", "path"), o.setAttribute("id", C), o.setAttribute("fill", "none"), f = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
216
|
+
const g = c(s.state);
|
|
217
|
+
return f.setAttribute("font-size", `${g}px`), v = g, f.setAttribute("fill", "currentColor"), f.style.textTransform = "uppercase", f.style.letterSpacing = "2px", i = document.createElementNS("http://www.w3.org/2000/svg", "textPath"), i.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", `#${C}`), i.setAttribute("href", `#${C}`), i.setAttribute("startOffset", "0%"), T = document.createTextNode(""), i.appendChild(T), f.appendChild(i), a.appendChild(o), a.appendChild(f), w.appendChild(a), w;
|
|
213
218
|
},
|
|
214
219
|
styles: {
|
|
215
220
|
color: "color"
|
|
216
221
|
},
|
|
217
|
-
update: (
|
|
218
|
-
let
|
|
219
|
-
const z =
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
223
|
-
const
|
|
224
|
-
i.setAttribute("textLength", String(
|
|
222
|
+
update: (s, w) => {
|
|
223
|
+
let g = x(s.state);
|
|
224
|
+
const z = d(s.state), L = c(s.state), E = r(s.state), k = R(s.state);
|
|
225
|
+
l.setStyle(w, "opacity", String(k));
|
|
226
|
+
const $ = s.state.interaction;
|
|
227
|
+
if ($.textRing && typeof $.textRing == "string" ? g = $.textRing : $.text && typeof $.text == "string" && (g = $.text), z !== n && (o.setAttribute("d", j(z)), n = z), y) {
|
|
228
|
+
const O = U(z);
|
|
229
|
+
i.setAttribute("textLength", String(O)), i.setAttribute("lengthAdjust", "spacing"), g = B(g, !0);
|
|
225
230
|
} else
|
|
226
231
|
i.removeAttribute("textLength"), i.removeAttribute("lengthAdjust");
|
|
227
|
-
|
|
228
|
-
const { x:
|
|
229
|
-
|
|
232
|
+
L !== v && (f.setAttribute("font-size", `${L}px`), v = L), g !== S && (T.textContent = g, S = g), A += E;
|
|
233
|
+
const { x: P, y: I } = s.state.smooth;
|
|
234
|
+
l.setTransform(w, P, I, A);
|
|
230
235
|
}
|
|
231
236
|
},
|
|
232
237
|
t
|
|
233
238
|
);
|
|
234
239
|
};
|
|
235
240
|
export {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
Q as SmartIcon,
|
|
242
|
+
Z as SmartRing,
|
|
243
|
+
_ as Sparkles,
|
|
244
|
+
tt as TextRing
|
|
240
245
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(C,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("@supermousejs/utils"),require("@supermousejs/zoetrope")):typeof define=="function"&&define.amd?define(["exports","@supermousejs/utils","@supermousejs/zoetrope"],e):(C=typeof globalThis<"u"?globalThis:C||self,e(C.SupermouseLabs={},C.SupermouseUtils,C.SupermouseZoetrope))})(this,(function(C,e,
|
|
1
|
+
(function(C,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("@supermousejs/utils"),require("@supermousejs/zoetrope")):typeof define=="function"&&define.amd?define(["exports","@supermousejs/utils","@supermousejs/zoetrope"],e):(C=typeof globalThis<"u"?globalThis:C||self,e(C.SupermouseLabs={},C.SupermouseUtils,C.SupermouseZoetrope))})(this,(function(C,e,k){"use strict";function D(t,s){const c=t.tagName.toLowerCase();if(c==="input"||c==="textarea"||t.isContentEditable){const l=t.type;if(["button","submit","checkbox","radio","range","color"].includes(l)){if(s.pointer)return"pointer"}else if(s.text)return"text"}else if((c==="a"||c==="button"||t.closest("a")||t.closest("button"))&&s.pointer)return"pointer";return null}const F=t=>{let s,c=t.defaultState||"default",l=t.defaultState||"default",d=null,z=null,w=!1,g,m=null,u=0;const E=t.switchDelay??80;let n=0,y=0;const x=e.normalize(t.size,24),f=e.normalize(t.followStrategy,"smooth"),i=e.normalize(t.anchor,"center"),o=e.normalize(t.rotateWithVelocity,!1),T=t.useSemanticTags??!0,b=t.transitionDuration??200,S=t.offset?t.offset[0]:0,a=t.offset?t.offset[1]:0;function p(r){l=r,w=!0,clearTimeout(g),s.style.transform="scale(0)",g=setTimeout(()=>{c=l,s.innerHTML=t.icons[c]||"",s.style.transform="scale(1)",g=setTimeout(()=>{w=!1},b/2)},b/2)}return e.definePlugin({name:t.name||"smart-icon",selector:"[data-supermouse-icon]",create:()=>{const r=e.dom.createActor("div");return r.style.zIndex=e.Layers.CURSOR,s=e.dom.createActor("div"),e.dom.applyStyles(s,{width:"100%",height:"100%",display:"flex",alignItems:"center",justifyContent:"center",transformOrigin:"center center",transform:"scale(1)",transition:`transform ${b/2}ms cubic-bezier(0.16, 1, 0.3, 1)`}),s.innerHTML=t.icons[c]||"",e.dom.injectStyles("supermouse-smart-icon-styles",`
|
|
2
2
|
@keyframes sm {
|
|
3
3
|
0% { transform: rotate(0deg); }
|
|
4
4
|
100% { transform: rotate(360deg); }
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
.supermouse-spin {
|
|
7
7
|
animation: sm 1s linear infinite;
|
|
8
8
|
}
|
|
9
|
-
`),
|
|
9
|
+
`),r.appendChild(s),r},styles:{color:"color"},update:(r,v,h)=>{const A=t.icons,M=r.state.hoverTarget;let R=t.defaultState||"default";if(M){M!==d&&(d=M,z=T?D(M,A):null);const P=r.state.interaction?.icon;P&&A[P]?R=P:z&&(R=z)}else d=null,z=null;R!==c&&!w?!A[R]&&R!==(t.defaultState||"default")?(m=null,u=0):R!==m?(m=R,u=0):(u+=h,u>=E&&(p(R),m=null,u=0)):R===c&&(m=null,u=0);const j=x(r.state);e.dom.setStyle(v,"width",`${j}px`),e.dom.setStyle(v,"height",`${j}px`);let L=0,I=0;const O=j/2,$=i(r.state);$!=="center"&&($.includes("left")&&(L=O),$.includes("right")&&(L=-O),$.includes("top")&&(I=O),$.includes("bottom")&&(I=-O));const q=c==="pointer"||c==="text";if(o(r.state)&&!q&&!r.state.reducedMotion){const{x:P,y:W}=r.state.velocity;e.math.dist(P,W)>1&&(y=e.math.angle(P,W)),n=e.math.lerpAngle(n,y,.15)}else n=e.math.lerpAngle(n,0,.15);const N=f(r.state)==="raw"?r.state.pointer:r.state.smooth;e.dom.setTransform(v,N.x+S+L,N.y+a+I,n)},cleanup(){clearTimeout(g)}},t)},H=(t={})=>{const s=e.normalize(t.size,20),c=e.normalize(t.hoverSize,40),l=e.normalize(t.color,"#ffffff"),d=e.normalize(t.borderWidth,2),z=e.normalize(t.fill,"transparent");let w=20,g=20,m=0,u=1,E=1;return e.definePlugin({name:t.name||"smart-ring",selector:"[data-supermouse-color]",create:n=>{const y=e.dom.createCircle(s(n.state),z(n.state));return e.dom.applyStyles(y,{zIndex:e.Layers.FOLLOWER,mixBlendMode:t.mixBlendMode||"difference",transition:"opacity 0.2s ease, border-radius 0.2s ease",borderStyle:"solid"}),y},update:(n,y)=>{const x=s(n.state),f=n.state.shape;let i=x,o=x,T="50%",b=l(n.state);f?(i=f.width,o=f.height,T=`${f.borderRadius}px`):(n.state.isHover&&(i=c(n.state),o=c(n.state)),n.state.isDown&&(i*=.9,o*=.9)),n.state.interaction.color&&(b=n.state.interaction.color),w=e.math.lerp(w,i,.2),g=e.math.lerp(g,o,.2),e.dom.setStyle(y,"width",`${w}px`),e.dom.setStyle(y,"height",`${g}px`),e.dom.setStyle(y,"borderRadius",T),e.dom.setStyle(y,"borderColor",b),e.dom.setStyle(y,"backgroundColor",z(n.state)),e.dom.setStyle(y,"borderWidth",`${d(n.state)}px`);let S=0,a=1,p=1;if(!f&&t.enableSkew&&!n.state.reducedMotion){const{velocity:h}=n.state,A=e.effects.getVelocityDistortion(h.x,h.y);S=A.rotation,a=A.scaleX,p=A.scaleY,m=e.math.lerpAngle(m,S,.15)}else m=0;u=e.math.lerp(u,a,.15),E=e.math.lerp(E,p,.15);const{x:r,y:v}=n.state.smooth;e.dom.setTransform(y,r,v,m,u,E)}},t)},U=(t={})=>{const s=t.count||30,c=t.decay||.05,l=t.frequency||10,d=t.scatter||5,w=e.normalize(t.color,"#ff00ff"),g=[];let m=0,u=0,E=!1,n=0;const y=(x,f,i)=>{const o=g.find(a=>!a.isActive);if(!o)return;o.isActive=!0,o.life=1,o.x=x+e.math.random(-d,d),o.y=f+e.math.random(-d,d);const T=e.math.random(0,Math.PI*2),b=e.math.random(.5,1.5);o.vx=Math.cos(T)*b,o.vy=Math.sin(T)*b,o.scale=e.math.random(.5,1.2),o.color=i;const S=e.math.random(2,5);e.dom.setStyle(o.el,"width",`${S}px`),e.dom.setStyle(o.el,"height",`${S}px`),e.dom.setStyle(o.el,"backgroundColor",i),e.dom.setStyle(o.el,"opacity","1"),e.dom.setTransform(o.el,o.x,o.y,0,o.scale,o.scale)};return e.definePlugin({name:t.name||"sparkles",install(x){for(let f=0;f<s;f++){const i=e.dom.createCircle(0,"transparent");e.dom.applyStyles(i,{zIndex:e.Layers.TRACE,opacity:"0",willChange:"transform, opacity",transition:"none"}),x.container.appendChild(i),g.push({el:i,isActive:!1,x:0,y:0,vx:0,vy:0,life:0,scale:1,color:""})}},update(x){const{x:f,y:i}=x.state.pointer;E||(m=f,u=i,E=!0);const o=f-m,T=i-u,b=Math.hypot(o,T);if(n+=b,n>l){const S=w(x.state),a=Math.floor(n/l);for(let p=0;p<a;p++){const r=p/a,v=m+o*r,h=u+T*r;y(v,h,S)}n=n%l}m=f,u=i;for(let S=0;S<s;S++){const a=g[S];if(a.isActive)if(a.x+=a.vx,a.y+=a.vy,a.life-=c,a.life<=0)a.isActive=!1,a.el.style.opacity="0";else{a.el.style.opacity=String(a.life);const p=a.scale*a.life;e.dom.setTransform(a.el,a.x,a.y,0,p,p)}}},destroy(){g.forEach(x=>x.el.remove()),g.length=0}},t)};let X=0;const Y=(t={})=>{let s,c,l,d,z;const w=`supermouse-text-ring-path-${X++}`,g="SUPERMOUSE • SUPERMOUSE • ",m=60,u=12,E=.5,n=t.className||"",y=t.spread??!1,x=e.normalize(t.text,g),f=e.normalize(t.radius,m),i=e.normalize(t.fontSize,u),o=e.normalize(t.speed,E),T=e.normalize(t.opacity,1);let b=0,S="",a=0,p=0;return e.definePlugin({name:"text-ring",selector:"[data-supermouse-text-ring]",create:r=>{const v=e.dom.createActor("div");e.dom.applyStyles(v,{zIndex:e.Layers.FOLLOWER,transition:"opacity 0.2s ease",opacity:"1",width:"0px",height:"0px",overflow:"visible",display:"flex",alignItems:"center",justifyContent:"center"}),n&&v.classList.add(...n.split(" ").filter(Boolean)),s=document.createElementNS("http://www.w3.org/2000/svg","svg"),s.style.overflow="visible",s.style.position="absolute",s.style.left="0",s.style.top="0",c=document.createElementNS("http://www.w3.org/2000/svg","path"),c.setAttribute("id",w),c.setAttribute("fill","none"),d=document.createElementNS("http://www.w3.org/2000/svg","text");const h=i(r.state);return d.setAttribute("font-size",`${h}px`),p=h,d.setAttribute("fill","currentColor"),d.style.textTransform="uppercase",d.style.letterSpacing="2px",l=document.createElementNS("http://www.w3.org/2000/svg","textPath"),l.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",`#${w}`),l.setAttribute("href",`#${w}`),l.setAttribute("startOffset","0%"),z=document.createTextNode(""),l.appendChild(z),d.appendChild(l),s.appendChild(c),s.appendChild(d),v.appendChild(s),v},styles:{color:"color"},update:(r,v)=>{let h=x(r.state);const A=f(r.state),M=i(r.state),R=o(r.state),j=T(r.state);e.dom.setStyle(v,"opacity",String(j));const L=r.state.interaction;if(L.textRing&&typeof L.textRing=="string"?h=L.textRing:L.text&&typeof L.text=="string"&&(h=L.text),A!==a&&(c.setAttribute("d",k.getCirclePath(A)),a=A),y){const $=k.getCircumference(A);l.setAttribute("textLength",String($)),l.setAttribute("lengthAdjust","spacing"),h=k.formatLoopText(h,!0)}else l.removeAttribute("textLength"),l.removeAttribute("lengthAdjust");M!==p&&(d.setAttribute("font-size",`${M}px`),p=M),h!==S&&(z.textContent=h,S=h),b+=R;const{x:I,y:O}=r.state.smooth;e.dom.setTransform(v,I,O,b)}},t)};C.SmartIcon=F,C.SmartRing=H,C.Sparkles=U,C.TextRing=Y,Object.defineProperty(C,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supermousejs/labs",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"main": "dist/index.umd.js",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
7
11
|
"author": "O.S David",
|
|
8
12
|
"url": "https://github.com/Whitestar14/supermouse-js",
|
|
9
13
|
"license": "MIT",
|
|
10
14
|
"dependencies": {
|
|
11
|
-
"@supermousejs/
|
|
12
|
-
"@supermousejs/
|
|
15
|
+
"@supermousejs/zoetrope": "2.3.1",
|
|
16
|
+
"@supermousejs/utils": "2.3.1"
|
|
13
17
|
},
|
|
14
18
|
"peerDependencies": {
|
|
15
|
-
"@supermousejs/core": "2.
|
|
19
|
+
"@supermousejs/core": "2.3.0"
|
|
16
20
|
},
|
|
17
21
|
"devDependencies": {
|
|
18
|
-
"@supermousejs/core": "2.
|
|
22
|
+
"@supermousejs/core": "2.3.0"
|
|
19
23
|
},
|
|
20
24
|
"repository": {
|
|
21
25
|
"type": "git",
|