@supermousejs/labs 2.4.4-beta.3 → 2.4.4-beta.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # @supermousejs/labs
2
2
 
3
+ ## 2.4.4-beta.5
4
+
5
+ ### Patch Changes
6
+
7
+ - d82c62d: ---
8
+
9
+ Beta.5 — cursor policy flattening, suppression simplification, and API renames.
10
+
11
+ ## Changed — breaking
12
+ - `cursorPolicy` option renamed to `nativeCursorSelectors` and flattened to a plain `string[]`. Migration: `cursorPolicy: { native: [".x"] }` → `nativeCursorSelectors: [".x"]`. The `hide` key is gone; cursor suppression is unconditional and no longer configurable.
13
+ - `CursorPolicy` and `CursorPolicyInput` types removed from the public export surface. Code importing them fails at compile time. The only remaining shape is `string[]`.
14
+ - `DEFAULT_CURSOR_POLICY` renamed to `DEFAULT_NATIVE_CURSOR_SELECTORS`. Value reduced to `["select", "[contenteditable]"]`.
15
+ - `registerHoverTarget(selector)` renamed to `addHoverSelectors(selectors)`. Same behavior — comma-separated selectors are added to the current scope's shared hover set. The new name matches `hoverSelectors` and reflects that it mutates a set rather than registering a single element.
16
+ - `@supermousejs/utils`: `VisualConfig.selector` renamed to `hoverSelector`. Update `definePlugin({ ..., selector: "x" })` to `definePlugin({ ..., hoverSelector: "x" })`.
17
+
18
+ ## Changed — behavior
19
+ - `input` and `textarea` removed from the default native cursor list. Text inputs and textareas are unaffected — their UA cursor is `text`, which the probe reads and treats as a fallback trigger. Button-like inputs (`<input type="button">`, `<input type="submit">`) and checkboxes/radios change: their UA cursor is `default`, which the probe classifies as non-fallback, so the custom cursor now shows over them. This matches the pre-existing treatment of `<button>`.
20
+ - Cursor suppression is now a single wildcard rule per scope instead of a wildcard plus per-selector rules. Behavior is unchanged — verified in Chromium and Firefox against `<a>`, `<button>`, `<input>` (all types), `<textarea>`, `<select>`, `[contenteditable]`, `[role="button"]`, `[tabindex]`, `<label>`, and a `<canvas>` with site CSS. Range slider thumb pseudo-elements retain their explicit rules (`*` does not match pseudo-elements).
21
+
22
+ ## Fixed
23
+ - `handleMouseOut` no longer leaves `state.isHover` and `state.isNative` stale when the pointer leaves from a descendant of the tracked element. Moving from `<span>` inside `<button>` directly outside the button previously failed to clear `hoverTarget` — the containment check was inverted.
24
+
25
+ ## Internal
26
+ - `policy.ts` removed from `@supermousejs/core`. The default moved to `constants.ts`; `normalizePolicy` dissolved into `??` fallbacks at the call sites.
27
+ - `Scope.hideSelectors` field removed.
28
+ - Size budget re-tightened to 6.2 kB gzip / 5.5 kB brotli.
29
+
30
+ - Updated dependencies [d82c62d]
31
+ - @supermousejs/utils@2.4.4-beta.5
32
+ - @supermousejs/core@2.5.0-beta.5
33
+
34
+ ## 2.4.4-beta.4
35
+
36
+ ### Patch Changes
37
+
38
+ - cb9bf9a: Beta.4
39
+
40
+ **Added**
41
+ - `state.authoredCursor` — the cursor value the page intends at the element under the pointer, resolved as if Supermouse's suppression were not active. Populated on every pointerTarget change, in all cursor modes. Read this to know what the page wants (`canvas { cursor: crosshair }`, `.drag-handle { cursor: grab }`, `[disabled] { cursor: not-allowed }`) rather than just whether the OS cursor should be shown (`state.isNative`).
42
+ - `state.pointerTarget` — the raw element under the pointer, regardless of hover selectors. Distinct from `state.hoverTarget`, which reports the nearest ancestor matching a hover selector.
43
+
44
+ **Fixed**
45
+ - Cursor detection in `auto` mode no longer reads its own suppression output. The previous implementation called `getComputedStyle(target).cursor` while the scope's hide class was active, so it always saw `"none"` and never triggered native fallback for authored exotic cursors. A probe attribute (`data-sm-probe`) is now excluded from every generated suppression rule, so the read sees the page's intended value.
46
+
47
+ **Changed**
48
+ - `@supermousejs/labs`: `SmartIcon` now reads `state.pointerTarget` and `state.authoredCursor` instead of relying on a broad hover-selector sweep. Hovering a `<p>` no longer sets `state.isHover` on the primary scope.
49
+ - `@supermousejs/labs`: `SmartIconOptions.useSemanticTags` renamed to `useSemanticDetection`. The old name referred to a `registerHoverTarget` sweep that no longer runs.
50
+
51
+ **Internal**
52
+ - Size budget raised to 6.5 kB gzip / 5.75 kB brotli to accommodate the beta.4 surface. Will be re-tightened once the shape settles.
53
+
54
+ - Updated dependencies [cb9bf9a]
55
+ - @supermousejs/core@2.5.0-beta.4
56
+ - @supermousejs/utils@2.4.4-beta.4
57
+
3
58
  ## 2.4.4-beta.3
4
59
 
5
60
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -14,7 +14,14 @@ export declare interface SmartIconOptions {
14
14
  isEnabled?: boolean;
15
15
  icons: SmartIconMap;
16
16
  defaultState?: string;
17
- useSemanticTags?: boolean;
17
+ /**
18
+ * If true (default), resolve icon state from the semantic meaning of the
19
+ * pointer target — text inputs become "text", links become "pointer",
20
+ * authored cursors feed the "text"/"grab" icons. If false, only
21
+ * `data-supermouse-icon` attributes drive state, with `defaultState`
22
+ * as the fallback.
23
+ */
24
+ useSemanticDetection?: boolean;
18
25
  transitionDuration?: number;
19
26
  /** Minimum ms a state must be requested before committing. Default 80. */
20
27
  switchDelay?: number;
package/dist/index.mjs CHANGED
@@ -1,48 +1,41 @@
1
- import { normalizeAll as X, definePlugin as N, css as x, math as M, createActor as j, Layers as U, injectStyles as tt, damp as V, effects as et, lerpAngle as rt, setTransform as D, createCircle as _, normalize as nt, circlePath as st, circumference as ot, createSVGElement as G, path as it, text as at, textPath as lt } from "@supermousejs/utils";
2
- function ct(t, e) {
3
- const f = t.tagName.toLowerCase();
4
- if (f === "input" || f === "textarea" || t.isContentEditable) {
5
- const a = t.type;
6
- if (["button", "submit", "checkbox", "radio", "range", "color"].includes(a)) {
7
- if (e.pointer)
1
+ import { normalizeAll as X, definePlugin as N, css as x, math as M, createActor as H, Layers as U, injectStyles as tt, damp as j, effects as et, lerpAngle as nt, setTransform as I, createCircle as _, normalize as st, circlePath as ot, circumference as rt, createSVGElement as G, path as it, text as at, textPath as lt } from "@supermousejs/utils";
2
+ function ct(t, n, u) {
3
+ const a = t.tagName.toLowerCase(), r = t.isContentEditable || t.closest(
4
+ '[contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]'
5
+ ) !== null;
6
+ if (a === "input" || a === "textarea" || r) {
7
+ const g = t.type;
8
+ if (["button", "submit", "checkbox", "radio", "range", "color"].includes(g)) {
9
+ if (n.pointer)
8
10
  return "pointer";
9
- } else if (e.text) return "text";
10
- } else if ((f === "a" || f === "button" || t.closest("a") || t.closest("button")) && e.pointer)
11
+ } else if (n.text) return "text";
12
+ } else if ((a === "a" || a === "button" || t.closest("a") || t.closest("button")) && n.pointer)
11
13
  return "pointer";
12
- if (e.text && ["p", "span", "h1", "h2", "h3", "h4", "h5", "h6", "li", "blockquote", "code", "pre"].includes(
13
- f
14
- ))
15
- return "text";
16
- if (e.text || e.grab) {
17
- const a = window.getComputedStyle(t).cursor;
18
- if (e.text && a === "text") return "text";
19
- if (e.grab && a === "grab") return "grab";
20
- }
21
- return null;
14
+ return n.text && t.closest("p, span, h1, h2, h3, h4, h5, h6, li, blockquote, code, pre") || n.text && u === "text" ? "text" : n.grab && u === "grab" ? "grab" : null;
22
15
  }
23
16
  const xt = (t) => {
24
- let e, f = t.defaultState ?? "default", a = null, i, g = "idle", c = 0, C = f, u = null, n = 0, o = 0, z = 0;
17
+ let n, u = t.defaultState ?? "default", a = null, r, g = "idle", c = 0, C = u, f = null, s = 0, i = 0, z = 0;
25
18
  const d = X(t, {
26
19
  size: 24,
27
20
  color: "",
28
21
  followStrategy: "smooth",
29
22
  anchor: "center",
30
23
  rotateWithVelocity: !1
31
- }), p = t.useSemanticTags ?? !0, m = t.transitionDuration ?? 200, r = t.switchDelay ?? 80, h = t.offset?.[0] ?? 0, y = t.offset?.[1] ?? 0, A = t.defaultState ?? "default", b = m / 2;
32
- function v(s) {
33
- x(e, { transform: `scale(${s})` });
24
+ }), p = t.useSemanticDetection ?? !0, m = t.transitionDuration ?? 200, e = t.switchDelay ?? 80, h = t.offset?.[0] ?? 0, y = t.offset?.[1] ?? 0, w = t.defaultState ?? "default", b = m / 2;
25
+ function v(o) {
26
+ x(n, { transform: `scale(${o})` });
34
27
  }
35
- function S(s) {
36
- f = s, e.innerHTML = t.icons[s] ?? "";
28
+ function S(o) {
29
+ u = o, n.innerHTML = t.icons[o] ?? "";
37
30
  }
38
31
  let l;
39
32
  return N(
40
33
  {
41
34
  name: t.name ?? "smart-icon",
42
- selector: "[data-supermouse-icon]",
43
- create: (s) => {
44
- const w = j("div");
45
- return x(w, { zIndex: U.CURSOR }), p && s.registerHoverTarget("p, span, h1, h2, h3, h4, h5, h6, li, blockquote, code, pre"), e = j("div"), x(e, {
35
+ hoverSelector: "[data-supermouse-icon]",
36
+ create: (o) => {
37
+ const A = H("div");
38
+ return x(A, { zIndex: U.CURSOR }), n = H("div"), x(n, {
46
39
  width: "100%",
47
40
  height: "100%",
48
41
  display: "flex",
@@ -51,7 +44,7 @@ const xt = (t) => {
51
44
  transformOrigin: "center center",
52
45
  transform: "scale(1)",
53
46
  transition: `transform ${b}ms cubic-bezier(0.16, 1, 0.3, 1)`
54
- }), e.innerHTML = t.icons[f] ?? "", tt(
47
+ }), n.innerHTML = t.icons[u] ?? "", tt(
55
48
  "supermouse-smart-icon-styles",
56
49
  `
57
50
  @keyframes sm {
@@ -62,27 +55,27 @@ const xt = (t) => {
62
55
  animation: sm 1s linear infinite;
63
56
  }
64
57
  `
65
- ), l = s.state.cursorMode, s.setCursor("custom"), w.appendChild(e), w;
58
+ ), l = o.state.cursorMode, o.setCursor("custom"), A.appendChild(n), A;
66
59
  },
67
- update: (s, w, $) => {
68
- const T = performance.now(), F = $ / 1e3, O = t.icons, k = s.state.hoverTarget, H = !!k, I = H && k !== a;
69
- let R = A;
70
- if (H) {
71
- I && (a = k, i = p ? ct(k, O) : null);
72
- const L = s.state.interaction?.icon;
73
- L && O[L] ? R = L : i && (R = i);
60
+ update: (o, A, $) => {
61
+ const R = performance.now(), F = $ / 1e3, D = t.icons, E = o.state.pointerTarget, V = !!E, O = V && E !== a;
62
+ let T = w;
63
+ if (V) {
64
+ O && (a = E, r = p ? ct(E, D, o.state.authoredCursor) : null);
65
+ const k = o.state.interaction?.icon;
66
+ k && D[k] ? T = k : r && (T = r);
74
67
  } else
75
- a && (a = null, i = null);
76
- R !== f && g === "idle" ? !!O[R] || R === A ? I ? (S(R), v(1), u = null, n = 0) : R !== u ? (u = R, n = 0) : (n += $, n >= r && (C = R, g = "out", c = T, v(0), u = null, n = 0)) : (u = null, n = 0) : R === f && (u = null, n = 0), g === "out" && T - c >= b && (S(C), g = "in", c = T, v(0)), g === "in" && T - c >= b && (g = "idle", v(1));
77
- const E = d.size(s.state), J = d.color(s.state);
78
- x(w, {
79
- width: `${E}px`,
80
- height: `${E}px`,
68
+ a && (a = null, r = null);
69
+ T !== u && g === "idle" ? !!D[T] || T === w ? O ? (S(T), v(1), f = null, s = 0) : T !== f ? (f = T, s = 0) : (s += $, s >= e && (C = T, g = "out", c = R, v(0), f = null, s = 0)) : (f = null, s = 0) : T === u && (f = null, s = 0), g === "out" && R - c >= b && (S(C), g = "in", c = R, v(0)), g === "in" && R - c >= b && (g = "idle", v(1));
70
+ const L = d.size(o.state), J = d.color(o.state);
71
+ x(A, {
72
+ width: `${L}px`,
73
+ height: `${L}px`,
81
74
  color: J || "inherit"
82
75
  });
83
76
  let P = 0, W = 0;
84
- const Y = E / 2;
85
- switch (d.anchor(s.state)) {
77
+ const Y = L / 2;
78
+ switch (d.anchor(o.state)) {
86
79
  case "center":
87
80
  P = -Y, W = -Y;
88
81
  break;
@@ -90,123 +83,123 @@ const xt = (t) => {
90
83
  P = 0, W = 0;
91
84
  break;
92
85
  case "top-right":
93
- P = -E, W = 0;
86
+ P = -L, W = 0;
94
87
  break;
95
88
  case "bottom-left":
96
- P = 0, W = -E;
89
+ P = 0, W = -L;
97
90
  break;
98
91
  case "bottom-right":
99
- P = -E, W = -E;
92
+ P = -L, W = -L;
100
93
  break;
101
94
  }
102
- const K = f === "pointer" || f === "text";
103
- if (d.rotateWithVelocity(s.state) && !K && !s.state.reducedMotion) {
104
- const { x: L, y: B } = s.state.velocity;
105
- M.dist(L, B) > 1 && (z = M.angle(L, B));
95
+ const K = u === "pointer" || u === "text";
96
+ if (d.rotateWithVelocity(o.state) && !K && !o.state.reducedMotion) {
97
+ const { x: k, y: B } = o.state.velocity;
98
+ M.dist(k, B) > 1 && (z = M.angle(k, B));
106
99
  const Z = 1 - Math.exp(-20 * F);
107
- o = M.lerpAngle(o, z, Z);
100
+ i = M.lerpAngle(i, z, Z);
108
101
  } else {
109
- const L = 1 - Math.exp(-20 * F);
110
- o = M.lerpAngle(o, 0, L);
102
+ const k = 1 - Math.exp(-20 * F);
103
+ i = M.lerpAngle(i, 0, k);
111
104
  }
112
- const q = d.followStrategy(s.state) === "raw" ? s.state.pointer : s.state.smooth, Q = `translate3d(${q.x + h + P}px, ${q.y + y + W}px, 0) rotate(${o}deg)`;
113
- w.style.transform = Q;
105
+ const q = d.followStrategy(o.state) === "raw" ? o.state.pointer : o.state.smooth, Q = `translate3d(${q.x + h + P}px, ${q.y + y + W}px, 0) rotate(${i}deg)`;
106
+ A.style.transform = Q;
114
107
  },
115
- cleanup(s) {
116
- s.setCursor(l);
108
+ cleanup(o) {
109
+ o.setCursor(l);
117
110
  }
118
111
  },
119
112
  t
120
113
  );
121
114
  }, gt = (t = {}) => {
122
- const e = X(t, {
115
+ const n = X(t, {
123
116
  size: 20,
124
117
  hoverSize: 40,
125
118
  color: "#ffffff",
126
119
  fill: "transparent",
127
120
  borderWidth: 2
128
121
  });
129
- let f = 20, a = 20, i = 0, g = 1, c = 1;
122
+ let u = 20, a = 20, r = 0, g = 1, c = 1;
130
123
  const C = 150;
131
- let u = null;
124
+ let f = null;
132
125
  return N(
133
126
  {
134
127
  name: t.name ?? "smart-ring",
135
- selector: "[data-supermouse-color]",
136
- create: (n) => {
137
- const o = _(e.size(n.state), e.fill(n.state));
138
- return x(o, {
128
+ hoverSelector: "[data-supermouse-color]",
129
+ create: (s) => {
130
+ const i = _(n.size(s.state), n.fill(s.state));
131
+ return x(i, {
139
132
  zIndex: U.FOLLOWER,
140
133
  mixBlendMode: t.mixBlendMode ?? "difference",
141
134
  transition: "border-radius 0.2s ease",
142
135
  borderStyle: "solid",
143
136
  opacity: "0"
144
- }), o;
137
+ }), i;
145
138
  },
146
- onEnable(n, o) {
147
- const z = e.size(n.state);
148
- f = z * 0.5, a = z * 0.5, i = 0, g = 1, c = 1, clearTimeout(u ?? void 0), o.style.display = "block", o.style.opacity = "1", o.style.transition = "border-radius 0.2s ease";
139
+ onEnable(s, i) {
140
+ const z = n.size(s.state);
141
+ u = z * 0.5, a = z * 0.5, r = 0, g = 1, c = 1, clearTimeout(f ?? void 0), i.style.display = "block", i.style.opacity = "1", i.style.transition = "border-radius 0.2s ease";
149
142
  },
150
- beforeDisable(n, o) {
151
- const { x: z, y: d } = n.state.smooth;
152
- return o.style.transition = `opacity ${C}ms ease, transform ${C}ms ease`, o.style.opacity = "0", D(o, z, d, 0, 0.2, 0.2), new Promise((p) => {
153
- u = setTimeout(() => {
154
- o.style.transition = "border-radius 0.2s ease", p();
143
+ beforeDisable(s, i) {
144
+ const { x: z, y: d } = s.state.smooth;
145
+ return i.style.transition = `opacity ${C}ms ease, transform ${C}ms ease`, i.style.opacity = "0", I(i, z, d, 0, 0.2, 0.2), new Promise((p) => {
146
+ f = setTimeout(() => {
147
+ i.style.transition = "border-radius 0.2s ease", p();
155
148
  }, C);
156
149
  });
157
150
  },
158
- update: (n, o, z) => {
159
- if (o.style.display === "none") return;
160
- const d = z / 1e3, p = e.size(n.state), m = n.state.shape;
161
- let r = p, h = p, y = "50%", A = e.color(n.state);
162
- m ? (r = m.width, h = m.height, y = `${m.borderRadius}px`) : (n.state.isHover && (r = e.hoverSize(n.state), h = e.hoverSize(n.state)), n.state.isDown && (r *= 0.9, h *= 0.9)), n.state.interaction.color && (A = n.state.interaction.color), f = V(f, r, 20, d), a = V(a, h, 20, d), x(o, {
163
- width: `${f}px`,
151
+ update: (s, i, z) => {
152
+ if (i.style.display === "none") return;
153
+ const d = z / 1e3, p = n.size(s.state), m = s.state.shape;
154
+ let e = p, h = p, y = "50%", w = n.color(s.state);
155
+ m ? (e = m.width, h = m.height, y = `${m.borderRadius}px`) : (s.state.isHover && (e = n.hoverSize(s.state), h = n.hoverSize(s.state)), s.state.isDown && (e *= 0.9, h *= 0.9)), s.state.interaction.color && (w = s.state.interaction.color), u = j(u, e, 20, d), a = j(a, h, 20, d), x(i, {
156
+ width: `${u}px`,
164
157
  height: `${a}px`,
165
158
  borderRadius: y,
166
- borderColor: A,
167
- backgroundColor: e.fill(n.state),
168
- borderWidth: `${e.borderWidth(n.state)}px`,
159
+ borderColor: w,
160
+ backgroundColor: n.fill(s.state),
161
+ borderWidth: `${n.borderWidth(s.state)}px`,
169
162
  opacity: "1"
170
163
  });
171
164
  let b = 0, v = 1, S = 1;
172
- if (!m && t.enableSkew && !n.state.reducedMotion) {
173
- const { displacement: w } = n.state, $ = et.getVelocityDistortion(w.x, w.y);
165
+ if (!m && t.enableSkew && !s.state.reducedMotion) {
166
+ const { displacement: A } = s.state, $ = et.getVelocityDistortion(A.x, A.y);
174
167
  b = $.rotation, v = $.scaleX, S = $.scaleY;
175
- const T = 1 - Math.exp(-20 * d);
176
- i = rt(i, b, T);
168
+ const R = 1 - Math.exp(-20 * d);
169
+ r = nt(r, b, R);
177
170
  } else
178
- i = 0;
179
- g = V(g, v, 20, d), c = V(c, S, 20, d);
180
- const { x: l, y: s } = n.state.smooth;
181
- D(o, l, s, i, g, c);
171
+ r = 0;
172
+ g = j(g, v, 20, d), c = j(c, S, 20, d);
173
+ const { x: l, y: o } = s.state.smooth;
174
+ I(i, l, o, r, g, c);
182
175
  }
183
176
  },
184
177
  t
185
178
  );
186
179
  }, yt = (t = {}) => {
187
- const e = t.count ?? 30, f = t.decay ?? 2.5, a = t.frequency ?? 10, i = t.scatter ?? 5, g = nt(t.color, "#ff00ff"), c = [];
188
- let C = 0, u = 0, n = !1, o = 0;
180
+ const n = t.count ?? 30, u = t.decay ?? 2.5, a = t.frequency ?? 10, r = t.scatter ?? 5, g = st(t.color, "#ff00ff"), c = [];
181
+ let C = 0, f = 0, s = !1, i = 0;
189
182
  const z = (d, p, m) => {
190
- const r = c.find((b) => !b.isActive);
191
- if (!r) return;
192
- r.isActive = !0, r.life = 1, r.x = d + M.random(-i, i), r.y = p + M.random(-i, i);
183
+ const e = c.find((b) => !b.isActive);
184
+ if (!e) return;
185
+ e.isActive = !0, e.life = 1, e.x = d + M.random(-r, r), e.y = p + M.random(-r, r);
193
186
  const h = M.random(0, Math.PI * 2), y = M.random(0.5, 1.5);
194
- r.vx = Math.cos(h) * y, r.vy = Math.sin(h) * y, r.scale = M.random(0.5, 1.2), r.color = m;
195
- const A = M.random(2, 5);
196
- x(r.el, {
197
- width: `${A}px`,
198
- height: `${A}px`,
187
+ e.vx = Math.cos(h) * y, e.vy = Math.sin(h) * y, e.scale = M.random(0.5, 1.2), e.color = m;
188
+ const w = M.random(2, 5);
189
+ x(e.el, {
190
+ width: `${w}px`,
191
+ height: `${w}px`,
199
192
  backgroundColor: m,
200
193
  opacity: "1"
201
- }), D(r.el, r.x, r.y, 0, r.scale, r.scale);
194
+ }), I(e.el, e.x, e.y, 0, e.scale, e.scale);
202
195
  };
203
196
  return N(
204
197
  {
205
198
  name: t.name ?? "sparkles",
206
199
  create: () => {
207
- const d = j("div");
200
+ const d = H("div");
208
201
  x(d, { zIndex: U.TRACE });
209
- for (let p = 0; p < e; p++) {
202
+ for (let p = 0; p < n; p++) {
210
203
  const m = _(0, "transparent");
211
204
  x(m, {
212
205
  opacity: "0",
@@ -226,26 +219,26 @@ const xt = (t) => {
226
219
  return d;
227
220
  },
228
221
  update: (d, p, m) => {
229
- const r = m / 1e3, { x: h, y } = d.state.pointer;
230
- n || (C = h, u = y, n = !0);
231
- const A = h - C, b = y - u, v = Math.hypot(A, b);
232
- if (o += v, o > a) {
233
- const S = g(d.state), l = Math.floor(o / a);
234
- for (let s = 0; s < l; s++) {
235
- const w = s / l;
236
- z(C + A * w, u + b * w, S);
222
+ const e = m / 1e3, { x: h, y } = d.state.pointer;
223
+ s || (C = h, f = y, s = !0);
224
+ const w = h - C, b = y - f, v = Math.hypot(w, b);
225
+ if (i += v, i > a) {
226
+ const S = g(d.state), l = Math.floor(i / a);
227
+ for (let o = 0; o < l; o++) {
228
+ const A = o / l;
229
+ z(C + w * A, f + b * A, S);
237
230
  }
238
- o = o % a;
231
+ i = i % a;
239
232
  }
240
- C = h, u = y;
241
- for (let S = 0; S < e; S++) {
233
+ C = h, f = y;
234
+ for (let S = 0; S < n; S++) {
242
235
  const l = c[S];
243
236
  if (l.isActive)
244
- if (l.x += l.vx * r * 60, l.y += l.vy * r * 60, l.life -= f * r, l.life <= 0)
237
+ if (l.x += l.vx * e * 60, l.y += l.vy * e * 60, l.life -= u * e, l.life <= 0)
245
238
  l.isActive = !1, x(l.el, { opacity: "0" });
246
239
  else {
247
- const s = l.scale * l.life;
248
- x(l.el, { opacity: String(l.life) }), D(l.el, l.x, l.y, 0, s, s);
240
+ const o = l.scale * l.life;
241
+ x(l.el, { opacity: String(l.life) }), I(l.el, l.x, l.y, 0, o, o);
249
242
  }
250
243
  }
251
244
  },
@@ -256,27 +249,27 @@ const xt = (t) => {
256
249
  t
257
250
  );
258
251
  };
259
- function dt(t, e) {
260
- return e ? t + " " : t;
252
+ function dt(t, n) {
253
+ return n ? t + " " : t;
261
254
  }
262
255
  let ft = 0;
263
- const pt = (t = {}) => {
264
- let e, f, a, i, g, c;
265
- const C = `supermouse-text-ring-path-${ft++}`, u = X(t, {
256
+ const St = (t = {}) => {
257
+ let n, u, a, r, g, c;
258
+ const C = `supermouse-text-ring-path-${ft++}`, f = X(t, {
266
259
  text: "SUPERMOUSE • SUPERMOUSE • ",
267
260
  radius: 60,
268
261
  fontSize: 12,
269
262
  speed: 30,
270
263
  opacity: 1,
271
264
  color: "currentColor"
272
- }), n = t.className ?? "", o = t.spread ?? !0;
265
+ }), s = t.className ?? "", i = t.spread ?? !0;
273
266
  let z = 0, d = "", p = 0, m = 0;
274
267
  return N(
275
268
  {
276
269
  name: t.name ?? "text-ring",
277
- selector: "[data-supermouse-text-ring]",
278
- create: (r) => {
279
- const h = j("div");
270
+ hoverSelector: "[data-supermouse-text-ring]",
271
+ create: (e) => {
272
+ const h = H("div");
280
273
  x(h, {
281
274
  zIndex: U.FOLLOWER,
282
275
  transition: "opacity 0.2s ease",
@@ -287,53 +280,53 @@ const pt = (t = {}) => {
287
280
  display: "flex",
288
281
  alignItems: "center",
289
282
  justifyContent: "center"
290
- }), n && h.classList.add(...n.split(" ").filter(Boolean)), e = G("svg"), x(e, {
283
+ }), s && h.classList.add(...s.split(" ").filter(Boolean)), n = G("svg"), x(n, {
291
284
  overflow: "visible",
292
285
  position: "absolute",
293
286
  left: "0",
294
287
  top: "0"
295
- }), f = it(void 0, { id: C, fill: "none" });
296
- const y = u.fontSize(r.state);
297
- return m = y, i = at({ "font-size": `${y}px`, fill: "currentColor" }), x(i, {
288
+ }), u = it(void 0, { id: C, fill: "none" });
289
+ const y = f.fontSize(e.state);
290
+ return m = y, r = at({ "font-size": `${y}px`, fill: "currentColor" }), x(r, {
298
291
  textTransform: "uppercase",
299
292
  letterSpacing: "2px"
300
- }), a = lt(`#${C}`, { startOffset: "0%" }), g = document.createTextNode(""), a.appendChild(g), i.appendChild(a), e.appendChild(f), e.appendChild(i), c = G("text"), x(c, {
293
+ }), a = lt(`#${C}`, { startOffset: "0%" }), g = document.createTextNode(""), a.appendChild(g), r.appendChild(a), n.appendChild(u), n.appendChild(r), c = G("text"), x(c, {
301
294
  visibility: "hidden",
302
295
  position: "absolute",
303
296
  pointerEvents: "none",
304
297
  whiteSpace: "nowrap"
305
- }), c.setAttribute("font-size", `${y}px`), c.setAttribute("font-family", getComputedStyle(i).fontFamily || "sans-serif"), c.setAttribute("font-weight", getComputedStyle(i).fontWeight || "normal"), c.setAttribute("font-style", getComputedStyle(i).fontStyle || "normal"), e.appendChild(c), h.appendChild(e), h;
298
+ }), c.setAttribute("font-size", `${y}px`), c.setAttribute("font-family", getComputedStyle(r).fontFamily || "sans-serif"), c.setAttribute("font-weight", getComputedStyle(r).fontWeight || "normal"), c.setAttribute("font-style", getComputedStyle(r).fontStyle || "normal"), n.appendChild(c), h.appendChild(n), h;
306
299
  },
307
- update: (r, h, y) => {
308
- const A = y / 1e3;
309
- let b = u.text(r.state);
310
- const v = u.radius(r.state), S = u.fontSize(r.state), l = u.speed(r.state), s = u.opacity(r.state), w = u.color(r.state);
311
- x(h, { color: w, opacity: String(s) });
312
- const $ = r.state.interaction;
300
+ update: (e, h, y) => {
301
+ const w = y / 1e3;
302
+ let b = f.text(e.state);
303
+ const v = f.radius(e.state), S = f.fontSize(e.state), l = f.speed(e.state), o = f.opacity(e.state), A = f.color(e.state);
304
+ x(h, { color: A, opacity: String(o) });
305
+ const $ = e.state.interaction;
313
306
  if ($.textRing && typeof $.textRing == "string" ? b = $.textRing : $.text && typeof $.text == "string" && (b = $.text), v !== p) {
314
- f.setAttribute("d", st(v));
315
- const k = v * 2;
316
- x(e, {
317
- width: `${k}px`,
318
- height: `${k}px`
307
+ u.setAttribute("d", ot(v));
308
+ const E = v * 2;
309
+ x(n, {
310
+ width: `${E}px`,
311
+ height: `${E}px`
319
312
  }), p = v;
320
313
  }
321
- const T = dt(b, o);
322
- if (S !== m && (i.setAttribute("font-size", `${S}px`), c.setAttribute("font-size", `${S}px`), m = S), T !== d && (g.textContent = T, d = T), o) {
323
- const k = ot(v);
324
- c.textContent = T;
325
- const H = c.getComputedTextLength(), I = T.length;
326
- if (I > 1) {
327
- const E = (k - H) / (I - 1);
328
- x(i, { letterSpacing: `${E}px` });
314
+ const R = dt(b, i);
315
+ if (S !== m && (r.setAttribute("font-size", `${S}px`), c.setAttribute("font-size", `${S}px`), m = S), R !== d && (g.textContent = R, d = R), i) {
316
+ const E = rt(v);
317
+ c.textContent = R;
318
+ const V = c.getComputedTextLength(), O = R.length;
319
+ if (O > 1) {
320
+ const L = (E - V) / (O - 1);
321
+ x(r, { letterSpacing: `${L}px` });
329
322
  } else
330
- x(i, { letterSpacing: "0px" });
331
- i.removeAttribute("textLength"), a.removeAttribute("textLength"), a.removeAttribute("lengthAdjust");
323
+ x(r, { letterSpacing: "0px" });
324
+ r.removeAttribute("textLength"), a.removeAttribute("textLength"), a.removeAttribute("lengthAdjust");
332
325
  } else
333
- x(i, { letterSpacing: "2px" }), i.removeAttribute("textLength"), a.removeAttribute("textLength"), a.removeAttribute("lengthAdjust");
334
- z += l * A;
335
- const { x: F, y: O } = r.state.smooth;
336
- D(h, F, O, z);
326
+ x(r, { letterSpacing: "2px" }), r.removeAttribute("textLength"), a.removeAttribute("textLength"), a.removeAttribute("lengthAdjust");
327
+ z += l * w;
328
+ const { x: F, y: D } = e.state.smooth;
329
+ I(h, F, D, z);
337
330
  }
338
331
  },
339
332
  t
@@ -343,5 +336,5 @@ export {
343
336
  xt as SmartIcon,
344
337
  gt as SmartRing,
345
338
  yt as Sparkles,
346
- pt as TextRing
339
+ St as TextRing
347
340
  };
package/dist/index.umd.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(L,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("@supermousejs/utils")):typeof define=="function"&&define.amd?define(["exports","@supermousejs/utils"],e):(L=typeof globalThis<"u"?globalThis:L||self,e(L.SupermouseLabs={},L.SupermouseUtils))})(this,(function(L,e){"use strict";function U(t,r){const m=t.tagName.toLowerCase();if(m==="input"||m==="textarea"||t.isContentEditable){const i=t.type;if(["button","submit","checkbox","radio","range","color"].includes(i)){if(r.pointer)return"pointer"}else if(r.text)return"text"}else if((m==="a"||m==="button"||t.closest("a")||t.closest("button"))&&r.pointer)return"pointer";if(r.text&&["p","span","h1","h2","h3","h4","h5","h6","li","blockquote","code","pre"].includes(m))return"text";if(r.text||r.grab){const i=window.getComputedStyle(t).cursor;if(r.text&&i==="text")return"text";if(r.grab&&i==="grab")return"grab"}return null}const q=t=>{let r,m=t.defaultState??"default",i=null,c,x="idle",d=0,C=m,h=null,o=0,a=0,z=0;const f=e.normalizeAll(t,{size:24,color:"",followStrategy:"smooth",anchor:"center",rotateWithVelocity:!1}),p=t.useSemanticTags??!0,g=t.transitionDuration??200,n=t.switchDelay??80,u=t.offset?.[0]??0,y=t.offset?.[1]??0,T=t.defaultState??"default",b=g/2;function v(s){e.css(r,{transform:`scale(${s})`})}function S(s){m=s,r.innerHTML=t.icons[s]??""}let l;return e.definePlugin({name:t.name??"smart-icon",selector:"[data-supermouse-icon]",create:s=>{const A=e.createActor("div");return e.css(A,{zIndex:e.Layers.CURSOR}),p&&s.registerHoverTarget("p, span, h1, h2, h3, h4, h5, h6, li, blockquote, code, pre"),r=e.createActor("div"),e.css(r,{width:"100%",height:"100%",display:"flex",alignItems:"center",justifyContent:"center",transformOrigin:"center center",transform:"scale(1)",transition:`transform ${b}ms cubic-bezier(0.16, 1, 0.3, 1)`}),r.innerHTML=t.icons[m]??"",e.injectStyles("supermouse-smart-icon-styles",`
1
+ (function(L,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("@supermousejs/utils")):typeof define=="function"&&define.amd?define(["exports","@supermousejs/utils"],e):(L=typeof globalThis<"u"?globalThis:L||self,e(L.SupermouseLabs={},L.SupermouseUtils))})(this,(function(L,e){"use strict";function H(t,r,h){const i=t.tagName.toLowerCase(),a=t.isContentEditable||t.closest('[contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]')!==null;if(i==="input"||i==="textarea"||a){const g=t.type;if(["button","submit","checkbox","radio","range","color"].includes(g)){if(r.pointer)return"pointer"}else if(r.text)return"text"}else if((i==="a"||i==="button"||t.closest("a")||t.closest("button"))&&r.pointer)return"pointer";return r.text&&t.closest("p, span, h1, h2, h3, h4, h5, h6, li, blockquote, code, pre")||r.text&&h==="text"?"text":r.grab&&h==="grab"?"grab":null}const N=t=>{let r,h=t.defaultState??"default",i=null,a,g="idle",d=0,C=h,m=null,o=0,c=0,z=0;const f=e.normalizeAll(t,{size:24,color:"",followStrategy:"smooth",anchor:"center",rotateWithVelocity:!1}),S=t.useSemanticDetection??!0,x=t.transitionDuration??200,n=t.switchDelay??80,u=t.offset?.[0]??0,y=t.offset?.[1]??0,T=t.defaultState??"default",b=x/2;function v(s){e.css(r,{transform:`scale(${s})`})}function p(s){h=s,r.innerHTML=t.icons[s]??""}let l;return e.definePlugin({name:t.name??"smart-icon",hoverSelector:"[data-supermouse-icon]",create:s=>{const A=e.createActor("div");return e.css(A,{zIndex:e.Layers.CURSOR}),r=e.createActor("div"),e.css(r,{width:"100%",height:"100%",display:"flex",alignItems:"center",justifyContent:"center",transformOrigin:"center center",transform:"scale(1)",transition:`transform ${b}ms cubic-bezier(0.16, 1, 0.3, 1)`}),r.innerHTML=t.icons[h]??"",e.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
- `),l=s.state.cursorMode,s.setCursor("custom"),A.appendChild(r),A},update:(s,A,w)=>{const $=performance.now(),j=w/1e3,W=t.icons,M=s.state.hoverTarget,D=!!M,I=D&&M!==i;let R=T;if(D){I&&(i=M,c=p?U(M,W):null);const E=s.state.interaction?.icon;E&&W[E]?R=E:c&&(R=c)}else i&&(i=null,c=null);R!==m&&x==="idle"?!!W[R]||R===T?I?(S(R),v(1),h=null,o=0):R!==h?(h=R,o=0):(o+=w,o>=n&&(C=R,x="out",d=$,v(0),h=null,o=0)):(h=null,o=0):R===m&&(h=null,o=0),x==="out"&&$-d>=b&&(S(C),x="in",d=$,v(0)),x==="in"&&$-d>=b&&(x="idle",v(1));const k=f.size(s.state),_=f.color(s.state);e.css(A,{width:`${k}px`,height:`${k}px`,color:_||"inherit"});let P=0,O=0;const F=k/2;switch(f.anchor(s.state)){case"center":P=-F,O=-F;break;case"top-left":P=0,O=0;break;case"top-right":P=-k,O=0;break;case"bottom-left":P=0,O=-k;break;case"bottom-right":P=-k,O=-k;break}const J=m==="pointer"||m==="text";if(f.rotateWithVelocity(s.state)&&!J&&!s.state.reducedMotion){const{x:E,y:H}=s.state.velocity;e.math.dist(E,H)>1&&(z=e.math.angle(E,H));const Q=1-Math.exp(-20*j);a=e.math.lerpAngle(a,z,Q)}else{const E=1-Math.exp(-20*j);a=e.math.lerpAngle(a,0,E)}const V=f.followStrategy(s.state)==="raw"?s.state.pointer:s.state.smooth,K=`translate3d(${V.x+u+P}px, ${V.y+y+O}px, 0) rotate(${a}deg)`;A.style.transform=K},cleanup(s){s.setCursor(l)}},t)},N=(t={})=>{const r=e.normalizeAll(t,{size:20,hoverSize:40,color:"#ffffff",fill:"transparent",borderWidth:2});let m=20,i=20,c=0,x=1,d=1;const C=150;let h=null;return e.definePlugin({name:t.name??"smart-ring",selector:"[data-supermouse-color]",create:o=>{const a=e.createCircle(r.size(o.state),r.fill(o.state));return e.css(a,{zIndex:e.Layers.FOLLOWER,mixBlendMode:t.mixBlendMode??"difference",transition:"border-radius 0.2s ease",borderStyle:"solid",opacity:"0"}),a},onEnable(o,a){const z=r.size(o.state);m=z*.5,i=z*.5,c=0,x=1,d=1,clearTimeout(h??void 0),a.style.display="block",a.style.opacity="1",a.style.transition="border-radius 0.2s ease"},beforeDisable(o,a){const{x:z,y:f}=o.state.smooth;return a.style.transition=`opacity ${C}ms ease, transform ${C}ms ease`,a.style.opacity="0",e.setTransform(a,z,f,0,.2,.2),new Promise(p=>{h=setTimeout(()=>{a.style.transition="border-radius 0.2s ease",p()},C)})},update:(o,a,z)=>{if(a.style.display==="none")return;const f=z/1e3,p=r.size(o.state),g=o.state.shape;let n=p,u=p,y="50%",T=r.color(o.state);g?(n=g.width,u=g.height,y=`${g.borderRadius}px`):(o.state.isHover&&(n=r.hoverSize(o.state),u=r.hoverSize(o.state)),o.state.isDown&&(n*=.9,u*=.9)),o.state.interaction.color&&(T=o.state.interaction.color),m=e.damp(m,n,20,f),i=e.damp(i,u,20,f),e.css(a,{width:`${m}px`,height:`${i}px`,borderRadius:y,borderColor:T,backgroundColor:r.fill(o.state),borderWidth:`${r.borderWidth(o.state)}px`,opacity:"1"});let b=0,v=1,S=1;if(!g&&t.enableSkew&&!o.state.reducedMotion){const{displacement:A}=o.state,w=e.effects.getVelocityDistortion(A.x,A.y);b=w.rotation,v=w.scaleX,S=w.scaleY;const $=1-Math.exp(-20*f);c=e.lerpAngle(c,b,$)}else c=0;x=e.damp(x,v,20,f),d=e.damp(d,S,20,f);const{x:l,y:s}=o.state.smooth;e.setTransform(a,l,s,c,x,d)}},t)},X=(t={})=>{const r=t.count??30,m=t.decay??2.5,i=t.frequency??10,c=t.scatter??5,x=e.normalize(t.color,"#ff00ff"),d=[];let C=0,h=0,o=!1,a=0;const z=(f,p,g)=>{const n=d.find(b=>!b.isActive);if(!n)return;n.isActive=!0,n.life=1,n.x=f+e.math.random(-c,c),n.y=p+e.math.random(-c,c);const u=e.math.random(0,Math.PI*2),y=e.math.random(.5,1.5);n.vx=Math.cos(u)*y,n.vy=Math.sin(u)*y,n.scale=e.math.random(.5,1.2),n.color=g;const T=e.math.random(2,5);e.css(n.el,{width:`${T}px`,height:`${T}px`,backgroundColor:g,opacity:"1"}),e.setTransform(n.el,n.x,n.y,0,n.scale,n.scale)};return e.definePlugin({name:t.name??"sparkles",create:()=>{const f=e.createActor("div");e.css(f,{zIndex:e.Layers.TRACE});for(let p=0;p<r;p++){const g=e.createCircle(0,"transparent");e.css(g,{opacity:"0",willChange:"transform, opacity"}),f.appendChild(g),d.push({el:g,isActive:!1,x:0,y:0,vx:0,vy:0,life:0,scale:1,color:""})}return f},update:(f,p,g)=>{const n=g/1e3,{x:u,y}=f.state.pointer;o||(C=u,h=y,o=!0);const T=u-C,b=y-h,v=Math.hypot(T,b);if(a+=v,a>i){const S=x(f.state),l=Math.floor(a/i);for(let s=0;s<l;s++){const A=s/l;z(C+T*A,h+b*A,S)}a=a%i}C=u,h=y;for(let S=0;S<r;S++){const l=d[S];if(l.isActive)if(l.x+=l.vx*n*60,l.y+=l.vy*n*60,l.life-=m*n,l.life<=0)l.isActive=!1,e.css(l.el,{opacity:"0"});else{const s=l.scale*l.life;e.css(l.el,{opacity:String(l.life)}),e.setTransform(l.el,l.x,l.y,0,s,s)}}},destroy:()=>{d.length=0}},t)};function Y(t,r){return r?t+" ":t}let B=0;const G=(t={})=>{let r,m,i,c,x,d;const C=`supermouse-text-ring-path-${B++}`,h=e.normalizeAll(t,{text:"SUPERMOUSE • SUPERMOUSE • ",radius:60,fontSize:12,speed:30,opacity:1,color:"currentColor"}),o=t.className??"",a=t.spread??!0;let z=0,f="",p=0,g=0;return e.definePlugin({name:t.name??"text-ring",selector:"[data-supermouse-text-ring]",create:n=>{const u=e.createActor("div");e.css(u,{zIndex:e.Layers.FOLLOWER,transition:"opacity 0.2s ease",opacity:"1",width:"0px",height:"0px",overflow:"visible",display:"flex",alignItems:"center",justifyContent:"center"}),o&&u.classList.add(...o.split(" ").filter(Boolean)),r=e.createSVGElement("svg"),e.css(r,{overflow:"visible",position:"absolute",left:"0",top:"0"}),m=e.path(void 0,{id:C,fill:"none"});const y=h.fontSize(n.state);return g=y,c=e.text({"font-size":`${y}px`,fill:"currentColor"}),e.css(c,{textTransform:"uppercase",letterSpacing:"2px"}),i=e.textPath(`#${C}`,{startOffset:"0%"}),x=document.createTextNode(""),i.appendChild(x),c.appendChild(i),r.appendChild(m),r.appendChild(c),d=e.createSVGElement("text"),e.css(d,{visibility:"hidden",position:"absolute",pointerEvents:"none",whiteSpace:"nowrap"}),d.setAttribute("font-size",`${y}px`),d.setAttribute("font-family",getComputedStyle(c).fontFamily||"sans-serif"),d.setAttribute("font-weight",getComputedStyle(c).fontWeight||"normal"),d.setAttribute("font-style",getComputedStyle(c).fontStyle||"normal"),r.appendChild(d),u.appendChild(r),u},update:(n,u,y)=>{const T=y/1e3;let b=h.text(n.state);const v=h.radius(n.state),S=h.fontSize(n.state),l=h.speed(n.state),s=h.opacity(n.state),A=h.color(n.state);e.css(u,{color:A,opacity:String(s)});const w=n.state.interaction;if(w.textRing&&typeof w.textRing=="string"?b=w.textRing:w.text&&typeof w.text=="string"&&(b=w.text),v!==p){m.setAttribute("d",e.circlePath(v));const M=v*2;e.css(r,{width:`${M}px`,height:`${M}px`}),p=v}const $=Y(b,a);if(S!==g&&(c.setAttribute("font-size",`${S}px`),d.setAttribute("font-size",`${S}px`),g=S),$!==f&&(x.textContent=$,f=$),a){const M=e.circumference(v);d.textContent=$;const D=d.getComputedTextLength(),I=$.length;if(I>1){const k=(M-D)/(I-1);e.css(c,{letterSpacing:`${k}px`})}else e.css(c,{letterSpacing:"0px"});c.removeAttribute("textLength"),i.removeAttribute("textLength"),i.removeAttribute("lengthAdjust")}else e.css(c,{letterSpacing:"2px"}),c.removeAttribute("textLength"),i.removeAttribute("textLength"),i.removeAttribute("lengthAdjust");z+=l*T;const{x:j,y:W}=n.state.smooth;e.setTransform(u,j,W,z)}},t)};L.SmartIcon=q,L.SmartRing=N,L.Sparkles=X,L.TextRing=G,Object.defineProperty(L,Symbol.toStringTag,{value:"Module"})}));
9
+ `),l=s.state.cursorMode,s.setCursor("custom"),A.appendChild(r),A},update:(s,A,w)=>{const $=performance.now(),I=w/1e3,W=t.icons,M=s.state.pointerTarget,j=!!M,D=j&&M!==i;let R=T;if(j){D&&(i=M,a=S?H(M,W,s.state.authoredCursor):null);const P=s.state.interaction?.icon;P&&W[P]?R=P:a&&(R=a)}else i&&(i=null,a=null);R!==h&&g==="idle"?!!W[R]||R===T?D?(p(R),v(1),m=null,o=0):R!==m?(m=R,o=0):(o+=w,o>=n&&(C=R,g="out",d=$,v(0),m=null,o=0)):(m=null,o=0):R===h&&(m=null,o=0),g==="out"&&$-d>=b&&(p(C),g="in",d=$,v(0)),g==="in"&&$-d>=b&&(g="idle",v(1));const E=f.size(s.state),_=f.color(s.state);e.css(A,{width:`${E}px`,height:`${E}px`,color:_||"inherit"});let k=0,O=0;const F=E/2;switch(f.anchor(s.state)){case"center":k=-F,O=-F;break;case"top-left":k=0,O=0;break;case"top-right":k=-E,O=0;break;case"bottom-left":k=0,O=-E;break;case"bottom-right":k=-E,O=-E;break}const J=h==="pointer"||h==="text";if(f.rotateWithVelocity(s.state)&&!J&&!s.state.reducedMotion){const{x:P,y:U}=s.state.velocity;e.math.dist(P,U)>1&&(z=e.math.angle(P,U));const Q=1-Math.exp(-20*I);c=e.math.lerpAngle(c,z,Q)}else{const P=1-Math.exp(-20*I);c=e.math.lerpAngle(c,0,P)}const V=f.followStrategy(s.state)==="raw"?s.state.pointer:s.state.smooth,K=`translate3d(${V.x+u+k}px, ${V.y+y+O}px, 0) rotate(${c}deg)`;A.style.transform=K},cleanup(s){s.setCursor(l)}},t)},X=(t={})=>{const r=e.normalizeAll(t,{size:20,hoverSize:40,color:"#ffffff",fill:"transparent",borderWidth:2});let h=20,i=20,a=0,g=1,d=1;const C=150;let m=null;return e.definePlugin({name:t.name??"smart-ring",hoverSelector:"[data-supermouse-color]",create:o=>{const c=e.createCircle(r.size(o.state),r.fill(o.state));return e.css(c,{zIndex:e.Layers.FOLLOWER,mixBlendMode:t.mixBlendMode??"difference",transition:"border-radius 0.2s ease",borderStyle:"solid",opacity:"0"}),c},onEnable(o,c){const z=r.size(o.state);h=z*.5,i=z*.5,a=0,g=1,d=1,clearTimeout(m??void 0),c.style.display="block",c.style.opacity="1",c.style.transition="border-radius 0.2s ease"},beforeDisable(o,c){const{x:z,y:f}=o.state.smooth;return c.style.transition=`opacity ${C}ms ease, transform ${C}ms ease`,c.style.opacity="0",e.setTransform(c,z,f,0,.2,.2),new Promise(S=>{m=setTimeout(()=>{c.style.transition="border-radius 0.2s ease",S()},C)})},update:(o,c,z)=>{if(c.style.display==="none")return;const f=z/1e3,S=r.size(o.state),x=o.state.shape;let n=S,u=S,y="50%",T=r.color(o.state);x?(n=x.width,u=x.height,y=`${x.borderRadius}px`):(o.state.isHover&&(n=r.hoverSize(o.state),u=r.hoverSize(o.state)),o.state.isDown&&(n*=.9,u*=.9)),o.state.interaction.color&&(T=o.state.interaction.color),h=e.damp(h,n,20,f),i=e.damp(i,u,20,f),e.css(c,{width:`${h}px`,height:`${i}px`,borderRadius:y,borderColor:T,backgroundColor:r.fill(o.state),borderWidth:`${r.borderWidth(o.state)}px`,opacity:"1"});let b=0,v=1,p=1;if(!x&&t.enableSkew&&!o.state.reducedMotion){const{displacement:A}=o.state,w=e.effects.getVelocityDistortion(A.x,A.y);b=w.rotation,v=w.scaleX,p=w.scaleY;const $=1-Math.exp(-20*f);a=e.lerpAngle(a,b,$)}else a=0;g=e.damp(g,v,20,f),d=e.damp(d,p,20,f);const{x:l,y:s}=o.state.smooth;e.setTransform(c,l,s,a,g,d)}},t)},Y=(t={})=>{const r=t.count??30,h=t.decay??2.5,i=t.frequency??10,a=t.scatter??5,g=e.normalize(t.color,"#ff00ff"),d=[];let C=0,m=0,o=!1,c=0;const z=(f,S,x)=>{const n=d.find(b=>!b.isActive);if(!n)return;n.isActive=!0,n.life=1,n.x=f+e.math.random(-a,a),n.y=S+e.math.random(-a,a);const u=e.math.random(0,Math.PI*2),y=e.math.random(.5,1.5);n.vx=Math.cos(u)*y,n.vy=Math.sin(u)*y,n.scale=e.math.random(.5,1.2),n.color=x;const T=e.math.random(2,5);e.css(n.el,{width:`${T}px`,height:`${T}px`,backgroundColor:x,opacity:"1"}),e.setTransform(n.el,n.x,n.y,0,n.scale,n.scale)};return e.definePlugin({name:t.name??"sparkles",create:()=>{const f=e.createActor("div");e.css(f,{zIndex:e.Layers.TRACE});for(let S=0;S<r;S++){const x=e.createCircle(0,"transparent");e.css(x,{opacity:"0",willChange:"transform, opacity"}),f.appendChild(x),d.push({el:x,isActive:!1,x:0,y:0,vx:0,vy:0,life:0,scale:1,color:""})}return f},update:(f,S,x)=>{const n=x/1e3,{x:u,y}=f.state.pointer;o||(C=u,m=y,o=!0);const T=u-C,b=y-m,v=Math.hypot(T,b);if(c+=v,c>i){const p=g(f.state),l=Math.floor(c/i);for(let s=0;s<l;s++){const A=s/l;z(C+T*A,m+b*A,p)}c=c%i}C=u,m=y;for(let p=0;p<r;p++){const l=d[p];if(l.isActive)if(l.x+=l.vx*n*60,l.y+=l.vy*n*60,l.life-=h*n,l.life<=0)l.isActive=!1,e.css(l.el,{opacity:"0"});else{const s=l.scale*l.life;e.css(l.el,{opacity:String(l.life)}),e.setTransform(l.el,l.x,l.y,0,s,s)}}},destroy:()=>{d.length=0}},t)};function q(t,r){return r?t+" ":t}let B=0;const G=(t={})=>{let r,h,i,a,g,d;const C=`supermouse-text-ring-path-${B++}`,m=e.normalizeAll(t,{text:"SUPERMOUSE • SUPERMOUSE • ",radius:60,fontSize:12,speed:30,opacity:1,color:"currentColor"}),o=t.className??"",c=t.spread??!0;let z=0,f="",S=0,x=0;return e.definePlugin({name:t.name??"text-ring",hoverSelector:"[data-supermouse-text-ring]",create:n=>{const u=e.createActor("div");e.css(u,{zIndex:e.Layers.FOLLOWER,transition:"opacity 0.2s ease",opacity:"1",width:"0px",height:"0px",overflow:"visible",display:"flex",alignItems:"center",justifyContent:"center"}),o&&u.classList.add(...o.split(" ").filter(Boolean)),r=e.createSVGElement("svg"),e.css(r,{overflow:"visible",position:"absolute",left:"0",top:"0"}),h=e.path(void 0,{id:C,fill:"none"});const y=m.fontSize(n.state);return x=y,a=e.text({"font-size":`${y}px`,fill:"currentColor"}),e.css(a,{textTransform:"uppercase",letterSpacing:"2px"}),i=e.textPath(`#${C}`,{startOffset:"0%"}),g=document.createTextNode(""),i.appendChild(g),a.appendChild(i),r.appendChild(h),r.appendChild(a),d=e.createSVGElement("text"),e.css(d,{visibility:"hidden",position:"absolute",pointerEvents:"none",whiteSpace:"nowrap"}),d.setAttribute("font-size",`${y}px`),d.setAttribute("font-family",getComputedStyle(a).fontFamily||"sans-serif"),d.setAttribute("font-weight",getComputedStyle(a).fontWeight||"normal"),d.setAttribute("font-style",getComputedStyle(a).fontStyle||"normal"),r.appendChild(d),u.appendChild(r),u},update:(n,u,y)=>{const T=y/1e3;let b=m.text(n.state);const v=m.radius(n.state),p=m.fontSize(n.state),l=m.speed(n.state),s=m.opacity(n.state),A=m.color(n.state);e.css(u,{color:A,opacity:String(s)});const w=n.state.interaction;if(w.textRing&&typeof w.textRing=="string"?b=w.textRing:w.text&&typeof w.text=="string"&&(b=w.text),v!==S){h.setAttribute("d",e.circlePath(v));const M=v*2;e.css(r,{width:`${M}px`,height:`${M}px`}),S=v}const $=q(b,c);if(p!==x&&(a.setAttribute("font-size",`${p}px`),d.setAttribute("font-size",`${p}px`),x=p),$!==f&&(g.textContent=$,f=$),c){const M=e.circumference(v);d.textContent=$;const j=d.getComputedTextLength(),D=$.length;if(D>1){const E=(M-j)/(D-1);e.css(a,{letterSpacing:`${E}px`})}else e.css(a,{letterSpacing:"0px"});a.removeAttribute("textLength"),i.removeAttribute("textLength"),i.removeAttribute("lengthAdjust")}else e.css(a,{letterSpacing:"2px"}),a.removeAttribute("textLength"),i.removeAttribute("textLength"),i.removeAttribute("lengthAdjust");z+=l*T;const{x:I,y:W}=n.state.smooth;e.setTransform(u,I,W,z)}},t)};L.SmartIcon=N,L.SmartRing=X,L.Sparkles=Y,L.TextRing=G,Object.defineProperty(L,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supermousejs/labs",
3
- "version": "2.4.4-beta.3",
3
+ "version": "2.4.4-beta.5",
4
4
  "main": "dist/index.umd.js",
5
5
  "module": "dist/index.mjs",
6
6
  "description": "Experimentental state machines and effects for supermouse",
@@ -14,13 +14,13 @@
14
14
  "url": "https://github.com/Whitestar14/supermouse-js",
15
15
  "license": "MIT",
16
16
  "dependencies": {
17
- "@supermousejs/utils": "2.4.4-beta.3"
17
+ "@supermousejs/utils": "2.4.4-beta.5"
18
18
  },
19
19
  "peerDependencies": {
20
- "@supermousejs/core": "2.5.0-beta.3"
20
+ "@supermousejs/core": "2.5.0-beta.5"
21
21
  },
22
22
  "devDependencies": {
23
- "@supermousejs/core": "2.5.0-beta.3"
23
+ "@supermousejs/core": "2.5.0-beta.5"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
@@ -42,6 +42,8 @@
42
42
  "access": "public"
43
43
  },
44
44
  "scripts": {
45
- "build": "vite build"
45
+ "build": "vite build",
46
+ "test": "vitest",
47
+ "test:watch": "vitest --watch"
46
48
  }
47
49
  }