@supermousejs/core 2.5.0-beta.1 → 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,12 @@
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
+
3
10
  ## 2.5.0-beta.1
4
11
 
5
12
  ### Patch Changes
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.1";
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.1";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.1",
3
+ "version": "2.5.0-beta.2",
4
4
  "files": [
5
5
  "dist",
6
6
  "README.md",