@supermousejs/core 2.5.0-beta.3 → 2.5.0-beta.4

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,25 @@
1
1
  # @supermousejs/core
2
2
 
3
+ ## 2.5.0-beta.4
4
+
5
+ ### Patch Changes
6
+
7
+ - cb9bf9a: Beta.4
8
+
9
+ **Added**
10
+ - `state.authoredCursor` — the cursor value the page intends at the element under the pointer, resolved as if Supermouse's suppression were not active. Populated on every pointerTarget change, in all cursor modes. Read this to know what the page wants (`canvas { cursor: crosshair }`, `.drag-handle { cursor: grab }`, `[disabled] { cursor: not-allowed }`) rather than just whether the OS cursor should be shown (`state.isNative`).
11
+ - `state.pointerTarget` — the raw element under the pointer, regardless of hover selectors. Distinct from `state.hoverTarget`, which reports the nearest ancestor matching a hover selector.
12
+
13
+ **Fixed**
14
+ - Cursor detection in `auto` mode no longer reads its own suppression output. The previous implementation called `getComputedStyle(target).cursor` while the scope's hide class was active, so it always saw `"none"` and never triggered native fallback for authored exotic cursors. A probe attribute (`data-sm-probe`) is now excluded from every generated suppression rule, so the read sees the page's intended value.
15
+
16
+ **Changed**
17
+ - `@supermousejs/labs`: `SmartIcon` now reads `state.pointerTarget` and `state.authoredCursor` instead of relying on a broad hover-selector sweep. Hovering a `<p>` no longer sets `state.isHover` on the primary scope.
18
+ - `@supermousejs/labs`: `SmartIconOptions.useSemanticTags` renamed to `useSemanticDetection`. The old name referred to a `registerHoverTarget` sweep that no longer runs.
19
+
20
+ **Internal**
21
+ - Size budget raised to 6.5 kB gzip / 5.75 kB brotli to accommodate the beta.4 surface. Will be re-tightened once the shape settles.
22
+
3
23
  ## 2.5.0-beta.3
4
24
 
5
25
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -74,6 +74,16 @@ export declare interface MouseState {
74
74
  isNative: boolean;
75
75
  /** Current cursor mode: auto, custom, native, or both. */
76
76
  cursorMode: CursorMode;
77
+ /**
78
+ * The raw element currently under the pointer, regardless of whether it
79
+ * matches any hover selector.
80
+ */
81
+ pointerTarget: HTMLElement | null;
82
+ /**
83
+ * The authored cursor value at `pointerTarget`, resolved as if
84
+ * Supermouse's suppression were not active.
85
+ */
86
+ authoredCursor: string | null;
77
87
  /** Currently hovered DOM element, if any. */
78
88
  hoverTarget: HTMLElement | null;
79
89
  /** User has `prefers-reduced-motion` enabled. */
package/dist/index.mjs CHANGED
@@ -19,7 +19,7 @@ function b(n) {
19
19
  } : S;
20
20
  }
21
21
  let y = 0;
22
- class P {
22
+ class C {
23
23
  element;
24
24
  scopeClass;
25
25
  hideClass;
@@ -92,13 +92,13 @@ class P {
92
92
  this._detach();
93
93
  }
94
94
  }
95
- class C {
95
+ class P {
96
96
  constructor(t, e) {
97
97
  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;
98
98
  const s = t.cursorPolicy ? b(t.cursorPolicy) : e.cursorPolicy;
99
99
  this.nativeSelectors = s.native, this.hideSelectors = s.hide;
100
100
  let i;
101
- typeof t.container == "string" ? (this.containerSelector = t.container, this._bound = !1, i = document.createElement("div"), i.setAttribute("data-supermouse-placeholder", "")) : (this.containerSelector = null, this._bound = !0, i = t.container), this.stage = new P(i, t.zIndex ?? e.zIndex);
101
+ typeof t.container == "string" ? (this.containerSelector = t.container, this._bound = !1, i = document.createElement("div"), i.setAttribute("data-supermouse-placeholder", "")) : (this.containerSelector = null, this._bound = !0, i = t.container), this.stage = new C(i, t.zIndex ?? e.zIndex);
102
102
  }
103
103
  config;
104
104
  stage;
@@ -159,17 +159,17 @@ class C {
159
159
  return this.nativeSelectors.join(", ");
160
160
  }
161
161
  buildRules() {
162
- const t = this.stage.getRulePrefix(), e = this.stage.getExclusion(), s = [
163
- `${t}${e} { cursor: none !important; }`,
164
- `${t} *${e} { cursor: none !important; }`
162
+ const t = this.stage.getRulePrefix(), e = this.stage.getExclusion(), s = ":not([data-sm-probe])", i = [
163
+ `${t}${e}${s} { cursor: none !important; }`,
164
+ `${t} *${e}${s} { cursor: none !important; }`
165
165
  ];
166
- for (const i of this.hideSelectors)
167
- s.push(`${t} ${i}${e} { cursor: none !important; }`);
168
- return s.push(
166
+ for (const h of this.hideSelectors)
167
+ i.push(`${t} ${h}${e}${s} { cursor: none !important; }`);
168
+ return i.push(
169
169
  `${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`
170
- ), s.push(
170
+ ), i.push(
171
171
  `${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`
172
- ), s;
172
+ ), i;
173
173
  }
174
174
  }
175
175
  const d = { x: -100, y: -100 }, E = /* @__PURE__ */ new Set([
@@ -290,8 +290,17 @@ class w {
290
290
  return !1;
291
291
  }
292
292
  }
293
- resolveComputedCursor(t) {
294
- return window.getComputedStyle(t).cursor;
293
+ /**
294
+ * Reads the element's authored cursor value without our own suppression
295
+ * interfering.
296
+ */
297
+ resolveAuthoredCursor(t) {
298
+ t.setAttribute("data-sm-probe", "");
299
+ try {
300
+ return window.getComputedStyle(t).cursor;
301
+ } finally {
302
+ t.removeAttribute("data-sm-probe");
303
+ }
295
304
  }
296
305
  handleMove = (t) => {
297
306
  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)));
@@ -317,23 +326,25 @@ class w {
317
326
  this.clearHover(), this.state.isNative = !0, this.nativeTarget = t;
318
327
  return;
319
328
  }
320
- this.state.isNative = !1, this.nativeTarget = null, this.currentTarget = t, this.parseDOMInteraction(t);
321
- const e = t.closest(this.activeScope.hoverSelectorString);
322
- if (e && (this.state.isHover = !0, this.state.hoverTarget = e), this.state.cursorMode === "auto") {
329
+ this.state.isNative = !1, this.nativeTarget = null, this.currentTarget = t, this.state.pointerTarget = t;
330
+ const e = this.resolveAuthoredCursor(t);
331
+ this.state.authoredCursor = e, this.parseDOMInteraction(t);
332
+ const s = t.closest(this.activeScope.hoverSelectorString);
333
+ if (s && (this.state.isHover = !0, this.state.hoverTarget = s), this.state.cursorMode === "auto") {
323
334
  if (this.matchesSelector(t, this.activeScope.nativeSelectorString)) {
324
335
  this.state.isNative = !0, this.nativeTarget = t;
325
336
  return;
326
337
  }
327
- (t.isContentEditable || !E.has(this.resolveComputedCursor(t))) && (this.state.isNative = !0, this.nativeTarget = t);
338
+ (t.isContentEditable || !E.has(e)) && (this.state.isNative = !0, this.nativeTarget = t);
328
339
  }
329
340
  }
330
341
  handleMouseOut = (t) => {
331
342
  if (!this.isEnabled) return;
332
343
  const e = t.target, s = t.relatedTarget;
333
- (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 = { ...d });
344
+ (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.state.pointerTarget = null, this.state.authoredCursor = null, this.lastParsedTarget = null, this.cachedChain = []), !s && this.options.hideOnLeave && (this.state.hasReceivedInput = !1, this.state.pointer = { ...d });
334
345
  };
335
346
  clearHover() {
336
- 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 = [];
347
+ this.state.isHover = !1, this.state.hoverTarget = null, this.state.isNative = !1, this.nativeTarget = null, this.state.interaction = {}, this.currentTarget = null, this.state.pointerTarget = null, this.state.authoredCursor = null, this.lastParsedTarget = null, this.cachedChain = [];
337
348
  }
338
349
  getCurrentTarget() {
339
350
  return this.currentTarget;
@@ -348,10 +359,10 @@ class w {
348
359
  }
349
360
  let x = 0;
350
361
  const f = /* @__PURE__ */ new Map();
351
- function M() {
362
+ function T() {
352
363
  return x++;
353
364
  }
354
- function T(n, t) {
365
+ function M(n, t) {
355
366
  let e = f.get(n);
356
367
  e || (e = document.createElement("style"), e.id = `supermouse-styles-${n}`, document.head.appendChild(e), f.set(n, e)), e.textContent = t.join(`
357
368
  `);
@@ -359,7 +370,7 @@ function T(n, t) {
359
370
  function A(n) {
360
371
  f.get(n)?.remove(), f.delete(n);
361
372
  }
362
- const g = "2.5.0-beta.3";
373
+ const g = "2.5.0-beta.4";
363
374
  function D(n, t, e) {
364
375
  return n + (t - n) * e;
365
376
  }
@@ -395,7 +406,7 @@ class I {
395
406
  zIndex: 9999,
396
407
  inheritDataAttributes: !0,
397
408
  ...t
398
- }, this.styleOwner = M(), this.state = {
409
+ }, this.styleOwner = T(), this.state = {
399
410
  pointer: { ...d },
400
411
  target: { ...d },
401
412
  smooth: { ...d },
@@ -406,7 +417,9 @@ class I {
406
417
  isHover: !1,
407
418
  isNative: !1,
408
419
  cursorMode: this.options.cursor,
420
+ pointerTarget: null,
409
421
  hoverTarget: null,
422
+ authoredCursor: null,
410
423
  reducedMotion: !1,
411
424
  hasReceivedInput: !1,
412
425
  shape: null,
@@ -556,7 +569,7 @@ class I {
556
569
  break;
557
570
  }
558
571
  }
559
- const e = new C(t, {
572
+ const e = new P(t, {
560
573
  cursor: this.options.cursor,
561
574
  hoverSelectors: this.options.hoverSelectors ?? _,
562
575
  cursorPolicy: this.options.cursorPolicy ? b(this.options.cursorPolicy) : S,
@@ -751,7 +764,7 @@ class I {
751
764
  rebuildStylesheet() {
752
765
  const t = [":where(.supermouse-scope .supermouse-scope) { cursor: auto }"];
753
766
  for (const e of this._scopes) t.push(...e.buildRules());
754
- T(this.styleOwner, t);
767
+ M(this.styleOwner, t);
755
768
  }
756
769
  runPluginSafe(t, e) {
757
770
  if (t.isEnabled !== !1)
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
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={native:["input","textarea","select","[contenteditable]"],hide:["input","textarea","select","[contenteditable]","a","button",'[role="button"]',"[tabindex]","label"]};function S(n){return n?{native:n.native??[],hide:n.hide??[]}:p}let P=0;class E{element;scopeClass;hideClass;container;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";_visible=!0;constructor(t,e){if(!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);const s=t.hasAttribute("data-supermouse-placeholder");!t.isConnected&&!s&&console.warn("[Supermouse] container is not attached to the document — stage sizing/positioning will be wrong until it is.");const i=P++;this.scopeClass=`supermouse-scope-${i}`,this.hideClass=`supermouse-hide-${i}`,this.element=document.createElement("div"),Object.assign(this.element.style,{position:"absolute",inset:"0px",pointerEvents:"none",zIndex:String(e),opacity:"1",transition:"opacity 0.15s ease"}),this.container=t,this._attach(t)}_attach(t){const e=t===document.body;if(this.element.style.position=e?"fixed":"absolute",e)this.originalContainerPosition="";else{const s=window.getComputedStyle(t);this.originalContainerPosition=s.position,s.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),t.classList.add("supermouse-scope",this.scopeClass)}_detach(){const t=this.container;t.classList.remove("supermouse-scope",this.scopeClass,this.hideClass),t!==document.body&&this.originalContainerPosition==="static"&&(t.style.position=""),t.style.cursor=this.originalContainerCursor,this.element.remove()}attach(t){if(this.container===t)return;const e=this.currentCursorState;this._detach(),this.container=t,this._attach(t),this.currentCursorState=null,e&&this.setNativeCursor(e)}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){t!==this._visible&&(this._visible=t,this.element.style.opacity=t?"1":"0")}setNativeCursor(t){t!==this.currentCursorState&&(this.currentCursorState=t,this.container.classList.toggle(this.hideClass,t==="none"))}destroy(){this._detach()}}class _{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?S(t.cursorPolicy):e.cursorPolicy;this.nativeSelectors=s.native,this.hideSelectors=s.hide;let i;typeof t.container=="string"?(this.containerSelector=t.container,this._bound=!1,i=document.createElement("div"),i.setAttribute("data-supermouse-placeholder","")):(this.containerSelector=null,this._bound=!0,i=t.container),this.stage=new E(i,t.zIndex??e.zIndex)}config;stage;containerSelector;hoverSelectors;plugins=[];nativeSelectors;hideSelectors;inheritDataAttributes;ruleEntries;name;cursorMode;active=!0;_bound;get container(){return this.stage.containerElement}get resolved(){return this._bound}match(t){if(this.containerSelector===null)return this.stage.containerElement===t;try{return t.matches(this.containerSelector)}catch{return!1}}bind(t){this.containerSelector!==null&&(this._bound&&this.stage.containerElement===t||(this.stage.attach(t),this._bound=!0))}contains(t){return this._bound&&this.stage.containerElement.contains(t)}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 i of this.hideSelectors)s.push(`${t} ${i}${e} { cursor: none !important; }`);return 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 f={x:-100,y:-100},w=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),b=["a","button","input","textarea","[data-hover]","[data-cursor]"];class x{constructor(t,e,s,i,h,r){this.state=t,this.options=e,this.onEnableChange=s,this.onActiveScopeChange=i,this.resolveScope=h,this.onHoverSettled=r,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;resolveScope;onHoverSettled;abortController=new AbortController;mediaQueryList;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;activeScope=null;nativeTarget=null;currentTarget=null;lastParsedTarget=null;hasSeenPointer=!1;isEnabled=!0;viewportX=0;viewportY=0;cachedChain=[];setActiveScope(t){t!==this.activeScope&&(this.activeScope=t,this.lastParsedTarget=null,this.cachedChain=[],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))}applyPointerToState(){const t=this.activeScope?.container??document.body;if(t===document.body){this.state.pointer.x=this.viewportX,this.state.pointer.y=this.viewportY;return}const e=t.getBoundingClientRect();this.state.pointer.x=this.viewportX-e.left,this.state.pointer.y=this.viewportY-e.top}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,i=this.normalizedDataPrefix,h=this.activeScope.ruleEntries;if(t!==this.lastParsedTarget){this.lastParsedTarget=t,this.cachedChain=[];let o=t;for(;o;){const v=[];for(const[a,l]of h)this.matchesSelector(o,a)&&v.push({selector:a,rules:l});if(this.cachedChain.push({element:o,matchedRules:v}),!s||o===e)break;const c=o.parentElement;if(!c||!e.contains(c))break;o=c}}const r={};for(const{element:o,matchedRules:v}of this.cachedChain){const c={};for(const{rules:a}of v)try{const l=typeof a=="function"?a(o):a;if(!l||typeof l!="object")continue;for(const[m,d]of Object.entries(l))c[m]=typeof d=="function"?d(o):d}catch(l){console.error("[Supermouse] Rule threw during evaluation:",l)}for(const a in o.dataset){if(!a.toLowerCase().startsWith(i))continue;const l=a.slice(i.length);if(!l)continue;const m=l[0].toLowerCase()+l.slice(1),d=o.dataset[a];c[m]=d==null||d===""?!0:d}for(const[a,l]of Object.entries(c))a in r||(r[a]=l)}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.resolveScope(e);s&&s!==this.activeScope&&this.setActiveScope(s),this.activeScope&&(this.settleHoverState(e),this.onHoverSettled())};isPointerInside(t){if(!this.hasSeenPointer)return!1;const e=t.getBoundingClientRect();return this.viewportX>=e.left&&this.viewportX<=e.right&&this.viewportY>=e.top&&this.viewportY<=e.bottom}settleHoverState(t){if(this.state.cursorMode==="auto"&&t.closest(`[${this.ignoreAttribute}]`)){this.clearHover(),this.state.isNative=!0,this.nativeTarget=t;return}this.state.isNative=!1,this.nativeTarget=null,this.currentTarget=t,this.parseDOMInteraction(t);const e=t.closest(this.activeScope.hoverSelectorString);if(e&&(this.state.isHover=!0,this.state.hoverTarget=e),this.state.cursorMode==="auto"){if(this.matchesSelector(t,this.activeScope.nativeSelectorString)){this.state.isNative=!0,this.nativeTarget=t;return}(t.isContentEditable||!w.has(this.resolveComputedCursor(t)))&&(this.state.isNative=!0,this.nativeTarget=t)}}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={...f})};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.cachedChain=[]}}let T=0;const g=new Map;function M(){return T++}function A(n,t){let e=g.get(n);e||(e=document.createElement("style"),e.id=`supermouse-styles-${n}`,document.head.appendChild(e),g.set(n,e)),e.textContent=t.join(`
2
- `)}function D(n){g.get(n)?.remove(),g.delete(n)}const y="2.5.0-beta.3";function I(n,t,e){return n+(t-n)*e}function C(n,t,e,s){return I(n,t,1-Math.exp(-e*s))}class O{static version=y;version=y;state;options;_scopes=[];_activeScope=null;_installingScope=null;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=M(),this.state={pointer:{...f},target:{...f},smooth:{...f},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 x(this.state,this.options,s=>{s||this.reset()},s=>this.handleActiveScopeChange(s),s=>this.resolveScopeForNode(s),()=>this.applyCursorNow()),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(i=>i.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.findScopeForPlugin(e);s&&s===this._activeScope&&s.active&&this.scopeActivatePlugin(e)}disablePlugin(t){const e=this.getPlugin(t);if(!e||e.isEnabled===!1)return;const s=this.findScopeForPlugin(e);s!==null&&s===this._activeScope&&s.active?this.deactivatePlugin(e):e.isEnabled=!1}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}setCursor(t){this._activeScope&&this.setScopeCursor(this._activeScope,t)}addScope(t){const e=this.createScope(t);return 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={...f},this.state.smooth={...f},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(s){console.error(s)}t.stage.destroy()}this._scopes=[],this.scopeByName.clear(),this.scopeHandles.clear(),this._activeScope=null,this.state.scope=null,D(this.styleOwner)}_running=!1;createScope(t){if(typeof t.container!="string"){const s=t.container;for(const i of this._scopes)if(i.containerSelector===null&&i.container===s){console.warn("[Supermouse] A scope is already registered for this container. The previous scope will no longer activate.");break}}const e=new _(t,{cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors??b,cursorPolicy:this.options.cursorPolicy?S(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),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.resolved?t.container:null},get active(){return t.active},get resolved(){return t.resolved},destroy:()=>this.destroyScope(t),setCursor:s=>this.setScopeCursor(t,s),deactivate:()=>this.deactivateScope(t),activate:()=>this.activateScope(t),use:s=>(this.installPlugin(t,s),e),removePlugin:s=>this.removePluginFromScope(t,s),getPlugin:s=>t.plugins.find(i=>i.name===s)};return e}destroyScope(t){const e=this._scopes.indexOf(t);if(e!==-1){for(const s of t.plugins)try{s.destroy?.(this)}catch(i){console.error(i)}if(t.plugins.length=0,t.stage.destroy(),this._scopes.splice(e,1),t.name&&this.scopeByName.delete(t.name),this.scopeHandles.delete(t),this._activeScope===t){const s=this.resolveScopeForNode(t.container.parentElement)??this._scopes.find(i=>i.active)??null;this.input.setActiveScope(s),this.input.clearHover(),this.applyCursorNow()}this.rebuildStylesheet()}}setScopeCursor(t,e){t.cursorMode=e,t===this._activeScope&&(this.state.cursorMode=e,this.applyCursorNow())}deactivateScope(t){if(t.active&&(t.active=!1,this._activeScope===t)){const e=this.resolveScopeForNode(t.container.parentElement)??this._scopes.find(s=>s.active)??null;this.input.setActiveScope(e),this.input.clearHover(),this.applyCursorNow()}}activateScope(t){if(t.active=!0,this._activeScope!==t&&this.input.hasSeenPointer){if(t.containerSelector!==null&&!t.resolved){const e=document.querySelectorAll(t.containerSelector);for(const s of e)if(this.input.isPointerInside(s)){t.bind(s);break}}t.resolved&&this.input.isPointerInside(t.container)&&(this.input.setActiveScope(t),this.applyCursorNow())}}resolveScopeForNode(t){for(let e=t;e;e=e.parentElement)for(const s of this._scopes)if(s.active&&s.match(e))return s.bind(e),s;return null}applyCursorNow(){const t=this._activeScope;t&&(t.stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&t.stage.setNativeCursor(this.resolveCursorState()))}findScopeForPlugin(t){for(const e of this._scopes)if(e.plugins.includes(t))return e;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)){console.warn(`[Supermouse] Plugin "${e.name}" already installed.`);return}e.isEnabled??=!0,this._installingScope=t;try{e.install?.(this)}catch(s){console.error(`[Supermouse] Failed to install plugin '${e.name}'.`,s),this._installingScope=null;return}this._installingScope=null,t.plugins.push(e),t.plugins.sort((s,i)=>(s.priority??0)-(i.priority??0)),(t!==this._activeScope||!t.active)&&e.element&&(e.element.style.display="none")}removePluginFromScope(t,e){const s=t.plugins.findIndex(o=>o.name===e);if(s===-1)return;const i=t.plugins[s];t.plugins.splice(s,1);const h=()=>{try{i.onDisable?.(this),i.destroy?.(this)}catch(o){console.error(`[Supermouse] Plugin '${e}' cleanup threw:`,o)}i.element?.remove()},r=i.onBeforeDisable?.(this);r&&typeof r.then=="function"?Promise.resolve(r).then(h).catch(o=>{console.error(`[Supermouse] Plugin '${e}' onBeforeDisable threw:`,o),h()}):h()}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(i=>{console.error(`[Supermouse] Plugin '${t.name}' onBeforeDisable threw:`,i),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(i=>{console.error(`[Supermouse] Plugin '${t.name}' onBeforeDisable threw:`,i),e()}):e()}scopeActivatePlugin(t){t.element&&(t.element.style.display=""),t.onEnable?.(this)}rebuildStylesheet(){const t=[":where(.supermouse-scope .supermouse-scope) { cursor: auto }"];for(const e of this._scopes)t.push(...e.buildRules());A(this.styleOwner,t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch(s){console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`,s),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(e){console.error(`[Supermouse] Failed to cleanup crashed plugin '${t.name}'.`,e)}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 i=this.input.getCurrentTarget();i&&!i.isConnected?this.input.clearHover():i&&this.input.parseDOMInteraction(i),this.input.isEnabled&&this.state.hasReceivedInput&&(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y);const h=this._activeScope;if(h){h.stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&h.stage.setNativeCursor(this.resolveCursorState());for(let r=0;r<h.plugins.length;r++)this.runPluginSafe(h.plugins[r],e)}if(this.cleanupCrashedPlugins(),this.input.isEnabled){const r=this.state.reducedMotion?1e3:1/this.options.smoothness*2,o=this.state.smooth.x,v=this.state.smooth.y;this.state.smooth.x=C(this.state.smooth.x,this.state.target.x,r,s),this.state.smooth.y=C(this.state.smooth.y,this.state.target.y,r,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-o)/s,this.state.velocity.y=(this.state.smooth.y-v)/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)))}registerHoverTarget(t){const e=this._installingScope??this._activeScope??this._scopes[0];if(e)for(const s of t.split(",")){const i=s.trim();i&&e.hoverSelectors.add(i)}}}u.DEFAULT_CURSOR_POLICY=p,u.DEFAULT_HOVER_SELECTORS=b,u.Supermouse=O,Object.defineProperty(u,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={native:["input","textarea","select","[contenteditable]"],hide:["input","textarea","select","[contenteditable]","a","button",'[role="button"]',"[tabindex]","label"]};function S(n){return n?{native:n.native??[],hide:n.hide??[]}:p}let P=0;class E{element;scopeClass;hideClass;container;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";_visible=!0;constructor(t,e){if(!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);const s=t.hasAttribute("data-supermouse-placeholder");!t.isConnected&&!s&&console.warn("[Supermouse] container is not attached to the document — stage sizing/positioning will be wrong until it is.");const i=P++;this.scopeClass=`supermouse-scope-${i}`,this.hideClass=`supermouse-hide-${i}`,this.element=document.createElement("div"),Object.assign(this.element.style,{position:"absolute",inset:"0px",pointerEvents:"none",zIndex:String(e),opacity:"1",transition:"opacity 0.15s ease"}),this.container=t,this._attach(t)}_attach(t){const e=t===document.body;if(this.element.style.position=e?"fixed":"absolute",e)this.originalContainerPosition="";else{const s=window.getComputedStyle(t);this.originalContainerPosition=s.position,s.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),t.classList.add("supermouse-scope",this.scopeClass)}_detach(){const t=this.container;t.classList.remove("supermouse-scope",this.scopeClass,this.hideClass),t!==document.body&&this.originalContainerPosition==="static"&&(t.style.position=""),t.style.cursor=this.originalContainerCursor,this.element.remove()}attach(t){if(this.container===t)return;const e=this.currentCursorState;this._detach(),this.container=t,this._attach(t),this.currentCursorState=null,e&&this.setNativeCursor(e)}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){t!==this._visible&&(this._visible=t,this.element.style.opacity=t?"1":"0")}setNativeCursor(t){t!==this.currentCursorState&&(this.currentCursorState=t,this.container.classList.toggle(this.hideClass,t==="none"))}destroy(){this._detach()}}class _{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?S(t.cursorPolicy):e.cursorPolicy;this.nativeSelectors=s.native,this.hideSelectors=s.hide;let i;typeof t.container=="string"?(this.containerSelector=t.container,this._bound=!1,i=document.createElement("div"),i.setAttribute("data-supermouse-placeholder","")):(this.containerSelector=null,this._bound=!0,i=t.container),this.stage=new E(i,t.zIndex??e.zIndex)}config;stage;containerSelector;hoverSelectors;plugins=[];nativeSelectors;hideSelectors;inheritDataAttributes;ruleEntries;name;cursorMode;active=!0;_bound;get container(){return this.stage.containerElement}get resolved(){return this._bound}match(t){if(this.containerSelector===null)return this.stage.containerElement===t;try{return t.matches(this.containerSelector)}catch{return!1}}bind(t){this.containerSelector!==null&&(this._bound&&this.stage.containerElement===t||(this.stage.attach(t),this._bound=!0))}contains(t){return this._bound&&this.stage.containerElement.contains(t)}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=":not([data-sm-probe])",i=[`${t}${e}${s} { cursor: none !important; }`,`${t} *${e}${s} { cursor: none !important; }`];for(const h of this.hideSelectors)i.push(`${t} ${h}${e}${s} { cursor: none !important; }`);return i.push(`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`),i.push(`${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`),i}}const f={x:-100,y:-100},w=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),b=["a","button","input","textarea","[data-hover]","[data-cursor]"];class x{constructor(t,e,s,i,h,r){this.state=t,this.options=e,this.onEnableChange=s,this.onActiveScopeChange=i,this.resolveScope=h,this.onHoverSettled=r,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;resolveScope;onHoverSettled;abortController=new AbortController;mediaQueryList;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;activeScope=null;nativeTarget=null;currentTarget=null;lastParsedTarget=null;hasSeenPointer=!1;isEnabled=!0;viewportX=0;viewportY=0;cachedChain=[];setActiveScope(t){t!==this.activeScope&&(this.activeScope=t,this.lastParsedTarget=null,this.cachedChain=[],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))}applyPointerToState(){const t=this.activeScope?.container??document.body;if(t===document.body){this.state.pointer.x=this.viewportX,this.state.pointer.y=this.viewportY;return}const e=t.getBoundingClientRect();this.state.pointer.x=this.viewportX-e.left,this.state.pointer.y=this.viewportY-e.top}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,i=this.normalizedDataPrefix,h=this.activeScope.ruleEntries;if(t!==this.lastParsedTarget){this.lastParsedTarget=t,this.cachedChain=[];let o=t;for(;o;){const v=[];for(const[a,l]of h)this.matchesSelector(o,a)&&v.push({selector:a,rules:l});if(this.cachedChain.push({element:o,matchedRules:v}),!s||o===e)break;const c=o.parentElement;if(!c||!e.contains(c))break;o=c}}const r={};for(const{element:o,matchedRules:v}of this.cachedChain){const c={};for(const{rules:a}of v)try{const l=typeof a=="function"?a(o):a;if(!l||typeof l!="object")continue;for(const[m,d]of Object.entries(l))c[m]=typeof d=="function"?d(o):d}catch(l){console.error("[Supermouse] Rule threw during evaluation:",l)}for(const a in o.dataset){if(!a.toLowerCase().startsWith(i))continue;const l=a.slice(i.length);if(!l)continue;const m=l[0].toLowerCase()+l.slice(1),d=o.dataset[a];c[m]=d==null||d===""?!0:d}for(const[a,l]of Object.entries(c))a in r||(r[a]=l)}this.state.interaction=r}matchesSelector(t,e){try{return t.matches(e)}catch{return!1}}resolveAuthoredCursor(t){t.setAttribute("data-sm-probe","");try{return window.getComputedStyle(t).cursor}finally{t.removeAttribute("data-sm-probe")}}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.resolveScope(e);s&&s!==this.activeScope&&this.setActiveScope(s),this.activeScope&&(this.settleHoverState(e),this.onHoverSettled())};isPointerInside(t){if(!this.hasSeenPointer)return!1;const e=t.getBoundingClientRect();return this.viewportX>=e.left&&this.viewportX<=e.right&&this.viewportY>=e.top&&this.viewportY<=e.bottom}settleHoverState(t){if(this.state.cursorMode==="auto"&&t.closest(`[${this.ignoreAttribute}]`)){this.clearHover(),this.state.isNative=!0,this.nativeTarget=t;return}this.state.isNative=!1,this.nativeTarget=null,this.currentTarget=t,this.state.pointerTarget=t;const e=this.resolveAuthoredCursor(t);this.state.authoredCursor=e,this.parseDOMInteraction(t);const s=t.closest(this.activeScope.hoverSelectorString);if(s&&(this.state.isHover=!0,this.state.hoverTarget=s),this.state.cursorMode==="auto"){if(this.matchesSelector(t,this.activeScope.nativeSelectorString)){this.state.isNative=!0,this.nativeTarget=t;return}(t.isContentEditable||!w.has(e))&&(this.state.isNative=!0,this.nativeTarget=t)}}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.state.pointerTarget=null,this.state.authoredCursor=null,this.lastParsedTarget=null,this.cachedChain=[]),!s&&this.options.hideOnLeave&&(this.state.hasReceivedInput=!1,this.state.pointer={...f})};clearHover(){this.state.isHover=!1,this.state.hoverTarget=null,this.state.isNative=!1,this.nativeTarget=null,this.state.interaction={},this.currentTarget=null,this.state.pointerTarget=null,this.state.authoredCursor=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.cachedChain=[]}}let T=0;const g=new Map;function M(){return T++}function A(n,t){let e=g.get(n);e||(e=document.createElement("style"),e.id=`supermouse-styles-${n}`,document.head.appendChild(e),g.set(n,e)),e.textContent=t.join(`
2
+ `)}function D(n){g.get(n)?.remove(),g.delete(n)}const y="2.5.0-beta.4";function I(n,t,e){return n+(t-n)*e}function C(n,t,e,s){return I(n,t,1-Math.exp(-e*s))}class O{static version=y;version=y;state;options;_scopes=[];_activeScope=null;_installingScope=null;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=M(),this.state={pointer:{...f},target:{...f},smooth:{...f},velocity:{x:0,y:0},displacement:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,cursorMode:this.options.cursor,pointerTarget:null,hoverTarget:null,authoredCursor: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 x(this.state,this.options,s=>{s||this.reset()},s=>this.handleActiveScopeChange(s),s=>this.resolveScopeForNode(s),()=>this.applyCursorNow()),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(i=>i.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.findScopeForPlugin(e);s&&s===this._activeScope&&s.active&&this.scopeActivatePlugin(e)}disablePlugin(t){const e=this.getPlugin(t);if(!e||e.isEnabled===!1)return;const s=this.findScopeForPlugin(e);s!==null&&s===this._activeScope&&s.active?this.deactivatePlugin(e):e.isEnabled=!1}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}setCursor(t){this._activeScope&&this.setScopeCursor(this._activeScope,t)}addScope(t){const e=this.createScope(t);return 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={...f},this.state.smooth={...f},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(s){console.error(s)}t.stage.destroy()}this._scopes=[],this.scopeByName.clear(),this.scopeHandles.clear(),this._activeScope=null,this.state.scope=null,D(this.styleOwner)}_running=!1;createScope(t){if(typeof t.container!="string"){const s=t.container;for(const i of this._scopes)if(i.containerSelector===null&&i.container===s){console.warn("[Supermouse] A scope is already registered for this container. The previous scope will no longer activate.");break}}const e=new _(t,{cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors??b,cursorPolicy:this.options.cursorPolicy?S(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),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.resolved?t.container:null},get active(){return t.active},get resolved(){return t.resolved},destroy:()=>this.destroyScope(t),setCursor:s=>this.setScopeCursor(t,s),deactivate:()=>this.deactivateScope(t),activate:()=>this.activateScope(t),use:s=>(this.installPlugin(t,s),e),removePlugin:s=>this.removePluginFromScope(t,s),getPlugin:s=>t.plugins.find(i=>i.name===s)};return e}destroyScope(t){const e=this._scopes.indexOf(t);if(e!==-1){for(const s of t.plugins)try{s.destroy?.(this)}catch(i){console.error(i)}if(t.plugins.length=0,t.stage.destroy(),this._scopes.splice(e,1),t.name&&this.scopeByName.delete(t.name),this.scopeHandles.delete(t),this._activeScope===t){const s=this.resolveScopeForNode(t.container.parentElement)??this._scopes.find(i=>i.active)??null;this.input.setActiveScope(s),this.input.clearHover(),this.applyCursorNow()}this.rebuildStylesheet()}}setScopeCursor(t,e){t.cursorMode=e,t===this._activeScope&&(this.state.cursorMode=e,this.applyCursorNow())}deactivateScope(t){if(t.active&&(t.active=!1,this._activeScope===t)){const e=this.resolveScopeForNode(t.container.parentElement)??this._scopes.find(s=>s.active)??null;this.input.setActiveScope(e),this.input.clearHover(),this.applyCursorNow()}}activateScope(t){if(t.active=!0,this._activeScope!==t&&this.input.hasSeenPointer){if(t.containerSelector!==null&&!t.resolved){const e=document.querySelectorAll(t.containerSelector);for(const s of e)if(this.input.isPointerInside(s)){t.bind(s);break}}t.resolved&&this.input.isPointerInside(t.container)&&(this.input.setActiveScope(t),this.applyCursorNow())}}resolveScopeForNode(t){for(let e=t;e;e=e.parentElement)for(const s of this._scopes)if(s.active&&s.match(e))return s.bind(e),s;return null}applyCursorNow(){const t=this._activeScope;t&&(t.stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&t.stage.setNativeCursor(this.resolveCursorState()))}findScopeForPlugin(t){for(const e of this._scopes)if(e.plugins.includes(t))return e;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)){console.warn(`[Supermouse] Plugin "${e.name}" already installed.`);return}e.isEnabled??=!0,this._installingScope=t;try{e.install?.(this)}catch(s){console.error(`[Supermouse] Failed to install plugin '${e.name}'.`,s),this._installingScope=null;return}this._installingScope=null,t.plugins.push(e),t.plugins.sort((s,i)=>(s.priority??0)-(i.priority??0)),(t!==this._activeScope||!t.active)&&e.element&&(e.element.style.display="none")}removePluginFromScope(t,e){const s=t.plugins.findIndex(o=>o.name===e);if(s===-1)return;const i=t.plugins[s];t.plugins.splice(s,1);const h=()=>{try{i.onDisable?.(this),i.destroy?.(this)}catch(o){console.error(`[Supermouse] Plugin '${e}' cleanup threw:`,o)}i.element?.remove()},r=i.onBeforeDisable?.(this);r&&typeof r.then=="function"?Promise.resolve(r).then(h).catch(o=>{console.error(`[Supermouse] Plugin '${e}' onBeforeDisable threw:`,o),h()}):h()}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(i=>{console.error(`[Supermouse] Plugin '${t.name}' onBeforeDisable threw:`,i),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(i=>{console.error(`[Supermouse] Plugin '${t.name}' onBeforeDisable threw:`,i),e()}):e()}scopeActivatePlugin(t){t.element&&(t.element.style.display=""),t.onEnable?.(this)}rebuildStylesheet(){const t=[":where(.supermouse-scope .supermouse-scope) { cursor: auto }"];for(const e of this._scopes)t.push(...e.buildRules());A(this.styleOwner,t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch(s){console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`,s),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(e){console.error(`[Supermouse] Failed to cleanup crashed plugin '${t.name}'.`,e)}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 i=this.input.getCurrentTarget();i&&!i.isConnected?this.input.clearHover():i&&this.input.parseDOMInteraction(i),this.input.isEnabled&&this.state.hasReceivedInput&&(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y);const h=this._activeScope;if(h){h.stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&h.stage.setNativeCursor(this.resolveCursorState());for(let r=0;r<h.plugins.length;r++)this.runPluginSafe(h.plugins[r],e)}if(this.cleanupCrashedPlugins(),this.input.isEnabled){const r=this.state.reducedMotion?1e3:1/this.options.smoothness*2,o=this.state.smooth.x,v=this.state.smooth.y;this.state.smooth.x=C(this.state.smooth.x,this.state.target.x,r,s),this.state.smooth.y=C(this.state.smooth.y,this.state.target.y,r,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-o)/s,this.state.velocity.y=(this.state.smooth.y-v)/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)))}registerHoverTarget(t){const e=this._installingScope??this._activeScope??this._scopes[0];if(e)for(const s of t.split(",")){const i=s.trim();i&&e.hoverSelectors.add(i)}}}u.DEFAULT_CURSOR_POLICY=p,u.DEFAULT_HOVER_SELECTORS=b,u.Supermouse=O,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.3",
3
+ "version": "2.5.0-beta.4",
4
4
  "sideEffects": false,
5
5
  "files": [
6
6
  "dist",