@supermousejs/core 2.5.0-beta.0 → 2.5.0-beta.2

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,18 @@
1
1
  # @supermousejs/core
2
2
 
3
+ ## 2.5.0-beta.2
4
+
5
+ ### Patch Changes
6
+
7
+ - ff288b4: Fixed Logic Plugins not have effect from wrong ordering of target overwrite
8
+ - 18b57de: Fixed CSS stylesheets being destroyed erroneously from a lack of a primary owner and plugins being activated all at once by the `States` plugin when re-entering previously exited scope
9
+
10
+ ## 2.5.0-beta.1
11
+
12
+ ### Patch Changes
13
+
14
+ - 5d5ec21: Updated README to document cursor policy and scopes
15
+
3
16
  ## 2.5.0-beta.0
4
17
 
5
18
  ### Minor Changes
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # Supermouse.js - TypeScript cursor engine
1
+ # @supermousejs/core
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@supermousejs/core.svg?style=flat-square)](https://www.npmjs.com/package/@supermousejs/core)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@supermousejs/core.svg?style=flat-square)](https://www.npmjs.com/package/@supermousejs/core)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
6
6
  ![npm bundle size](https://img.shields.io/bundlephobia/minzip/%40supermousejs%2Fcore?label=minzip)
7
7
 
8
- Supermouse is a headless, physics‑based cursor engine for the web written in TypeScript. It provides pointer tracking, state, physics, and a plugin lifecycle. You install plugins (or write your own) to render custom cursors and effects. The core is zero‑dependency and TypeScript‑first.
8
+ Supermouse is a headless, physics-based cursor engine for the web, written in TypeScript. It provides pointer tracking, state, physics, and a plugin lifecycle. You install plugins (or write your own) to render custom cursors and effects. Zero runtime dependencies.
9
9
 
10
10
  **Documentation:** [supermouse.js.org](https://supermouse.js.org)
11
11
 
@@ -34,7 +34,7 @@ const mouse = new Supermouse({
34
34
  });
35
35
  ```
36
36
 
37
- Or use the plugin interface directly:
37
+ Or write a plugin directly:
38
38
 
39
39
  ```ts
40
40
  import { Supermouse } from "@supermousejs/core";
@@ -59,46 +59,104 @@ const redDot = {
59
59
  const mouse = new Supermouse({ plugins: [redDot] });
60
60
  ```
61
61
 
62
+ > Mount plugin elements to `app.stage`, not to `document.body`, so cursor suppression, scope switching, and cleanup work automatically.
63
+
62
64
  ## Options
63
65
 
64
- | Option | Default | Description |
65
- | --------------------- | ----------------------------------------------------------------------- | --------------------------------------------- |
66
- | `smoothness` | `0.15` | Lower = smoother cursor follow |
67
- | `hoverSelectors` | `["a", "button", "input", "textarea", "[data-hover]", "[data-cursor]"]` | Selectors that set `state.isHover` |
68
- | `enableTouch` | `false` | Allow touch events to move cursor |
69
- | `autoDisableOnMobile` | `true` | Disable on coarse‑pointer devices |
70
- | `cursor` | `"auto"` | `"auto"`, `"custom"`, `"native"`, or `"both"` |
71
- | `hideOnLeave` | `true` | Hide when pointer leaves window |
72
- | `container` | `document.body` | Scoping container |
73
- | `zIndex` | `9999` | Stage stacking order |
74
- | `dataPrefix` | `"supermouse"` | Prefix for data attributes |
75
- | `rules` | — | Map of selectors to interaction data |
76
- | `plugins` | — | Plugins to install at creation |
77
- | `autoStart` | `true` | Set `false` and call `.start()` manually |
66
+ | Option | Default | Description |
67
+ | ----------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------- |
68
+ | `smoothness` | `0.15` | Lower = smoother cursor follow |
69
+ | `hoverSelectors` | `["a", "button", "input", "textarea", "[data-hover]", "[data-cursor]"]` | Selectors that set `state.isHover` |
70
+ | `enableTouch` | `false` | Allow touch events to move the cursor |
71
+ | `autoDisableOnMobile` | `true` | Disable on coarse-pointer devices |
72
+ | `cursor` | `"auto"` | `"auto"`, `"custom"`, `"native"`, or `"both"` |
73
+ | `cursorPolicy` | `DEFAULT_CURSOR_POLICY` | Rules for native-cursor fallback and CSS suppression |
74
+ | `inheritDataAttributes` | `true` | Cascade `data-*` attributes and `rules` from ancestors |
75
+ | `hideOnLeave` | `true` | Hide when the pointer leaves the window |
76
+ | `container` | `document.body` | Primary scope's container |
77
+ | `scopes` | — | Additional scopes registered at construction |
78
+ | `zIndex` | `9999` | Stage stacking order |
79
+ | `dataPrefix` | `"supermouse"` | Prefix for data attributes |
80
+ | `rules` | — | Map of selectors to interaction data |
81
+ | `plugins` | — | Plugins to install at creation |
82
+ | `autoStart` | `true` | Set `false` and call `.start()` manually |
78
83
 
79
84
  ## Cursor Modes
80
85
 
81
- - `"auto"` – native cursor on interactive elements, custom elsewhere.
82
- - `"custom"` – always custom, hide native.
83
- - `"native"` – always native, hide custom.
84
- - `"both"` – show both native and custom together.
86
+ The `cursor` option decides which cursor(s) to show:
87
+
88
+ - `"auto"` — native cursor on elements that should own it (inputs, links), custom elsewhere.
89
+ - `"custom"` — always custom, hide native.
90
+ - `"native"` — always native, hide custom.
91
+ - `"both"` — show both native and custom together.
85
92
 
86
93
  Change at runtime with `mouse.setCursor("both")`.
87
94
 
88
- ## Containers & Multiple Instances
95
+ The [Cursor Policy](#cursor-policy) decides which elements are considered native in `"auto"` mode.
96
+
97
+ ## Cursor Policy
98
+
99
+ A single object maps selectors to two independent flags:
100
+
101
+ - `native` — in `"auto"` mode, matching elements yield to the OS cursor.
102
+ - `hide` — when the custom cursor is active, matching elements get `cursor: none !important`.
103
+
104
+ Extend the default policy:
105
+
106
+ ```ts
107
+ import { Supermouse, DEFAULT_CURSOR_POLICY } from "@supermousejs/core";
108
+
109
+ const mouse = new Supermouse({
110
+ cursorPolicy: {
111
+ rules: [
112
+ ...DEFAULT_CURSOR_POLICY.rules,
113
+ { selector: "[data-native]", native: true }
114
+ ]
115
+ }
116
+ });
117
+ ```
89
118
 
90
- Scope an instance to a container:
119
+ Or shorthand:
91
120
 
92
121
  ```ts
93
- const modal = document.getElementById("modal");
94
- const mouse = new Supermouse({ container: modal, cursor: "custom" });
122
+ const mouse = new Supermouse({
123
+ cursorPolicy: {
124
+ native: ["input", "textarea", "select", "[data-native]"],
125
+ hide: ["a", "button", "[role='button']"]
126
+ }
127
+ });
95
128
  ```
96
129
 
97
- Multiple instances can coexist; CSS rules are scoped automatically.
130
+ ## Scopes
131
+
132
+ A single Supermouse instance can own multiple scopes. Each scope has its own container, cursor mode, hover selectors, cursor policy, and plugins. The innermost scope containing the pointer is the active one.
133
+
134
+ ```ts
135
+ const mouse = new Supermouse({
136
+ scopes: [
137
+ { name: "main", container: document.body, plugins: [Dot({ color: "red" })] },
138
+ { name: "sidebar", container: sidebarEl, cursor: "custom" }
139
+ ]
140
+ });
141
+ ```
142
+
143
+ Or add at runtime:
144
+
145
+ ```ts
146
+ const handle = mouse.addScope({ container: modalEl, cursor: "both" });
147
+ handle.setCursor("auto");
148
+ handle.remove();
149
+ ```
150
+
151
+ The single-container form is shorthand for one scope:
152
+
153
+ ```ts
154
+ const mouse = new Supermouse({ container: modalEl, cursor: "custom" });
155
+ ```
98
156
 
99
157
  ## Native Cursor Fallback
100
158
 
101
- In `"auto"` mode, add `data-supermouse-ignore` to force the native cursor on an element and its descendants.
159
+ In `"auto"` mode, add `data-supermouse-ignore` to force the native cursor on an element and its descendants:
102
160
 
103
161
  ```html
104
162
  <div data-supermouse-ignore>Native cursor here</div>
@@ -106,7 +164,7 @@ In `"auto"` mode, add `data-supermouse-ignore` to force the native cursor on an
106
164
 
107
165
  ## Data Attributes
108
166
 
109
- Plugins can react to `data-*` attributes, e.g. `data-supermouse-color`. The prefix is configurable via `dataPrefix`.
167
+ Plugins can react to `data-*` attributes (e.g. `data-supermouse-color`). Attributes cascade from ancestors to the hovered element when `inheritDataAttributes` is `true`. Change the prefix with `dataPrefix`.
110
168
 
111
169
  ## Rules
112
170
 
@@ -120,33 +178,37 @@ const mouse = new Supermouse({
120
178
  });
121
179
  ```
122
180
 
123
- HTML `data-*` attributes override rule values per property.
181
+ Rules match ancestors as well as the hovered element. HTML `data-*` attributes override rule values per property.
124
182
 
125
183
  ## API
126
184
 
127
185
  ```ts
128
- mouse.state; // current MouseState
129
- mouse.options; // resolved options
130
- mouse.stage; // DOM element plugins render into
131
- mouse.isEnabled; // boolean
186
+ mouse.state; // current MouseState
187
+ mouse.options; // resolved options
188
+ mouse.stage; // DOM element plugins render into
189
+ mouse.container; // container element (active scope)
190
+ mouse.isEnabled; // input processing flag
191
+ mouse.isRunning; // animation loop flag
192
+
193
+ mouse.enable(); // start input, apply cursor state
194
+ mouse.disable(); // stop input, restore native cursor
195
+ mouse.disable({ reset: true }); // also reset physics and hover state
196
+ mouse.reset(); // reset state only
132
197
 
133
- mouse.enable(); // start input, hide native cursor
134
- mouse.disable(); // stop input, show native cursor, reset
135
- mouse.suspend(); // pause non‑destructively
136
- mouse.resume(); // resume from suspend
198
+ mouse.setCursor(mode); // "auto" | "custom" | "native" | "both"
137
199
 
138
- mouse.setCursor(mode); // "auto" | "custom" | "native" | "both"
200
+ mouse.addScope(config); // -> { name, container, setCursor, remove }
139
201
 
140
- mouse.use(plugin); // install plugin
141
- mouse.getPlugin(name); // retrieve plugin
142
- mouse.enablePlugin(name); // enable plugin
143
- mouse.disablePlugin(name); // disable plugin
144
- mouse.togglePlugin(name); // toggle plugin
202
+ mouse.use(plugin); // install plugin
203
+ mouse.getPlugin(name); // retrieve plugin
204
+ mouse.enablePlugin(name); // enable plugin
205
+ mouse.disablePlugin(name); // disable plugin
206
+ mouse.togglePlugin(name); // toggle plugin
145
207
 
146
208
  mouse.registerHoverTarget(sel); // add hover selector at runtime
147
- mouse.start(); // start animation loop
148
- mouse.step(time); // advance one frame manually
149
- mouse.destroy(); // destroy instance and plugins
209
+ mouse.start(); // start animation loop
210
+ mouse.step(time); // advance one frame manually
211
+ mouse.destroy(); // destroy instance and plugins
150
212
  ```
151
213
 
152
214
  ## Browser Support
@@ -155,4 +217,4 @@ All modern browsers.
155
217
 
156
218
  ## License
157
219
 
158
- MIT
220
+ MIT
package/dist/index.d.ts CHANGED
@@ -91,6 +91,11 @@ export declare interface MouseState {
91
91
  shape: ShapeState | null;
92
92
  /** Centralized store for hover metadata from data attributes and rules. */
93
93
  interaction: InteractionState;
94
+ /** The currently active scope's identity, or null when none is active. */
95
+ scope: {
96
+ name: string | undefined;
97
+ container: HTMLElement;
98
+ } | null;
94
99
  }
95
100
 
96
101
  declare type ResolvedOptions = SupermouseOptions & Required<Pick<SupermouseOptions, "smoothness" | "enableTouch" | "autoDisableOnMobile" | "cursor" | "hideOnLeave" | "autoStart" | "container" | "dataPrefix" | "zIndex" | "inheritDataAttributes">>;
@@ -119,6 +124,12 @@ export declare interface ScopeConfig {
119
124
  cursorPolicy?: CursorPolicyInput;
120
125
  /** Plugins installed when this scope activates. */
121
126
  plugins?: SupermousePlugin[];
127
+ /**
128
+ * Rules evaluated against hovered elements inside this scope. If omitted,
129
+ * the scope inherits the primary scope's rules. If provided, the scope
130
+ * uses only its own rules.
131
+ */
132
+ rules?: Record<string, RuleDefinition>;
122
133
  /**
123
134
  * Whether data attributes and rules on ancestors cascade to the hovered
124
135
  * element. Inherits from top-level if omitted.
@@ -132,8 +143,14 @@ export declare interface ScopeConfig {
132
143
  export declare interface ScopeHandle {
133
144
  readonly name: string | undefined;
134
145
  readonly container: HTMLElement;
146
+ readonly disabled: boolean;
135
147
  remove(): void;
136
148
  setCursor(mode: CursorMode): void;
149
+ disable(): void;
150
+ enable(): void;
151
+ use(plugin: SupermousePlugin): ScopeHandle;
152
+ removePlugin(name: string): void;
153
+ getPlugin(name: string): SupermousePlugin | undefined;
137
154
  }
138
155
 
139
156
  export declare interface ShapeState {
@@ -151,7 +168,10 @@ export declare class Supermouse {
151
168
  private _activeScope;
152
169
  private _installingScope;
153
170
  private scopeByContainer;
171
+ private scopeByName;
172
+ private scopeHandles;
154
173
  private input;
174
+ private styleOwner;
155
175
  private rafId;
156
176
  private lastTime;
157
177
  private visibilityAbortController;
@@ -163,6 +183,7 @@ export declare class Supermouse {
163
183
  get isRunning(): boolean;
164
184
  use(plugin: SupermousePlugin): this;
165
185
  getPlugin(name: string): SupermousePlugin | undefined;
186
+ getScope(name: string): ScopeHandle | undefined;
166
187
  enablePlugin(name: string): void;
167
188
  disablePlugin(name: string): void;
168
189
  togglePlugin(name: string): void;
@@ -178,13 +199,24 @@ export declare class Supermouse {
178
199
  destroy(): void;
179
200
  private _running;
180
201
  private createScope;
202
+ private buildScopeHandle;
181
203
  private removeScope;
182
204
  private setScopeCursor;
205
+ private disableScope;
206
+ private enableScope;
207
+ private findScopeAbove;
183
208
  private installPlugins;
184
209
  private installPlugin;
210
+ private removePluginFromScope;
185
211
  private handleActiveScopeChange;
186
- private activatePlugin;
187
212
  private deactivatePlugin;
213
+ /**
214
+ * Runs the deactivation lifecycle for a plugin whose owning scope just
215
+ * became inactive. Does NOT flip `plugin.isEnabled`, so user intent
216
+ * (e.g. States disabling a plugin) survives the scope round-trip.
217
+ */
218
+ private scopeDeactivatePlugin;
219
+ private scopeActivatePlugin;
188
220
  private rebuildStylesheet;
189
221
  private runPluginSafe;
190
222
  private cleanupCrashedPlugins;
@@ -196,21 +228,22 @@ export declare class Supermouse {
196
228
  private bindVisibilityHandling;
197
229
  private startLoop;
198
230
  /**
199
- * @deprecated Prefer setting `hoverSelectors` at scope creation, or use
200
- * `definePlugin`'s `selector` option. This method is kept for raw-object
201
- * plugins and runtime extension; it mutates the active scope's selector set.
202
- */
203
- registerHoverTarget(selector: string): void;
204
- /**
205
- * @deprecated Read from the active scope instead. Exposed for tests and
206
- * debugging only.
231
+ * @deprecated Read from the active scope instead.
232
+ * Exposed for tests and debugging.
207
233
  */
208
234
  get hoverSelectors(): Set<string>;
209
235
  /**
210
- * @deprecated Read from the active scope instead. Exposed for tests and
211
- * debugging only.
236
+ * @deprecated Read from the active scope instead.
237
+ * Exposed for tests and debugging.
212
238
  */
213
239
  get plugins(): SupermousePlugin[];
240
+ /**
241
+ * Adds one or more hover selectors to the current scope. Intended for
242
+ * raw-object plugins during `install`. Plugins written with `definePlugin`
243
+ * should use the `selector` option instead, and consumers setting up a
244
+ * scope should prefer the `hoverSelectors` option at construction.
245
+ */
246
+ registerHoverTarget(selector: string): void;
214
247
  }
215
248
 
216
249
  export declare type SupermouseInstance = Supermouse;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const w = {
1
+ const x = {
2
2
  rules: [
3
3
  { selector: "input", native: !0, hide: !0 },
4
4
  { selector: "textarea", native: !0, hide: !0 },
@@ -10,31 +10,31 @@ const w = {
10
10
  { selector: "[tabindex]", native: !1, hide: !0 }
11
11
  ]
12
12
  };
13
- function x(i) {
14
- if (!i) return w;
13
+ function _(i) {
14
+ if (!i) return x;
15
15
  if ("rules" in i) return i;
16
16
  const t = [], e = new Set(i.native ?? []), s = new Set(i.hide ?? []), n = /* @__PURE__ */ new Set([...e, ...s]);
17
- for (const r of n)
17
+ for (const o of n)
18
18
  t.push({
19
- selector: r,
20
- native: e.has(r),
21
- hide: s.has(r)
19
+ selector: o,
20
+ native: e.has(o),
21
+ hide: s.has(o)
22
22
  });
23
23
  return { rules: t };
24
24
  }
25
- function T(i) {
25
+ function A(i) {
26
26
  const t = [], e = [];
27
27
  for (const s of i.rules)
28
28
  s.native !== !1 && t.push(s.selector), s.hide !== !1 && e.push(s.selector);
29
29
  return { native: t, hide: e };
30
30
  }
31
- let L = 0;
32
- class A {
31
+ let D = 0;
32
+ class O {
33
33
  constructor(t, e) {
34
34
  if (this.container = t, !t || !(t instanceof HTMLElement))
35
35
  throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);
36
36
  t.isConnected;
37
- const s = L++;
37
+ const s = D++;
38
38
  this.scopeClass = `supermouse-scope-${s}`, this.hideClass = `supermouse-hide-${s}`;
39
39
  const n = t === document.body;
40
40
  if (this.element = document.createElement("div"), Object.assign(this.element.style, {
@@ -45,8 +45,8 @@ class A {
45
45
  opacity: "1",
46
46
  transition: "opacity 0.15s ease"
47
47
  }), !n) {
48
- const r = window.getComputedStyle(t);
49
- this.originalContainerPosition = r.position, r.position === "static" && (t.style.position = "relative");
48
+ const o = window.getComputedStyle(t);
49
+ this.originalContainerPosition = o.position, o.position === "static" && (t.style.position = "relative");
50
50
  }
51
51
  this.originalContainerCursor = t.style.cursor, t.appendChild(this.element), t.classList.add("supermouse-scope", this.scopeClass);
52
52
  }
@@ -78,11 +78,11 @@ class A {
78
78
  this.element.remove(), this.container.style.cursor = this.originalContainerCursor, this.container.classList.remove("supermouse-scope", this.scopeClass, this.hideClass), this.container !== document.body && this.originalContainerPosition === "static" && (this.container.style.position = "");
79
79
  }
80
80
  }
81
- class I {
81
+ class L {
82
82
  constructor(t, e) {
83
- this.config = t, this.name = t.name, this.cursorMode = t.cursor ?? e.cursor, this.hoverSelectors = new Set(t.hoverSelectors ?? e.hoverSelectors), this.inheritDataAttributes = t.inheritDataAttributes ?? e.inheritDataAttributes;
84
- const s = t.cursorPolicy ? x(t.cursorPolicy) : e.cursorPolicy, n = T(s);
85
- this.nativeSelectors = n.native, this.hideSelectors = n.hide, this.stage = new A(t.container, t.zIndex ?? e.zIndex);
83
+ this.config = t, this.name = t.name, this.cursorMode = t.cursor ?? e.cursor, this.hoverSelectors = new Set(t.hoverSelectors ?? e.hoverSelectors), this.inheritDataAttributes = t.inheritDataAttributes ?? e.inheritDataAttributes, this.ruleEntries = t.rules ? Object.entries(t.rules) : e.ruleEntries;
84
+ const s = t.cursorPolicy ? _(t.cursorPolicy) : e.cursorPolicy, n = A(s);
85
+ this.nativeSelectors = n.native, this.hideSelectors = n.hide, this.stage = new O(t.container, t.zIndex ?? e.zIndex);
86
86
  }
87
87
  config;
88
88
  stage;
@@ -91,8 +91,10 @@ class I {
91
91
  nativeSelectors;
92
92
  hideSelectors;
93
93
  inheritDataAttributes;
94
+ ruleEntries;
94
95
  name;
95
96
  cursorMode;
97
+ disabled = !1;
96
98
  contains(t) {
97
99
  return this.stage.containerElement.contains(t);
98
100
  }
@@ -105,7 +107,6 @@ class I {
105
107
  get nativeSelectorString() {
106
108
  return this.nativeSelectors.join(", ");
107
109
  }
108
- /** Build the CSS rules this scope contributes to the shared stylesheet. */
109
110
  buildRules() {
110
111
  const t = this.stage.getRulePrefix(), e = this.stage.getExclusion(), s = [
111
112
  `${t}${e} { cursor: none !important; }`,
@@ -120,7 +121,7 @@ class I {
120
121
  ), s;
121
122
  }
122
123
  }
123
- const f = { x: -100, y: -100 }, R = /* @__PURE__ */ new Set([
124
+ const f = { x: -100, y: -100 }, I = /* @__PURE__ */ new Set([
124
125
  "default",
125
126
  "auto",
126
127
  "pointer",
@@ -128,55 +129,55 @@ const f = { x: -100, y: -100 }, R = /* @__PURE__ */ new Set([
128
129
  "inherit",
129
130
  "grab",
130
131
  "grabbing"
131
- ]), D = [
132
+ ]), R = [
132
133
  "a",
133
134
  "button",
134
135
  "input",
135
136
  "textarea",
136
137
  "[data-hover]",
137
138
  "[data-cursor]"
138
- ], u = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Map();
139
- let v = null, g = !1, m = !1, S = 0;
140
- function C(i) {
139
+ ], u = /* @__PURE__ */ new Map(), M = /* @__PURE__ */ new Map();
140
+ let v = null, g = !1, m = !1, C = 0;
141
+ function E(i) {
141
142
  const t = i.getBoundingClientRect();
142
143
  return { left: t.left, top: t.top, width: t.width, height: t.height };
143
144
  }
144
- function M(i) {
145
- u.set(i, C(i));
146
- const t = _.get(i);
145
+ function T(i) {
146
+ u.set(i, E(i));
147
+ const t = M.get(i);
147
148
  if (t) for (const e of t) e();
148
149
  }
149
- function y() {
150
- for (const i of u.keys()) M(i);
150
+ function b() {
151
+ for (const i of u.keys()) T(i);
151
152
  }
152
- function O() {
153
+ function $() {
153
154
  v || typeof ResizeObserver > "u" || (v = new ResizeObserver((i) => {
154
155
  for (const t of i) {
155
156
  const e = t.target;
156
- u.has(e) && M(e);
157
+ u.has(e) && T(e);
157
158
  }
158
159
  }));
159
160
  }
160
- function $() {
161
- typeof window > "u" || (g || (window.addEventListener("scroll", y, { passive: !0, capture: !0 }), g = !0), m || (window.addEventListener("resize", y, { passive: !0 }), m = !0));
161
+ function B() {
162
+ typeof window > "u" || (g || (window.addEventListener("scroll", b, { passive: !0, capture: !0 }), g = !0), m || (window.addEventListener("resize", b, { passive: !0 }), m = !0));
162
163
  }
163
- function z(i, t) {
164
- return S++, u.has(i) || (u.set(i, C(i)), O(), v?.observe(i), $()), () => {
165
- S--, S === 0 && (v?.disconnect(), v = null, u.clear(), _.clear(), g && (window.removeEventListener("scroll", y, { capture: !0 }), g = !1), m && (window.removeEventListener("resize", y), m = !1));
164
+ function H(i, t) {
165
+ return C++, u.has(i) || (u.set(i, E(i)), $(), v?.observe(i), B()), () => {
166
+ C--, C === 0 && (v?.disconnect(), v = null, u.clear(), M.clear(), g && (window.removeEventListener("scroll", b, { capture: !0 }), g = !1), m && (window.removeEventListener("resize", b), m = !1));
166
167
  };
167
168
  }
168
- function k(i) {
169
+ function N(i) {
169
170
  let t = u.get(i);
170
- return t || (t = C(i), u.set(i, t)), t;
171
+ return t || (t = E(i), u.set(i, t)), t;
171
172
  }
172
- function N(i, t, e) {
173
+ function z(i, t, e) {
173
174
  if (i === document.body) return { x: t, y: e };
174
- const s = k(i);
175
+ const s = N(i);
175
176
  return { x: t - s.left, y: e - s.top };
176
177
  }
177
- class B {
178
+ class k {
178
179
  constructor(t, e, s, n) {
179
- this.state = t, this.options = e, this.onEnableChange = s, this.onActiveScopeChange = n, this.dataPrefix = e.dataPrefix ?? "supermouse", this.normalizedDataPrefix = this.dataPrefix.toLowerCase(), this.ignoreAttribute = `data-${this.dataPrefix}-ignore`, this.ruleEntries = e.rules ? Object.entries(e.rules) : [], this.checkDeviceCapability(), this.checkMotionPreference(), this.bindEvents();
180
+ this.state = t, this.options = e, this.onEnableChange = s, this.onActiveScopeChange = n, this.dataPrefix = e.dataPrefix ?? "supermouse", this.normalizedDataPrefix = this.dataPrefix.toLowerCase(), this.ignoreAttribute = `data-${this.dataPrefix}-ignore`, this.checkDeviceCapability(), this.checkMotionPreference(), this.bindEvents();
180
181
  }
181
182
  state;
182
183
  options;
@@ -193,7 +194,6 @@ class B {
193
194
  nativeTarget = null;
194
195
  currentTarget = null;
195
196
  lastParsedTarget = null;
196
- ruleEntries;
197
197
  releaseViewport = null;
198
198
  hasSeenPointer = !1;
199
199
  isEnabled = !0;
@@ -206,19 +206,19 @@ class B {
206
206
  for (const e of t) this.scopeByContainer.set(e.container, e);
207
207
  }
208
208
  setActiveScope(t) {
209
- t !== this.activeScope && (this.activeScope = t, this.releaseViewport?.(), this.releaseViewport = t && t.container !== document.body ? z(t.container) : null, this.hasSeenPointer && (this.applyPointerToState(), this.state.target.x = this.state.smooth.x = this.state.pointer.x, this.state.target.y = this.state.smooth.y = this.state.pointer.y), this.onActiveScopeChange(t));
209
+ t !== this.activeScope && (this.activeScope = t, this.lastParsedTarget = null, this.cachedChain = [], this.releaseViewport?.(), this.releaseViewport = t && t.container !== document.body ? H(t.container) : null, this.hasSeenPointer && (this.applyPointerToState(), this.state.target.x = this.state.smooth.x = this.state.pointer.x, this.state.target.y = this.state.smooth.y = this.state.pointer.y), this.onActiveScopeChange(t));
210
210
  }
211
211
  findScope(t) {
212
212
  let e = t;
213
213
  for (; e; ) {
214
214
  const s = this.scopeByContainer.get(e);
215
- if (s) return s;
215
+ if (s && !s.disabled) return s;
216
216
  e = e.parentElement;
217
217
  }
218
218
  return null;
219
219
  }
220
220
  applyPointerToState() {
221
- const t = this.activeScope?.container ?? document.body, e = N(t, this.viewportX, this.viewportY);
221
+ const t = this.activeScope?.container ?? document.body, e = z(t, this.viewportX, this.viewportY);
222
222
  this.state.pointer.x = e.x, this.state.pointer.y = e.y;
223
223
  }
224
224
  checkDeviceCapability() {
@@ -239,42 +239,43 @@ class B {
239
239
  this.isEnabled = t, this.onEnableChange(t);
240
240
  }
241
241
  parseDOMInteraction(t) {
242
- const e = this.activeScope?.container ?? document.body, s = this.activeScope?.inheritDataAttributes ?? !0, n = this.normalizedDataPrefix;
242
+ if (!this.activeScope) return;
243
+ const e = this.activeScope.container, s = this.activeScope.inheritDataAttributes, n = this.normalizedDataPrefix, o = this.activeScope.ruleEntries;
243
244
  if (t !== this.lastParsedTarget) {
244
245
  this.lastParsedTarget = t, this.cachedChain = [];
245
- let o = t;
246
- for (; o; ) {
247
- const d = [];
248
- for (const [a, h] of this.ruleEntries)
249
- this.matchesSelector(o, a) && d.push({ selector: a, rules: h });
250
- if (this.cachedChain.push({ element: o, matchedRules: d }), !s || o === e) break;
251
- const c = o.parentElement;
246
+ let r = t;
247
+ for (; r; ) {
248
+ const p = [];
249
+ for (const [a, l] of o)
250
+ this.matchesSelector(r, a) && p.push({ selector: a, rules: l });
251
+ if (this.cachedChain.push({ element: r, matchedRules: p }), !s || r === e) break;
252
+ const c = r.parentElement;
252
253
  if (!c || !e.contains(c)) break;
253
- o = c;
254
+ r = c;
254
255
  }
255
256
  }
256
- const r = {};
257
- for (const { element: o, matchedRules: d } of this.cachedChain) {
257
+ const h = {};
258
+ for (const { element: r, matchedRules: p } of this.cachedChain) {
258
259
  const c = {};
259
- for (const { rules: a } of d)
260
+ for (const { rules: a } of p)
260
261
  try {
261
- const h = typeof a == "function" ? a(o) : a;
262
- if (!h || typeof h != "object") continue;
263
- for (const [b, p] of Object.entries(h))
264
- c[b] = typeof p == "function" ? p(o) : p;
262
+ const l = typeof a == "function" ? a(r) : a;
263
+ if (!l || typeof l != "object") continue;
264
+ for (const [S, d] of Object.entries(l))
265
+ c[S] = typeof d == "function" ? d(r) : d;
265
266
  } catch {
266
267
  }
267
- for (const a in o.dataset) {
268
+ for (const a in r.dataset) {
268
269
  if (!a.toLowerCase().startsWith(n)) continue;
269
- const h = a.slice(n.length);
270
- if (!h) continue;
271
- const b = h[0].toLowerCase() + h.slice(1), p = o.dataset[a];
272
- c[b] = p == null || p === "" ? !0 : p;
270
+ const l = a.slice(n.length);
271
+ if (!l) continue;
272
+ const S = l[0].toLowerCase() + l.slice(1), d = r.dataset[a];
273
+ c[S] = d == null || d === "" ? !0 : d;
273
274
  }
274
- for (const [a, h] of Object.entries(c))
275
- a in r || (r[a] = h);
275
+ for (const [a, l] of Object.entries(c))
276
+ a in h || (h[a] = l);
276
277
  }
277
- this.state.interaction = r;
278
+ this.state.interaction = h;
278
279
  }
279
280
  matchesSelector(t, e) {
280
281
  try {
@@ -310,7 +311,7 @@ class B {
310
311
  this.state.isNative = !0, this.nativeTarget = e;
311
312
  return;
312
313
  }
313
- (e.isContentEditable || !R.has(this.resolveComputedCursor(e))) && (this.state.isNative = !0, this.nativeTarget = e);
314
+ (e.isContentEditable || !I.has(this.resolveComputedCursor(e))) && (this.state.isNative = !0, this.nativeTarget = e);
314
315
  }
315
316
  };
316
317
  handleMouseOut = (t) => {
@@ -332,34 +333,39 @@ class B {
332
333
  this.abortController.abort(), this.releaseViewport?.(), this.cachedChain = [];
333
334
  }
334
335
  }
335
- let l = null;
336
- function H() {
337
- l || typeof document > "u" || (l = document.createElement("style"), l.id = "supermouse-styles", document.head.appendChild(l));
336
+ let V = 0;
337
+ const y = /* @__PURE__ */ new Map();
338
+ function F() {
339
+ return V++;
338
340
  }
339
- function V(i) {
340
- H(), l && (l.textContent = i.join(`
341
- `));
341
+ function j(i, t) {
342
+ let e = y.get(i);
343
+ e || (e = document.createElement("style"), e.id = `supermouse-styles-${i}`, document.head.appendChild(e), y.set(i, e)), e.textContent = t.join(`
344
+ `);
342
345
  }
343
- function F() {
344
- l?.remove(), l = null;
346
+ function Q(i) {
347
+ y.get(i)?.remove(), y.delete(i);
345
348
  }
346
- const E = "2.5.0-beta.0";
347
- function j(i, t, e) {
349
+ const P = "2.5.0-beta.2";
350
+ function U(i, t, e) {
348
351
  return i + (t - i) * e;
349
352
  }
350
- function P(i, t, e, s) {
351
- return j(i, t, 1 - Math.exp(-e * s));
353
+ function w(i, t, e, s) {
354
+ return U(i, t, 1 - Math.exp(-e * s));
352
355
  }
353
- class Q {
354
- static version = E;
355
- version = E;
356
+ class Y {
357
+ static version = P;
358
+ version = P;
356
359
  state;
357
360
  options;
358
361
  _scopes = [];
359
362
  _activeScope = null;
360
363
  _installingScope = null;
361
364
  scopeByContainer = /* @__PURE__ */ new Map();
365
+ scopeByName = /* @__PURE__ */ new Map();
366
+ scopeHandles = /* @__PURE__ */ new Map();
362
367
  input;
368
+ styleOwner;
363
369
  rafId = 0;
364
370
  lastTime = 0;
365
371
  visibilityAbortController = new AbortController();
@@ -377,7 +383,7 @@ class Q {
377
383
  zIndex: 9999,
378
384
  inheritDataAttributes: !0,
379
385
  ...t
380
- }, this.state = {
386
+ }, this.styleOwner = F(), this.state = {
381
387
  pointer: { ...f },
382
388
  target: { ...f },
383
389
  smooth: { ...f },
@@ -392,7 +398,8 @@ class Q {
392
398
  reducedMotion: !1,
393
399
  hasReceivedInput: !1,
394
400
  shape: null,
395
- interaction: {}
401
+ interaction: {},
402
+ scope: null
396
403
  };
397
404
  const e = this.createScope({
398
405
  container: this.options.container,
@@ -400,9 +407,10 @@ class Q {
400
407
  hoverSelectors: this.options.hoverSelectors,
401
408
  cursorPolicy: this.options.cursorPolicy,
402
409
  plugins: this.options.plugins,
410
+ rules: this.options.rules,
403
411
  zIndex: this.options.zIndex
404
412
  });
405
- if (this.input = new B(
413
+ if (this.input = new k(
406
414
  this.state,
407
415
  this.options,
408
416
  (s) => {
@@ -435,9 +443,16 @@ class Q {
435
443
  if (s) return s;
436
444
  }
437
445
  }
446
+ getScope(t) {
447
+ const e = this.scopeByName.get(t);
448
+ return e ? this.scopeHandles.get(e) : void 0;
449
+ }
438
450
  enablePlugin(t) {
439
451
  const e = this.getPlugin(t);
440
- e && e.isEnabled === !1 && (e.isEnabled = !0, e.element && (e.element.style.display = ""), e.onEnable?.(this));
452
+ if (!e || e.isEnabled !== !1) return;
453
+ e.isEnabled = !0;
454
+ const s = this._activeScope;
455
+ s && !s.disabled && s.plugins.includes(e) && this.scopeActivatePlugin(e);
441
456
  }
442
457
  disablePlugin(t) {
443
458
  const e = this.getPlugin(t);
@@ -452,12 +467,7 @@ class Q {
452
467
  }
453
468
  addScope(t) {
454
469
  const e = this.createScope(t);
455
- return this.input.setScopes(this._scopes), this.installPlugins(e), this.rebuildStylesheet(), {
456
- name: e.name,
457
- container: e.container,
458
- remove: () => this.removeScope(e),
459
- setCursor: (s) => this.setScopeCursor(e, s)
460
- };
470
+ return this.input.setScopes(this._scopes), this.installPlugins(e), this.rebuildStylesheet(), this.scopeHandles.get(e);
461
471
  }
462
472
  enable() {
463
473
  this.input.isEnabled = !0, this.input.hasSeenPointer && (this.state.target.x = this.state.smooth.x = this.state.pointer.x, this.state.target.y = this.state.smooth.y = this.state.pointer.y, this.resetMotion(), this.state.hasReceivedInput = !0), this._activeScope && this._activeScope.stage.setNativeCursor(this.resolveCursorState());
@@ -484,19 +494,42 @@ class Q {
484
494
  }
485
495
  t.stage.destroy();
486
496
  }
487
- this._scopes = [], this.scopeByContainer.clear(), this._activeScope = null, F();
497
+ this._scopes = [], this.scopeByContainer.clear(), this.scopeByName.clear(), this.scopeHandles.clear(), this._activeScope = null, this.state.scope = null, Q(this.styleOwner);
488
498
  }
489
499
  // ─── Internal ───
490
500
  _running = !1;
491
501
  createScope(t) {
492
- const e = new I(t, {
502
+ this.scopeByContainer.has(t.container);
503
+ const e = new L(t, {
493
504
  cursor: this.options.cursor,
494
- hoverSelectors: this.options.hoverSelectors ?? D,
495
- cursorPolicy: this.options.cursorPolicy ? x(this.options.cursorPolicy) : w,
505
+ hoverSelectors: this.options.hoverSelectors ?? R,
506
+ cursorPolicy: this.options.cursorPolicy ? _(this.options.cursorPolicy) : x,
496
507
  zIndex: this.options.zIndex,
497
- inheritDataAttributes: this.options.inheritDataAttributes
508
+ inheritDataAttributes: this.options.inheritDataAttributes,
509
+ ruleEntries: this.options.rules ? Object.entries(this.options.rules) : []
498
510
  });
499
- return this._scopes.push(e), this.scopeByContainer.set(e.container, e), e;
511
+ return this._scopes.push(e), this.scopeByContainer.set(e.container, e), e.name && this.scopeByName.set(e.name, e), this.scopeHandles.set(e, this.buildScopeHandle(e)), e;
512
+ }
513
+ buildScopeHandle(t) {
514
+ const e = {
515
+ get name() {
516
+ return t.name;
517
+ },
518
+ get container() {
519
+ return t.container;
520
+ },
521
+ get disabled() {
522
+ return t.disabled;
523
+ },
524
+ remove: () => this.removeScope(t),
525
+ setCursor: (s) => this.setScopeCursor(t, s),
526
+ disable: () => this.disableScope(t),
527
+ enable: () => this.enableScope(t),
528
+ use: (s) => (this.installPlugin(t, s), e),
529
+ removePlugin: (s) => this.removePluginFromScope(t, s),
530
+ getPlugin: (s) => t.plugins.find((n) => n.name === s)
531
+ };
532
+ return e;
500
533
  }
501
534
  removeScope(t) {
502
535
  const e = this._scopes.indexOf(t);
@@ -506,12 +539,34 @@ class Q {
506
539
  s.destroy?.(this);
507
540
  } catch {
508
541
  }
509
- t.plugins.length = 0, t.stage.destroy(), this._scopes.splice(e, 1), this.scopeByContainer.delete(t.container), this.input.setScopes(this._scopes), this._activeScope === t && this.input.setActiveScope(this._scopes[0] ?? null), this.rebuildStylesheet();
542
+ if (t.plugins.length = 0, t.stage.destroy(), this._scopes.splice(e, 1), this.scopeByContainer.delete(t.container), t.name && this.scopeByName.delete(t.name), this.scopeHandles.delete(t), this.input.setScopes(this._scopes), this._activeScope === t) {
543
+ const s = this.findScopeAbove(t.container.parentElement) ?? this._scopes.find((n) => !n.disabled) ?? null;
544
+ this.input.setActiveScope(s);
545
+ }
546
+ this.rebuildStylesheet();
510
547
  }
511
548
  }
512
549
  setScopeCursor(t, e) {
513
550
  t.cursorMode = e, t === this._activeScope && (this.state.cursorMode = e);
514
551
  }
552
+ disableScope(t) {
553
+ if (!t.disabled && (t.disabled = !0, this._activeScope === t)) {
554
+ const e = this.findScopeAbove(t.container.parentElement) ?? this._scopes.find((s) => !s.disabled) ?? null;
555
+ this.input.setActiveScope(e);
556
+ }
557
+ }
558
+ enableScope(t) {
559
+ t.disabled = !1;
560
+ }
561
+ findScopeAbove(t) {
562
+ let e = t;
563
+ for (; e; ) {
564
+ const s = this.scopeByContainer.get(e);
565
+ if (s && !s.disabled) return s;
566
+ e = e.parentElement;
567
+ }
568
+ return null;
569
+ }
515
570
  installPlugins(t) {
516
571
  if (t.config.plugins)
517
572
  for (const e of t.config.plugins) this.installPlugin(t, e);
@@ -525,23 +580,39 @@ class Q {
525
580
  this._installingScope = null;
526
581
  return;
527
582
  }
528
- this._installingScope = null, t.plugins.push(e), t.plugins.sort((s, n) => (s.priority ?? 0) - (n.priority ?? 0)), t !== this._activeScope && (e.isEnabled = !1, e.element && (e.element.style.display = "none"));
583
+ this._installingScope = null, t.plugins.push(e), t.plugins.sort((s, n) => (s.priority ?? 0) - (n.priority ?? 0)), (t !== this._activeScope || t.disabled) && e.element && (e.element.style.display = "none");
529
584
  }
530
585
  }
586
+ removePluginFromScope(t, e) {
587
+ const s = t.plugins.findIndex((r) => r.name === e);
588
+ if (s === -1) return;
589
+ const n = t.plugins[s];
590
+ t.plugins.splice(s, 1);
591
+ const o = () => {
592
+ try {
593
+ n.onDisable?.(this), n.destroy?.(this);
594
+ } catch {
595
+ }
596
+ n.element?.remove();
597
+ }, h = n.onBeforeDisable?.(this);
598
+ h && typeof h.then == "function" ? Promise.resolve(h).then(o).catch((r) => {
599
+ o();
600
+ }) : o();
601
+ }
531
602
  handleActiveScopeChange(t) {
532
603
  const e = this._activeScope;
533
604
  if (e !== t) {
534
605
  if (e)
535
- for (const s of e.plugins) this.deactivatePlugin(s);
606
+ for (const s of e.plugins)
607
+ s.isEnabled !== !1 && this.scopeDeactivatePlugin(s);
536
608
  if (this._activeScope = t, t) {
537
- this.state.cursorMode = t.cursorMode;
538
- for (const s of t.plugins) this.activatePlugin(s);
539
- }
609
+ this.state.cursorMode = t.cursorMode, this.state.scope = { name: t.name, container: t.container };
610
+ for (const s of t.plugins)
611
+ s.isEnabled !== !1 && this.scopeActivatePlugin(s);
612
+ } else
613
+ this.state.scope = null;
540
614
  }
541
615
  }
542
- activatePlugin(t) {
543
- t.isEnabled === !1 && (t.isEnabled = !0, t.element && (t.element.style.display = ""), t.onEnable?.(this));
544
- }
545
616
  deactivatePlugin(t) {
546
617
  if (t.isEnabled === !1) return;
547
618
  t.isEnabled = !1;
@@ -552,10 +623,26 @@ class Q {
552
623
  e();
553
624
  }) : e();
554
625
  }
626
+ /**
627
+ * Runs the deactivation lifecycle for a plugin whose owning scope just
628
+ * became inactive. Does NOT flip `plugin.isEnabled`, so user intent
629
+ * (e.g. States disabling a plugin) survives the scope round-trip.
630
+ */
631
+ scopeDeactivatePlugin(t) {
632
+ const e = () => {
633
+ t.element && (t.element.style.display = "none"), t.onDisable?.(this);
634
+ }, s = t.onBeforeDisable?.(this);
635
+ s && typeof s.then == "function" ? Promise.resolve(s).then(e).catch((n) => {
636
+ e();
637
+ }) : e();
638
+ }
639
+ scopeActivatePlugin(t) {
640
+ t.element && (t.element.style.display = ""), t.onEnable?.(this);
641
+ }
555
642
  rebuildStylesheet() {
556
643
  const t = [];
557
644
  for (const e of this._scopes) t.push(...e.buildRules());
558
- V(t);
645
+ j(this.styleOwner, t);
559
646
  }
560
647
  runPluginSafe(t, e) {
561
648
  if (t.isEnabled !== !1)
@@ -597,18 +684,18 @@ class Q {
597
684
  const e = t - this.lastTime, s = Math.min(e / 1e3, 0.1);
598
685
  this.lastTime = t;
599
686
  const n = this.input.getCurrentTarget();
600
- n && !n.isConnected ? this.input.clearHover() : n && this.input.parseDOMInteraction(n);
601
- const r = this._activeScope;
602
- if (r) {
603
- r.stage.setVisibility(this.resolveStageVisibility()), this.input.isEnabled && r.stage.setNativeCursor(this.resolveCursorState());
604
- for (let o = 0; o < r.plugins.length; o++)
605
- this.runPluginSafe(r.plugins[o], e);
687
+ n && !n.isConnected ? this.input.clearHover() : n && this.input.parseDOMInteraction(n), this.input.isEnabled && this.state.hasReceivedInput && (this.state.target.x = this.state.pointer.x, this.state.target.y = this.state.pointer.y);
688
+ const o = this._activeScope;
689
+ if (o) {
690
+ o.stage.setVisibility(this.resolveStageVisibility()), this.input.isEnabled && o.stage.setNativeCursor(this.resolveCursorState());
691
+ for (let h = 0; h < o.plugins.length; h++)
692
+ this.runPluginSafe(o.plugins[h], e);
606
693
  }
607
- if (this.cleanupCrashedPlugins(), this.input.isEnabled && this.state.hasReceivedInput && (this.state.target.x = this.state.pointer.x, this.state.target.y = this.state.pointer.y), this.input.isEnabled) {
608
- const o = this.state.reducedMotion ? 1e3 : 1 / this.options.smoothness * 2, d = this.state.smooth.x, c = this.state.smooth.y;
609
- this.state.smooth.x = P(this.state.smooth.x, this.state.target.x, o, s), this.state.smooth.y = P(this.state.smooth.y, this.state.target.y, o, s), this.state.displacement.x = this.state.target.x - this.state.smooth.x, this.state.displacement.y = this.state.target.y - this.state.smooth.y, s > 0 ? (this.state.velocity.x = (this.state.smooth.x - d) / s, this.state.velocity.y = (this.state.smooth.y - c) / s) : (this.state.velocity.x = 0, this.state.velocity.y = 0);
610
- const { x: a, y: h } = this.state.velocity;
611
- (Math.abs(a) > 0.1 || Math.abs(h) > 0.1) && (this.state.angle = Math.atan2(h, a) * (180 / Math.PI));
694
+ if (this.cleanupCrashedPlugins(), this.input.isEnabled) {
695
+ const h = this.state.reducedMotion ? 1e3 : 1 / this.options.smoothness * 2, r = this.state.smooth.x, p = this.state.smooth.y;
696
+ this.state.smooth.x = w(this.state.smooth.x, this.state.target.x, h, s), this.state.smooth.y = w(this.state.smooth.y, this.state.target.y, h, s), this.state.displacement.x = this.state.target.x - this.state.smooth.x, this.state.displacement.y = this.state.target.y - this.state.smooth.y, s > 0 ? (this.state.velocity.x = (this.state.smooth.x - r) / s, this.state.velocity.y = (this.state.smooth.y - p) / s) : (this.state.velocity.x = 0, this.state.velocity.y = 0);
697
+ const { x: c, y: a } = this.state.velocity;
698
+ (Math.abs(c) > 0.1 || Math.abs(a) > 0.1) && (this.state.angle = Math.atan2(a, c) * (180 / Math.PI));
612
699
  }
613
700
  }
614
701
  tick = (t) => {
@@ -627,37 +714,38 @@ class Q {
627
714
  this._running || (this._running = !0, !document.hidden && (this.lastTime = performance.now(), this.rafId = requestAnimationFrame(this.tick)));
628
715
  }
629
716
  /**
630
- * @deprecated Prefer setting `hoverSelectors` at scope creation, or use
631
- * `definePlugin`'s `selector` option. This method is kept for raw-object
632
- * plugins and runtime extension; it mutates the active scope's selector set.
633
- */
634
- registerHoverTarget(t) {
635
- const e = this._installingScope ?? this._activeScope ?? this._scopes[0];
636
- if (e)
637
- for (const s of t.split(",")) {
638
- const n = s.trim();
639
- n && e.hoverSelectors.add(n);
640
- }
641
- }
642
- /**
643
- * @deprecated Read from the active scope instead. Exposed for tests and
644
- * debugging only.
717
+ * @deprecated Read from the active scope instead.
718
+ * Exposed for tests and debugging.
645
719
  */
646
720
  get hoverSelectors() {
647
721
  const t = this._activeScope ?? this._scopes[0];
648
722
  return t ? t.hoverSelectors : /* @__PURE__ */ new Set();
649
723
  }
650
724
  /**
651
- * @deprecated Read from the active scope instead. Exposed for tests and
652
- * debugging only.
725
+ * @deprecated Read from the active scope instead.
726
+ * Exposed for tests and debugging.
653
727
  */
654
728
  get plugins() {
655
729
  const t = this._activeScope ?? this._scopes[0];
656
730
  return t ? t.plugins : [];
657
731
  }
732
+ /**
733
+ * Adds one or more hover selectors to the current scope. Intended for
734
+ * raw-object plugins during `install`. Plugins written with `definePlugin`
735
+ * should use the `selector` option instead, and consumers setting up a
736
+ * scope should prefer the `hoverSelectors` option at construction.
737
+ */
738
+ registerHoverTarget(t) {
739
+ const e = this._installingScope ?? this._activeScope ?? this._scopes[0];
740
+ if (e)
741
+ for (const s of t.split(",")) {
742
+ const n = s.trim();
743
+ n && e.hoverSelectors.add(n);
744
+ }
745
+ }
658
746
  }
659
747
  export {
660
- w as DEFAULT_CURSOR_POLICY,
661
- D as DEFAULT_HOVER_SELECTORS,
662
- Q as Supermouse
748
+ x as DEFAULT_CURSOR_POLICY,
749
+ R as DEFAULT_HOVER_SELECTORS,
750
+ Y as Supermouse
663
751
  };
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- (function(l,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(l=typeof globalThis<"u"?globalThis:l||self,p(l.SupermouseCore={}))})(this,(function(l){"use strict";const p={rules:[{selector:"input",native:!0,hide:!0},{selector:"textarea",native:!0,hide:!0},{selector:"select",native:!0,hide:!0},{selector:"[contenteditable]",native:!0,hide:!0},{selector:"a",native:!1,hide:!0},{selector:"button",native:!1,hide:!0},{selector:'[role="button"]',native:!1,hide:!0},{selector:"[tabindex]",native:!1,hide:!0}]};function w(i){if(!i)return p;if("rules"in i)return i;const t=[],e=new Set(i.native??[]),s=new Set(i.hide??[]),n=new Set([...e,...s]);for(const r of n)t.push({selector:r,native:e.has(r),hide:s.has(r)});return{rules:t}}function A(i){const t=[],e=[];for(const s of i.rules)s.native!==!1&&t.push(s.selector),s.hide!==!1&&e.push(s.selector);return{native:t,hide:e}}let R=0;class O{constructor(t,e){if(this.container=t,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);t.isConnected;const s=R++;this.scopeClass=`supermouse-scope-${s}`,this.hideClass=`supermouse-hide-${s}`;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:String(e),opacity:"1",transition:"opacity 0.15s ease"}),!n){const r=window.getComputedStyle(t);this.originalContainerPosition=r.position,r.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),t.classList.add("supermouse-scope",this.scopeClass)}container;element;scopeClass;hideClass;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";get containerElement(){return this.container}getRulePrefix(){return`.${this.scopeClass}.${this.hideClass}`}getExclusion(){return`:not(.${this.scopeClass} .supermouse-scope):not(.${this.scopeClass} .supermouse-scope *)`}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){t!==this.currentCursorState&&(this.currentCursorState=t,this.container.classList.toggle(this.hideClass,t==="none"),t==="none"?this.container.style.cursor="none":this.container===document.body?this.container.style.cursor=this.originalContainerCursor:this.container.style.cursor=this.originalContainerCursor||"auto")}destroy(){this.element.remove(),this.container.style.cursor=this.originalContainerCursor,this.container.classList.remove("supermouse-scope",this.scopeClass,this.hideClass),this.container!==document.body&&this.originalContainerPosition==="static"&&(this.container.style.position="")}}class I{constructor(t,e){this.config=t,this.name=t.name,this.cursorMode=t.cursor??e.cursor,this.hoverSelectors=new Set(t.hoverSelectors??e.hoverSelectors),this.inheritDataAttributes=t.inheritDataAttributes??e.inheritDataAttributes;const s=t.cursorPolicy?w(t.cursorPolicy):e.cursorPolicy,n=A(s);this.nativeSelectors=n.native,this.hideSelectors=n.hide,this.stage=new O(t.container,t.zIndex??e.zIndex)}config;stage;hoverSelectors;plugins=[];nativeSelectors;hideSelectors;inheritDataAttributes;name;cursorMode;contains(t){return this.stage.containerElement.contains(t)}get container(){return this.stage.containerElement}get hoverSelectorString(){return Array.from(this.hoverSelectors).join(", ")}get nativeSelectorString(){return this.nativeSelectors.join(", ")}buildRules(){const t=this.stage.getRulePrefix(),e=this.stage.getExclusion(),s=[`${t}${e} { cursor: none !important; }`,`${t} *${e} { cursor: none !important; }`];for(const n of this.hideSelectors)s.push(`${t} ${n}${e} { cursor: none !important; }`);return s.push(`${t} label${e} { cursor: none !important; }`),s.push(`${t} select${e} { cursor: none !important; }`),s.push(`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`),s.push(`${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`),s}}const v={x:-100,y:-100},D=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),x=["a","button","input","textarea","[data-hover]","[data-cursor]"],u=new Map,_=new Map;let m=null,y=!1,S=!1,C=0;function E(i){const t=i.getBoundingClientRect();return{left:t.left,top:t.top,width:t.width,height:t.height}}function T(i){u.set(i,E(i));const t=_.get(i);if(t)for(const e of t)e()}function b(){for(const i of u.keys())T(i)}function $(){m||typeof ResizeObserver>"u"||(m=new ResizeObserver(i=>{for(const t of i){const e=t.target;u.has(e)&&T(e)}}))}function z(){typeof window>"u"||(y||(window.addEventListener("scroll",b,{passive:!0,capture:!0}),y=!0),S||(window.addEventListener("resize",b,{passive:!0}),S=!0))}function k(i,t){return C++,u.has(i)||(u.set(i,E(i)),$(),m?.observe(i),z()),()=>{C--,C===0&&(m?.disconnect(),m=null,u.clear(),_.clear(),y&&(window.removeEventListener("scroll",b,{capture:!0}),y=!1),S&&(window.removeEventListener("resize",b),S=!1))}}function N(i){let t=u.get(i);return t||(t=E(i),u.set(i,t)),t}function H(i,t,e){if(i===document.body)return{x:t,y:e};const s=N(i);return{x:t-s.left,y:e-s.top}}class V{constructor(t,e,s,n){this.state=t,this.options=e,this.onEnableChange=s,this.onActiveScopeChange=n,this.dataPrefix=e.dataPrefix??"supermouse",this.normalizedDataPrefix=this.dataPrefix.toLowerCase(),this.ignoreAttribute=`data-${this.dataPrefix}-ignore`,this.ruleEntries=e.rules?Object.entries(e.rules):[],this.checkDeviceCapability(),this.checkMotionPreference(),this.bindEvents()}state;options;onEnableChange;onActiveScopeChange;abortController=new AbortController;mediaQueryList;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;activeScope=null;scopeByContainer=new Map;nativeTarget=null;currentTarget=null;lastParsedTarget=null;ruleEntries;releaseViewport=null;hasSeenPointer=!1;isEnabled=!0;viewportX=0;viewportY=0;cachedChain=[];setScopes(t){this.scopeByContainer.clear();for(const e of t)this.scopeByContainer.set(e.container,e)}setActiveScope(t){t!==this.activeScope&&(this.activeScope=t,this.releaseViewport?.(),this.releaseViewport=t&&t.container!==document.body?k(t.container):null,this.hasSeenPointer&&(this.applyPointerToState(),this.state.target.x=this.state.smooth.x=this.state.pointer.x,this.state.target.y=this.state.smooth.y=this.state.pointer.y),this.onActiveScopeChange(t))}findScope(t){let e=t;for(;e;){const s=this.scopeByContainer.get(e);if(s)return s;e=e.parentElement}return null}applyPointerToState(){const t=this.activeScope?.container??document.body,e=H(t,this.viewportX,this.viewportY);this.state.pointer.x=e.x,this.state.pointer.y=e.y}checkDeviceCapability(){this.options.autoDisableOnMobile&&(this.mediaQueryList=window.matchMedia("(pointer: fine)"),this.updateEnabledState(this.mediaQueryList.matches),this.mediaQueryList.addEventListener("change",t=>this.updateEnabledState(t.matches),{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){const e=this.activeScope?.container??document.body,s=this.activeScope?.inheritDataAttributes??!0,n=this.normalizedDataPrefix;if(t!==this.lastParsedTarget){this.lastParsedTarget=t,this.cachedChain=[];let o=t;for(;o;){const g=[];for(const[a,h]of this.ruleEntries)this.matchesSelector(o,a)&&g.push({selector:a,rules:h});if(this.cachedChain.push({element:o,matchedRules:g}),!s||o===e)break;const c=o.parentElement;if(!c||!e.contains(c))break;o=c}}const r={};for(const{element:o,matchedRules:g}of this.cachedChain){const c={};for(const{rules:a}of g)try{const h=typeof a=="function"?a(o):a;if(!h||typeof h!="object")continue;for(const[P,f]of Object.entries(h))c[P]=typeof f=="function"?f(o):f}catch{}for(const a in o.dataset){if(!a.toLowerCase().startsWith(n))continue;const h=a.slice(n.length);if(!h)continue;const P=h[0].toLowerCase()+h.slice(1),f=o.dataset[a];c[P]=f==null||f===""?!0:f}for(const[a,h]of Object.entries(c))a in r||(r[a]=h)}this.state.interaction=r}matchesSelector(t,e){try{return t.matches(e)}catch{return!1}}resolveComputedCursor(t){return window.getComputedStyle(t).cursor}handleMove=t=>{this.options.autoDisableOnMobile&&t.pointerType==="touch"&&!this.options.enableTouch||(this.viewportX=t.clientX,this.viewportY=t.clientY,this.hasSeenPointer=!0,this.applyPointerToState(),this.isEnabled&&(this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=this.state.pointer.x,this.state.target.y=this.state.smooth.y=this.state.pointer.y)))};handleDown=()=>{this.isEnabled&&(this.state.isDown=!0)};handleUp=()=>{this.isEnabled&&(this.state.isDown=!1)};handleMouseOver=t=>{if(!this.isEnabled)return;const e=t.target,s=this.findScope(e);if(s&&s!==this.activeScope&&this.setActiveScope(s),!this.activeScope)return;if(this.state.cursorMode==="auto"&&e.closest(`[${this.ignoreAttribute}]`)){this.clearHover(),this.state.isNative=!0,this.nativeTarget=e;return}this.state.isNative=!1,this.nativeTarget=null,this.currentTarget=e,this.parseDOMInteraction(e);const n=e.closest(this.activeScope.hoverSelectorString);if(n&&(this.state.isHover=!0,this.state.hoverTarget=n),this.state.cursorMode==="auto"){if(this.matchesSelector(e,this.activeScope.nativeSelectorString)){this.state.isNative=!0,this.nativeTarget=e;return}(e.isContentEditable||!D.has(this.resolveComputedCursor(e)))&&(this.state.isNative=!0,this.nativeTarget=e)}};handleMouseOut=t=>{if(!this.isEnabled)return;const e=t.target,s=t.relatedTarget;(e===this.state.hoverTarget||e.contains(this.state.hoverTarget))&&(!s||!this.state.hoverTarget?.contains(s))&&(this.state.isHover=!1,this.state.hoverTarget=null),this.nativeTarget&&(e===this.nativeTarget||e.contains(this.nativeTarget))&&(!s||!this.nativeTarget.contains(s))&&(this.state.isNative=!1,this.nativeTarget=null),e===this.currentTarget&&(this.currentTarget=null,this.lastParsedTarget=null,this.cachedChain=[]),!s&&this.options.hideOnLeave&&(this.state.hasReceivedInput=!1,this.state.pointer={...v})};clearHover(){this.state.isHover=!1,this.state.hoverTarget=null,this.state.isNative=!1,this.nativeTarget=null,this.state.interaction={},this.currentTarget=null,this.lastParsedTarget=null,this.cachedChain=[]}getCurrentTarget(){return this.currentTarget}bindEvents(){const{signal:t}=this.abortController;window.addEventListener("pointermove",this.handleMove,{passive:!0,signal:t}),window.addEventListener("pointerdown",this.handleDown,{passive:!0,signal:t}),window.addEventListener("pointerup",this.handleUp,{signal:t}),document.addEventListener("mouseover",this.handleMouseOver,{signal:t}),document.addEventListener("mouseout",this.handleMouseOut,{signal:t})}destroy(){this.abortController.abort(),this.releaseViewport?.(),this.cachedChain=[]}}let d=null;function B(){d||typeof document>"u"||(d=document.createElement("style"),d.id="supermouse-styles",document.head.appendChild(d))}function F(i){B(),d&&(d.textContent=i.join(`
2
- `))}function U(){d?.remove(),d=null}const M="2.5.0-beta.0";function j(i,t,e){return i+(t-i)*e}function L(i,t,e,s){return j(i,t,1-Math.exp(-e*s))}class Q{static version=M;version=M;state;options;_scopes=[];_activeScope=null;_installingScope=null;scopeByContainer=new Map;input;rafId=0;lastTime=0;visibilityAbortController=new AbortController;crashedPlugins=[];constructor(t={}){this.options={smoothness:.15,enableTouch:!1,autoDisableOnMobile:!0,cursor:"auto",hideOnLeave:!0,autoStart:!0,container:document.body,dataPrefix:"supermouse",zIndex:9999,inheritDataAttributes:!0,...t},this.state={pointer:{...v},target:{...v},smooth:{...v},velocity:{x:0,y:0},displacement:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,cursorMode:this.options.cursor,hoverTarget:null,reducedMotion:!1,hasReceivedInput:!1,shape:null,interaction:{}};const e=this.createScope({container:this.options.container,cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors,cursorPolicy:this.options.cursorPolicy,plugins:this.options.plugins,zIndex:this.options.zIndex});if(this.input=new V(this.state,this.options,s=>{s||this.reset()},s=>this.handleActiveScopeChange(s)),this.input.setScopes(this._scopes),this.input.setActiveScope(e),this.installPlugins(e),this.options.scopes)for(const s of this.options.scopes)this.addScope(s);this.rebuildStylesheet(),this.bindVisibilityHandling(),this.options.autoStart&&this.startLoop()}get container(){return(this._activeScope??this._scopes[0]).container}get stage(){return(this._installingScope??this._activeScope??this._scopes[0]).stage.element}get isEnabled(){return this.input.isEnabled}get isRunning(){return this._running}use(t){return this.installPlugin(this._scopes[0],t),this}getPlugin(t){for(const e of this._scopes){const s=e.plugins.find(n=>n.name===t);if(s)return s}}enablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled===!1&&(e.isEnabled=!0,e.element&&(e.element.style.display=""),e.onEnable?.(this))}disablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled!==!1&&this.deactivatePlugin(e)}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}setCursor(t){this._activeScope&&(this._activeScope.cursorMode=t,this.state.cursorMode=t)}addScope(t){const e=this.createScope(t);return this.input.setScopes(this._scopes),this.installPlugins(e),this.rebuildStylesheet(),{name:e.name,container:e.container,remove:()=>this.removeScope(e),setCursor:s=>this.setScopeCursor(e,s)}}enable(){this.input.isEnabled=!0,this.input.hasSeenPointer&&(this.state.target.x=this.state.smooth.x=this.state.pointer.x,this.state.target.y=this.state.smooth.y=this.state.pointer.y,this.resetMotion(),this.state.hasReceivedInput=!0),this._activeScope&&this._activeScope.stage.setNativeCursor(this.resolveCursorState())}disable(t){this.input.isEnabled=!1,this._activeScope&&(this._activeScope.stage.setNativeCursor("auto"),this._activeScope.stage.setVisibility(!1)),t?.reset&&this.reset()}reset(){this.state.target={...v},this.state.smooth={...v},this.resetMotion(),this.state.angle=0,this.state.hasReceivedInput=!1,this.state.shape=null,this.state.interaction={}}start(){this.startLoop()}step(t){this.update(t)}destroy(){this._running=!1,cancelAnimationFrame(this.rafId),this.visibilityAbortController.abort(),this.input.destroy();for(const t of this._scopes){for(const e of t.plugins)try{e.destroy?.(this)}catch{}t.stage.destroy()}this._scopes=[],this.scopeByContainer.clear(),this._activeScope=null,U()}_running=!1;createScope(t){const e=new I(t,{cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors??x,cursorPolicy:this.options.cursorPolicy?w(this.options.cursorPolicy):p,zIndex:this.options.zIndex,inheritDataAttributes:this.options.inheritDataAttributes});return this._scopes.push(e),this.scopeByContainer.set(e.container,e),e}removeScope(t){const e=this._scopes.indexOf(t);if(e!==-1){for(const s of t.plugins)try{s.destroy?.(this)}catch{}t.plugins.length=0,t.stage.destroy(),this._scopes.splice(e,1),this.scopeByContainer.delete(t.container),this.input.setScopes(this._scopes),this._activeScope===t&&this.input.setActiveScope(this._scopes[0]??null),this.rebuildStylesheet()}}setScopeCursor(t,e){t.cursorMode=e,t===this._activeScope&&(this.state.cursorMode=e)}installPlugins(t){if(t.config.plugins)for(const e of t.config.plugins)this.installPlugin(t,e)}installPlugin(t,e){if(!t.plugins.some(s=>s.name===e.name)){e.isEnabled??=!0,this._installingScope=t;try{e.install?.(this)}catch{this._installingScope=null;return}this._installingScope=null,t.plugins.push(e),t.plugins.sort((s,n)=>(s.priority??0)-(n.priority??0)),t!==this._activeScope&&(e.isEnabled=!1,e.element&&(e.element.style.display="none"))}}handleActiveScopeChange(t){const e=this._activeScope;if(e!==t){if(e)for(const s of e.plugins)this.deactivatePlugin(s);if(this._activeScope=t,t){this.state.cursorMode=t.cursorMode;for(const s of t.plugins)this.activatePlugin(s)}}}activatePlugin(t){t.isEnabled===!1&&(t.isEnabled=!0,t.element&&(t.element.style.display=""),t.onEnable?.(this))}deactivatePlugin(t){if(t.isEnabled===!1)return;t.isEnabled=!1;const e=()=>{t.element&&(t.element.style.display="none"),t.onDisable?.(this)},s=t.onBeforeDisable?.(this);s&&typeof s.then=="function"?Promise.resolve(s).then(e).catch(n=>{e()}):e()}rebuildStylesheet(){const t=[];for(const e of this._scopes)t.push(...e.buildRules());F(t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch{t.isEnabled=!1,this.crashedPlugins.push(t)}}cleanupCrashedPlugins(){if(this.crashedPlugins.length!==0){for(const t of this.crashedPlugins){for(const e of this._scopes){const s=e.plugins.indexOf(t);if(s!==-1){e.plugins.splice(s,1);break}}try{t.onDisable?.(this),t.destroy?.(this)}catch{}t.element?.remove()}this.crashedPlugins=[]}}resolveStageVisibility(){return this.state.cursorMode==="native"?!1:this.state.cursorMode==="custom"||this.state.cursorMode==="both"?this.input.isEnabled&&this.state.hasReceivedInput:this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput}resolveCursorState(){return!this.input.isEnabled||this.state.cursorMode==="native"||this.state.cursorMode==="both"?"auto":this.state.cursorMode==="custom"?"none":this.state.isNative||!this.state.hasReceivedInput?"auto":"none"}resetMotion(){this.state.velocity={x:0,y:0},this.state.displacement={x:0,y:0}}update(t){const e=t-this.lastTime,s=Math.min(e/1e3,.1);this.lastTime=t;const n=this.input.getCurrentTarget();n&&!n.isConnected?this.input.clearHover():n&&this.input.parseDOMInteraction(n);const r=this._activeScope;if(r){r.stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&r.stage.setNativeCursor(this.resolveCursorState());for(let o=0;o<r.plugins.length;o++)this.runPluginSafe(r.plugins[o],e)}if(this.cleanupCrashedPlugins(),this.input.isEnabled&&this.state.hasReceivedInput&&(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y),this.input.isEnabled){const o=this.state.reducedMotion?1e3:1/this.options.smoothness*2,g=this.state.smooth.x,c=this.state.smooth.y;this.state.smooth.x=L(this.state.smooth.x,this.state.target.x,o,s),this.state.smooth.y=L(this.state.smooth.y,this.state.target.y,o,s),this.state.displacement.x=this.state.target.x-this.state.smooth.x,this.state.displacement.y=this.state.target.y-this.state.smooth.y,s>0?(this.state.velocity.x=(this.state.smooth.x-g)/s,this.state.velocity.y=(this.state.smooth.y-c)/s):(this.state.velocity.x=0,this.state.velocity.y=0);const{x:a,y:h}=this.state.velocity;(Math.abs(a)>.1||Math.abs(h)>.1)&&(this.state.angle=Math.atan2(h,a)*(180/Math.PI))}}tick=t=>{this.update(t),this._running&&(this.rafId=requestAnimationFrame(this.tick))};bindVisibilityHandling(){document.addEventListener("visibilitychange",()=>{this._running&&(document.hidden?cancelAnimationFrame(this.rafId):(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))},{signal:this.visibilityAbortController.signal})}startLoop(){this._running||(this._running=!0,!document.hidden&&(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))}registerHoverTarget(t){const e=this._installingScope??this._activeScope??this._scopes[0];if(e)for(const s of t.split(",")){const n=s.trim();n&&e.hoverSelectors.add(n)}}get hoverSelectors(){const t=this._activeScope??this._scopes[0];return t?t.hoverSelectors:new Set}get plugins(){const t=this._activeScope??this._scopes[0];return t?t.plugins:[]}}l.DEFAULT_CURSOR_POLICY=p,l.DEFAULT_HOVER_SELECTORS=x,l.Supermouse=Q,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(u,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(u=typeof globalThis<"u"?globalThis:u||self,p(u.SupermouseCore={}))})(this,(function(u){"use strict";const p={rules:[{selector:"input",native:!0,hide:!0},{selector:"textarea",native:!0,hide:!0},{selector:"select",native:!0,hide:!0},{selector:"[contenteditable]",native:!0,hide:!0},{selector:"a",native:!1,hide:!0},{selector:"button",native:!1,hide:!0},{selector:'[role="button"]',native:!1,hide:!0},{selector:"[tabindex]",native:!1,hide:!0}]};function x(i){if(!i)return p;if("rules"in i)return i;const t=[],e=new Set(i.native??[]),s=new Set(i.hide??[]),n=new Set([...e,...s]);for(const o of n)t.push({selector:o,native:e.has(o),hide:s.has(o)});return{rules:t}}function L(i){const t=[],e=[];for(const s of i.rules)s.native!==!1&&t.push(s.selector),s.hide!==!1&&e.push(s.selector);return{native:t,hide:e}}let D=0;class I{constructor(t,e){if(this.container=t,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);t.isConnected;const s=D++;this.scopeClass=`supermouse-scope-${s}`,this.hideClass=`supermouse-hide-${s}`;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:String(e),opacity:"1",transition:"opacity 0.15s ease"}),!n){const o=window.getComputedStyle(t);this.originalContainerPosition=o.position,o.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),t.classList.add("supermouse-scope",this.scopeClass)}container;element;scopeClass;hideClass;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";get containerElement(){return this.container}getRulePrefix(){return`.${this.scopeClass}.${this.hideClass}`}getExclusion(){return`:not(.${this.scopeClass} .supermouse-scope):not(.${this.scopeClass} .supermouse-scope *)`}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){t!==this.currentCursorState&&(this.currentCursorState=t,this.container.classList.toggle(this.hideClass,t==="none"),t==="none"?this.container.style.cursor="none":this.container===document.body?this.container.style.cursor=this.originalContainerCursor:this.container.style.cursor=this.originalContainerCursor||"auto")}destroy(){this.element.remove(),this.container.style.cursor=this.originalContainerCursor,this.container.classList.remove("supermouse-scope",this.scopeClass,this.hideClass),this.container!==document.body&&this.originalContainerPosition==="static"&&(this.container.style.position="")}}class R{constructor(t,e){this.config=t,this.name=t.name,this.cursorMode=t.cursor??e.cursor,this.hoverSelectors=new Set(t.hoverSelectors??e.hoverSelectors),this.inheritDataAttributes=t.inheritDataAttributes??e.inheritDataAttributes,this.ruleEntries=t.rules?Object.entries(t.rules):e.ruleEntries;const s=t.cursorPolicy?x(t.cursorPolicy):e.cursorPolicy,n=L(s);this.nativeSelectors=n.native,this.hideSelectors=n.hide,this.stage=new I(t.container,t.zIndex??e.zIndex)}config;stage;hoverSelectors;plugins=[];nativeSelectors;hideSelectors;inheritDataAttributes;ruleEntries;name;cursorMode;disabled=!1;contains(t){return this.stage.containerElement.contains(t)}get container(){return this.stage.containerElement}get hoverSelectorString(){return Array.from(this.hoverSelectors).join(", ")}get nativeSelectorString(){return this.nativeSelectors.join(", ")}buildRules(){const t=this.stage.getRulePrefix(),e=this.stage.getExclusion(),s=[`${t}${e} { cursor: none !important; }`,`${t} *${e} { cursor: none !important; }`];for(const n of this.hideSelectors)s.push(`${t} ${n}${e} { cursor: none !important; }`);return s.push(`${t} label${e} { cursor: none !important; }`),s.push(`${t} select${e} { cursor: none !important; }`),s.push(`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`),s.push(`${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`),s}}const v={x:-100,y:-100},$=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),_=["a","button","input","textarea","[data-hover]","[data-cursor]"],d=new Map,M=new Map;let m=null,b=!1,y=!1,E=0;function P(i){const t=i.getBoundingClientRect();return{left:t.left,top:t.top,width:t.width,height:t.height}}function T(i){d.set(i,P(i));const t=M.get(i);if(t)for(const e of t)e()}function S(){for(const i of d.keys())T(i)}function B(){m||typeof ResizeObserver>"u"||(m=new ResizeObserver(i=>{for(const t of i){const e=t.target;d.has(e)&&T(e)}}))}function H(){typeof window>"u"||(b||(window.addEventListener("scroll",S,{passive:!0,capture:!0}),b=!0),y||(window.addEventListener("resize",S,{passive:!0}),y=!0))}function N(i,t){return E++,d.has(i)||(d.set(i,P(i)),B(),m?.observe(i),H()),()=>{E--,E===0&&(m?.disconnect(),m=null,d.clear(),M.clear(),b&&(window.removeEventListener("scroll",S,{capture:!0}),b=!1),y&&(window.removeEventListener("resize",S),y=!1))}}function z(i){let t=d.get(i);return t||(t=P(i),d.set(i,t)),t}function k(i,t,e){if(i===document.body)return{x:t,y:e};const s=z(i);return{x:t-s.left,y:e-s.top}}class V{constructor(t,e,s,n){this.state=t,this.options=e,this.onEnableChange=s,this.onActiveScopeChange=n,this.dataPrefix=e.dataPrefix??"supermouse",this.normalizedDataPrefix=this.dataPrefix.toLowerCase(),this.ignoreAttribute=`data-${this.dataPrefix}-ignore`,this.checkDeviceCapability(),this.checkMotionPreference(),this.bindEvents()}state;options;onEnableChange;onActiveScopeChange;abortController=new AbortController;mediaQueryList;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;activeScope=null;scopeByContainer=new Map;nativeTarget=null;currentTarget=null;lastParsedTarget=null;releaseViewport=null;hasSeenPointer=!1;isEnabled=!0;viewportX=0;viewportY=0;cachedChain=[];setScopes(t){this.scopeByContainer.clear();for(const e of t)this.scopeByContainer.set(e.container,e)}setActiveScope(t){t!==this.activeScope&&(this.activeScope=t,this.lastParsedTarget=null,this.cachedChain=[],this.releaseViewport?.(),this.releaseViewport=t&&t.container!==document.body?N(t.container):null,this.hasSeenPointer&&(this.applyPointerToState(),this.state.target.x=this.state.smooth.x=this.state.pointer.x,this.state.target.y=this.state.smooth.y=this.state.pointer.y),this.onActiveScopeChange(t))}findScope(t){let e=t;for(;e;){const s=this.scopeByContainer.get(e);if(s&&!s.disabled)return s;e=e.parentElement}return null}applyPointerToState(){const t=this.activeScope?.container??document.body,e=k(t,this.viewportX,this.viewportY);this.state.pointer.x=e.x,this.state.pointer.y=e.y}checkDeviceCapability(){this.options.autoDisableOnMobile&&(this.mediaQueryList=window.matchMedia("(pointer: fine)"),this.updateEnabledState(this.mediaQueryList.matches),this.mediaQueryList.addEventListener("change",t=>this.updateEnabledState(t.matches),{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.activeScope)return;const e=this.activeScope.container,s=this.activeScope.inheritDataAttributes,n=this.normalizedDataPrefix,o=this.activeScope.ruleEntries;if(t!==this.lastParsedTarget){this.lastParsedTarget=t,this.cachedChain=[];let r=t;for(;r;){const g=[];for(const[a,l]of o)this.matchesSelector(r,a)&&g.push({selector:a,rules:l});if(this.cachedChain.push({element:r,matchedRules:g}),!s||r===e)break;const c=r.parentElement;if(!c||!e.contains(c))break;r=c}}const h={};for(const{element:r,matchedRules:g}of this.cachedChain){const c={};for(const{rules:a}of g)try{const l=typeof a=="function"?a(r):a;if(!l||typeof l!="object")continue;for(const[w,f]of Object.entries(l))c[w]=typeof f=="function"?f(r):f}catch{}for(const a in r.dataset){if(!a.toLowerCase().startsWith(n))continue;const l=a.slice(n.length);if(!l)continue;const w=l[0].toLowerCase()+l.slice(1),f=r.dataset[a];c[w]=f==null||f===""?!0:f}for(const[a,l]of Object.entries(c))a in h||(h[a]=l)}this.state.interaction=h}matchesSelector(t,e){try{return t.matches(e)}catch{return!1}}resolveComputedCursor(t){return window.getComputedStyle(t).cursor}handleMove=t=>{this.options.autoDisableOnMobile&&t.pointerType==="touch"&&!this.options.enableTouch||(this.viewportX=t.clientX,this.viewportY=t.clientY,this.hasSeenPointer=!0,this.applyPointerToState(),this.isEnabled&&(this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=this.state.pointer.x,this.state.target.y=this.state.smooth.y=this.state.pointer.y)))};handleDown=()=>{this.isEnabled&&(this.state.isDown=!0)};handleUp=()=>{this.isEnabled&&(this.state.isDown=!1)};handleMouseOver=t=>{if(!this.isEnabled)return;const e=t.target,s=this.findScope(e);if(s&&s!==this.activeScope&&this.setActiveScope(s),!this.activeScope)return;if(this.state.cursorMode==="auto"&&e.closest(`[${this.ignoreAttribute}]`)){this.clearHover(),this.state.isNative=!0,this.nativeTarget=e;return}this.state.isNative=!1,this.nativeTarget=null,this.currentTarget=e,this.parseDOMInteraction(e);const n=e.closest(this.activeScope.hoverSelectorString);if(n&&(this.state.isHover=!0,this.state.hoverTarget=n),this.state.cursorMode==="auto"){if(this.matchesSelector(e,this.activeScope.nativeSelectorString)){this.state.isNative=!0,this.nativeTarget=e;return}(e.isContentEditable||!$.has(this.resolveComputedCursor(e)))&&(this.state.isNative=!0,this.nativeTarget=e)}};handleMouseOut=t=>{if(!this.isEnabled)return;const e=t.target,s=t.relatedTarget;(e===this.state.hoverTarget||e.contains(this.state.hoverTarget))&&(!s||!this.state.hoverTarget?.contains(s))&&(this.state.isHover=!1,this.state.hoverTarget=null),this.nativeTarget&&(e===this.nativeTarget||e.contains(this.nativeTarget))&&(!s||!this.nativeTarget.contains(s))&&(this.state.isNative=!1,this.nativeTarget=null),e===this.currentTarget&&(this.currentTarget=null,this.lastParsedTarget=null,this.cachedChain=[]),!s&&this.options.hideOnLeave&&(this.state.hasReceivedInput=!1,this.state.pointer={...v})};clearHover(){this.state.isHover=!1,this.state.hoverTarget=null,this.state.isNative=!1,this.nativeTarget=null,this.state.interaction={},this.currentTarget=null,this.lastParsedTarget=null,this.cachedChain=[]}getCurrentTarget(){return this.currentTarget}bindEvents(){const{signal:t}=this.abortController;window.addEventListener("pointermove",this.handleMove,{passive:!0,signal:t}),window.addEventListener("pointerdown",this.handleDown,{passive:!0,signal:t}),window.addEventListener("pointerup",this.handleUp,{signal:t}),document.addEventListener("mouseover",this.handleMouseOver,{signal:t}),document.addEventListener("mouseout",this.handleMouseOut,{signal:t})}destroy(){this.abortController.abort(),this.releaseViewport?.(),this.cachedChain=[]}}let F=0;const C=new Map;function j(){return F++}function U(i,t){let e=C.get(i);e||(e=document.createElement("style"),e.id=`supermouse-styles-${i}`,document.head.appendChild(e),C.set(i,e)),e.textContent=t.join(`
2
+ `)}function Q(i){C.get(i)?.remove(),C.delete(i)}const A="2.5.0-beta.2";function Y(i,t,e){return i+(t-i)*e}function O(i,t,e,s){return Y(i,t,1-Math.exp(-e*s))}class q{static version=A;version=A;state;options;_scopes=[];_activeScope=null;_installingScope=null;scopeByContainer=new Map;scopeByName=new Map;scopeHandles=new Map;input;styleOwner;rafId=0;lastTime=0;visibilityAbortController=new AbortController;crashedPlugins=[];constructor(t={}){this.options={smoothness:.15,enableTouch:!1,autoDisableOnMobile:!0,cursor:"auto",hideOnLeave:!0,autoStart:!0,container:document.body,dataPrefix:"supermouse",zIndex:9999,inheritDataAttributes:!0,...t},this.styleOwner=j(),this.state={pointer:{...v},target:{...v},smooth:{...v},velocity:{x:0,y:0},displacement:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,cursorMode:this.options.cursor,hoverTarget:null,reducedMotion:!1,hasReceivedInput:!1,shape:null,interaction:{},scope:null};const e=this.createScope({container:this.options.container,cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors,cursorPolicy:this.options.cursorPolicy,plugins:this.options.plugins,rules:this.options.rules,zIndex:this.options.zIndex});if(this.input=new V(this.state,this.options,s=>{s||this.reset()},s=>this.handleActiveScopeChange(s)),this.input.setScopes(this._scopes),this.input.setActiveScope(e),this.installPlugins(e),this.options.scopes)for(const s of this.options.scopes)this.addScope(s);this.rebuildStylesheet(),this.bindVisibilityHandling(),this.options.autoStart&&this.startLoop()}get container(){return(this._activeScope??this._scopes[0]).container}get stage(){return(this._installingScope??this._activeScope??this._scopes[0]).stage.element}get isEnabled(){return this.input.isEnabled}get isRunning(){return this._running}use(t){return this.installPlugin(this._scopes[0],t),this}getPlugin(t){for(const e of this._scopes){const s=e.plugins.find(n=>n.name===t);if(s)return s}}getScope(t){const e=this.scopeByName.get(t);return e?this.scopeHandles.get(e):void 0}enablePlugin(t){const e=this.getPlugin(t);if(!e||e.isEnabled!==!1)return;e.isEnabled=!0;const s=this._activeScope;s&&!s.disabled&&s.plugins.includes(e)&&this.scopeActivatePlugin(e)}disablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled!==!1&&this.deactivatePlugin(e)}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}setCursor(t){this._activeScope&&(this._activeScope.cursorMode=t,this.state.cursorMode=t)}addScope(t){const e=this.createScope(t);return this.input.setScopes(this._scopes),this.installPlugins(e),this.rebuildStylesheet(),this.scopeHandles.get(e)}enable(){this.input.isEnabled=!0,this.input.hasSeenPointer&&(this.state.target.x=this.state.smooth.x=this.state.pointer.x,this.state.target.y=this.state.smooth.y=this.state.pointer.y,this.resetMotion(),this.state.hasReceivedInput=!0),this._activeScope&&this._activeScope.stage.setNativeCursor(this.resolveCursorState())}disable(t){this.input.isEnabled=!1,this._activeScope&&(this._activeScope.stage.setNativeCursor("auto"),this._activeScope.stage.setVisibility(!1)),t?.reset&&this.reset()}reset(){this.state.target={...v},this.state.smooth={...v},this.resetMotion(),this.state.angle=0,this.state.hasReceivedInput=!1,this.state.shape=null,this.state.interaction={}}start(){this.startLoop()}step(t){this.update(t)}destroy(){this._running=!1,cancelAnimationFrame(this.rafId),this.visibilityAbortController.abort(),this.input.destroy();for(const t of this._scopes){for(const e of t.plugins)try{e.destroy?.(this)}catch{}t.stage.destroy()}this._scopes=[],this.scopeByContainer.clear(),this.scopeByName.clear(),this.scopeHandles.clear(),this._activeScope=null,this.state.scope=null,Q(this.styleOwner)}_running=!1;createScope(t){this.scopeByContainer.has(t.container);const e=new R(t,{cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors??_,cursorPolicy:this.options.cursorPolicy?x(this.options.cursorPolicy):p,zIndex:this.options.zIndex,inheritDataAttributes:this.options.inheritDataAttributes,ruleEntries:this.options.rules?Object.entries(this.options.rules):[]});return this._scopes.push(e),this.scopeByContainer.set(e.container,e),e.name&&this.scopeByName.set(e.name,e),this.scopeHandles.set(e,this.buildScopeHandle(e)),e}buildScopeHandle(t){const e={get name(){return t.name},get container(){return t.container},get disabled(){return t.disabled},remove:()=>this.removeScope(t),setCursor:s=>this.setScopeCursor(t,s),disable:()=>this.disableScope(t),enable:()=>this.enableScope(t),use:s=>(this.installPlugin(t,s),e),removePlugin:s=>this.removePluginFromScope(t,s),getPlugin:s=>t.plugins.find(n=>n.name===s)};return e}removeScope(t){const e=this._scopes.indexOf(t);if(e!==-1){for(const s of t.plugins)try{s.destroy?.(this)}catch{}if(t.plugins.length=0,t.stage.destroy(),this._scopes.splice(e,1),this.scopeByContainer.delete(t.container),t.name&&this.scopeByName.delete(t.name),this.scopeHandles.delete(t),this.input.setScopes(this._scopes),this._activeScope===t){const s=this.findScopeAbove(t.container.parentElement)??this._scopes.find(n=>!n.disabled)??null;this.input.setActiveScope(s)}this.rebuildStylesheet()}}setScopeCursor(t,e){t.cursorMode=e,t===this._activeScope&&(this.state.cursorMode=e)}disableScope(t){if(!t.disabled&&(t.disabled=!0,this._activeScope===t)){const e=this.findScopeAbove(t.container.parentElement)??this._scopes.find(s=>!s.disabled)??null;this.input.setActiveScope(e)}}enableScope(t){t.disabled=!1}findScopeAbove(t){let e=t;for(;e;){const s=this.scopeByContainer.get(e);if(s&&!s.disabled)return s;e=e.parentElement}return null}installPlugins(t){if(t.config.plugins)for(const e of t.config.plugins)this.installPlugin(t,e)}installPlugin(t,e){if(!t.plugins.some(s=>s.name===e.name)){e.isEnabled??=!0,this._installingScope=t;try{e.install?.(this)}catch{this._installingScope=null;return}this._installingScope=null,t.plugins.push(e),t.plugins.sort((s,n)=>(s.priority??0)-(n.priority??0)),(t!==this._activeScope||t.disabled)&&e.element&&(e.element.style.display="none")}}removePluginFromScope(t,e){const s=t.plugins.findIndex(r=>r.name===e);if(s===-1)return;const n=t.plugins[s];t.plugins.splice(s,1);const o=()=>{try{n.onDisable?.(this),n.destroy?.(this)}catch{}n.element?.remove()},h=n.onBeforeDisable?.(this);h&&typeof h.then=="function"?Promise.resolve(h).then(o).catch(r=>{o()}):o()}handleActiveScopeChange(t){const e=this._activeScope;if(e!==t){if(e)for(const s of e.plugins)s.isEnabled!==!1&&this.scopeDeactivatePlugin(s);if(this._activeScope=t,t){this.state.cursorMode=t.cursorMode,this.state.scope={name:t.name,container:t.container};for(const s of t.plugins)s.isEnabled!==!1&&this.scopeActivatePlugin(s)}else this.state.scope=null}}deactivatePlugin(t){if(t.isEnabled===!1)return;t.isEnabled=!1;const e=()=>{t.element&&(t.element.style.display="none"),t.onDisable?.(this)},s=t.onBeforeDisable?.(this);s&&typeof s.then=="function"?Promise.resolve(s).then(e).catch(n=>{e()}):e()}scopeDeactivatePlugin(t){const e=()=>{t.element&&(t.element.style.display="none"),t.onDisable?.(this)},s=t.onBeforeDisable?.(this);s&&typeof s.then=="function"?Promise.resolve(s).then(e).catch(n=>{e()}):e()}scopeActivatePlugin(t){t.element&&(t.element.style.display=""),t.onEnable?.(this)}rebuildStylesheet(){const t=[];for(const e of this._scopes)t.push(...e.buildRules());U(this.styleOwner,t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch{t.isEnabled=!1,this.crashedPlugins.push(t)}}cleanupCrashedPlugins(){if(this.crashedPlugins.length!==0){for(const t of this.crashedPlugins){for(const e of this._scopes){const s=e.plugins.indexOf(t);if(s!==-1){e.plugins.splice(s,1);break}}try{t.onDisable?.(this),t.destroy?.(this)}catch{}t.element?.remove()}this.crashedPlugins=[]}}resolveStageVisibility(){return this.state.cursorMode==="native"?!1:this.state.cursorMode==="custom"||this.state.cursorMode==="both"?this.input.isEnabled&&this.state.hasReceivedInput:this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput}resolveCursorState(){return!this.input.isEnabled||this.state.cursorMode==="native"||this.state.cursorMode==="both"?"auto":this.state.cursorMode==="custom"?"none":this.state.isNative||!this.state.hasReceivedInput?"auto":"none"}resetMotion(){this.state.velocity={x:0,y:0},this.state.displacement={x:0,y:0}}update(t){const e=t-this.lastTime,s=Math.min(e/1e3,.1);this.lastTime=t;const n=this.input.getCurrentTarget();n&&!n.isConnected?this.input.clearHover():n&&this.input.parseDOMInteraction(n),this.input.isEnabled&&this.state.hasReceivedInput&&(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y);const o=this._activeScope;if(o){o.stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&o.stage.setNativeCursor(this.resolveCursorState());for(let h=0;h<o.plugins.length;h++)this.runPluginSafe(o.plugins[h],e)}if(this.cleanupCrashedPlugins(),this.input.isEnabled){const h=this.state.reducedMotion?1e3:1/this.options.smoothness*2,r=this.state.smooth.x,g=this.state.smooth.y;this.state.smooth.x=O(this.state.smooth.x,this.state.target.x,h,s),this.state.smooth.y=O(this.state.smooth.y,this.state.target.y,h,s),this.state.displacement.x=this.state.target.x-this.state.smooth.x,this.state.displacement.y=this.state.target.y-this.state.smooth.y,s>0?(this.state.velocity.x=(this.state.smooth.x-r)/s,this.state.velocity.y=(this.state.smooth.y-g)/s):(this.state.velocity.x=0,this.state.velocity.y=0);const{x:c,y:a}=this.state.velocity;(Math.abs(c)>.1||Math.abs(a)>.1)&&(this.state.angle=Math.atan2(a,c)*(180/Math.PI))}}tick=t=>{this.update(t),this._running&&(this.rafId=requestAnimationFrame(this.tick))};bindVisibilityHandling(){document.addEventListener("visibilitychange",()=>{this._running&&(document.hidden?cancelAnimationFrame(this.rafId):(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))},{signal:this.visibilityAbortController.signal})}startLoop(){this._running||(this._running=!0,!document.hidden&&(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))}get hoverSelectors(){const t=this._activeScope??this._scopes[0];return t?t.hoverSelectors:new Set}get plugins(){const t=this._activeScope??this._scopes[0];return t?t.plugins:[]}registerHoverTarget(t){const e=this._installingScope??this._activeScope??this._scopes[0];if(e)for(const s of t.split(",")){const n=s.trim();n&&e.hoverSelectors.add(n)}}}u.DEFAULT_CURSOR_POLICY=p,u.DEFAULT_HOVER_SELECTORS=_,u.Supermouse=q,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supermousejs/core",
3
- "version": "2.5.0-beta.0",
3
+ "version": "2.5.0-beta.2",
4
4
  "files": [
5
5
  "dist",
6
6
  "README.md",