@supermousejs/core 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,78 +1,13 @@
1
- let d = 0;
2
- class c {
3
- constructor(t = document.body, e) {
4
- if (this.container = t, this.hideNativeCursor = e, !t || !(t instanceof HTMLElement))
5
- throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);
6
- const i = d++;
7
- this.id = `supermouse-style-${i}`, this.scopeClass = `supermouse-scope-${i}`;
8
- const n = t === document.body;
9
- this.element = document.createElement("div"), Object.assign(this.element.style, {
10
- position: n ? "fixed" : "absolute",
11
- top: "0",
12
- left: "0",
13
- width: "100%",
14
- height: "100%",
15
- pointerEvents: "none",
16
- zIndex: "9999",
17
- opacity: "1",
18
- transition: "opacity 0.15s ease"
19
- }), n || window.getComputedStyle(t).position === "static" && (t.style.position = "relative"), t.appendChild(this.element), this.styleTag = document.createElement("style"), this.styleTag.id = this.id, document.head.appendChild(this.styleTag), this.container.classList.add(this.scopeClass), this.hideNativeCursor && this.setNativeCursor("none");
20
- }
21
- container;
22
- hideNativeCursor;
23
- /** The container element appended to the document. */
24
- element;
25
- styleTag;
26
- id;
27
- scopeClass;
28
- currentCursorState = null;
29
- selectors = /* @__PURE__ */ new Set([
30
- "a",
31
- "button",
32
- "input",
33
- "textarea",
34
- "select",
35
- '[role="button"]',
36
- "[tabindex]"
37
- ]);
38
- /**
39
- * Adds a new CSS selector to the Hide Native Cursor list.
40
- * Called by `Supermouse` (and subsequently plugins) during install to ensure
41
- * the native cursor is hidden on their specific interactive targets.
42
- */
43
- addSelector(t) {
44
- this.selectors.add(t), this.hideNativeCursor && this.updateCursorCSS();
45
- }
46
- setVisibility(t) {
47
- this.element.style.opacity = t ? "1" : "0";
48
- }
49
- /**
50
- * Toggles the visibility of the native cursor via CSS injection.
51
- * @param type 'none' to hide, 'auto' to show.
52
- */
53
- setNativeCursor(t) {
54
- !this.hideNativeCursor && t === "none" || t !== this.currentCursorState && (this.currentCursorState = t, t === "none" ? (this.container.style.cursor = "none", this.updateCursorCSS()) : (this.container.style.cursor = "", this.styleTag.innerText = ""));
55
- }
56
- updateCursorCSS() {
57
- const t = Array.from(this.selectors);
58
- if (t.length === 0) {
59
- this.styleTag.innerText = "";
60
- return;
61
- }
62
- const e = t.map((i) => `.${this.scopeClass} ${i}`).join(", ");
63
- this.styleTag.innerText = `
64
- ${e} {
65
- cursor: none !important;
66
- }
67
- `;
68
- }
69
- destroy() {
70
- this.element.remove(), this.styleTag.remove(), this.container.style.cursor = "", this.container.classList.remove(this.scopeClass);
71
- }
1
+ const d = "2.3.0";
2
+ function p(n, t, e) {
3
+ return n + (t - n) * e;
4
+ }
5
+ function c(n, t, e, i) {
6
+ return p(n, t, 1 - Math.exp(-e * i));
72
7
  }
73
- class p {
74
- constructor(t, e, i, n) {
75
- this.state = t, this.options = e, this.getHoverSelector = i, this.onEnableChange = n, this.checkDeviceCapability(), this.checkMotionPreference(), this.bindEvents();
8
+ class f {
9
+ constructor(t, e, i, a) {
10
+ this.state = t, this.options = e, this.getHoverSelector = i, this.onEnableChange = a, this.dataPrefix = this.options.dataPrefix ?? "supermouse", this.normalizedDataPrefix = this.dataPrefix.toLowerCase(), this.ignoreAttribute = `data-${this.dataPrefix}-ignore`, this.checkDeviceCapability(), this.checkMotionPreference(), this.bindEvents();
76
11
  }
77
12
  state;
78
13
  options;
@@ -81,58 +16,67 @@ class p {
81
16
  mediaQueryList;
82
17
  mediaQueryHandler;
83
18
  motionQuery;
19
+ dataPrefix;
20
+ normalizedDataPrefix;
21
+ ignoreAttribute;
84
22
  /**
85
23
  * Master switch for input processing.
86
24
  * Toggled by `Supermouse.enable()`/`disable()` or automatically by device capability checks.
87
25
  */
88
26
  isEnabled = !0;
27
+ abortController = new AbortController();
89
28
  /**
90
29
  * Automatically disables the custom cursor on devices without fine pointer control.
91
- * Relies on `matchMedia('(pointer: fine)')`.
92
30
  */
93
31
  checkDeviceCapability() {
94
32
  this.options.autoDisableOnMobile && (this.mediaQueryList = window.matchMedia("(pointer: fine)"), this.updateEnabledState(this.mediaQueryList.matches), this.mediaQueryHandler = (t) => {
95
33
  this.updateEnabledState(t.matches);
96
- }, this.mediaQueryList.addEventListener("change", this.mediaQueryHandler));
34
+ }, this.mediaQueryList.addEventListener("change", this.mediaQueryHandler, {
35
+ signal: this.abortController.signal
36
+ }));
97
37
  }
98
38
  /**
99
39
  * Checks for `prefers-reduced-motion`.
100
40
  * If true, the core physics engine will switch to instant snapping (high damping) to avoid motion sickness.
101
41
  */
102
42
  checkMotionPreference() {
103
- this.motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)"), this.state.reducedMotion = this.motionQuery.matches, this.motionQuery.addEventListener("change", (t) => {
104
- this.state.reducedMotion = t.matches;
105
- });
43
+ this.motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)"), this.state.reducedMotion = this.motionQuery.matches, this.motionQuery.addEventListener(
44
+ "change",
45
+ (t) => {
46
+ this.state.reducedMotion = t.matches;
47
+ },
48
+ { signal: this.abortController.signal }
49
+ );
106
50
  }
107
51
  updateEnabledState(t) {
108
52
  this.isEnabled = t, this.onEnableChange(t);
109
53
  }
110
54
  parseDOMInteraction(t) {
111
55
  if (this.options.resolveInteraction) {
112
- this.state.interaction = this.options.resolveInteraction(t);
56
+ this.state.interaction = this.options.resolveInteraction(t) || {};
113
57
  return;
114
58
  }
115
59
  const e = {};
116
60
  if (this.options.rules)
117
- for (const [n, s] of Object.entries(this.options.rules))
118
- t.matches(n) && Object.assign(e, s);
119
- const i = t.dataset;
120
- for (const n in i)
121
- if (n.startsWith("supermouse")) {
122
- const s = n.slice(10);
123
- if (s) {
124
- const r = s.charAt(0).toLowerCase() + s.slice(1), a = i[n];
125
- a !== void 0 && (e[r] = a === "" ? !0 : a);
126
- }
127
- }
61
+ for (const [s, o] of Object.entries(this.options.rules))
62
+ t.matches(s) && Object.assign(e, o);
63
+ const i = this.normalizedDataPrefix, a = this.dataPrefix.length;
64
+ for (const s in t.dataset) {
65
+ if (!s.toLowerCase().startsWith(i)) continue;
66
+ const o = s.slice(a);
67
+ if (!o) continue;
68
+ const r = t.dataset[s];
69
+ e[o[0].toLowerCase() + o.slice(1)] = r === "" ? !0 : r;
70
+ }
128
71
  this.state.interaction = e;
129
72
  }
130
73
  handleMove(t) {
131
- if (!this.isEnabled || this.options.autoDisableOnMobile && t.pointerType === "touch") return;
74
+ if (!this.isEnabled || this.options.autoDisableOnMobile && t.pointerType === "touch" && !this.options.enableTouch)
75
+ return;
132
76
  let e = t.clientX, i = t.clientY;
133
77
  if (this.options.container && this.options.container !== document.body) {
134
- const n = this.options.container.getBoundingClientRect();
135
- e -= n.left, i -= n.top;
78
+ const a = this.options.container.getBoundingClientRect();
79
+ e -= a.left, i -= a.top;
136
80
  }
137
81
  this.state.pointer.x = e, this.state.pointer.y = i, this.state.hasReceivedInput || (this.state.hasReceivedInput = !0, this.state.target.x = this.state.smooth.x = e, this.state.target.y = this.state.smooth.y = i);
138
82
  }
@@ -145,25 +89,25 @@ class p {
145
89
  handleMouseOver(t) {
146
90
  if (!this.isEnabled) return;
147
91
  const e = t.target;
148
- if (e.closest("[data-supermouse-ignore]")) {
92
+ if (e.closest(`[${this.ignoreAttribute}]`)) {
149
93
  this.state.isNative = !0;
150
94
  return;
151
95
  }
152
- const i = this.getHoverSelector(), n = e.closest(i);
153
- n && (this.state.isHover = !0, this.state.hoverTarget = n, this.parseDOMInteraction(this.state.hoverTarget));
96
+ const i = this.getHoverSelector(), a = e.closest(i);
97
+ a && (this.state.isHover = !0, this.state.hoverTarget = a, this.parseDOMInteraction(this.state.hoverTarget));
154
98
  const s = this.options.ignoreOnNative;
155
- if (s) {
156
- const r = s === !0 || s === "auto" || s === "tag", a = s === !0 || s === "auto" || s === "css";
157
- let h = !1;
158
- if (r) {
159
- const l = e.localName;
160
- (l === "input" || l === "textarea" || l === "select" || e.isContentEditable) && (h = !0);
99
+ if (s && s !== null) {
100
+ const o = s === "auto" || s === "tag", r = s === "auto" || s === "css";
101
+ let u = !1;
102
+ if (o) {
103
+ const h = e.localName;
104
+ (h === "input" || h === "textarea" || h === "select" || e.isContentEditable) && (u = !0);
161
105
  }
162
- if (!h && a) {
163
- const l = window.getComputedStyle(e).cursor;
164
- ["default", "auto", "pointer", "none", "inherit"].includes(l) || (h = !0);
106
+ if (!u && r) {
107
+ const h = window.getComputedStyle(e).cursor;
108
+ ["default", "auto", "pointer", "none", "inherit"].includes(h) || (u = !0);
165
109
  }
166
- h && (this.state.isNative = !0);
110
+ u && (this.state.isNative = !0);
167
111
  }
168
112
  }
169
113
  handleMouseOut(t) {
@@ -172,28 +116,95 @@ class p {
172
116
  (e === this.state.hoverTarget || e.contains(this.state.hoverTarget)) && (!t.relatedTarget || !this.state.hoverTarget?.contains(t.relatedTarget)) && (this.state.isHover = !1, this.state.hoverTarget = null, this.state.interaction = {}), this.state.isNative && (this.state.isNative = !1);
173
117
  }
174
118
  handleWindowLeave() {
175
- this.options.hideOnLeave && (this.state.hasReceivedInput = !1);
119
+ this.options.hideOnLeave && (this.state.hasReceivedInput = !1, this.state.pointer = { ...l });
176
120
  }
177
121
  clearHover() {
178
- this.state.isHover = !1, this.state.hoverTarget = null, this.state.isNative = !1;
122
+ this.state.isHover = !1, this.state.hoverTarget = null, this.state.isNative = !1, this.state.interaction = {};
179
123
  }
180
124
  bindEvents() {
181
- window.addEventListener("pointermove", this.handleMove.bind(this), { passive: !0 }), window.addEventListener("pointerdown", this.handleDown.bind(this), { passive: !0 }), window.addEventListener("pointerup", this.handleUp.bind(this)), document.addEventListener("mouseover", this.handleMouseOver.bind(this)), document.addEventListener("mouseout", this.handleMouseOut.bind(this)), document.addEventListener("mouseleave", this.handleWindowLeave.bind(this));
125
+ const { signal: t } = this.abortController;
126
+ window.addEventListener("pointermove", this.handleMove.bind(this), { passive: !0, signal: t }), window.addEventListener("pointerdown", this.handleDown.bind(this), { passive: !0, signal: t }), window.addEventListener("pointerup", this.handleUp.bind(this), { signal: t }), document.addEventListener("mouseover", this.handleMouseOver.bind(this), { signal: t }), document.addEventListener("mouseout", this.handleMouseOut.bind(this), { signal: t }), document.addEventListener("mouseleave", this.handleWindowLeave.bind(this), { signal: t });
182
127
  }
183
128
  destroy() {
184
- this.mediaQueryList && this.mediaQueryHandler && this.mediaQueryList.removeEventListener("change", this.mediaQueryHandler), this.motionQuery && (this.motionQuery.onchange = null), window.removeEventListener("pointermove", this.handleMove), window.removeEventListener("pointerdown", this.handleDown), window.removeEventListener("pointerup", this.handleUp), document.removeEventListener("mouseover", this.handleMouseOver), document.removeEventListener("mouseout", this.handleMouseOut), document.removeEventListener("mouseleave", this.handleWindowLeave);
129
+ this.abortController.abort();
185
130
  }
186
131
  }
187
- function v(o, t, e) {
188
- return o + (t - o) * e;
189
- }
190
- function u(o, t, e, i) {
191
- return v(o, t, 1 - Math.exp(-e * i));
192
- }
193
- function f(o, t) {
194
- return Math.atan2(t, o) * (180 / Math.PI);
132
+ let g = 0;
133
+ class v {
134
+ constructor(t = document.body, e) {
135
+ if (this.container = t, this.hideNativeCursor = e, !t || !(t instanceof HTMLElement))
136
+ throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);
137
+ const i = g++;
138
+ this.id = `supermouse-style-${i}`, this.scopeClass = `supermouse-scope-${i}`;
139
+ const a = t === document.body;
140
+ if (this.element = document.createElement("div"), Object.assign(this.element.style, {
141
+ position: a ? "fixed" : "absolute",
142
+ inset: "0px",
143
+ pointerEvents: "none",
144
+ zIndex: "9999",
145
+ opacity: "1",
146
+ transition: "opacity 0.15s ease"
147
+ }), !a) {
148
+ const s = window.getComputedStyle(t);
149
+ this.originalContainerPosition = s.position, s.position === "static" && (t.style.position = "relative");
150
+ }
151
+ this.originalContainerCursor = t.style.cursor, t.appendChild(this.element), this.styleTag = document.createElement("style"), this.styleTag.id = this.id, document.head.appendChild(this.styleTag), this.container.classList.add(this.scopeClass), this.hideNativeCursor && this.setNativeCursor("none");
152
+ }
153
+ container;
154
+ hideNativeCursor;
155
+ /** The container element appended to the document. */
156
+ element;
157
+ styleTag;
158
+ id;
159
+ scopeClass;
160
+ currentCursorState = null;
161
+ originalContainerPosition = "";
162
+ originalContainerCursor = "";
163
+ selectors = /* @__PURE__ */ new Set([
164
+ "a",
165
+ "button",
166
+ "input",
167
+ "textarea",
168
+ "select",
169
+ '[role="button"]',
170
+ "[tabindex]"
171
+ ]);
172
+ /**
173
+ * Adds a new CSS selector to the `selectors` set.
174
+ * Called by `Supermouse` and subsequently plugins during install to ensure
175
+ * the native cursor is hidden on their specific interactive targets.
176
+ */
177
+ addSelector(t) {
178
+ this.selectors.add(t), this.hideNativeCursor && this.updateCursorCSS();
179
+ }
180
+ setVisibility(t) {
181
+ this.element.style.opacity = t ? "1" : "0";
182
+ }
183
+ /**
184
+ * Toggles the visibility of the native cursor via CSS injection.
185
+ * @param type 'none' to hide, 'auto' to show.
186
+ */
187
+ setNativeCursor(t) {
188
+ !this.hideNativeCursor && t === "none" || t !== this.currentCursorState && (this.currentCursorState = t, t === "none" ? (this.container.style.cursor = "none", this.updateCursorCSS()) : (this.container.style.cursor = "", this.styleTag.innerText = ""));
189
+ }
190
+ updateCursorCSS() {
191
+ const t = Array.from(this.selectors);
192
+ if (t.length === 0) {
193
+ this.styleTag.innerText = "";
194
+ return;
195
+ }
196
+ const e = t.map((i) => `.${this.scopeClass} ${i}`).join(", ");
197
+ this.styleTag.innerText = `
198
+ ${e} {
199
+ cursor: none !important;
200
+ }
201
+ `;
202
+ }
203
+ destroy() {
204
+ this.element.remove(), this.styleTag.remove(), this.container.style.cursor = this.originalContainerCursor, this.container.classList.remove(this.scopeClass), this.container !== document.body && this.originalContainerPosition === "static" && (this.container.style.position = "");
205
+ }
195
206
  }
196
- const g = [
207
+ const l = { x: -100, y: -100 }, m = [
197
208
  "a",
198
209
  "button",
199
210
  "input",
@@ -202,8 +213,8 @@ const g = [
202
213
  "[data-cursor]"
203
214
  ];
204
215
  class y {
205
- static version = "2.1.0";
206
- version = "2.1.0";
216
+ static version = d;
217
+ version = d;
207
218
  state;
208
219
  /**
209
220
  * Configuration options.
@@ -232,8 +243,9 @@ class y {
232
243
  hideOnLeave: !0,
233
244
  autoStart: !0,
234
245
  container: document.body,
246
+ dataPrefix: "supermouse",
235
247
  ...t
236
- }, this.options.container || (this.options.container = document.body), this.state = {
248
+ }, this.state = {
237
249
  pointer: { x: -100, y: -100 },
238
250
  target: { x: -100, y: -100 },
239
251
  smooth: { x: -100, y: -100 },
@@ -248,12 +260,12 @@ class y {
248
260
  hasReceivedInput: !1,
249
261
  shape: null,
250
262
  interaction: {}
251
- }, this.options.hoverSelectors ? this.hoverSelectors = new Set(this.options.hoverSelectors) : this.hoverSelectors = new Set(g), this.stage = new c(this.options.container, !!this.options.hideCursor), this.hoverSelectors.forEach((e) => this.stage.addSelector(e)), this.input = new p(
263
+ }, this.options.hoverSelectors ? this.hoverSelectors = new Set(this.options.hoverSelectors) : this.hoverSelectors = new Set(m), this.stage = new v(this.options.container, !!this.options.hideCursor), this.hoverSelectors.forEach((e) => this.stage.addSelector(e)), this.input = new f(
252
264
  this.state,
253
265
  this.options,
254
266
  () => Array.from(this.hoverSelectors).join(", "),
255
267
  (e) => {
256
- e || this.resetPosition();
268
+ e || this.reset(!0);
257
269
  }
258
270
  ), this.options.plugins && this.options.plugins.forEach((e) => this.use(e)), this.init();
259
271
  }
@@ -302,12 +314,12 @@ class y {
302
314
  return this.stage.element;
303
315
  }
304
316
  /**
305
- * Manually override the native cursor visibility.
317
+ * Sets the native cursor visibility.
306
318
  *
307
- * @param type 'auto' (Show Native), 'none' (Hide Native), or null (Resume Auto-detection)
319
+ * @param mode
308
320
  */
309
- setCursor(t) {
310
- this.state.forcedCursor = t;
321
+ setNativeCursor(t) {
322
+ this.state.forcedCursor = t === "auto" ? null : t === "hide" ? "none" : "auto";
311
323
  }
312
324
  init() {
313
325
  this.options.autoStart && this.startLoop();
@@ -316,7 +328,7 @@ class y {
316
328
  this.input.isEnabled = !0, this.stage.setNativeCursor("none");
317
329
  }
318
330
  disable() {
319
- this.input.isEnabled = !1, this.stage.setNativeCursor("auto"), this.resetPosition();
331
+ this.input.isEnabled = !1, this.stage.setNativeCursor("auto"), this.reset(!0);
320
332
  }
321
333
  /**
322
334
  * Registers a new plugin.
@@ -324,15 +336,29 @@ class y {
324
336
  * @param plugin - The plugin object to install.
325
337
  */
326
338
  use(t) {
327
- return this.plugins.find((e) => e.name === t.name) ? (console.warn(`[Supermouse] Plugin "${t.name}" already installed.`), this) : (t.isEnabled === void 0 && (t.isEnabled = !0), this.plugins.push(t), this.plugins.sort((e, i) => (e.priority || 0) - (i.priority || 0)), t.install?.(this), this);
339
+ if (this.plugins.some((i) => i.name === t.name))
340
+ return console.warn(`[Supermouse] Plugin "${t.name}" already installed.`), this;
341
+ t.isEnabled === void 0 && (t.isEnabled = !0);
342
+ try {
343
+ t.install?.(this);
344
+ } catch (i) {
345
+ return console.error(`[Supermouse] Failed to install plugin '${t.name}'.`, i), this;
346
+ }
347
+ return this.plugins.push(t), this.plugins.sort((i, a) => (i.priority || 0) - (a.priority || 0)), this;
328
348
  }
329
- resetPosition() {
330
- const t = { x: -100, y: -100 };
331
- this.state.pointer = { ...t }, this.state.target = { ...t }, this.state.smooth = { ...t }, this.state.velocity = { x: 0, y: 0 }, this.state.angle = 0, this.state.hasReceivedInput = !1, this.state.shape = null, this.state.interaction = {};
349
+ reset(t = !1) {
350
+ this.state.pointer = { ...l }, this.state.target = { ...l }, this.state.smooth = { ...l }, this.state.velocity = { x: 0, y: 0 }, this.state.angle = 0, t && (this.state.hasReceivedInput = !1, this.state.shape = null, this.state.interaction = {});
332
351
  }
333
352
  startLoop() {
334
353
  this.isRunning || (this.isRunning = !0, this.lastTime = performance.now(), this.tick(this.lastTime));
335
354
  }
355
+ /**
356
+ * Starts the animation loop. This is automatically called if `autoStart` is true.
357
+ * Plugins can call this method to resume the loop if it has been stopped.
358
+ */
359
+ start() {
360
+ this.startLoop();
361
+ }
336
362
  /**
337
363
  * Manually steps the animation loop.
338
364
  *
@@ -346,10 +372,13 @@ class y {
346
372
  try {
347
373
  t.update?.(this, e);
348
374
  } catch (i) {
349
- console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`, i), t.isEnabled = !1;
375
+ console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`, i);
376
+ const a = this.plugins.indexOf(t);
377
+ a > -1 && this.plugins.splice(a, 1), t.isEnabled = !1;
350
378
  try {
351
- t.onDisable?.(this);
352
- } catch {
379
+ t.destroy?.(this), t.onDisable?.(this);
380
+ } catch (s) {
381
+ console.error(`[Supermouse] Failed to cleanup crashed plugin '${t.name}'.`, s);
353
382
  }
354
383
  }
355
384
  }
@@ -359,25 +388,21 @@ class y {
359
388
  tick = (t) => {
360
389
  const e = t - this.lastTime, i = Math.min(e / 1e3, 0.1);
361
390
  this.lastTime = t, this.state.hoverTarget && !this.state.hoverTarget.isConnected && this.input.clearHover();
362
- const n = this.input.isEnabled && !this.state.isNative && this.state.hasReceivedInput;
363
- if (this.stage.setVisibility(n), this.input.isEnabled && this.options.hideCursor) {
391
+ const a = this.input.isEnabled && !this.state.isNative && this.state.hasReceivedInput;
392
+ if (this.stage.setVisibility(a), this.input.isEnabled && this.options.hideCursor) {
364
393
  let s = "auto";
365
394
  this.state.forcedCursor !== null ? s = this.state.forcedCursor : s = this.state.isNative || !this.state.hasReceivedInput ? "auto" : "none", this.stage.setNativeCursor(s);
366
395
  }
396
+ this.input.isEnabled && this.state.hasReceivedInput ? (this.state.target.x = this.state.pointer.x, this.state.target.y = this.state.pointer.y) : this.state.target = { ...l };
397
+ for (let s = 0; s < this.plugins.length; s++)
398
+ this.runPluginSafe(this.plugins[s], e);
367
399
  if (this.input.isEnabled) {
368
- this.state.target.x = this.state.pointer.x, this.state.target.y = this.state.pointer.y;
369
- for (let h = 0; h < this.plugins.length; h++)
370
- this.runPluginSafe(this.plugins[h], e);
371
400
  const s = this.state.reducedMotion ? 1e3 : 1 / this.options.smoothness * 2;
372
- this.state.smooth.x = u(this.state.smooth.x, this.state.target.x, s, i), this.state.smooth.y = u(this.state.smooth.y, this.state.target.y, s, i);
373
- const r = this.state.target.x - this.state.smooth.x, a = this.state.target.y - this.state.smooth.y;
374
- this.state.velocity.x = r, this.state.velocity.y = a, (Math.abs(r) > 0.1 || Math.abs(a) > 0.1) && (this.state.angle = f(r, a));
375
- } else {
376
- this.state.smooth.x = -100, this.state.smooth.y = -100, this.state.pointer.x = -100, this.state.pointer.y = -100, this.state.velocity.x = 0, this.state.velocity.y = 0;
377
- for (let s = 0; s < this.plugins.length; s++)
378
- this.runPluginSafe(this.plugins[s], e);
401
+ this.state.smooth.x = c(this.state.smooth.x, this.state.target.x, s, i), this.state.smooth.y = c(this.state.smooth.y, this.state.target.y, s, i), this.state.velocity.x = this.state.target.x - this.state.smooth.x, this.state.velocity.y = this.state.target.y - this.state.smooth.y;
402
+ const { x: o, y: r } = this.state.velocity;
403
+ (Math.abs(o) > 0.1 || Math.abs(r) > 0.1) && (this.state.angle = Math.atan2(r, o) * (180 / Math.PI));
379
404
  }
380
- this.options.autoStart && this.isRunning && (this.rafId = requestAnimationFrame(this.tick));
405
+ this.isRunning && (this.rafId = requestAnimationFrame(this.tick));
381
406
  };
382
407
  /**
383
408
  * Destroys the instance.
@@ -387,6 +412,8 @@ class y {
387
412
  }
388
413
  }
389
414
  export {
390
- g as DEFAULT_HOVER_SELECTORS,
415
+ m as DEFAULT_HOVER_SELECTORS,
416
+ f as Input,
417
+ v as Stage,
391
418
  y as Supermouse
392
419
  };
package/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
- (function(l,u){typeof exports=="object"&&typeof module<"u"?u(exports):typeof define=="function"&&define.amd?define(["exports"],u):(l=typeof globalThis<"u"?globalThis:l||self,u(l.SupermouseCore={}))})(this,(function(l){"use strict";let u=0;class f{constructor(t=document.body,e){if(this.container=t,this.hideNativeCursor=e,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);const i=u++;this.id=`supermouse-style-${i}`,this.scopeClass=`supermouse-scope-${i}`;const n=t===document.body;this.element=document.createElement("div"),Object.assign(this.element.style,{position:n?"fixed":"absolute",top:"0",left:"0",width:"100%",height:"100%",pointerEvents:"none",zIndex:"9999",opacity:"1",transition:"opacity 0.15s ease"}),n||window.getComputedStyle(t).position==="static"&&(t.style.position="relative"),t.appendChild(this.element),this.styleTag=document.createElement("style"),this.styleTag.id=this.id,document.head.appendChild(this.styleTag),this.container.classList.add(this.scopeClass),this.hideNativeCursor&&this.setNativeCursor("none")}container;hideNativeCursor;element;styleTag;id;scopeClass;currentCursorState=null;selectors=new Set(["a","button","input","textarea","select",'[role="button"]',"[tabindex]"]);addSelector(t){this.selectors.add(t),this.hideNativeCursor&&this.updateCursorCSS()}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){!this.hideNativeCursor&&t==="none"||t!==this.currentCursorState&&(this.currentCursorState=t,t==="none"?(this.container.style.cursor="none",this.updateCursorCSS()):(this.container.style.cursor="",this.styleTag.innerText=""))}updateCursorCSS(){const t=Array.from(this.selectors);if(t.length===0){this.styleTag.innerText="";return}const e=t.map(i=>`.${this.scopeClass} ${i}`).join(", ");this.styleTag.innerText=`
1
+ (function(a,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(a=typeof globalThis<"u"?globalThis:a||self,l(a.SupermouseCore={}))})(this,(function(a){"use strict";const l="2.3.0";function m(r,t,e){return r+(t-r)*e}function p(r,t,e,i){return m(r,t,1-Math.exp(-e*i))}class f{constructor(t,e,i,n){this.state=t,this.options=e,this.getHoverSelector=i,this.onEnableChange=n,this.dataPrefix=this.options.dataPrefix??"supermouse",this.normalizedDataPrefix=this.dataPrefix.toLowerCase(),this.ignoreAttribute=`data-${this.dataPrefix}-ignore`,this.checkDeviceCapability(),this.checkMotionPreference(),this.bindEvents()}state;options;getHoverSelector;onEnableChange;mediaQueryList;mediaQueryHandler;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;isEnabled=!0;abortController=new AbortController;checkDeviceCapability(){this.options.autoDisableOnMobile&&(this.mediaQueryList=window.matchMedia("(pointer: fine)"),this.updateEnabledState(this.mediaQueryList.matches),this.mediaQueryHandler=t=>{this.updateEnabledState(t.matches)},this.mediaQueryList.addEventListener("change",this.mediaQueryHandler,{signal:this.abortController.signal}))}checkMotionPreference(){this.motionQuery=window.matchMedia("(prefers-reduced-motion: reduce)"),this.state.reducedMotion=this.motionQuery.matches,this.motionQuery.addEventListener("change",t=>{this.state.reducedMotion=t.matches},{signal:this.abortController.signal})}updateEnabledState(t){this.isEnabled=t,this.onEnableChange(t)}parseDOMInteraction(t){if(this.options.resolveInteraction){this.state.interaction=this.options.resolveInteraction(t)||{};return}const e={};if(this.options.rules)for(const[s,o]of Object.entries(this.options.rules))t.matches(s)&&Object.assign(e,o);const i=this.normalizedDataPrefix,n=this.dataPrefix.length;for(const s in t.dataset){if(!s.toLowerCase().startsWith(i))continue;const o=s.slice(n);if(!o)continue;const h=t.dataset[s];e[o[0].toLowerCase()+o.slice(1)]=h===""?!0:h}this.state.interaction=e}handleMove(t){if(!this.isEnabled||this.options.autoDisableOnMobile&&t.pointerType==="touch"&&!this.options.enableTouch)return;let e=t.clientX,i=t.clientY;if(this.options.container&&this.options.container!==document.body){const n=this.options.container.getBoundingClientRect();e-=n.left,i-=n.top}this.state.pointer.x=e,this.state.pointer.y=i,this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=e,this.state.target.y=this.state.smooth.y=i)}handleDown(){this.isEnabled&&(this.state.isDown=!0)}handleUp(){this.isEnabled&&(this.state.isDown=!1)}handleMouseOver(t){if(!this.isEnabled)return;const e=t.target;if(e.closest(`[${this.ignoreAttribute}]`)){this.state.isNative=!0;return}const i=this.getHoverSelector(),n=e.closest(i);n&&(this.state.isHover=!0,this.state.hoverTarget=n,this.parseDOMInteraction(this.state.hoverTarget));const s=this.options.ignoreOnNative;if(s&&s!==null){const o=s==="auto"||s==="tag",h=s==="auto"||s==="css";let c=!1;if(o){const d=e.localName;(d==="input"||d==="textarea"||d==="select"||e.isContentEditable)&&(c=!0)}if(!c&&h){const d=window.getComputedStyle(e).cursor;["default","auto","pointer","none","inherit"].includes(d)||(c=!0)}c&&(this.state.isNative=!0)}}handleMouseOut(t){if(!this.isEnabled)return;const e=t.target;(e===this.state.hoverTarget||e.contains(this.state.hoverTarget))&&(!t.relatedTarget||!this.state.hoverTarget?.contains(t.relatedTarget))&&(this.state.isHover=!1,this.state.hoverTarget=null,this.state.interaction={}),this.state.isNative&&(this.state.isNative=!1)}handleWindowLeave(){this.options.hideOnLeave&&(this.state.hasReceivedInput=!1,this.state.pointer={...u})}clearHover(){this.state.isHover=!1,this.state.hoverTarget=null,this.state.isNative=!1,this.state.interaction={}}bindEvents(){const{signal:t}=this.abortController;window.addEventListener("pointermove",this.handleMove.bind(this),{passive:!0,signal:t}),window.addEventListener("pointerdown",this.handleDown.bind(this),{passive:!0,signal:t}),window.addEventListener("pointerup",this.handleUp.bind(this),{signal:t}),document.addEventListener("mouseover",this.handleMouseOver.bind(this),{signal:t}),document.addEventListener("mouseout",this.handleMouseOut.bind(this),{signal:t}),document.addEventListener("mouseleave",this.handleWindowLeave.bind(this),{signal:t})}destroy(){this.abortController.abort()}}let b=0;class g{constructor(t=document.body,e){if(this.container=t,this.hideNativeCursor=e,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);const i=b++;this.id=`supermouse-style-${i}`,this.scopeClass=`supermouse-scope-${i}`;const n=t===document.body;if(this.element=document.createElement("div"),Object.assign(this.element.style,{position:n?"fixed":"absolute",inset:"0px",pointerEvents:"none",zIndex:"9999",opacity:"1",transition:"opacity 0.15s ease"}),!n){const s=window.getComputedStyle(t);this.originalContainerPosition=s.position,s.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),this.styleTag=document.createElement("style"),this.styleTag.id=this.id,document.head.appendChild(this.styleTag),this.container.classList.add(this.scopeClass),this.hideNativeCursor&&this.setNativeCursor("none")}container;hideNativeCursor;element;styleTag;id;scopeClass;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";selectors=new Set(["a","button","input","textarea","select",'[role="button"]',"[tabindex]"]);addSelector(t){this.selectors.add(t),this.hideNativeCursor&&this.updateCursorCSS()}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){!this.hideNativeCursor&&t==="none"||t!==this.currentCursorState&&(this.currentCursorState=t,t==="none"?(this.container.style.cursor="none",this.updateCursorCSS()):(this.container.style.cursor="",this.styleTag.innerText=""))}updateCursorCSS(){const t=Array.from(this.selectors);if(t.length===0){this.styleTag.innerText="";return}const e=t.map(i=>`.${this.scopeClass} ${i}`).join(", ");this.styleTag.innerText=`
2
2
  ${e} {
3
3
  cursor: none !important;
4
4
  }
5
- `}destroy(){this.element.remove(),this.styleTag.remove(),this.container.style.cursor="",this.container.classList.remove(this.scopeClass)}}class v{constructor(t,e,i,n){this.state=t,this.options=e,this.getHoverSelector=i,this.onEnableChange=n,this.checkDeviceCapability(),this.checkMotionPreference(),this.bindEvents()}state;options;getHoverSelector;onEnableChange;mediaQueryList;mediaQueryHandler;motionQuery;isEnabled=!0;checkDeviceCapability(){this.options.autoDisableOnMobile&&(this.mediaQueryList=window.matchMedia("(pointer: fine)"),this.updateEnabledState(this.mediaQueryList.matches),this.mediaQueryHandler=t=>{this.updateEnabledState(t.matches)},this.mediaQueryList.addEventListener("change",this.mediaQueryHandler))}checkMotionPreference(){this.motionQuery=window.matchMedia("(prefers-reduced-motion: reduce)"),this.state.reducedMotion=this.motionQuery.matches,this.motionQuery.addEventListener("change",t=>{this.state.reducedMotion=t.matches})}updateEnabledState(t){this.isEnabled=t,this.onEnableChange(t)}parseDOMInteraction(t){if(this.options.resolveInteraction){this.state.interaction=this.options.resolveInteraction(t);return}const e={};if(this.options.rules)for(const[n,s]of Object.entries(this.options.rules))t.matches(n)&&Object.assign(e,s);const i=t.dataset;for(const n in i)if(n.startsWith("supermouse")){const s=n.slice(10);if(s){const r=s.charAt(0).toLowerCase()+s.slice(1),a=i[n];a!==void 0&&(e[r]=a===""?!0:a)}}this.state.interaction=e}handleMove(t){if(!this.isEnabled||this.options.autoDisableOnMobile&&t.pointerType==="touch")return;let e=t.clientX,i=t.clientY;if(this.options.container&&this.options.container!==document.body){const n=this.options.container.getBoundingClientRect();e-=n.left,i-=n.top}this.state.pointer.x=e,this.state.pointer.y=i,this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=e,this.state.target.y=this.state.smooth.y=i)}handleDown(){this.isEnabled&&(this.state.isDown=!0)}handleUp(){this.isEnabled&&(this.state.isDown=!1)}handleMouseOver(t){if(!this.isEnabled)return;const e=t.target;if(e.closest("[data-supermouse-ignore]")){this.state.isNative=!0;return}const i=this.getHoverSelector(),n=e.closest(i);n&&(this.state.isHover=!0,this.state.hoverTarget=n,this.parseDOMInteraction(this.state.hoverTarget));const s=this.options.ignoreOnNative;if(s){const r=s===!0||s==="auto"||s==="tag",a=s===!0||s==="auto"||s==="css";let h=!1;if(r){const d=e.localName;(d==="input"||d==="textarea"||d==="select"||e.isContentEditable)&&(h=!0)}if(!h&&a){const d=window.getComputedStyle(e).cursor;["default","auto","pointer","none","inherit"].includes(d)||(h=!0)}h&&(this.state.isNative=!0)}}handleMouseOut(t){if(!this.isEnabled)return;const e=t.target;(e===this.state.hoverTarget||e.contains(this.state.hoverTarget))&&(!t.relatedTarget||!this.state.hoverTarget?.contains(t.relatedTarget))&&(this.state.isHover=!1,this.state.hoverTarget=null,this.state.interaction={}),this.state.isNative&&(this.state.isNative=!1)}handleWindowLeave(){this.options.hideOnLeave&&(this.state.hasReceivedInput=!1)}clearHover(){this.state.isHover=!1,this.state.hoverTarget=null,this.state.isNative=!1}bindEvents(){window.addEventListener("pointermove",this.handleMove.bind(this),{passive:!0}),window.addEventListener("pointerdown",this.handleDown.bind(this),{passive:!0}),window.addEventListener("pointerup",this.handleUp.bind(this)),document.addEventListener("mouseover",this.handleMouseOver.bind(this)),document.addEventListener("mouseout",this.handleMouseOut.bind(this)),document.addEventListener("mouseleave",this.handleWindowLeave.bind(this))}destroy(){this.mediaQueryList&&this.mediaQueryHandler&&this.mediaQueryList.removeEventListener("change",this.mediaQueryHandler),this.motionQuery&&(this.motionQuery.onchange=null),window.removeEventListener("pointermove",this.handleMove),window.removeEventListener("pointerdown",this.handleDown),window.removeEventListener("pointerup",this.handleUp),document.removeEventListener("mouseover",this.handleMouseOver),document.removeEventListener("mouseout",this.handleMouseOut),document.removeEventListener("mouseleave",this.handleWindowLeave)}}function m(o,t,e){return o+(t-o)*e}function c(o,t,e,i){return m(o,t,1-Math.exp(-e*i))}function g(o,t){return Math.atan2(t,o)*(180/Math.PI)}const p=["a","button","input","textarea","[data-hover]","[data-cursor]"];class y{static version="2.1.0";version="2.1.0";state;options;plugins=[];stage;input;rafId=0;lastTime=0;isRunning=!1;hoverSelectors;constructor(t={}){this.options={smoothness:.15,enableTouch:!1,autoDisableOnMobile:!0,ignoreOnNative:"auto",hideCursor:!0,hideOnLeave:!0,autoStart:!0,container:document.body,...t},this.options.container||(this.options.container=document.body),this.state={pointer:{x:-100,y:-100},target:{x:-100,y:-100},smooth:{x:-100,y:-100},velocity:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,forcedCursor:null,hoverTarget:null,reducedMotion:!1,hasReceivedInput:!1,shape:null,interaction:{}},this.options.hoverSelectors?this.hoverSelectors=new Set(this.options.hoverSelectors):this.hoverSelectors=new Set(p),this.stage=new f(this.options.container,!!this.options.hideCursor),this.hoverSelectors.forEach(e=>this.stage.addSelector(e)),this.input=new v(this.state,this.options,()=>Array.from(this.hoverSelectors).join(", "),e=>{e||this.resetPosition()}),this.options.plugins&&this.options.plugins.forEach(e=>this.use(e)),this.init()}getPlugin(t){return this.plugins.find(e=>e.name===t)}get isEnabled(){return this.input.isEnabled}enablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled===!1&&(e.isEnabled=!0,e.onEnable?.(this))}disablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled!==!1&&(e.isEnabled=!1,e.onDisable?.(this))}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}registerHoverTarget(t){this.hoverSelectors.has(t)||(this.hoverSelectors.add(t),this.stage.addSelector(t))}get container(){return this.stage.element}setCursor(t){this.state.forcedCursor=t}init(){this.options.autoStart&&this.startLoop()}enable(){this.input.isEnabled=!0,this.stage.setNativeCursor("none")}disable(){this.input.isEnabled=!1,this.stage.setNativeCursor("auto"),this.resetPosition()}use(t){return this.plugins.find(e=>e.name===t.name)?(console.warn(`[Supermouse] Plugin "${t.name}" already installed.`),this):(t.isEnabled===void 0&&(t.isEnabled=!0),this.plugins.push(t),this.plugins.sort((e,i)=>(e.priority||0)-(i.priority||0)),t.install?.(this),this)}resetPosition(){const t={x:-100,y:-100};this.state.pointer={...t},this.state.target={...t},this.state.smooth={...t},this.state.velocity={x:0,y:0},this.state.angle=0,this.state.hasReceivedInput=!1,this.state.shape=null,this.state.interaction={}}startLoop(){this.isRunning||(this.isRunning=!0,this.lastTime=performance.now(),this.tick(this.lastTime))}step(t){this.tick(t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch(i){console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`,i),t.isEnabled=!1;try{t.onDisable?.(this)}catch{}}}tick=t=>{const e=t-this.lastTime,i=Math.min(e/1e3,.1);this.lastTime=t,this.state.hoverTarget&&!this.state.hoverTarget.isConnected&&this.input.clearHover();const n=this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput;if(this.stage.setVisibility(n),this.input.isEnabled&&this.options.hideCursor){let s="auto";this.state.forcedCursor!==null?s=this.state.forcedCursor:s=this.state.isNative||!this.state.hasReceivedInput?"auto":"none",this.stage.setNativeCursor(s)}if(this.input.isEnabled){this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y;for(let h=0;h<this.plugins.length;h++)this.runPluginSafe(this.plugins[h],e);const s=this.state.reducedMotion?1e3:1/this.options.smoothness*2;this.state.smooth.x=c(this.state.smooth.x,this.state.target.x,s,i),this.state.smooth.y=c(this.state.smooth.y,this.state.target.y,s,i);const r=this.state.target.x-this.state.smooth.x,a=this.state.target.y-this.state.smooth.y;this.state.velocity.x=r,this.state.velocity.y=a,(Math.abs(r)>.1||Math.abs(a)>.1)&&(this.state.angle=g(r,a))}else{this.state.smooth.x=-100,this.state.smooth.y=-100,this.state.pointer.x=-100,this.state.pointer.y=-100,this.state.velocity.x=0,this.state.velocity.y=0;for(let s=0;s<this.plugins.length;s++)this.runPluginSafe(this.plugins[s],e)}this.options.autoStart&&this.isRunning&&(this.rafId=requestAnimationFrame(this.tick))};destroy(){this.isRunning=!1,cancelAnimationFrame(this.rafId),this.input.destroy(),this.stage.destroy(),this.plugins.forEach(t=>t.destroy?.(this)),this.plugins=[]}}l.DEFAULT_HOVER_SELECTORS=p,l.Supermouse=y,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
5
+ `}destroy(){this.element.remove(),this.styleTag.remove(),this.container.style.cursor=this.originalContainerCursor,this.container.classList.remove(this.scopeClass),this.container!==document.body&&this.originalContainerPosition==="static"&&(this.container.style.position="")}}const u={x:-100,y:-100},v=["a","button","input","textarea","[data-hover]","[data-cursor]"];class y{static version=l;version=l;state;options;plugins=[];stage;input;rafId=0;lastTime=0;isRunning=!1;hoverSelectors;constructor(t={}){this.options={smoothness:.15,enableTouch:!1,autoDisableOnMobile:!0,ignoreOnNative:"auto",hideCursor:!0,hideOnLeave:!0,autoStart:!0,container:document.body,dataPrefix:"supermouse",...t},this.state={pointer:{x:-100,y:-100},target:{x:-100,y:-100},smooth:{x:-100,y:-100},velocity:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,forcedCursor:null,hoverTarget:null,reducedMotion:!1,hasReceivedInput:!1,shape:null,interaction:{}},this.options.hoverSelectors?this.hoverSelectors=new Set(this.options.hoverSelectors):this.hoverSelectors=new Set(v),this.stage=new g(this.options.container,!!this.options.hideCursor),this.hoverSelectors.forEach(e=>this.stage.addSelector(e)),this.input=new f(this.state,this.options,()=>Array.from(this.hoverSelectors).join(", "),e=>{e||this.reset(!0)}),this.options.plugins&&this.options.plugins.forEach(e=>this.use(e)),this.init()}getPlugin(t){return this.plugins.find(e=>e.name===t)}get isEnabled(){return this.input.isEnabled}enablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled===!1&&(e.isEnabled=!0,e.onEnable?.(this))}disablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled!==!1&&(e.isEnabled=!1,e.onDisable?.(this))}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}registerHoverTarget(t){this.hoverSelectors.has(t)||(this.hoverSelectors.add(t),this.stage.addSelector(t))}get container(){return this.stage.element}setNativeCursor(t){this.state.forcedCursor=t==="auto"?null:t==="hide"?"none":"auto"}init(){this.options.autoStart&&this.startLoop()}enable(){this.input.isEnabled=!0,this.stage.setNativeCursor("none")}disable(){this.input.isEnabled=!1,this.stage.setNativeCursor("auto"),this.reset(!0)}use(t){if(this.plugins.some(i=>i.name===t.name))return console.warn(`[Supermouse] Plugin "${t.name}" already installed.`),this;t.isEnabled===void 0&&(t.isEnabled=!0);try{t.install?.(this)}catch(i){return console.error(`[Supermouse] Failed to install plugin '${t.name}'.`,i),this}return this.plugins.push(t),this.plugins.sort((i,n)=>(i.priority||0)-(n.priority||0)),this}reset(t=!1){this.state.pointer={...u},this.state.target={...u},this.state.smooth={...u},this.state.velocity={x:0,y:0},this.state.angle=0,t&&(this.state.hasReceivedInput=!1,this.state.shape=null,this.state.interaction={})}startLoop(){this.isRunning||(this.isRunning=!0,this.lastTime=performance.now(),this.tick(this.lastTime))}start(){this.startLoop()}step(t){this.tick(t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch(i){console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`,i);const n=this.plugins.indexOf(t);n>-1&&this.plugins.splice(n,1),t.isEnabled=!1;try{t.destroy?.(this),t.onDisable?.(this)}catch(s){console.error(`[Supermouse] Failed to cleanup crashed plugin '${t.name}'.`,s)}}}tick=t=>{const e=t-this.lastTime,i=Math.min(e/1e3,.1);this.lastTime=t,this.state.hoverTarget&&!this.state.hoverTarget.isConnected&&this.input.clearHover();const n=this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput;if(this.stage.setVisibility(n),this.input.isEnabled&&this.options.hideCursor){let s="auto";this.state.forcedCursor!==null?s=this.state.forcedCursor:s=this.state.isNative||!this.state.hasReceivedInput?"auto":"none",this.stage.setNativeCursor(s)}this.input.isEnabled&&this.state.hasReceivedInput?(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y):this.state.target={...u};for(let s=0;s<this.plugins.length;s++)this.runPluginSafe(this.plugins[s],e);if(this.input.isEnabled){const s=this.state.reducedMotion?1e3:1/this.options.smoothness*2;this.state.smooth.x=p(this.state.smooth.x,this.state.target.x,s,i),this.state.smooth.y=p(this.state.smooth.y,this.state.target.y,s,i),this.state.velocity.x=this.state.target.x-this.state.smooth.x,this.state.velocity.y=this.state.target.y-this.state.smooth.y;const{x:o,y:h}=this.state.velocity;(Math.abs(o)>.1||Math.abs(h)>.1)&&(this.state.angle=Math.atan2(h,o)*(180/Math.PI))}this.isRunning&&(this.rafId=requestAnimationFrame(this.tick))};destroy(){this.isRunning=!1,cancelAnimationFrame(this.rafId),this.input.destroy(),this.stage.destroy(),this.plugins.forEach(t=>t.destroy?.(this)),this.plugins=[]}}a.DEFAULT_HOVER_SELECTORS=v,a.Input=f,a.Stage=g,a.Supermouse=y,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supermousejs/core",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "The core physics engine and state manager for Supermouse.",
5
5
  "main": "dist/index.umd.js",
6
6
  "module": "dist/index.mjs",