@supermousejs/core 2.5.0-beta.4 → 2.5.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +40 -43
- package/dist/index.d.ts +34 -36
- package/dist/index.mjs +91 -107
- package/dist/index.umd.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @supermousejs/core
|
|
2
2
|
|
|
3
|
+
## 2.5.0-beta.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d82c62d: ---
|
|
8
|
+
|
|
9
|
+
Beta.5 — cursor policy flattening, suppression simplification, and API renames.
|
|
10
|
+
|
|
11
|
+
## Changed — breaking
|
|
12
|
+
- `cursorPolicy` option renamed to `nativeCursorSelectors` and flattened to a plain `string[]`. Migration: `cursorPolicy: { native: [".x"] }` → `nativeCursorSelectors: [".x"]`. The `hide` key is gone; cursor suppression is unconditional and no longer configurable.
|
|
13
|
+
- `CursorPolicy` and `CursorPolicyInput` types removed from the public export surface. Code importing them fails at compile time. The only remaining shape is `string[]`.
|
|
14
|
+
- `DEFAULT_CURSOR_POLICY` renamed to `DEFAULT_NATIVE_CURSOR_SELECTORS`. Value reduced to `["select", "[contenteditable]"]`.
|
|
15
|
+
- `registerHoverTarget(selector)` renamed to `addHoverSelectors(selectors)`. Same behavior — comma-separated selectors are added to the current scope's shared hover set. The new name matches `hoverSelectors` and reflects that it mutates a set rather than registering a single element.
|
|
16
|
+
- `@supermousejs/utils`: `VisualConfig.selector` renamed to `hoverSelector`. Update `definePlugin({ ..., selector: "x" })` to `definePlugin({ ..., hoverSelector: "x" })`.
|
|
17
|
+
|
|
18
|
+
## Changed — behavior
|
|
19
|
+
- `input` and `textarea` removed from the default native cursor list. Text inputs and textareas are unaffected — their UA cursor is `text`, which the probe reads and treats as a fallback trigger. Button-like inputs (`<input type="button">`, `<input type="submit">`) and checkboxes/radios change: their UA cursor is `default`, which the probe classifies as non-fallback, so the custom cursor now shows over them. This matches the pre-existing treatment of `<button>`.
|
|
20
|
+
- Cursor suppression is now a single wildcard rule per scope instead of a wildcard plus per-selector rules. Behavior is unchanged — verified in Chromium and Firefox against `<a>`, `<button>`, `<input>` (all types), `<textarea>`, `<select>`, `[contenteditable]`, `[role="button"]`, `[tabindex]`, `<label>`, and a `<canvas>` with site CSS. Range slider thumb pseudo-elements retain their explicit rules (`*` does not match pseudo-elements).
|
|
21
|
+
|
|
22
|
+
## Fixed
|
|
23
|
+
- `handleMouseOut` no longer leaves `state.isHover` and `state.isNative` stale when the pointer leaves from a descendant of the tracked element. Moving from `<span>` inside `<button>` directly outside the button previously failed to clear `hoverTarget` — the containment check was inverted.
|
|
24
|
+
|
|
25
|
+
## Internal
|
|
26
|
+
- `policy.ts` removed from `@supermousejs/core`. The default moved to `constants.ts`; `normalizePolicy` dissolved into `??` fallbacks at the call sites.
|
|
27
|
+
- `Scope.hideSelectors` field removed.
|
|
28
|
+
- Size budget re-tightened to 6.2 kB gzip / 5.5 kB brotli.
|
|
29
|
+
|
|
3
30
|
## 2.5.0-beta.4
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -63,23 +63,23 @@ const mouse = new Supermouse({ plugins: [redDot] });
|
|
|
63
63
|
|
|
64
64
|
## Options
|
|
65
65
|
|
|
66
|
-
| Option | Default | Description
|
|
67
|
-
| ----------------------- | ----------------------------------------------------------------------- |
|
|
68
|
-
| `smoothness` | `0.15` | Lower = smoother cursor follow
|
|
69
|
-
| `hoverSelectors` | `["a", "button", "input", "textarea", "[data-hover]", "[data-cursor]"]` | Selectors that set `state.isHover`
|
|
70
|
-
| `enableTouch` | `false` | Allow touch events to move the cursor
|
|
71
|
-
| `autoDisableOnMobile` | `true` | Disable on coarse-pointer devices
|
|
72
|
-
| `cursor` | `"auto"` | `"auto"`, `"custom"`, `"native"`, or `"both"`
|
|
73
|
-
| `cursorPolicy` | `DEFAULT_CURSOR_POLICY` | Rules for native-cursor fallback and CSS suppression
|
|
74
|
-
| `inheritDataAttributes` | `true` | Cascade `data-*` attributes and `rules` from ancestors
|
|
75
|
-
| `hideOnLeave` | `true` | Hide when the pointer leaves the window
|
|
76
|
-
| `container` | `document.body` | Primary scope's container
|
|
77
|
-
| `scopes` | — | Additional scopes registered at construction
|
|
78
|
-
| `zIndex` | `9999` | Stage stacking order
|
|
79
|
-
| `dataPrefix` | `"supermouse"` | Prefix for data attributes
|
|
80
|
-
| `rules` | — | Map of selectors to interaction data
|
|
81
|
-
| `plugins` | — | Plugins to install at creation
|
|
82
|
-
| `autoStart` | `true` | Set `false` and call `.start()` manually
|
|
66
|
+
| Option | Default | Description |
|
|
67
|
+
| ----------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
68
|
+
| `smoothness` | `0.15` | Lower = smoother cursor follow |
|
|
69
|
+
| `hoverSelectors` | `["a", "button", "input", "textarea", "[data-hover]", "[data-cursor]"]` | Selectors that set `state.isHover` |
|
|
70
|
+
| `enableTouch` | `false` | Allow touch events to move the cursor |
|
|
71
|
+
| `autoDisableOnMobile` | `true` | Disable on coarse-pointer devices |
|
|
72
|
+
| `cursor` | `"auto"` | `"auto"`, `"custom"`, `"native"`, or `"both"` |
|
|
73
|
+
| `cursorPolicy` | `DEFAULT_CURSOR_POLICY` | Rules for native-cursor fallback and CSS suppression |
|
|
74
|
+
| `inheritDataAttributes` | `true` | Cascade `data-*` attributes and `rules` from ancestors |
|
|
75
|
+
| `hideOnLeave` | `true` | Hide when the pointer leaves the window |
|
|
76
|
+
| `container` | `document.body` | Primary scope's container |
|
|
77
|
+
| `scopes` | — | Additional scopes registered at construction |
|
|
78
|
+
| `zIndex` | `9999` | Stage stacking order |
|
|
79
|
+
| `dataPrefix` | `"supermouse"` | Prefix for data attributes |
|
|
80
|
+
| `rules` | — | Map of selectors to interaction data |
|
|
81
|
+
| `plugins` | — | Plugins to install at creation |
|
|
82
|
+
| `autoStart` | `true` | Set `false` and call `.start()` manually |
|
|
83
83
|
|
|
84
84
|
## Cursor Modes
|
|
85
85
|
|
|
@@ -108,10 +108,7 @@ import { Supermouse, DEFAULT_CURSOR_POLICY } from "@supermousejs/core";
|
|
|
108
108
|
|
|
109
109
|
const mouse = new Supermouse({
|
|
110
110
|
cursorPolicy: {
|
|
111
|
-
rules: [
|
|
112
|
-
...DEFAULT_CURSOR_POLICY.rules,
|
|
113
|
-
{ selector: "[data-native]", native: true }
|
|
114
|
-
]
|
|
111
|
+
rules: [...DEFAULT_CURSOR_POLICY.rules, { selector: "[data-native]", native: true }]
|
|
115
112
|
}
|
|
116
113
|
});
|
|
117
114
|
```
|
|
@@ -183,32 +180,32 @@ Rules match ancestors as well as the hovered element. HTML `data-*` attributes o
|
|
|
183
180
|
## API
|
|
184
181
|
|
|
185
182
|
```ts
|
|
186
|
-
mouse.state;
|
|
187
|
-
mouse.options;
|
|
188
|
-
mouse.stage;
|
|
189
|
-
mouse.container;
|
|
190
|
-
mouse.isEnabled;
|
|
191
|
-
mouse.isRunning;
|
|
192
|
-
|
|
193
|
-
mouse.enable();
|
|
194
|
-
mouse.disable();
|
|
183
|
+
mouse.state; // current MouseState
|
|
184
|
+
mouse.options; // resolved options
|
|
185
|
+
mouse.stage; // DOM element plugins render into
|
|
186
|
+
mouse.container; // container element (active scope)
|
|
187
|
+
mouse.isEnabled; // input processing flag
|
|
188
|
+
mouse.isRunning; // animation loop flag
|
|
189
|
+
|
|
190
|
+
mouse.enable(); // start input, apply cursor state
|
|
191
|
+
mouse.disable(); // stop input, restore native cursor
|
|
195
192
|
mouse.disable({ reset: true }); // also reset physics and hover state
|
|
196
|
-
mouse.reset();
|
|
193
|
+
mouse.reset(); // reset state only
|
|
197
194
|
|
|
198
|
-
mouse.setCursor(mode);
|
|
195
|
+
mouse.setCursor(mode); // "auto" | "custom" | "native" | "both"
|
|
199
196
|
|
|
200
|
-
mouse.addScope(config);
|
|
197
|
+
mouse.addScope(config); // -> { name, container, setCursor, remove }
|
|
201
198
|
|
|
202
|
-
mouse.use(plugin);
|
|
203
|
-
mouse.getPlugin(name);
|
|
204
|
-
mouse.enablePlugin(name);
|
|
205
|
-
mouse.disablePlugin(name);
|
|
206
|
-
mouse.togglePlugin(name);
|
|
199
|
+
mouse.use(plugin); // install plugin
|
|
200
|
+
mouse.getPlugin(name); // retrieve plugin
|
|
201
|
+
mouse.enablePlugin(name); // enable plugin
|
|
202
|
+
mouse.disablePlugin(name); // disable plugin
|
|
203
|
+
mouse.togglePlugin(name); // toggle plugin
|
|
207
204
|
|
|
208
|
-
mouse.
|
|
209
|
-
mouse.start();
|
|
210
|
-
mouse.step(time);
|
|
211
|
-
mouse.destroy();
|
|
205
|
+
mouse.addHoverSelector(sel); // add hover selector at runtime
|
|
206
|
+
mouse.start(); // start animation loop
|
|
207
|
+
mouse.step(time); // advance one frame manually
|
|
208
|
+
mouse.destroy(); // destroy instance and plugins
|
|
212
209
|
```
|
|
213
210
|
|
|
214
211
|
## Browser Support
|
|
@@ -217,4 +214,4 @@ All modern browsers.
|
|
|
217
214
|
|
|
218
215
|
## License
|
|
219
216
|
|
|
220
|
-
MIT
|
|
217
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,35 +1,23 @@
|
|
|
1
1
|
/** Overall cursor mode. */
|
|
2
2
|
export declare type CursorMode = "auto" | "custom" | "native" | "both";
|
|
3
3
|
|
|
4
|
+
export declare const DEFAULT_HOVER_SELECTORS: string[];
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
|
-
*
|
|
7
|
+
* Selectors whose elements yield to the OS cursor in `"auto"` mode.
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* The engine emits one wildcard rule per scope that suppresses the native
|
|
10
|
+
* cursor over every element (with `!important`, exclusions, and the probe
|
|
11
|
+
* attribute opt-out). This list is the exception: elements matching these
|
|
12
|
+
* selectors override the wildcard and let the OS cursor through.
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* `input` and `textarea` are not listed. Their UA cursor is `text`, which
|
|
15
|
+
* is not in `SUPERMOUSE_CURSORS`, so the probe already treats them as
|
|
16
|
+
* fallback candidates. `select` and `[contenteditable]` have UA cursors
|
|
17
|
+
* (`default`, `auto`) that the probe classifies as non-fallback, so they
|
|
18
|
+
* need explicit entries.
|
|
15
19
|
*/
|
|
16
|
-
export declare
|
|
17
|
-
native: string[];
|
|
18
|
-
hide: string[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Shorthand accepted at the public API boundary. `{ native?: [...], hide?: [...] }`
|
|
23
|
-
* normalizes to the full `CursorPolicy` shape with missing keys defaulting to `[]`.
|
|
24
|
-
*/
|
|
25
|
-
export declare type CursorPolicyInput = CursorPolicy | {
|
|
26
|
-
native?: string[];
|
|
27
|
-
hide?: string[];
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export declare const DEFAULT_CURSOR_POLICY: CursorPolicy;
|
|
31
|
-
|
|
32
|
-
export declare const DEFAULT_HOVER_SELECTORS: string[];
|
|
20
|
+
export declare const DEFAULT_NATIVE_CURSOR_SELECTORS: string[];
|
|
33
21
|
|
|
34
22
|
/**
|
|
35
23
|
* Interaction state consumed by plugins.
|
|
@@ -126,8 +114,11 @@ export declare interface ScopeConfig {
|
|
|
126
114
|
cursor?: CursorMode;
|
|
127
115
|
/** Hover selectors for this scope. Inherits from top-level if omitted. */
|
|
128
116
|
hoverSelectors?: string[];
|
|
129
|
-
/**
|
|
130
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Selectors whose elements yield to the OS cursor in `"auto"` mode.
|
|
119
|
+
* Defaults to `DEFAULT_NATIVE_CURSOR_SELECTORS`.
|
|
120
|
+
*/
|
|
121
|
+
nativeCursorSelectors?: string[];
|
|
131
122
|
/** Plugins installed when this scope activates. */
|
|
132
123
|
plugins?: SupermousePlugin[];
|
|
133
124
|
/**
|
|
@@ -313,12 +304,21 @@ export declare class Supermouse {
|
|
|
313
304
|
private bindVisibilityHandling;
|
|
314
305
|
private startLoop;
|
|
315
306
|
/**
|
|
316
|
-
* Adds one or more hover selectors to the current scope
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
307
|
+
* Adds one or more hover selectors to the current scope's shared set.
|
|
308
|
+
*
|
|
309
|
+
* During a plugin's `install()`, writes to that plugin's owning scope.
|
|
310
|
+
* At runtime, writes to the currently active scope. All plugins in the
|
|
311
|
+
* scope share one selector set: `state.hoverTarget` is the innermost
|
|
312
|
+
* element matching any registered selector, so two plugins that
|
|
313
|
+
* register different granularities (e.g. `a` vs `p`) receive the same
|
|
314
|
+
* `hoverTarget` — the innermost match.
|
|
315
|
+
*
|
|
316
|
+
* Prefer the `hoverSelectors` option at construction for static cases,
|
|
317
|
+
* or a visual plugin's `hoverSelector` field for plugins that need
|
|
318
|
+
* their own contribution. Use this method for dynamic registration —
|
|
319
|
+
* elements that mount after construction.
|
|
320
320
|
*/
|
|
321
|
-
|
|
321
|
+
addHoverSelectors(selectors: string): void;
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
export declare type SupermouseInstance = Supermouse;
|
|
@@ -354,10 +354,8 @@ export declare interface SupermouseOptions {
|
|
|
354
354
|
* @default "auto"
|
|
355
355
|
*/
|
|
356
356
|
cursor?: CursorMode;
|
|
357
|
-
/**
|
|
358
|
-
|
|
359
|
-
*/
|
|
360
|
-
cursorPolicy?: CursorPolicyInput;
|
|
357
|
+
/** Native cursor selectors for this scope. Inherits from top-level if omitted. */
|
|
358
|
+
nativeCursorSelectors?: string[];
|
|
361
359
|
/**
|
|
362
360
|
* Additional scopes registered at construction. The primary scope is
|
|
363
361
|
* created from the top-level `container` / `hoverSelectors` / `plugins`
|
package/dist/index.mjs
CHANGED
|
@@ -1,25 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
hide: [
|
|
4
|
-
"input",
|
|
5
|
-
"textarea",
|
|
6
|
-
"select",
|
|
7
|
-
"[contenteditable]",
|
|
8
|
-
"a",
|
|
9
|
-
"button",
|
|
10
|
-
'[role="button"]',
|
|
11
|
-
"[tabindex]",
|
|
12
|
-
"label"
|
|
13
|
-
]
|
|
14
|
-
};
|
|
15
|
-
function b(n) {
|
|
16
|
-
return n ? {
|
|
17
|
-
native: n.native ?? [],
|
|
18
|
-
hide: n.hide ?? []
|
|
19
|
-
} : S;
|
|
20
|
-
}
|
|
21
|
-
let y = 0;
|
|
22
|
-
class C {
|
|
1
|
+
let S = 0;
|
|
2
|
+
class b {
|
|
23
3
|
element;
|
|
24
4
|
scopeClass;
|
|
25
5
|
hideClass;
|
|
@@ -37,7 +17,7 @@ class C {
|
|
|
37
17
|
!t.isConnected && !s && console.warn(
|
|
38
18
|
"[Supermouse] container is not attached to the document — stage sizing/positioning will be wrong until it is."
|
|
39
19
|
);
|
|
40
|
-
const i =
|
|
20
|
+
const i = S++;
|
|
41
21
|
this.scopeClass = `supermouse-scope-${i}`, this.hideClass = `supermouse-hide-${i}`, this.element = document.createElement("div"), Object.assign(this.element.style, {
|
|
42
22
|
position: "absolute",
|
|
43
23
|
inset: "0px",
|
|
@@ -92,13 +72,11 @@ class C {
|
|
|
92
72
|
this._detach();
|
|
93
73
|
}
|
|
94
74
|
}
|
|
95
|
-
class
|
|
75
|
+
class y {
|
|
96
76
|
constructor(t, e) {
|
|
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
|
-
|
|
99
|
-
this.
|
|
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 C(i, t.zIndex ?? e.zIndex);
|
|
77
|
+
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, this.nativeSelectors = t.nativeCursorSelectors ?? e.nativeCursorSelectors;
|
|
78
|
+
let s;
|
|
79
|
+
typeof t.container == "string" ? (this.containerSelector = t.container, this._bound = !1, s = document.createElement("div"), s.setAttribute("data-supermouse-placeholder", "")) : (this.containerSelector = null, this._bound = !0, s = t.container), this.stage = new b(s, t.zIndex ?? e.zIndex);
|
|
102
80
|
}
|
|
103
81
|
config;
|
|
104
82
|
stage;
|
|
@@ -111,7 +89,6 @@ class P {
|
|
|
111
89
|
hoverSelectors;
|
|
112
90
|
plugins = [];
|
|
113
91
|
nativeSelectors;
|
|
114
|
-
hideSelectors;
|
|
115
92
|
inheritDataAttributes;
|
|
116
93
|
ruleEntries;
|
|
117
94
|
name;
|
|
@@ -159,20 +136,18 @@ class P {
|
|
|
159
136
|
return this.nativeSelectors.join(", ");
|
|
160
137
|
}
|
|
161
138
|
buildRules() {
|
|
162
|
-
const t = this.stage.getRulePrefix(), e = this.stage.getExclusion(), s = ":not([data-sm-probe])"
|
|
139
|
+
const t = this.stage.getRulePrefix(), e = this.stage.getExclusion(), s = ":not([data-sm-probe])";
|
|
140
|
+
return [
|
|
163
141
|
`${t}${e}${s} { cursor: none !important; }`,
|
|
164
|
-
`${t} *${e}${s} { cursor: none !important; }
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return i.push(
|
|
169
|
-
`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`
|
|
170
|
-
), i.push(
|
|
142
|
+
`${t} *${e}${s} { cursor: none !important; }`,
|
|
143
|
+
`${t} *${e}${s} { cursor: none !important; }`,
|
|
144
|
+
// Pseudo-elements are not matched by `*`; they need explicit rules.
|
|
145
|
+
`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`,
|
|
171
146
|
`${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`
|
|
172
|
-
|
|
147
|
+
];
|
|
173
148
|
}
|
|
174
149
|
}
|
|
175
|
-
const d = { x: -100, y: -100 },
|
|
150
|
+
const d = { x: -100, y: -100 }, C = /* @__PURE__ */ new Set([
|
|
176
151
|
"default",
|
|
177
152
|
"auto",
|
|
178
153
|
"pointer",
|
|
@@ -180,7 +155,7 @@ const d = { x: -100, y: -100 }, E = /* @__PURE__ */ new Set([
|
|
|
180
155
|
"inherit",
|
|
181
156
|
"grab",
|
|
182
157
|
"grabbing"
|
|
183
|
-
]),
|
|
158
|
+
]), P = ["select", "[contenteditable]"], E = [
|
|
184
159
|
"a",
|
|
185
160
|
"button",
|
|
186
161
|
"input",
|
|
@@ -188,9 +163,9 @@ const d = { x: -100, y: -100 }, E = /* @__PURE__ */ new Set([
|
|
|
188
163
|
"[data-hover]",
|
|
189
164
|
"[data-cursor]"
|
|
190
165
|
];
|
|
191
|
-
class
|
|
192
|
-
constructor(t, e, s, i, h,
|
|
193
|
-
this.state = t, this.options = e, this.onEnableChange = s, this.onActiveScopeChange = i, this.resolveScope = h, this.onHoverSettled =
|
|
166
|
+
class _ {
|
|
167
|
+
constructor(t, e, s, i, h, o) {
|
|
168
|
+
this.state = t, this.options = e, this.onEnableChange = s, this.onActiveScopeChange = i, this.resolveScope = h, this.onHoverSettled = o, this.dataPrefix = e.dataPrefix ?? "supermouse", this.normalizedDataPrefix = this.dataPrefix.toLowerCase(), this.ignoreAttribute = `data-${this.dataPrefix}-ignore`, this.checkDeviceCapability(), this.checkMotionPreference(), this.bindEvents();
|
|
194
169
|
}
|
|
195
170
|
state;
|
|
196
171
|
options;
|
|
@@ -248,40 +223,40 @@ class w {
|
|
|
248
223
|
const e = this.activeScope.container, s = this.activeScope.inheritDataAttributes, i = this.normalizedDataPrefix, h = this.activeScope.ruleEntries;
|
|
249
224
|
if (t !== this.lastParsedTarget) {
|
|
250
225
|
this.lastParsedTarget = t, this.cachedChain = [];
|
|
251
|
-
let
|
|
252
|
-
for (;
|
|
226
|
+
let n = t;
|
|
227
|
+
for (; n; ) {
|
|
253
228
|
const p = [];
|
|
254
|
-
for (const [
|
|
255
|
-
this.matchesSelector(
|
|
256
|
-
if (this.cachedChain.push({ element:
|
|
257
|
-
const c =
|
|
229
|
+
for (const [r, l] of h)
|
|
230
|
+
this.matchesSelector(n, r) && p.push({ selector: r, rules: l });
|
|
231
|
+
if (this.cachedChain.push({ element: n, matchedRules: p }), !s || n === e) break;
|
|
232
|
+
const c = n.parentElement;
|
|
258
233
|
if (!c || !e.contains(c)) break;
|
|
259
|
-
|
|
234
|
+
n = c;
|
|
260
235
|
}
|
|
261
236
|
}
|
|
262
|
-
const
|
|
263
|
-
for (const { element:
|
|
237
|
+
const o = {};
|
|
238
|
+
for (const { element: n, matchedRules: p } of this.cachedChain) {
|
|
264
239
|
const c = {};
|
|
265
|
-
for (const { rules:
|
|
240
|
+
for (const { rules: r } of p)
|
|
266
241
|
try {
|
|
267
|
-
const l = typeof
|
|
242
|
+
const l = typeof r == "function" ? r(n) : r;
|
|
268
243
|
if (!l || typeof l != "object") continue;
|
|
269
244
|
for (const [v, u] of Object.entries(l))
|
|
270
|
-
c[v] = typeof u == "function" ? u(
|
|
245
|
+
c[v] = typeof u == "function" ? u(n) : u;
|
|
271
246
|
} catch (l) {
|
|
272
247
|
console.error("[Supermouse] Rule threw during evaluation:", l);
|
|
273
248
|
}
|
|
274
|
-
for (const
|
|
275
|
-
if (!
|
|
276
|
-
const l =
|
|
249
|
+
for (const r in n.dataset) {
|
|
250
|
+
if (!r.toLowerCase().startsWith(i)) continue;
|
|
251
|
+
const l = r.slice(i.length);
|
|
277
252
|
if (!l) continue;
|
|
278
|
-
const v = l[0].toLowerCase() + l.slice(1), u =
|
|
253
|
+
const v = l[0].toLowerCase() + l.slice(1), u = n.dataset[r];
|
|
279
254
|
c[v] = u == null || u === "" ? !0 : u;
|
|
280
255
|
}
|
|
281
|
-
for (const [
|
|
282
|
-
|
|
256
|
+
for (const [r, l] of Object.entries(c))
|
|
257
|
+
r in o || (o[r] = l);
|
|
283
258
|
}
|
|
284
|
-
this.state.interaction =
|
|
259
|
+
this.state.interaction = o;
|
|
285
260
|
}
|
|
286
261
|
matchesSelector(t, e) {
|
|
287
262
|
try {
|
|
@@ -335,13 +310,13 @@ class w {
|
|
|
335
310
|
this.state.isNative = !0, this.nativeTarget = t;
|
|
336
311
|
return;
|
|
337
312
|
}
|
|
338
|
-
(t.isContentEditable || !
|
|
313
|
+
(t.isContentEditable || !C.has(e)) && (this.state.isNative = !0, this.nativeTarget = t);
|
|
339
314
|
}
|
|
340
315
|
}
|
|
341
316
|
handleMouseOut = (t) => {
|
|
342
317
|
if (!this.isEnabled) return;
|
|
343
318
|
const e = t.target, s = t.relatedTarget;
|
|
344
|
-
(e === this.state.hoverTarget ||
|
|
319
|
+
(e === this.state.hoverTarget || this.state.hoverTarget?.contains(e)) && (!s || !this.state.hoverTarget?.contains(s)) && (this.state.isHover = !1, this.state.hoverTarget = null), this.nativeTarget && (e === this.nativeTarget || this.nativeTarget.contains(e)) && (!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 });
|
|
345
320
|
};
|
|
346
321
|
clearHover() {
|
|
347
322
|
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 = [];
|
|
@@ -357,27 +332,27 @@ class w {
|
|
|
357
332
|
this.abortController.abort(), this.cachedChain = [];
|
|
358
333
|
}
|
|
359
334
|
}
|
|
360
|
-
let
|
|
335
|
+
let w = 0;
|
|
361
336
|
const f = /* @__PURE__ */ new Map();
|
|
362
|
-
function
|
|
363
|
-
return
|
|
337
|
+
function x() {
|
|
338
|
+
return w++;
|
|
364
339
|
}
|
|
365
|
-
function
|
|
366
|
-
let e = f.get(
|
|
367
|
-
e || (e = document.createElement("style"), e.id = `supermouse-styles-${
|
|
340
|
+
function T(a, t) {
|
|
341
|
+
let e = f.get(a);
|
|
342
|
+
e || (e = document.createElement("style"), e.id = `supermouse-styles-${a}`, document.head.appendChild(e), f.set(a, e)), e.textContent = t.join(`
|
|
368
343
|
`);
|
|
369
344
|
}
|
|
370
|
-
function
|
|
371
|
-
f.get(
|
|
345
|
+
function M(a) {
|
|
346
|
+
f.get(a)?.remove(), f.delete(a);
|
|
372
347
|
}
|
|
373
|
-
const g = "2.5.0-beta.
|
|
374
|
-
function
|
|
375
|
-
return
|
|
348
|
+
const g = "2.5.0-beta.5";
|
|
349
|
+
function A(a, t, e) {
|
|
350
|
+
return a + (t - a) * e;
|
|
376
351
|
}
|
|
377
|
-
function m(
|
|
378
|
-
return
|
|
352
|
+
function m(a, t, e, s) {
|
|
353
|
+
return A(a, t, 1 - Math.exp(-e * s));
|
|
379
354
|
}
|
|
380
|
-
class
|
|
355
|
+
class D {
|
|
381
356
|
static version = g;
|
|
382
357
|
version = g;
|
|
383
358
|
state;
|
|
@@ -406,7 +381,7 @@ class I {
|
|
|
406
381
|
zIndex: 9999,
|
|
407
382
|
inheritDataAttributes: !0,
|
|
408
383
|
...t
|
|
409
|
-
}, this.styleOwner =
|
|
384
|
+
}, this.styleOwner = x(), this.state = {
|
|
410
385
|
pointer: { ...d },
|
|
411
386
|
target: { ...d },
|
|
412
387
|
smooth: { ...d },
|
|
@@ -430,12 +405,12 @@ class I {
|
|
|
430
405
|
container: this.options.container,
|
|
431
406
|
cursor: this.options.cursor,
|
|
432
407
|
hoverSelectors: this.options.hoverSelectors,
|
|
433
|
-
|
|
408
|
+
nativeCursorSelectors: this.options.nativeCursorSelectors,
|
|
434
409
|
plugins: this.options.plugins,
|
|
435
410
|
rules: this.options.rules,
|
|
436
411
|
zIndex: this.options.zIndex
|
|
437
412
|
});
|
|
438
|
-
if (this.input = new
|
|
413
|
+
if (this.input = new _(
|
|
439
414
|
this.state,
|
|
440
415
|
this.options,
|
|
441
416
|
(s) => {
|
|
@@ -554,7 +529,7 @@ class I {
|
|
|
554
529
|
}
|
|
555
530
|
t.stage.destroy();
|
|
556
531
|
}
|
|
557
|
-
this._scopes = [], this.scopeByName.clear(), this.scopeHandles.clear(), this._activeScope = null, this.state.scope = null,
|
|
532
|
+
this._scopes = [], this.scopeByName.clear(), this.scopeHandles.clear(), this._activeScope = null, this.state.scope = null, M(this.styleOwner);
|
|
558
533
|
}
|
|
559
534
|
// ─── Internal ───
|
|
560
535
|
_running = !1;
|
|
@@ -569,10 +544,10 @@ class I {
|
|
|
569
544
|
break;
|
|
570
545
|
}
|
|
571
546
|
}
|
|
572
|
-
const e = new
|
|
547
|
+
const e = new y(t, {
|
|
573
548
|
cursor: this.options.cursor,
|
|
574
|
-
hoverSelectors: this.options.hoverSelectors ??
|
|
575
|
-
|
|
549
|
+
hoverSelectors: this.options.hoverSelectors ?? E,
|
|
550
|
+
nativeCursorSelectors: this.options.nativeCursorSelectors ?? P,
|
|
576
551
|
zIndex: this.options.zIndex,
|
|
577
552
|
inheritDataAttributes: this.options.inheritDataAttributes,
|
|
578
553
|
ruleEntries: this.options.rules ? Object.entries(this.options.rules) : []
|
|
@@ -705,20 +680,20 @@ class I {
|
|
|
705
680
|
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");
|
|
706
681
|
}
|
|
707
682
|
removePluginFromScope(t, e) {
|
|
708
|
-
const s = t.plugins.findIndex((
|
|
683
|
+
const s = t.plugins.findIndex((n) => n.name === e);
|
|
709
684
|
if (s === -1) return;
|
|
710
685
|
const i = t.plugins[s];
|
|
711
686
|
t.plugins.splice(s, 1);
|
|
712
687
|
const h = () => {
|
|
713
688
|
try {
|
|
714
689
|
i.onDisable?.(this), i.destroy?.(this);
|
|
715
|
-
} catch (
|
|
716
|
-
console.error(`[Supermouse] Plugin '${e}' cleanup threw:`,
|
|
690
|
+
} catch (n) {
|
|
691
|
+
console.error(`[Supermouse] Plugin '${e}' cleanup threw:`, n);
|
|
717
692
|
}
|
|
718
693
|
i.element?.remove();
|
|
719
|
-
},
|
|
720
|
-
|
|
721
|
-
console.error(`[Supermouse] Plugin '${e}' onBeforeDisable threw:`,
|
|
694
|
+
}, o = i.onBeforeDisable?.(this);
|
|
695
|
+
o && typeof o.then == "function" ? Promise.resolve(o).then(h).catch((n) => {
|
|
696
|
+
console.error(`[Supermouse] Plugin '${e}' onBeforeDisable threw:`, n), h();
|
|
722
697
|
}) : h();
|
|
723
698
|
}
|
|
724
699
|
handleActiveScopeChange(t) {
|
|
@@ -764,7 +739,7 @@ class I {
|
|
|
764
739
|
rebuildStylesheet() {
|
|
765
740
|
const t = [":where(.supermouse-scope .supermouse-scope) { cursor: auto }"];
|
|
766
741
|
for (const e of this._scopes) t.push(...e.buildRules());
|
|
767
|
-
|
|
742
|
+
T(this.styleOwner, t);
|
|
768
743
|
}
|
|
769
744
|
runPluginSafe(t, e) {
|
|
770
745
|
if (t.isEnabled !== !1)
|
|
@@ -811,14 +786,14 @@ class I {
|
|
|
811
786
|
const h = this._activeScope;
|
|
812
787
|
if (h) {
|
|
813
788
|
h.stage.setVisibility(this.resolveStageVisibility()), this.input.isEnabled && h.stage.setNativeCursor(this.resolveCursorState());
|
|
814
|
-
for (let
|
|
815
|
-
this.runPluginSafe(h.plugins[
|
|
789
|
+
for (let o = 0; o < h.plugins.length; o++)
|
|
790
|
+
this.runPluginSafe(h.plugins[o], e);
|
|
816
791
|
}
|
|
817
792
|
if (this.cleanupCrashedPlugins(), this.input.isEnabled) {
|
|
818
|
-
const
|
|
819
|
-
this.state.smooth.x = m(this.state.smooth.x, this.state.target.x,
|
|
820
|
-
const { x: c, y:
|
|
821
|
-
(Math.abs(c) > 0.1 || Math.abs(
|
|
793
|
+
const o = this.state.reducedMotion ? 1e3 : 1 / this.options.smoothness * 2, n = this.state.smooth.x, p = this.state.smooth.y;
|
|
794
|
+
this.state.smooth.x = m(this.state.smooth.x, this.state.target.x, o, s), this.state.smooth.y = m(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 - n) / s, this.state.velocity.y = (this.state.smooth.y - p) / s) : (this.state.velocity.x = 0, this.state.velocity.y = 0);
|
|
795
|
+
const { x: c, y: r } = this.state.velocity;
|
|
796
|
+
(Math.abs(c) > 0.1 || Math.abs(r) > 0.1) && (this.state.angle = Math.atan2(r, c) * (180 / Math.PI));
|
|
822
797
|
}
|
|
823
798
|
}
|
|
824
799
|
tick = (t) => {
|
|
@@ -837,12 +812,21 @@ class I {
|
|
|
837
812
|
this._running || (this._running = !0, !document.hidden && (this.lastTime = performance.now(), this.rafId = requestAnimationFrame(this.tick)));
|
|
838
813
|
}
|
|
839
814
|
/**
|
|
840
|
-
* Adds one or more hover selectors to the current scope
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
815
|
+
* Adds one or more hover selectors to the current scope's shared set.
|
|
816
|
+
*
|
|
817
|
+
* During a plugin's `install()`, writes to that plugin's owning scope.
|
|
818
|
+
* At runtime, writes to the currently active scope. All plugins in the
|
|
819
|
+
* scope share one selector set: `state.hoverTarget` is the innermost
|
|
820
|
+
* element matching any registered selector, so two plugins that
|
|
821
|
+
* register different granularities (e.g. `a` vs `p`) receive the same
|
|
822
|
+
* `hoverTarget` — the innermost match.
|
|
823
|
+
*
|
|
824
|
+
* Prefer the `hoverSelectors` option at construction for static cases,
|
|
825
|
+
* or a visual plugin's `hoverSelector` field for plugins that need
|
|
826
|
+
* their own contribution. Use this method for dynamic registration —
|
|
827
|
+
* elements that mount after construction.
|
|
844
828
|
*/
|
|
845
|
-
|
|
829
|
+
addHoverSelectors(t) {
|
|
846
830
|
const e = this._installingScope ?? this._activeScope ?? this._scopes[0];
|
|
847
831
|
if (e)
|
|
848
832
|
for (const s of t.split(",")) {
|
|
@@ -852,7 +836,7 @@ class I {
|
|
|
852
836
|
}
|
|
853
837
|
}
|
|
854
838
|
export {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
839
|
+
E as DEFAULT_HOVER_SELECTORS,
|
|
840
|
+
P as DEFAULT_NATIVE_CURSOR_SELECTORS,
|
|
841
|
+
D as Supermouse
|
|
858
842
|
};
|
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=":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"})}));
|
|
1
|
+
(function(u,v){typeof exports=="object"&&typeof module<"u"?v(exports):typeof define=="function"&&define.amd?define(["exports"],v):(u=typeof globalThis<"u"?globalThis:u||self,v(u.SupermouseCore={}))})(this,(function(u){"use strict";let v=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=v++;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 P{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,this.nativeSelectors=t.nativeCursorSelectors??e.nativeCursorSelectors;let s;typeof t.container=="string"?(this.containerSelector=t.container,this._bound=!1,s=document.createElement("div"),s.setAttribute("data-supermouse-placeholder","")):(this.containerSelector=null,this._bound=!0,s=t.container),this.stage=new E(s,t.zIndex??e.zIndex)}config;stage;containerSelector;hoverSelectors;plugins=[];nativeSelectors;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])";return[`${t}${e}${s} { cursor: none !important; }`,`${t} *${e}${s} { cursor: none !important; }`,`${t} *${e}${s} { cursor: none !important; }`,`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`,`${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`]}}const d={x:-100,y:-100},_=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),S=["select","[contenteditable]"],b=["a","button","input","textarea","[data-hover]","[data-cursor]"];class w{constructor(t,e,s,i,h,o){this.state=t,this.options=e,this.onEnableChange=s,this.onActiveScopeChange=i,this.resolveScope=h,this.onHoverSettled=o,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 n=t;for(;n;){const f=[];for(const[r,l]of h)this.matchesSelector(n,r)&&f.push({selector:r,rules:l});if(this.cachedChain.push({element:n,matchedRules:f}),!s||n===e)break;const c=n.parentElement;if(!c||!e.contains(c))break;n=c}}const o={};for(const{element:n,matchedRules:f}of this.cachedChain){const c={};for(const{rules:r}of f)try{const l=typeof r=="function"?r(n):r;if(!l||typeof l!="object")continue;for(const[m,p]of Object.entries(l))c[m]=typeof p=="function"?p(n):p}catch(l){console.error("[Supermouse] Rule threw during evaluation:",l)}for(const r in n.dataset){if(!r.toLowerCase().startsWith(i))continue;const l=r.slice(i.length);if(!l)continue;const m=l[0].toLowerCase()+l.slice(1),p=n.dataset[r];c[m]=p==null||p===""?!0:p}for(const[r,l]of Object.entries(c))r in o||(o[r]=l)}this.state.interaction=o}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||!_.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||this.state.hoverTarget?.contains(e))&&(!s||!this.state.hoverTarget?.contains(s))&&(this.state.isHover=!1,this.state.hoverTarget=null),this.nativeTarget&&(e===this.nativeTarget||this.nativeTarget.contains(e))&&(!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})};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 x=0;const g=new Map;function T(){return x++}function M(a,t){let e=g.get(a);e||(e=document.createElement("style"),e.id=`supermouse-styles-${a}`,document.head.appendChild(e),g.set(a,e)),e.textContent=t.join(`
|
|
2
|
+
`)}function A(a){g.get(a)?.remove(),g.delete(a)}const y="2.5.0-beta.5";function D(a,t,e){return a+(t-a)*e}function C(a,t,e,s){return D(a,t,1-Math.exp(-e*s))}class I{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=T(),this.state={pointer:{...d},target:{...d},smooth:{...d},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,nativeCursorSelectors:this.options.nativeCursorSelectors,plugins:this.options.plugins,rules:this.options.rules,zIndex:this.options.zIndex});if(this.input=new w(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={...d},this.state.smooth={...d},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,A(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 P(t,{cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors??b,nativeCursorSelectors:this.options.nativeCursorSelectors??S,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(n=>n.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(n){console.error(`[Supermouse] Plugin '${e}' cleanup threw:`,n)}i.element?.remove()},o=i.onBeforeDisable?.(this);o&&typeof o.then=="function"?Promise.resolve(o).then(h).catch(n=>{console.error(`[Supermouse] Plugin '${e}' onBeforeDisable threw:`,n),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());M(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 o=0;o<h.plugins.length;o++)this.runPluginSafe(h.plugins[o],e)}if(this.cleanupCrashedPlugins(),this.input.isEnabled){const o=this.state.reducedMotion?1e3:1/this.options.smoothness*2,n=this.state.smooth.x,f=this.state.smooth.y;this.state.smooth.x=C(this.state.smooth.x,this.state.target.x,o,s),this.state.smooth.y=C(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-n)/s,this.state.velocity.y=(this.state.smooth.y-f)/s):(this.state.velocity.x=0,this.state.velocity.y=0);const{x:c,y:r}=this.state.velocity;(Math.abs(c)>.1||Math.abs(r)>.1)&&(this.state.angle=Math.atan2(r,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)))}addHoverSelectors(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_HOVER_SELECTORS=b,u.DEFAULT_NATIVE_CURSOR_SELECTORS=S,u.Supermouse=I,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})}));
|