@supermousejs/core 2.4.2 → 2.4.3
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 +6 -0
- package/README.md +70 -246
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -5,330 +5,154 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
<img src="https://raw.githubusercontent.com/Whitestar14/supermouse-js/main/docs/public/favicon.svg" width="180" height="180">
|
|
10
|
-
</div>
|
|
8
|
+
Supermouse is a headless, physics‑based cursor engine for the web written in TypeScript. It provides pointer tracking, state, physics, and a plugin lifecycle. You install plugins (or write your own) to render custom cursors and effects. The core is zero‑dependency and TypeScript‑first.
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
[Documentation](https://supermouse.js.org) | [Examples](https://supermouse.js.org/docs/guide/cookbook) | [License](#license)
|
|
10
|
+
**Documentation:** [supermouse.js.org](https://supermouse.js.org)
|
|
15
11
|
|
|
16
12
|
## Installation
|
|
17
13
|
|
|
18
14
|
```bash
|
|
19
15
|
pnpm add @supermousejs/core
|
|
20
|
-
|
|
21
16
|
npm install @supermousejs/core
|
|
22
17
|
```
|
|
23
18
|
|
|
24
|
-
Install
|
|
19
|
+
Install plugins you need:
|
|
25
20
|
|
|
26
21
|
```bash
|
|
27
22
|
pnpm add @supermousejs/dot @supermousejs/ring
|
|
28
|
-
|
|
29
23
|
npm install @supermousejs/dot @supermousejs/ring
|
|
30
24
|
```
|
|
31
25
|
|
|
32
|
-
##
|
|
33
|
-
|
|
34
|
-
Supermouse itself does not render a cursor, as it is not a component system. Nor does it render a default stub.
|
|
35
|
-
|
|
36
|
-
The core is essentially a headless system that provides pointer tracking, state, physics, and a plugin lifecycle. Plugins automatically use the internal Supermouse engine to render to the DOM, but you can write a renderer yourself like in the example below:
|
|
26
|
+
## Quick Start
|
|
37
27
|
|
|
38
28
|
```ts
|
|
39
29
|
import { Supermouse } from "@supermousejs/core";
|
|
30
|
+
import { Dot } from "@supermousejs/dot";
|
|
40
31
|
|
|
41
32
|
const mouse = new Supermouse({
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const dot = document.createElement("div");
|
|
46
|
-
|
|
47
|
-
Object.assign(dot.style, {
|
|
48
|
-
width: "8px",
|
|
49
|
-
height: "8px",
|
|
50
|
-
borderRadius: "50%",
|
|
51
|
-
background: "red",
|
|
52
|
-
position: "absolute",
|
|
53
|
-
transform: "translate(-50%, -50%)",
|
|
54
|
-
pointerEvents: "none"
|
|
33
|
+
plugins: [Dot({ size: 8 })]
|
|
55
34
|
});
|
|
56
|
-
|
|
57
|
-
mouse.container.appendChild(dot);
|
|
58
|
-
|
|
59
|
-
function render() {
|
|
60
|
-
const { smooth } = mouse.state;
|
|
61
|
-
|
|
62
|
-
dot.style.transform = `translate3d(${smooth.x}px, ${smooth.y}px, 0) translate(-50%, -50%)`;
|
|
63
|
-
|
|
64
|
-
requestAnimationFrame(render);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
render();
|
|
68
35
|
```
|
|
69
36
|
|
|
70
|
-
|
|
37
|
+
Or use the plugin interface directly:
|
|
71
38
|
|
|
72
39
|
```ts
|
|
73
40
|
import { Supermouse } from "@supermousejs/core";
|
|
74
41
|
|
|
75
42
|
const dot = document.createElement("div");
|
|
76
|
-
|
|
77
|
-
Object.assign(dot.style, {
|
|
78
|
-
width: "8px",
|
|
79
|
-
height: "8px",
|
|
80
|
-
borderRadius: "50%",
|
|
81
|
-
background: "red",
|
|
82
|
-
position: "absolute",
|
|
83
|
-
transform: "translate(-50%, -50%)",
|
|
84
|
-
pointerEvents: "none"
|
|
85
|
-
});
|
|
43
|
+
// ... style dot ...
|
|
86
44
|
|
|
87
45
|
const redDot = {
|
|
88
46
|
name: "red-dot",
|
|
89
|
-
install(
|
|
90
|
-
|
|
47
|
+
install(app) {
|
|
48
|
+
app.stage.appendChild(dot);
|
|
91
49
|
},
|
|
92
|
-
update(
|
|
93
|
-
const { smooth } =
|
|
94
|
-
|
|
95
|
-
dot.style.transform = `translate3d(${smooth.x}px, ${smooth.y}px, 0) translate(-50%, -50%)`;
|
|
50
|
+
update(app) {
|
|
51
|
+
const { smooth } = app.state;
|
|
52
|
+
dot.style.transform = `translate3d(${smooth.x}px, ${smooth.y}px, 0)`;
|
|
96
53
|
},
|
|
97
54
|
destroy() {
|
|
98
55
|
dot.remove();
|
|
99
56
|
}
|
|
100
57
|
};
|
|
101
58
|
|
|
102
|
-
const mouse = new Supermouse({
|
|
103
|
-
plugins: [redDot]
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Now your dot has all the capabilities of Supermouse (the native cursor automatically hidden, the input normalized, hover detection and accessibility baked in, and the red dot part of the plugin lifecycle). However, if your goal is a simple red dot on your webpage, Supermouse might be overkill, even though the core is designed to be lightweight. For simple effects, plain HTML/CSS and JavaScript may suffice.
|
|
108
|
-
|
|
109
|
-
Supermouse's advantages become apparent when you need to handle increasingly complex effects with granularity. For example, adding a `Ring` to the cursor can be done declaratively:
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
import { Dot } from "@supermousejs/dot";
|
|
113
|
-
import { Ring } from "@supermousejs/ring";
|
|
114
|
-
|
|
115
|
-
const app = new Supermouse({
|
|
116
|
-
plugins: [Dot({ size: 8 }), Ring({ size: 24 })]
|
|
117
|
-
});
|
|
59
|
+
const mouse = new Supermouse({ plugins: [redDot] });
|
|
118
60
|
```
|
|
119
61
|
|
|
120
|
-
You can also chain plugin instantiation imperatively with `.use`:
|
|
121
|
-
|
|
122
|
-
```ts
|
|
123
|
-
app.use(Dot({ size: 8 }))
|
|
124
|
-
|
|
125
|
-
if (someEffect) {
|
|
126
|
-
app.use(Effect1({...})).use(Effect2({...}))
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Read more about plugins and how to write them [here](https://github.com/Whitestar14/supermouse-js/blob/main/PLUGINS.md).
|
|
131
|
-
|
|
132
62
|
## Options
|
|
133
63
|
|
|
134
|
-
| Option | Default | Description
|
|
135
|
-
| --------------------- | ----------------------------------------------------------------------- |
|
|
136
|
-
| `smoothness` | `0.15` | Lower
|
|
137
|
-
| `hoverSelectors` | `["a", "button", "input", "textarea", "[data-hover]", "[data-cursor]"]` | Selectors that set `state.isHover`
|
|
138
|
-
| `enableTouch` | `false` |
|
|
139
|
-
| `autoDisableOnMobile` | `true` |
|
|
140
|
-
| `cursor` | `"auto"` |
|
|
141
|
-
| `hideOnLeave` | `true` |
|
|
142
|
-
| `container` | `document.body` |
|
|
143
|
-
| `zIndex` | `9999` |
|
|
144
|
-
| `dataPrefix` | `"supermouse"` |
|
|
145
|
-
| `rules` | — |
|
|
146
|
-
| `plugins` | — | Plugins to install
|
|
147
|
-
| `autoStart` | `true` | Set
|
|
148
|
-
|
|
149
|
-
### Cursor Modes
|
|
150
|
-
|
|
151
|
-
Prior to v2.4, earlier versions used two separate options, `hideCursor` and `ignoreOnNative`, to control when the native cursor should be hidden or shown. In v2.4, these have been combined into a single **`cursor`** option that decides both behaviors at once.
|
|
152
|
-
|
|
153
|
-
```ts
|
|
154
|
-
const app = new Supermouse({
|
|
155
|
-
cursor: "auto"
|
|
156
|
-
});
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
There are four modes:
|
|
160
|
-
|
|
161
|
-
- **`"auto"`** (default) – Supermouse looks at whatever is under the pointer and makes a reasonable choice. Over buttons, links, inputs, and other native controls, the native OS cursor appears; everywhere else, your custom cursor takes over. This is the best starting point and for most projects, it's what you're going to use without extra configuration.
|
|
162
|
-
|
|
163
|
-
- **`"custom"`** – The custom cursor is always shown, and the native cursor is always hidden. This is the mode you'd use when you want complete visual control and are confident your custom cursor handles all interactions gracefully.
|
|
164
|
-
|
|
165
|
-
- **`"native"`** – The native cursor is always visible, and the custom cursor stays hidden. Useful when you temporarily want to give full control back to the OS.
|
|
166
|
-
|
|
167
|
-
- **`"both"`** – Both the native cursor and the custom cursor are visible at the same time. This is particularly useful for effects that surround the native pointer such as a ring that highlights the native arrow, or a trail that follows the real cursor.
|
|
168
|
-
|
|
169
|
-
You can switch modes at any time with:
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
mouse.setCursor("both");
|
|
173
|
-
```
|
|
64
|
+
| Option | Default | Description |
|
|
65
|
+
| --------------------- | ----------------------------------------------------------------------- | --------------------------------------------- |
|
|
66
|
+
| `smoothness` | `0.15` | Lower = smoother cursor follow |
|
|
67
|
+
| `hoverSelectors` | `["a", "button", "input", "textarea", "[data-hover]", "[data-cursor]"]` | Selectors that set `state.isHover` |
|
|
68
|
+
| `enableTouch` | `false` | Allow touch events to move cursor |
|
|
69
|
+
| `autoDisableOnMobile` | `true` | Disable on coarse‑pointer devices |
|
|
70
|
+
| `cursor` | `"auto"` | `"auto"`, `"custom"`, `"native"`, or `"both"` |
|
|
71
|
+
| `hideOnLeave` | `true` | Hide when pointer leaves window |
|
|
72
|
+
| `container` | `document.body` | Scoping container |
|
|
73
|
+
| `zIndex` | `9999` | Stage stacking order |
|
|
74
|
+
| `dataPrefix` | `"supermouse"` | Prefix for data attributes |
|
|
75
|
+
| `rules` | — | Map of selectors to interaction data |
|
|
76
|
+
| `plugins` | — | Plugins to install at creation |
|
|
77
|
+
| `autoStart` | `true` | Set `false` and call `.start()` manually |
|
|
174
78
|
|
|
175
|
-
|
|
79
|
+
## Cursor Modes
|
|
176
80
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| `hideCursor: false` | `"both"` or `"native"` depending on the rest of your setup |
|
|
81
|
+
- `"auto"` – native cursor on interactive elements, custom elsewhere.
|
|
82
|
+
- `"custom"` – always custom, hide native.
|
|
83
|
+
- `"native"` – always native, hide custom.
|
|
84
|
+
- `"both"` – show both native and custom together.
|
|
182
85
|
|
|
183
|
-
|
|
86
|
+
Change at runtime with `mouse.setCursor("both")`.
|
|
184
87
|
|
|
185
|
-
|
|
88
|
+
## Containers & Multiple Instances
|
|
186
89
|
|
|
187
|
-
|
|
90
|
+
Scope an instance to a container:
|
|
188
91
|
|
|
189
92
|
```ts
|
|
190
|
-
const modal = document.getElementById("
|
|
191
|
-
|
|
192
|
-
const app = new Supermouse({
|
|
193
|
-
container: modal,
|
|
194
|
-
cursor: "custom"
|
|
195
|
-
});
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
This allows multiple independent instances on the same page. CSS and cursor‑hiding rules are scoped to avoid leakage. For example:
|
|
199
|
-
|
|
200
|
-
```ts
|
|
201
|
-
// Main page cursor
|
|
202
|
-
const app1 = new Supermouse({
|
|
203
|
-
container: document.body,
|
|
204
|
-
cursor: "custom"
|
|
205
|
-
});
|
|
206
|
-
app1.use(Dot({ color: "red" }));
|
|
207
|
-
|
|
208
|
-
// Modal cursor
|
|
209
|
-
const app2 = new Supermouse({
|
|
210
|
-
container: document.getElementById("modal"),
|
|
211
|
-
cursor: "both"
|
|
212
|
-
});
|
|
213
|
-
app2.use(Dot({ color: "blue" }));
|
|
93
|
+
const modal = document.getElementById("modal");
|
|
94
|
+
const mouse = new Supermouse({ container: modal, cursor: "custom" });
|
|
214
95
|
```
|
|
215
96
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
When `cursor` is `"auto"`, Supermouse automatically detects when to show the native OS cursor. To force native cursor on an element and its descendants, add the attribute `data-supermouse-ignore`:
|
|
97
|
+
Multiple instances can coexist; CSS rules are scoped automatically.
|
|
219
98
|
|
|
220
|
-
|
|
221
|
-
<div data-supermouse-ignore>This area will show the native cursor</div>
|
|
222
|
-
```
|
|
99
|
+
## Native Cursor Fallback
|
|
223
100
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
> **Note:** Custom cursors often break usability on native controls (inputs, text selection, drag handles). The `"auto"` cursor mode briefly yields control back to the OS cursor for these interactions, ensuring accessibility.
|
|
227
|
-
|
|
228
|
-
### Data Attributes
|
|
229
|
-
|
|
230
|
-
Some plugins can be reactive to HTML data attributes. For example, `Dot` watches for `data-supermouse-color`:
|
|
101
|
+
In `"auto"` mode, add `data-supermouse-ignore` to force the native cursor on an element and its descendants.
|
|
231
102
|
|
|
232
103
|
```html
|
|
233
|
-
<div data-supermouse-
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
The `dataPrefix` option can customize this:
|
|
237
|
-
|
|
238
|
-
```ts
|
|
239
|
-
const app = new Supermouse({ dataPrefix: "sm" });
|
|
104
|
+
<div data-supermouse-ignore>Native cursor here</div>
|
|
240
105
|
```
|
|
241
106
|
|
|
242
|
-
|
|
243
|
-
<div data-sm-stick>Sticky Zone</div>
|
|
244
|
-
```
|
|
107
|
+
## Data Attributes
|
|
245
108
|
|
|
246
|
-
`data
|
|
109
|
+
Plugins can react to `data-*` attributes, e.g. `data-supermouse-color`. The prefix is configurable via `dataPrefix`.
|
|
247
110
|
|
|
248
|
-
|
|
111
|
+
## Rules
|
|
249
112
|
|
|
250
|
-
|
|
113
|
+
Define interaction data without writing many attributes:
|
|
251
114
|
|
|
252
115
|
```ts
|
|
253
|
-
const
|
|
116
|
+
const mouse = new Supermouse({
|
|
254
117
|
rules: {
|
|
255
|
-
".primary-action": {
|
|
256
|
-
magnetic: true,
|
|
257
|
-
distance: 200,
|
|
258
|
-
color: "red",
|
|
259
|
-
text: "Click!",
|
|
260
|
-
scale: 1.5
|
|
261
|
-
}
|
|
118
|
+
".primary-action": { magnetic: true, color: "red" }
|
|
262
119
|
}
|
|
263
120
|
});
|
|
264
121
|
```
|
|
265
122
|
|
|
266
|
-
|
|
123
|
+
HTML `data-*` attributes override rule values per property.
|
|
267
124
|
|
|
268
125
|
## API
|
|
269
126
|
|
|
270
127
|
```ts
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
//
|
|
274
|
-
mouse.
|
|
275
|
-
// All options with defaults applied
|
|
276
|
-
mouse.options
|
|
277
|
-
// The DOM element the plugins render into
|
|
278
|
-
mouse.stage
|
|
279
|
-
|
|
280
|
-
// Whether the instance is currently processing input
|
|
281
|
-
mouse.isEnabled
|
|
282
|
-
|
|
283
|
-
// Start processing input and re-apply cursor state
|
|
284
|
-
mouse.enable()
|
|
285
|
-
// Stop processing input, restore native cursor, reset state
|
|
286
|
-
mouse.disable()
|
|
287
|
-
// Pause input and hide the stage without destroying the instance
|
|
288
|
-
mouse.suspend()
|
|
289
|
-
// Resume input and show the stage
|
|
290
|
-
mouse.resume()
|
|
291
|
-
|
|
292
|
-
// Set cursor mode: "auto" | "custom" | "native" | "both"
|
|
293
|
-
mouse.setCursor(mode)
|
|
294
|
-
|
|
295
|
-
// Install a plugin
|
|
296
|
-
mouse.use(plugin)
|
|
297
|
-
// Return a plugin by name
|
|
298
|
-
mouse.getPlugin(name)
|
|
299
|
-
// Enable a disabled plugin
|
|
300
|
-
mouse.enablePlugin(name)
|
|
301
|
-
// Disable a plugin
|
|
302
|
-
mouse.disablePlugin(name)
|
|
303
|
-
// Toggle a plugin's enabled state
|
|
304
|
-
mouse.togglePlugin(name)
|
|
305
|
-
|
|
306
|
-
// Add a selector at runtime. Whenever the cursor hovers over this selector, Supermouse detects it and hides the native cursor for it
|
|
307
|
-
mouse.registerHoverTarget(selector)
|
|
308
|
-
|
|
309
|
-
// Start the animation loop if stopped
|
|
310
|
-
mouse.start()
|
|
311
|
-
// Advance one frame manually
|
|
312
|
-
mouse.step(time)
|
|
313
|
-
|
|
314
|
-
// Destroy Supermouse and plugin instances
|
|
315
|
-
mouse.destroy()
|
|
316
|
-
```
|
|
128
|
+
mouse.state; // current MouseState
|
|
129
|
+
mouse.options; // resolved options
|
|
130
|
+
mouse.stage; // DOM element plugins render into
|
|
131
|
+
mouse.isEnabled; // boolean
|
|
317
132
|
|
|
318
|
-
|
|
133
|
+
mouse.enable(); // start input, hide native cursor
|
|
134
|
+
mouse.disable(); // stop input, show native cursor, reset
|
|
135
|
+
mouse.suspend(); // pause non‑destructively
|
|
136
|
+
mouse.resume(); // resume from suspend
|
|
319
137
|
|
|
320
|
-
|
|
138
|
+
mouse.setCursor(mode); // "auto" | "custom" | "native" | "both"
|
|
321
139
|
|
|
322
|
-
|
|
140
|
+
mouse.use(plugin); // install plugin
|
|
141
|
+
mouse.getPlugin(name); // retrieve plugin
|
|
142
|
+
mouse.enablePlugin(name); // enable plugin
|
|
143
|
+
mouse.disablePlugin(name); // disable plugin
|
|
144
|
+
mouse.togglePlugin(name); // toggle plugin
|
|
323
145
|
|
|
324
|
-
|
|
146
|
+
mouse.registerHoverTarget(sel); // add hover selector at runtime
|
|
147
|
+
mouse.start(); // start animation loop
|
|
148
|
+
mouse.step(time); // advance one frame manually
|
|
149
|
+
mouse.destroy(); // destroy instance and plugins
|
|
150
|
+
```
|
|
325
151
|
|
|
326
|
-
##
|
|
152
|
+
## Browser Support
|
|
327
153
|
|
|
328
|
-
|
|
154
|
+
All modern browsers.
|
|
329
155
|
|
|
330
156
|
## License
|
|
331
157
|
|
|
332
158
|
MIT
|
|
333
|
-
|
|
334
|
-
Built and maintained by [Whitestar14](https://github.com/Whitestar14)
|
package/dist/index.mjs
CHANGED
package/dist/index.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(r,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(r=typeof globalThis<"u"?globalThis:r||self,l(r.SupermouseCore={}))})(this,(function(r){"use strict";const l="2.4.
|
|
1
|
+
(function(r,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(r=typeof globalThis<"u"?globalThis:r||self,l(r.SupermouseCore={}))})(this,(function(r){"use strict";const l="2.4.3";function v(a,t,e){return a+(t-a)*e}function c(a,t,e,s){return v(a,t,1-Math.exp(-e*s))}const u={x:-100,y:-100},b=new Set(["input","textarea","select"]),y=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),d=["a","button","input","textarea","[data-hover]","[data-cursor]"];class p{constructor(t,e,s,i){this.state=t,this.options=e,this.getHoverSelector=s,this.onEnableChange=i,this.dataPrefix=this.options.dataPrefix??"supermouse",this.normalizedDataPrefix=this.dataPrefix.toLowerCase(),this.ignoreAttribute=`data-${this.dataPrefix}-ignore`,this.ruleEntries=this.options.rules?Object.entries(this.options.rules):[],this.checkDeviceCapability(),this.checkMotionPreference(),this.setupContainerRectTracking(),this.bindEvents()}state;options;getHoverSelector;onEnableChange;mediaQueryList;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;abortController=new AbortController;nativeTarget=null;hasSeenPointer=!1;isEnabled=!0;containerRect=null;resizeObserver;matchedRules=[];lastParsedTarget=null;ruleEntries;currentTarget=null;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)}setupContainerRectTracking(){const t=this.options.container;if(!t||t===document.body)return;const e=()=>{this.containerRect=t.getBoundingClientRect()};e(),window.addEventListener("resize",e,{signal:this.abortController.signal}),window.addEventListener("scroll",e,{passive:!0,signal:this.abortController.signal}),typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(e),this.resizeObserver.observe(t))}parseDOMInteraction(t){if(t!==this.lastParsedTarget){this.lastParsedTarget=t,this.matchedRules=[];for(const[i,n]of this.ruleEntries)this.matchesSelector(t,i)&&this.matchedRules.push({selector:i,rules:n})}const e={};for(const{rules:i}of this.matchedRules)try{const n=typeof i=="function"?i(t):i;if(!n||typeof n!="object")continue;for(const[o,h]of Object.entries(n))e[o]=typeof h=="function"?h(t):h}catch(n){console.error("[Supermouse] Rule threw during evaluation:",n)}const s=this.normalizedDataPrefix;for(const i in t.dataset){if(!i.toLowerCase().startsWith(s))continue;const n=i.slice(s.length);if(!n)continue;const o=t.dataset[i];e[n[0].toLowerCase()+n.slice(1)]=o===""?!0:o}this.state.interaction=e}matchesSelector(t,e){try{if(!/\s/.test(e.trim()))return t.matches(e)}catch{}const s=e.trim().split(/\s+/);if(s.length<2)return!1;const i=s.pop(),n=s.join(" ");if(!i||!n)return!1;try{return t.matches(i)&&!!t.closest(n)}catch{return!1}}isOutsideContainer(t){const{container:e}=this.options;return!!e&&e!==document.body&&!e.contains(t)}resolveComputedCursor(t){return window.getComputedStyle(t).cursor}handleMove=t=>{if(this.options.autoDisableOnMobile&&t.pointerType==="touch"&&!this.options.enableTouch)return;let e=t.clientX,s=t.clientY;const i=this.options.container;i&&this.containerRect&&i!==document.body&&(e-=this.containerRect.left,s-=this.containerRect.top),this.state.pointer.x=e,this.state.pointer.y=s,this.hasSeenPointer=!0,this.isEnabled&&(this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=e,this.state.target.y=this.state.smooth.y=s))};handleDown=()=>{this.isEnabled&&(this.state.isDown=!0)};handleUp=()=>{this.isEnabled&&(this.state.isDown=!1)};handleMouseOver=t=>{if(!this.isEnabled)return;const e=t.target;if(this.isOutsideContainer(e))return;if(this.state.cursorMode==="auto"&&e.closest(`[${this.ignoreAttribute}]`)){this.state.isHover=!1,this.state.hoverTarget=null,this.state.interaction={},this.currentTarget=null,this.lastParsedTarget=null,this.matchedRules=[],this.state.isNative=!0,this.nativeTarget=e;return}if(this.state.isNative=!1,this.nativeTarget=null,this.currentTarget=e,this.parseDOMInteraction(e),this.state.cursorMode!=="auto"){const o=e.closest(this.getHoverSelector());o&&(this.state.isHover=!0,this.state.hoverTarget=o);return}const s=e.closest(this.getHoverSelector());s&&(this.state.isHover=!0,this.state.hoverTarget=s);const i=b.has(e.localName)||e.isContentEditable,n=!y.has(this.resolveComputedCursor(e));(i||n)&&(this.state.isNative=!0,this.nativeTarget=e)};handleMouseOut=t=>{if(!this.isEnabled)return;const e=t.target,s=t.relatedTarget;this.isOutsideContainer(e)||((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.matchedRules=[]))};handleDocumentMouseOut=t=>{this.isEnabled&&t.relatedTarget===null&&this.options.hideOnLeave&&this.handleWindowLeave()};handleWindowLeave=()=>{this.options.hideOnLeave&&(this.state.hasReceivedInput=!1,this.state.pointer={...u})};clearHover(){this.state.isHover=!1,this.state.hoverTarget=null,this.state.isNative=!1,this.nativeTarget=null,this.state.interaction={},this.currentTarget=null,this.lastParsedTarget=null,this.matchedRules=[]}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});const s=!this.options.container||this.options.container===document.body?document:this.options.container;s.addEventListener("mouseover",this.handleMouseOver,{signal:t}),s.addEventListener("mouseout",this.handleMouseOut,{signal:t}),document.addEventListener("mouseout",this.handleDocumentMouseOut,{signal:t})}destroy(){this.abortController.abort(),this.resizeObserver?.disconnect()}}let C=0;class g{constructor(t=document.body,e=9999){if(this.container=t,this.zIndex=e,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);t.isConnected||console.warn("[Supermouse] container is not attached to the document — stage sizing/positioning will be wrong until it is.");const s=C++;this.id=`supermouse-style-${s}`,this.scopeClass=`supermouse-scope-${s}`,this.hideClass=`supermouse-hide-${s}`;const i=t===document.body;if(this.element=document.createElement("div"),Object.assign(this.element.style,{position:i?"fixed":"absolute",inset:"0px",pointerEvents:"none",zIndex:String(this.zIndex),opacity:"1",transition:"opacity 0.15s ease"}),!i){const n=window.getComputedStyle(t);this.originalContainerPosition=n.position,n.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),this.styleTag=document.createElement("style"),this.styleTag.id=this.id,document.head.appendChild(this.styleTag),this.container.classList.add("supermouse-scope",this.scopeClass),this.updateCursorCSS()}container;zIndex;element;styleTag;id;scopeClass;hideClass;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";selectors=new Set(["a","button","input","textarea","select",'[role="button"]',"[tabindex]"]);addSelectors(t){let e=!1;for(const s of t)s.split(",").forEach(i=>{const n=i.trim();n&&!this.selectors.has(n)&&(this.selectors.add(n),e=!0)});e&&this.updateCursorCSS()}addSelector(t){this.addSelectors([t])}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){t!==this.currentCursorState&&(this.currentCursorState=t,this.container.classList.toggle(this.hideClass,t==="none"),this.container.style.cursor=t==="none"?"none":this.originalContainerCursor)}updateCursorCSS(){const t=Array.from(this.selectors);if(t.length===0){this.styleTag.innerText="";return}const e=`:not(.${this.scopeClass} .supermouse-scope):not(.${this.scopeClass} .supermouse-scope *)`,s=h=>`.${this.scopeClass}.${this.hideClass} ${h}${e} { cursor: none !important; }`,i=t.map(s).join(`
|
|
2
2
|
`),n=`.${this.scopeClass}.${this.hideClass} *${e} { cursor: none !important; }`,o=`.${this.scopeClass}.${this.hideClass} { cursor: none !important; }`;this.styleTag.innerText=`
|
|
3
3
|
${o}
|
|
4
4
|
${n}
|