@supermousejs/core 2.5.0-beta.1 → 2.5.0-beta.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 +41 -0
- package/dist/index.d.ts +143 -45
- package/dist/index.mjs +443 -261
- package/dist/index.umd.js +2 -2
- package/package.json +8 -3
package/dist/index.mjs
CHANGED
|
@@ -1,62 +1,76 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
const S = {
|
|
2
|
+
native: ["input", "textarea", "select", "[contenteditable]"],
|
|
3
|
+
hide: [
|
|
4
|
+
"input",
|
|
5
|
+
"textarea",
|
|
6
|
+
"select",
|
|
7
|
+
"[contenteditable]",
|
|
8
|
+
"a",
|
|
9
|
+
"button",
|
|
10
|
+
'[role="button"]',
|
|
11
|
+
"[tabindex]",
|
|
12
|
+
"label"
|
|
11
13
|
]
|
|
12
14
|
};
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
t.push({
|
|
19
|
-
selector: r,
|
|
20
|
-
native: e.has(r),
|
|
21
|
-
hide: s.has(r)
|
|
22
|
-
});
|
|
23
|
-
return { rules: t };
|
|
24
|
-
}
|
|
25
|
-
function T(i) {
|
|
26
|
-
const t = [], e = [];
|
|
27
|
-
for (const s of i.rules)
|
|
28
|
-
s.native !== !1 && t.push(s.selector), s.hide !== !1 && e.push(s.selector);
|
|
29
|
-
return { native: t, hide: e };
|
|
15
|
+
function b(n) {
|
|
16
|
+
return n ? {
|
|
17
|
+
native: n.native ?? [],
|
|
18
|
+
hide: n.hide ?? []
|
|
19
|
+
} : S;
|
|
30
20
|
}
|
|
31
|
-
let
|
|
32
|
-
class
|
|
21
|
+
let y = 0;
|
|
22
|
+
class P {
|
|
23
|
+
element;
|
|
24
|
+
scopeClass;
|
|
25
|
+
hideClass;
|
|
26
|
+
container;
|
|
27
|
+
currentCursorState = null;
|
|
28
|
+
originalContainerPosition = "";
|
|
29
|
+
originalContainerCursor = "";
|
|
30
|
+
_visible = !0;
|
|
33
31
|
constructor(t, e) {
|
|
34
|
-
if (
|
|
35
|
-
throw new Error(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
if (!t || !(t instanceof HTMLElement))
|
|
33
|
+
throw new Error(
|
|
34
|
+
`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`
|
|
35
|
+
);
|
|
36
|
+
const s = t.hasAttribute("data-supermouse-placeholder");
|
|
37
|
+
!t.isConnected && !s && console.warn(
|
|
38
|
+
"[Supermouse] container is not attached to the document — stage sizing/positioning will be wrong until it is."
|
|
39
|
+
);
|
|
40
|
+
const i = y++;
|
|
41
|
+
this.scopeClass = `supermouse-scope-${i}`, this.hideClass = `supermouse-hide-${i}`, this.element = document.createElement("div"), Object.assign(this.element.style, {
|
|
42
|
+
position: "absolute",
|
|
42
43
|
inset: "0px",
|
|
43
44
|
pointerEvents: "none",
|
|
44
45
|
zIndex: String(e),
|
|
45
46
|
opacity: "1",
|
|
46
47
|
transition: "opacity 0.15s ease"
|
|
47
|
-
}),
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
}), this.container = t, this._attach(t);
|
|
49
|
+
}
|
|
50
|
+
_attach(t) {
|
|
51
|
+
const e = t === document.body;
|
|
52
|
+
if (this.element.style.position = e ? "fixed" : "absolute", e)
|
|
53
|
+
this.originalContainerPosition = "";
|
|
54
|
+
else {
|
|
55
|
+
const s = window.getComputedStyle(t);
|
|
56
|
+
this.originalContainerPosition = s.position, s.position === "static" && (t.style.position = "relative");
|
|
50
57
|
}
|
|
51
58
|
this.originalContainerCursor = t.style.cursor, t.appendChild(this.element), t.classList.add("supermouse-scope", this.scopeClass);
|
|
52
59
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
_detach() {
|
|
61
|
+
const t = this.container;
|
|
62
|
+
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();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Rebinds this stage to a new container. The previous container is
|
|
66
|
+
* restored to its pre-Supermouse state, and the current cursor
|
|
67
|
+
* suppression is re-applied to the new container.
|
|
68
|
+
*/
|
|
69
|
+
attach(t) {
|
|
70
|
+
if (this.container === t) return;
|
|
71
|
+
const e = this.currentCursorState;
|
|
72
|
+
this._detach(), this.container = t, this._attach(t), this.currentCursorState = null, e && this.setNativeCursor(e);
|
|
73
|
+
}
|
|
60
74
|
get containerElement() {
|
|
61
75
|
return this.container;
|
|
62
76
|
}
|
|
@@ -69,58 +83,96 @@ class A {
|
|
|
69
83
|
return `:not(.${this.scopeClass} .supermouse-scope):not(.${this.scopeClass} .supermouse-scope *)`;
|
|
70
84
|
}
|
|
71
85
|
setVisibility(t) {
|
|
72
|
-
this.element.style.opacity = t ? "1" : "0";
|
|
86
|
+
t !== this._visible && (this._visible = t, this.element.style.opacity = t ? "1" : "0");
|
|
73
87
|
}
|
|
74
88
|
setNativeCursor(t) {
|
|
75
|
-
t !== this.currentCursorState && (this.currentCursorState = t, this.container.classList.toggle(this.hideClass, t === "none")
|
|
89
|
+
t !== this.currentCursorState && (this.currentCursorState = t, this.container.classList.toggle(this.hideClass, t === "none"));
|
|
76
90
|
}
|
|
77
91
|
destroy() {
|
|
78
|
-
this.
|
|
92
|
+
this._detach();
|
|
79
93
|
}
|
|
80
94
|
}
|
|
81
|
-
class
|
|
95
|
+
class C {
|
|
82
96
|
constructor(t, e) {
|
|
83
|
-
this.config = t, this.name = t.name, this.cursorMode = t.cursor ?? e.cursor, this.hoverSelectors = new Set(t.hoverSelectors ?? e.hoverSelectors), this.inheritDataAttributes = t.inheritDataAttributes ?? e.inheritDataAttributes;
|
|
84
|
-
const s = t.cursorPolicy ?
|
|
85
|
-
this.nativeSelectors =
|
|
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
|
+
const s = t.cursorPolicy ? b(t.cursorPolicy) : e.cursorPolicy;
|
|
99
|
+
this.nativeSelectors = s.native, this.hideSelectors = s.hide;
|
|
100
|
+
let i;
|
|
101
|
+
typeof t.container == "string" ? (this.containerSelector = t.container, this._bound = !1, i = document.createElement("div"), i.setAttribute("data-supermouse-placeholder", "")) : (this.containerSelector = null, this._bound = !0, i = t.container), this.stage = new P(i, t.zIndex ?? e.zIndex);
|
|
86
102
|
}
|
|
87
103
|
config;
|
|
88
104
|
stage;
|
|
105
|
+
/**
|
|
106
|
+
* The CSS selector used for lazy resolution, or null for eager scopes.
|
|
107
|
+
* Derived from `config.container` at construction: a string means lazy,
|
|
108
|
+
* an element means eager.
|
|
109
|
+
*/
|
|
110
|
+
containerSelector;
|
|
89
111
|
hoverSelectors;
|
|
90
112
|
plugins = [];
|
|
91
113
|
nativeSelectors;
|
|
92
114
|
hideSelectors;
|
|
93
115
|
inheritDataAttributes;
|
|
116
|
+
ruleEntries;
|
|
94
117
|
name;
|
|
95
118
|
cursorMode;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
119
|
+
active = !0;
|
|
120
|
+
_bound;
|
|
99
121
|
get container() {
|
|
100
122
|
return this.stage.containerElement;
|
|
101
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* True for eager scopes, and for selector scopes that have matched a
|
|
126
|
+
* live element at least once.
|
|
127
|
+
*/
|
|
128
|
+
get resolved() {
|
|
129
|
+
return this._bound;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* True if this scope owns the given element. Element equality for eager
|
|
133
|
+
* scopes; `Element.matches` for selector scopes. Invalid selectors are
|
|
134
|
+
* treated as non-matching; validation happens once at scope creation.
|
|
135
|
+
*/
|
|
136
|
+
match(t) {
|
|
137
|
+
if (this.containerSelector === null)
|
|
138
|
+
return this.stage.containerElement === t;
|
|
139
|
+
try {
|
|
140
|
+
return t.matches(this.containerSelector);
|
|
141
|
+
} catch {
|
|
142
|
+
return !1;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Rebinds this scope's stage to a matched element. No-op for eager
|
|
147
|
+
* scopes, and no-op if the stage is already attached to `el`.
|
|
148
|
+
*/
|
|
149
|
+
bind(t) {
|
|
150
|
+
this.containerSelector !== null && (this._bound && this.stage.containerElement === t || (this.stage.attach(t), this._bound = !0));
|
|
151
|
+
}
|
|
152
|
+
contains(t) {
|
|
153
|
+
return this._bound && this.stage.containerElement.contains(t);
|
|
154
|
+
}
|
|
102
155
|
get hoverSelectorString() {
|
|
103
156
|
return Array.from(this.hoverSelectors).join(", ");
|
|
104
157
|
}
|
|
105
158
|
get nativeSelectorString() {
|
|
106
159
|
return this.nativeSelectors.join(", ");
|
|
107
160
|
}
|
|
108
|
-
/** Build the CSS rules this scope contributes to the shared stylesheet. */
|
|
109
161
|
buildRules() {
|
|
110
162
|
const t = this.stage.getRulePrefix(), e = this.stage.getExclusion(), s = [
|
|
111
163
|
`${t}${e} { cursor: none !important; }`,
|
|
112
164
|
`${t} *${e} { cursor: none !important; }`
|
|
113
165
|
];
|
|
114
|
-
for (const
|
|
115
|
-
s.push(`${t} ${
|
|
116
|
-
return s.push(
|
|
166
|
+
for (const i of this.hideSelectors)
|
|
167
|
+
s.push(`${t} ${i}${e} { cursor: none !important; }`);
|
|
168
|
+
return s.push(
|
|
117
169
|
`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`
|
|
118
170
|
), s.push(
|
|
119
171
|
`${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`
|
|
120
172
|
), s;
|
|
121
173
|
}
|
|
122
174
|
}
|
|
123
|
-
const
|
|
175
|
+
const d = { x: -100, y: -100 }, E = /* @__PURE__ */ new Set([
|
|
124
176
|
"default",
|
|
125
177
|
"auto",
|
|
126
178
|
"pointer",
|
|
@@ -128,60 +180,24 @@ const f = { x: -100, y: -100 }, R = /* @__PURE__ */ new Set([
|
|
|
128
180
|
"inherit",
|
|
129
181
|
"grab",
|
|
130
182
|
"grabbing"
|
|
131
|
-
]),
|
|
183
|
+
]), _ = [
|
|
132
184
|
"a",
|
|
133
185
|
"button",
|
|
134
186
|
"input",
|
|
135
187
|
"textarea",
|
|
136
188
|
"[data-hover]",
|
|
137
189
|
"[data-cursor]"
|
|
138
|
-
]
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return { left: t.left, top: t.top, width: t.width, height: t.height };
|
|
143
|
-
}
|
|
144
|
-
function M(i) {
|
|
145
|
-
u.set(i, C(i));
|
|
146
|
-
const t = _.get(i);
|
|
147
|
-
if (t) for (const e of t) e();
|
|
148
|
-
}
|
|
149
|
-
function y() {
|
|
150
|
-
for (const i of u.keys()) M(i);
|
|
151
|
-
}
|
|
152
|
-
function O() {
|
|
153
|
-
v || typeof ResizeObserver > "u" || (v = new ResizeObserver((i) => {
|
|
154
|
-
for (const t of i) {
|
|
155
|
-
const e = t.target;
|
|
156
|
-
u.has(e) && M(e);
|
|
157
|
-
}
|
|
158
|
-
}));
|
|
159
|
-
}
|
|
160
|
-
function $() {
|
|
161
|
-
typeof window > "u" || (g || (window.addEventListener("scroll", y, { passive: !0, capture: !0 }), g = !0), m || (window.addEventListener("resize", y, { passive: !0 }), m = !0));
|
|
162
|
-
}
|
|
163
|
-
function z(i, t) {
|
|
164
|
-
return S++, u.has(i) || (u.set(i, C(i)), O(), v?.observe(i), $()), () => {
|
|
165
|
-
S--, S === 0 && (v?.disconnect(), v = null, u.clear(), _.clear(), g && (window.removeEventListener("scroll", y, { capture: !0 }), g = !1), m && (window.removeEventListener("resize", y), m = !1));
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
function k(i) {
|
|
169
|
-
let t = u.get(i);
|
|
170
|
-
return t || (t = C(i), u.set(i, t)), t;
|
|
171
|
-
}
|
|
172
|
-
function N(i, t, e) {
|
|
173
|
-
if (i === document.body) return { x: t, y: e };
|
|
174
|
-
const s = k(i);
|
|
175
|
-
return { x: t - s.left, y: e - s.top };
|
|
176
|
-
}
|
|
177
|
-
class B {
|
|
178
|
-
constructor(t, e, s, n) {
|
|
179
|
-
this.state = t, this.options = e, this.onEnableChange = s, this.onActiveScopeChange = n, this.dataPrefix = e.dataPrefix ?? "supermouse", this.normalizedDataPrefix = this.dataPrefix.toLowerCase(), this.ignoreAttribute = `data-${this.dataPrefix}-ignore`, this.ruleEntries = e.rules ? Object.entries(e.rules) : [], this.checkDeviceCapability(), this.checkMotionPreference(), this.bindEvents();
|
|
190
|
+
];
|
|
191
|
+
class w {
|
|
192
|
+
constructor(t, e, s, i, h, r) {
|
|
193
|
+
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();
|
|
180
194
|
}
|
|
181
195
|
state;
|
|
182
196
|
options;
|
|
183
197
|
onEnableChange;
|
|
184
198
|
onActiveScopeChange;
|
|
199
|
+
resolveScope;
|
|
200
|
+
onHoverSettled;
|
|
185
201
|
abortController = new AbortController();
|
|
186
202
|
mediaQueryList;
|
|
187
203
|
motionQuery;
|
|
@@ -189,37 +205,26 @@ class B {
|
|
|
189
205
|
normalizedDataPrefix;
|
|
190
206
|
ignoreAttribute;
|
|
191
207
|
activeScope = null;
|
|
192
|
-
scopeByContainer = /* @__PURE__ */ new Map();
|
|
193
208
|
nativeTarget = null;
|
|
194
209
|
currentTarget = null;
|
|
195
210
|
lastParsedTarget = null;
|
|
196
|
-
ruleEntries;
|
|
197
|
-
releaseViewport = null;
|
|
198
211
|
hasSeenPointer = !1;
|
|
199
212
|
isEnabled = !0;
|
|
200
213
|
viewportX = 0;
|
|
201
214
|
viewportY = 0;
|
|
202
215
|
/** Cached matched rules per ancestor. Recomputed only when the hover target changes. */
|
|
203
216
|
cachedChain = [];
|
|
204
|
-
setScopes(t) {
|
|
205
|
-
this.scopeByContainer.clear();
|
|
206
|
-
for (const e of t) this.scopeByContainer.set(e.container, e);
|
|
207
|
-
}
|
|
208
217
|
setActiveScope(t) {
|
|
209
|
-
t !== this.activeScope && (this.activeScope = t, this.
|
|
210
|
-
}
|
|
211
|
-
findScope(t) {
|
|
212
|
-
let e = t;
|
|
213
|
-
for (; e; ) {
|
|
214
|
-
const s = this.scopeByContainer.get(e);
|
|
215
|
-
if (s) return s;
|
|
216
|
-
e = e.parentElement;
|
|
217
|
-
}
|
|
218
|
-
return null;
|
|
218
|
+
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));
|
|
219
219
|
}
|
|
220
220
|
applyPointerToState() {
|
|
221
|
-
const t = this.activeScope?.container ?? document.body
|
|
222
|
-
|
|
221
|
+
const t = this.activeScope?.container ?? document.body;
|
|
222
|
+
if (t === document.body) {
|
|
223
|
+
this.state.pointer.x = this.viewportX, this.state.pointer.y = this.viewportY;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const e = t.getBoundingClientRect();
|
|
227
|
+
this.state.pointer.x = this.viewportX - e.left, this.state.pointer.y = this.viewportY - e.top;
|
|
223
228
|
}
|
|
224
229
|
checkDeviceCapability() {
|
|
225
230
|
this.options.autoDisableOnMobile && (this.mediaQueryList = window.matchMedia("(pointer: fine)"), this.updateEnabledState(this.mediaQueryList.matches), this.mediaQueryList.addEventListener("change", (t) => this.updateEnabledState(t.matches), {
|
|
@@ -239,40 +244,42 @@ class B {
|
|
|
239
244
|
this.isEnabled = t, this.onEnableChange(t);
|
|
240
245
|
}
|
|
241
246
|
parseDOMInteraction(t) {
|
|
242
|
-
|
|
247
|
+
if (!this.activeScope) return;
|
|
248
|
+
const e = this.activeScope.container, s = this.activeScope.inheritDataAttributes, i = this.normalizedDataPrefix, h = this.activeScope.ruleEntries;
|
|
243
249
|
if (t !== this.lastParsedTarget) {
|
|
244
250
|
this.lastParsedTarget = t, this.cachedChain = [];
|
|
245
251
|
let o = t;
|
|
246
252
|
for (; o; ) {
|
|
247
|
-
const
|
|
248
|
-
for (const [a,
|
|
249
|
-
this.matchesSelector(o, a) &&
|
|
250
|
-
if (this.cachedChain.push({ element: o, matchedRules:
|
|
253
|
+
const p = [];
|
|
254
|
+
for (const [a, l] of h)
|
|
255
|
+
this.matchesSelector(o, a) && p.push({ selector: a, rules: l });
|
|
256
|
+
if (this.cachedChain.push({ element: o, matchedRules: p }), !s || o === e) break;
|
|
251
257
|
const c = o.parentElement;
|
|
252
258
|
if (!c || !e.contains(c)) break;
|
|
253
259
|
o = c;
|
|
254
260
|
}
|
|
255
261
|
}
|
|
256
262
|
const r = {};
|
|
257
|
-
for (const { element: o, matchedRules:
|
|
263
|
+
for (const { element: o, matchedRules: p } of this.cachedChain) {
|
|
258
264
|
const c = {};
|
|
259
|
-
for (const { rules: a } of
|
|
265
|
+
for (const { rules: a } of p)
|
|
260
266
|
try {
|
|
261
|
-
const
|
|
262
|
-
if (!
|
|
263
|
-
for (const [
|
|
264
|
-
c[
|
|
265
|
-
} catch {
|
|
267
|
+
const l = typeof a == "function" ? a(o) : a;
|
|
268
|
+
if (!l || typeof l != "object") continue;
|
|
269
|
+
for (const [v, u] of Object.entries(l))
|
|
270
|
+
c[v] = typeof u == "function" ? u(o) : u;
|
|
271
|
+
} catch (l) {
|
|
272
|
+
console.error("[Supermouse] Rule threw during evaluation:", l);
|
|
266
273
|
}
|
|
267
274
|
for (const a in o.dataset) {
|
|
268
|
-
if (!a.toLowerCase().startsWith(
|
|
269
|
-
const
|
|
270
|
-
if (!
|
|
271
|
-
const
|
|
272
|
-
c[
|
|
275
|
+
if (!a.toLowerCase().startsWith(i)) continue;
|
|
276
|
+
const l = a.slice(i.length);
|
|
277
|
+
if (!l) continue;
|
|
278
|
+
const v = l[0].toLowerCase() + l.slice(1), u = o.dataset[a];
|
|
279
|
+
c[v] = u == null || u === "" ? !0 : u;
|
|
273
280
|
}
|
|
274
|
-
for (const [a,
|
|
275
|
-
a in r || (r[a] =
|
|
281
|
+
for (const [a, l] of Object.entries(c))
|
|
282
|
+
a in r || (r[a] = l);
|
|
276
283
|
}
|
|
277
284
|
this.state.interaction = r;
|
|
278
285
|
}
|
|
@@ -297,26 +304,33 @@ class B {
|
|
|
297
304
|
};
|
|
298
305
|
handleMouseOver = (t) => {
|
|
299
306
|
if (!this.isEnabled) return;
|
|
300
|
-
const e = t.target, s = this.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
307
|
+
const e = t.target, s = this.resolveScope(e);
|
|
308
|
+
s && s !== this.activeScope && this.setActiveScope(s), this.activeScope && (this.settleHoverState(e), this.onHoverSettled());
|
|
309
|
+
};
|
|
310
|
+
isPointerInside(t) {
|
|
311
|
+
if (!this.hasSeenPointer) return !1;
|
|
312
|
+
const e = t.getBoundingClientRect();
|
|
313
|
+
return this.viewportX >= e.left && this.viewportX <= e.right && this.viewportY >= e.top && this.viewportY <= e.bottom;
|
|
314
|
+
}
|
|
315
|
+
settleHoverState(t) {
|
|
316
|
+
if (this.state.cursorMode === "auto" && t.closest(`[${this.ignoreAttribute}]`)) {
|
|
317
|
+
this.clearHover(), this.state.isNative = !0, this.nativeTarget = t;
|
|
304
318
|
return;
|
|
305
319
|
}
|
|
306
|
-
this.state.isNative = !1, this.nativeTarget = null, this.currentTarget =
|
|
307
|
-
const
|
|
308
|
-
if (
|
|
309
|
-
if (this.matchesSelector(
|
|
310
|
-
this.state.isNative = !0, this.nativeTarget =
|
|
320
|
+
this.state.isNative = !1, this.nativeTarget = null, this.currentTarget = t, this.parseDOMInteraction(t);
|
|
321
|
+
const e = t.closest(this.activeScope.hoverSelectorString);
|
|
322
|
+
if (e && (this.state.isHover = !0, this.state.hoverTarget = e), this.state.cursorMode === "auto") {
|
|
323
|
+
if (this.matchesSelector(t, this.activeScope.nativeSelectorString)) {
|
|
324
|
+
this.state.isNative = !0, this.nativeTarget = t;
|
|
311
325
|
return;
|
|
312
326
|
}
|
|
313
|
-
(
|
|
327
|
+
(t.isContentEditable || !E.has(this.resolveComputedCursor(t))) && (this.state.isNative = !0, this.nativeTarget = t);
|
|
314
328
|
}
|
|
315
|
-
}
|
|
329
|
+
}
|
|
316
330
|
handleMouseOut = (t) => {
|
|
317
331
|
if (!this.isEnabled) return;
|
|
318
332
|
const e = t.target, s = t.relatedTarget;
|
|
319
|
-
(e === this.state.hoverTarget || e.contains(this.state.hoverTarget)) && (!s || !this.state.hoverTarget?.contains(s)) && (this.state.isHover = !1, this.state.hoverTarget = null), this.nativeTarget && (e === this.nativeTarget || e.contains(this.nativeTarget)) && (!s || !this.nativeTarget.contains(s)) && (this.state.isNative = !1, this.nativeTarget = null), e === this.currentTarget && (this.currentTarget = null, this.lastParsedTarget = null, this.cachedChain = []), !s && this.options.hideOnLeave && (this.state.hasReceivedInput = !1, this.state.pointer = { ...
|
|
333
|
+
(e === this.state.hoverTarget || e.contains(this.state.hoverTarget)) && (!s || !this.state.hoverTarget?.contains(s)) && (this.state.isHover = !1, this.state.hoverTarget = null), this.nativeTarget && (e === this.nativeTarget || e.contains(this.nativeTarget)) && (!s || !this.nativeTarget.contains(s)) && (this.state.isNative = !1, this.nativeTarget = null), e === this.currentTarget && (this.currentTarget = null, this.lastParsedTarget = null, this.cachedChain = []), !s && this.options.hideOnLeave && (this.state.hasReceivedInput = !1, this.state.pointer = { ...d });
|
|
320
334
|
};
|
|
321
335
|
clearHover() {
|
|
322
336
|
this.state.isHover = !1, this.state.hoverTarget = null, this.state.isNative = !1, this.nativeTarget = null, this.state.interaction = {}, this.currentTarget = null, this.lastParsedTarget = null, this.cachedChain = [];
|
|
@@ -329,37 +343,41 @@ class B {
|
|
|
329
343
|
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 });
|
|
330
344
|
}
|
|
331
345
|
destroy() {
|
|
332
|
-
this.abortController.abort(), this.
|
|
346
|
+
this.abortController.abort(), this.cachedChain = [];
|
|
333
347
|
}
|
|
334
348
|
}
|
|
335
|
-
let
|
|
336
|
-
|
|
337
|
-
|
|
349
|
+
let x = 0;
|
|
350
|
+
const f = /* @__PURE__ */ new Map();
|
|
351
|
+
function M() {
|
|
352
|
+
return x++;
|
|
338
353
|
}
|
|
339
|
-
function
|
|
340
|
-
|
|
341
|
-
`))
|
|
354
|
+
function T(n, t) {
|
|
355
|
+
let e = f.get(n);
|
|
356
|
+
e || (e = document.createElement("style"), e.id = `supermouse-styles-${n}`, document.head.appendChild(e), f.set(n, e)), e.textContent = t.join(`
|
|
357
|
+
`);
|
|
342
358
|
}
|
|
343
|
-
function
|
|
344
|
-
|
|
359
|
+
function A(n) {
|
|
360
|
+
f.get(n)?.remove(), f.delete(n);
|
|
345
361
|
}
|
|
346
|
-
const
|
|
347
|
-
function
|
|
348
|
-
return
|
|
362
|
+
const g = "2.5.0-beta.3";
|
|
363
|
+
function D(n, t, e) {
|
|
364
|
+
return n + (t - n) * e;
|
|
349
365
|
}
|
|
350
|
-
function
|
|
351
|
-
return
|
|
366
|
+
function m(n, t, e, s) {
|
|
367
|
+
return D(n, t, 1 - Math.exp(-e * s));
|
|
352
368
|
}
|
|
353
|
-
class
|
|
354
|
-
static version =
|
|
355
|
-
version =
|
|
369
|
+
class I {
|
|
370
|
+
static version = g;
|
|
371
|
+
version = g;
|
|
356
372
|
state;
|
|
357
373
|
options;
|
|
358
374
|
_scopes = [];
|
|
359
375
|
_activeScope = null;
|
|
360
376
|
_installingScope = null;
|
|
361
|
-
|
|
377
|
+
scopeByName = /* @__PURE__ */ new Map();
|
|
378
|
+
scopeHandles = /* @__PURE__ */ new Map();
|
|
362
379
|
input;
|
|
380
|
+
styleOwner;
|
|
363
381
|
rafId = 0;
|
|
364
382
|
lastTime = 0;
|
|
365
383
|
visibilityAbortController = new AbortController();
|
|
@@ -377,10 +395,10 @@ class Q {
|
|
|
377
395
|
zIndex: 9999,
|
|
378
396
|
inheritDataAttributes: !0,
|
|
379
397
|
...t
|
|
380
|
-
}, this.state = {
|
|
381
|
-
pointer: { ...
|
|
382
|
-
target: { ...
|
|
383
|
-
smooth: { ...
|
|
398
|
+
}, this.styleOwner = M(), this.state = {
|
|
399
|
+
pointer: { ...d },
|
|
400
|
+
target: { ...d },
|
|
401
|
+
smooth: { ...d },
|
|
384
402
|
velocity: { x: 0, y: 0 },
|
|
385
403
|
displacement: { x: 0, y: 0 },
|
|
386
404
|
angle: 0,
|
|
@@ -392,7 +410,8 @@ class Q {
|
|
|
392
410
|
reducedMotion: !1,
|
|
393
411
|
hasReceivedInput: !1,
|
|
394
412
|
shape: null,
|
|
395
|
-
interaction: {}
|
|
413
|
+
interaction: {},
|
|
414
|
+
scope: null
|
|
396
415
|
};
|
|
397
416
|
const e = this.createScope({
|
|
398
417
|
container: this.options.container,
|
|
@@ -400,16 +419,19 @@ class Q {
|
|
|
400
419
|
hoverSelectors: this.options.hoverSelectors,
|
|
401
420
|
cursorPolicy: this.options.cursorPolicy,
|
|
402
421
|
plugins: this.options.plugins,
|
|
422
|
+
rules: this.options.rules,
|
|
403
423
|
zIndex: this.options.zIndex
|
|
404
424
|
});
|
|
405
|
-
if (this.input = new
|
|
425
|
+
if (this.input = new w(
|
|
406
426
|
this.state,
|
|
407
427
|
this.options,
|
|
408
428
|
(s) => {
|
|
409
429
|
s || this.reset();
|
|
410
430
|
},
|
|
411
|
-
(s) => this.handleActiveScopeChange(s)
|
|
412
|
-
|
|
431
|
+
(s) => this.handleActiveScopeChange(s),
|
|
432
|
+
(s) => this.resolveScopeForNode(s),
|
|
433
|
+
() => this.applyCursorNow()
|
|
434
|
+
), this.input.setActiveScope(e), this.installPlugins(e), this.options.scopes)
|
|
413
435
|
for (const s of this.options.scopes) this.addScope(s);
|
|
414
436
|
this.rebuildStylesheet(), this.bindVisibilityHandling(), this.options.autoStart && this.startLoop();
|
|
415
437
|
}
|
|
@@ -426,38 +448,72 @@ class Q {
|
|
|
426
448
|
get isRunning() {
|
|
427
449
|
return this._running;
|
|
428
450
|
}
|
|
451
|
+
/**
|
|
452
|
+
* Installs a plugin into the primary scope.
|
|
453
|
+
*
|
|
454
|
+
* In multi-scope mode, prefer `handle.use(plugin)` to target a specific
|
|
455
|
+
* scope. This method always installs to the primary scope, regardless of
|
|
456
|
+
* which scope is currently active.
|
|
457
|
+
*/
|
|
429
458
|
use(t) {
|
|
430
459
|
return this.installPlugin(this._scopes[0], t), this;
|
|
431
460
|
}
|
|
461
|
+
/**
|
|
462
|
+
* Searches every scope and returns the first plugin matching `name`.
|
|
463
|
+
* Scopes are searched in registration order (primary first).
|
|
464
|
+
*/
|
|
432
465
|
getPlugin(t) {
|
|
433
466
|
for (const e of this._scopes) {
|
|
434
|
-
const s = e.plugins.find((
|
|
467
|
+
const s = e.plugins.find((i) => i.name === t);
|
|
435
468
|
if (s) return s;
|
|
436
469
|
}
|
|
437
470
|
}
|
|
471
|
+
getScope(t) {
|
|
472
|
+
const e = this.scopeByName.get(t);
|
|
473
|
+
return e ? this.scopeHandles.get(e) : void 0;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Enables a plugin by name, wherever it lives.
|
|
477
|
+
*
|
|
478
|
+
* If the plugin's scope is currently active, the activation lifecycle
|
|
479
|
+
* runs immediately. If the scope is inactive, `isEnabled` is set but
|
|
480
|
+
* hooks do not fire until the scope next activates.
|
|
481
|
+
*/
|
|
438
482
|
enablePlugin(t) {
|
|
439
483
|
const e = this.getPlugin(t);
|
|
440
|
-
e
|
|
484
|
+
if (!e || e.isEnabled !== !1) return;
|
|
485
|
+
e.isEnabled = !0;
|
|
486
|
+
const s = this.findScopeForPlugin(e);
|
|
487
|
+
s && s === this._activeScope && s.active && this.scopeActivatePlugin(e);
|
|
441
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Disables a plugin by name, wherever it lives.
|
|
491
|
+
*
|
|
492
|
+
* If the plugin's scope is currently active, the deactivation lifecycle
|
|
493
|
+
* runs immediately. If the scope is inactive, `isEnabled` is set but
|
|
494
|
+
* hooks do not fire — they already ran when the scope went inactive.
|
|
495
|
+
*/
|
|
442
496
|
disablePlugin(t) {
|
|
443
497
|
const e = this.getPlugin(t);
|
|
444
|
-
e
|
|
498
|
+
if (!e || e.isEnabled === !1) return;
|
|
499
|
+
const s = this.findScopeForPlugin(e);
|
|
500
|
+
s !== null && s === this._activeScope && s.active ? this.deactivatePlugin(e) : e.isEnabled = !1;
|
|
445
501
|
}
|
|
446
502
|
togglePlugin(t) {
|
|
447
503
|
const e = this.getPlugin(t);
|
|
448
504
|
e && (e.isEnabled === !1 ? this.enablePlugin(t) : this.disablePlugin(t));
|
|
449
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Sets the cursor mode on the *active* scope.
|
|
508
|
+
*
|
|
509
|
+
* To set the mode on a specific scope, use `handle.setCursor(mode)`.
|
|
510
|
+
*/
|
|
450
511
|
setCursor(t) {
|
|
451
|
-
this._activeScope && (this._activeScope
|
|
512
|
+
this._activeScope && this.setScopeCursor(this._activeScope, t);
|
|
452
513
|
}
|
|
453
514
|
addScope(t) {
|
|
454
515
|
const e = this.createScope(t);
|
|
455
|
-
return this.
|
|
456
|
-
name: e.name,
|
|
457
|
-
container: e.container,
|
|
458
|
-
remove: () => this.removeScope(e),
|
|
459
|
-
setCursor: (s) => this.setScopeCursor(e, s)
|
|
460
|
-
};
|
|
516
|
+
return this.installPlugins(e), this.rebuildStylesheet(), this.scopeHandles.get(e);
|
|
461
517
|
}
|
|
462
518
|
enable() {
|
|
463
519
|
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());
|
|
@@ -466,7 +522,7 @@ class Q {
|
|
|
466
522
|
this.input.isEnabled = !1, this._activeScope && (this._activeScope.stage.setNativeCursor("auto"), this._activeScope.stage.setVisibility(!1)), t?.reset && this.reset();
|
|
467
523
|
}
|
|
468
524
|
reset() {
|
|
469
|
-
this.state.target = { ...
|
|
525
|
+
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 = {};
|
|
470
526
|
}
|
|
471
527
|
start() {
|
|
472
528
|
this.startLoop();
|
|
@@ -480,89 +536,229 @@ class Q {
|
|
|
480
536
|
for (const e of t.plugins)
|
|
481
537
|
try {
|
|
482
538
|
e.destroy?.(this);
|
|
483
|
-
} catch {
|
|
539
|
+
} catch (s) {
|
|
540
|
+
console.error(s);
|
|
484
541
|
}
|
|
485
542
|
t.stage.destroy();
|
|
486
543
|
}
|
|
487
|
-
this._scopes = [], this.
|
|
544
|
+
this._scopes = [], this.scopeByName.clear(), this.scopeHandles.clear(), this._activeScope = null, this.state.scope = null, A(this.styleOwner);
|
|
488
545
|
}
|
|
489
546
|
// ─── Internal ───
|
|
490
547
|
_running = !1;
|
|
491
548
|
createScope(t) {
|
|
492
|
-
|
|
549
|
+
if (typeof t.container != "string") {
|
|
550
|
+
const s = t.container;
|
|
551
|
+
for (const i of this._scopes)
|
|
552
|
+
if (i.containerSelector === null && i.container === s) {
|
|
553
|
+
console.warn(
|
|
554
|
+
"[Supermouse] A scope is already registered for this container. The previous scope will no longer activate."
|
|
555
|
+
);
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
const e = new C(t, {
|
|
493
560
|
cursor: this.options.cursor,
|
|
494
|
-
hoverSelectors: this.options.hoverSelectors ??
|
|
495
|
-
cursorPolicy: this.options.cursorPolicy ?
|
|
561
|
+
hoverSelectors: this.options.hoverSelectors ?? _,
|
|
562
|
+
cursorPolicy: this.options.cursorPolicy ? b(this.options.cursorPolicy) : S,
|
|
496
563
|
zIndex: this.options.zIndex,
|
|
497
|
-
inheritDataAttributes: this.options.inheritDataAttributes
|
|
564
|
+
inheritDataAttributes: this.options.inheritDataAttributes,
|
|
565
|
+
ruleEntries: this.options.rules ? Object.entries(this.options.rules) : []
|
|
498
566
|
});
|
|
499
|
-
return this._scopes.push(e), this.
|
|
567
|
+
return this._scopes.push(e), e.name && this.scopeByName.set(e.name, e), this.scopeHandles.set(e, this.buildScopeHandle(e)), e;
|
|
568
|
+
}
|
|
569
|
+
buildScopeHandle(t) {
|
|
570
|
+
const e = {
|
|
571
|
+
get name() {
|
|
572
|
+
return t.name;
|
|
573
|
+
},
|
|
574
|
+
get container() {
|
|
575
|
+
return t.resolved ? t.container : null;
|
|
576
|
+
},
|
|
577
|
+
get active() {
|
|
578
|
+
return t.active;
|
|
579
|
+
},
|
|
580
|
+
get resolved() {
|
|
581
|
+
return t.resolved;
|
|
582
|
+
},
|
|
583
|
+
destroy: () => this.destroyScope(t),
|
|
584
|
+
setCursor: (s) => this.setScopeCursor(t, s),
|
|
585
|
+
deactivate: () => this.deactivateScope(t),
|
|
586
|
+
activate: () => this.activateScope(t),
|
|
587
|
+
use: (s) => (this.installPlugin(t, s), e),
|
|
588
|
+
removePlugin: (s) => this.removePluginFromScope(t, s),
|
|
589
|
+
getPlugin: (s) => t.plugins.find((i) => i.name === s)
|
|
590
|
+
};
|
|
591
|
+
return e;
|
|
500
592
|
}
|
|
501
|
-
|
|
593
|
+
destroyScope(t) {
|
|
502
594
|
const e = this._scopes.indexOf(t);
|
|
503
595
|
if (e !== -1) {
|
|
504
596
|
for (const s of t.plugins)
|
|
505
597
|
try {
|
|
506
598
|
s.destroy?.(this);
|
|
507
|
-
} catch {
|
|
599
|
+
} catch (i) {
|
|
600
|
+
console.error(i);
|
|
508
601
|
}
|
|
509
|
-
t.plugins.length = 0, t.stage.destroy(), this._scopes.splice(e, 1), this.
|
|
602
|
+
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) {
|
|
603
|
+
const s = this.resolveScopeForNode(t.container.parentElement) ?? this._scopes.find((i) => i.active) ?? null;
|
|
604
|
+
this.input.setActiveScope(s), this.input.clearHover(), this.applyCursorNow();
|
|
605
|
+
}
|
|
606
|
+
this.rebuildStylesheet();
|
|
510
607
|
}
|
|
511
608
|
}
|
|
512
609
|
setScopeCursor(t, e) {
|
|
513
|
-
t.cursorMode = e, t === this._activeScope && (this.state.cursorMode = e);
|
|
610
|
+
t.cursorMode = e, t === this._activeScope && (this.state.cursorMode = e, this.applyCursorNow());
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Marks the scope ineligible for activation and, if it was active, yields
|
|
614
|
+
* immediately to the nearest active ancestor scope (or nothing).
|
|
615
|
+
*/
|
|
616
|
+
deactivateScope(t) {
|
|
617
|
+
if (t.active && (t.active = !1, this._activeScope === t)) {
|
|
618
|
+
const e = this.resolveScopeForNode(t.container.parentElement) ?? this._scopes.find((s) => s.active) ?? null;
|
|
619
|
+
this.input.setActiveScope(e), this.input.clearHover(), this.applyCursorNow();
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Marks the scope eligible for activation.
|
|
624
|
+
*
|
|
625
|
+
* If the pointer is already inside the scope's container, the scope
|
|
626
|
+
* becomes active immediately. Otherwise it activates on the next
|
|
627
|
+
* `mouseover` inside the container. Deactivation is always eager.
|
|
628
|
+
*/
|
|
629
|
+
activateScope(t) {
|
|
630
|
+
if (t.active = !0, this._activeScope !== t && this.input.hasSeenPointer) {
|
|
631
|
+
if (t.containerSelector !== null && !t.resolved) {
|
|
632
|
+
const e = document.querySelectorAll(t.containerSelector);
|
|
633
|
+
for (const s of e)
|
|
634
|
+
if (this.input.isPointerInside(s)) {
|
|
635
|
+
t.bind(s);
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
t.resolved && this.input.isPointerInside(t.container) && (this.input.setActiveScope(t), this.applyCursorNow());
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Called by `Input` on every `mouseover`, and internally when the active
|
|
644
|
+
* scope is removed or deactivated. Walks from `node` up the ancestor
|
|
645
|
+
* chain, returning the innermost active scope whose `match` succeeds
|
|
646
|
+
* for an ancestor. The matched scope is bound to that ancestor before
|
|
647
|
+
* return.
|
|
648
|
+
*
|
|
649
|
+
* The walk order is what enforces "innermost wins": the first ancestor
|
|
650
|
+
* matching any active scope is, by construction, the closest one to the
|
|
651
|
+
* event target. Detached containers can never be ancestors of a live
|
|
652
|
+
* event target, so no cleanup of stale bindings is required here.
|
|
653
|
+
*/
|
|
654
|
+
resolveScopeForNode(t) {
|
|
655
|
+
for (let e = t; e; e = e.parentElement)
|
|
656
|
+
for (const s of this._scopes)
|
|
657
|
+
if (s.active && s.match(e))
|
|
658
|
+
return s.bind(e), s;
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Synchronously writes the current cursor and stage visibility for the
|
|
663
|
+
* active scope. Called after hover state settles, on cursor mode changes,
|
|
664
|
+
* and on programmatic scope transitions. The `update()` rAF path calls
|
|
665
|
+
* the same writers as a backstop.
|
|
666
|
+
*/
|
|
667
|
+
applyCursorNow() {
|
|
668
|
+
const t = this._activeScope;
|
|
669
|
+
t && (t.stage.setVisibility(this.resolveStageVisibility()), this.input.isEnabled && t.stage.setNativeCursor(this.resolveCursorState()));
|
|
670
|
+
}
|
|
671
|
+
findScopeForPlugin(t) {
|
|
672
|
+
for (const e of this._scopes)
|
|
673
|
+
if (e.plugins.includes(t)) return e;
|
|
674
|
+
return null;
|
|
514
675
|
}
|
|
515
676
|
installPlugins(t) {
|
|
516
677
|
if (t.config.plugins)
|
|
517
678
|
for (const e of t.config.plugins) this.installPlugin(t, e);
|
|
518
679
|
}
|
|
519
680
|
installPlugin(t, e) {
|
|
520
|
-
if (
|
|
521
|
-
|
|
681
|
+
if (t.plugins.some((s) => s.name === e.name)) {
|
|
682
|
+
console.warn(`[Supermouse] Plugin "${e.name}" already installed.`);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
e.isEnabled ??= !0, this._installingScope = t;
|
|
686
|
+
try {
|
|
687
|
+
e.install?.(this);
|
|
688
|
+
} catch (s) {
|
|
689
|
+
console.error(`[Supermouse] Failed to install plugin '${e.name}'.`, s), this._installingScope = null;
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
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");
|
|
693
|
+
}
|
|
694
|
+
removePluginFromScope(t, e) {
|
|
695
|
+
const s = t.plugins.findIndex((o) => o.name === e);
|
|
696
|
+
if (s === -1) return;
|
|
697
|
+
const i = t.plugins[s];
|
|
698
|
+
t.plugins.splice(s, 1);
|
|
699
|
+
const h = () => {
|
|
522
700
|
try {
|
|
523
|
-
|
|
524
|
-
} catch {
|
|
525
|
-
|
|
526
|
-
return;
|
|
701
|
+
i.onDisable?.(this), i.destroy?.(this);
|
|
702
|
+
} catch (o) {
|
|
703
|
+
console.error(`[Supermouse] Plugin '${e}' cleanup threw:`, o);
|
|
527
704
|
}
|
|
528
|
-
|
|
529
|
-
}
|
|
705
|
+
i.element?.remove();
|
|
706
|
+
}, r = i.onBeforeDisable?.(this);
|
|
707
|
+
r && typeof r.then == "function" ? Promise.resolve(r).then(h).catch((o) => {
|
|
708
|
+
console.error(`[Supermouse] Plugin '${e}' onBeforeDisable threw:`, o), h();
|
|
709
|
+
}) : h();
|
|
530
710
|
}
|
|
531
711
|
handleActiveScopeChange(t) {
|
|
532
712
|
const e = this._activeScope;
|
|
533
713
|
if (e !== t) {
|
|
534
714
|
if (e)
|
|
535
|
-
for (const s of e.plugins)
|
|
715
|
+
for (const s of e.plugins)
|
|
716
|
+
s.isEnabled !== !1 && this.scopeDeactivatePlugin(s);
|
|
536
717
|
if (this._activeScope = t, t) {
|
|
537
|
-
this.state.cursorMode = t.cursorMode;
|
|
538
|
-
for (const s of t.plugins)
|
|
539
|
-
|
|
718
|
+
this.state.cursorMode = t.cursorMode, this.state.scope = { name: t.name, container: t.container };
|
|
719
|
+
for (const s of t.plugins)
|
|
720
|
+
s.isEnabled !== !1 && this.scopeActivatePlugin(s);
|
|
721
|
+
} else
|
|
722
|
+
this.state.scope = null;
|
|
540
723
|
}
|
|
541
724
|
}
|
|
542
|
-
activatePlugin(t) {
|
|
543
|
-
t.isEnabled === !1 && (t.isEnabled = !0, t.element && (t.element.style.display = ""), t.onEnable?.(this));
|
|
544
|
-
}
|
|
545
725
|
deactivatePlugin(t) {
|
|
546
726
|
if (t.isEnabled === !1) return;
|
|
547
727
|
t.isEnabled = !1;
|
|
548
728
|
const e = () => {
|
|
549
729
|
t.element && (t.element.style.display = "none"), t.onDisable?.(this);
|
|
550
730
|
}, s = t.onBeforeDisable?.(this);
|
|
551
|
-
s && typeof s.then == "function" ? Promise.resolve(s).then(e).catch((
|
|
552
|
-
e();
|
|
731
|
+
s && typeof s.then == "function" ? Promise.resolve(s).then(e).catch((i) => {
|
|
732
|
+
console.error(`[Supermouse] Plugin '${t.name}' onBeforeDisable threw:`, i), e();
|
|
733
|
+
}) : e();
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Runs the deactivation lifecycle for a plugin whose owning scope just
|
|
737
|
+
* became inactive. Does NOT flip `plugin.isEnabled`, so user intent
|
|
738
|
+
* (e.g. States disabling a plugin) survives the scope round-trip.
|
|
739
|
+
*/
|
|
740
|
+
scopeDeactivatePlugin(t) {
|
|
741
|
+
const e = () => {
|
|
742
|
+
t.element && (t.element.style.display = "none"), t.onDisable?.(this);
|
|
743
|
+
}, s = t.onBeforeDisable?.(this);
|
|
744
|
+
s && typeof s.then == "function" ? Promise.resolve(s).then(e).catch((i) => {
|
|
745
|
+
console.error(`[Supermouse] Plugin '${t.name}' onBeforeDisable threw:`, i), e();
|
|
553
746
|
}) : e();
|
|
554
747
|
}
|
|
748
|
+
scopeActivatePlugin(t) {
|
|
749
|
+
t.element && (t.element.style.display = ""), t.onEnable?.(this);
|
|
750
|
+
}
|
|
555
751
|
rebuildStylesheet() {
|
|
556
|
-
const t = [];
|
|
752
|
+
const t = [":where(.supermouse-scope .supermouse-scope) { cursor: auto }"];
|
|
557
753
|
for (const e of this._scopes) t.push(...e.buildRules());
|
|
558
|
-
|
|
754
|
+
T(this.styleOwner, t);
|
|
559
755
|
}
|
|
560
756
|
runPluginSafe(t, e) {
|
|
561
757
|
if (t.isEnabled !== !1)
|
|
562
758
|
try {
|
|
563
759
|
t.update?.(this, e);
|
|
564
|
-
} catch {
|
|
565
|
-
t.isEnabled = !1, this.crashedPlugins.push(t);
|
|
760
|
+
} catch (s) {
|
|
761
|
+
console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`, s), t.isEnabled = !1, this.crashedPlugins.push(t);
|
|
566
762
|
}
|
|
567
763
|
}
|
|
568
764
|
cleanupCrashedPlugins() {
|
|
@@ -577,7 +773,8 @@ class Q {
|
|
|
577
773
|
}
|
|
578
774
|
try {
|
|
579
775
|
t.onDisable?.(this), t.destroy?.(this);
|
|
580
|
-
} catch {
|
|
776
|
+
} catch (e) {
|
|
777
|
+
console.error(`[Supermouse] Failed to cleanup crashed plugin '${t.name}'.`, e);
|
|
581
778
|
}
|
|
582
779
|
t.element?.remove();
|
|
583
780
|
}
|
|
@@ -596,19 +793,19 @@ class Q {
|
|
|
596
793
|
update(t) {
|
|
597
794
|
const e = t - this.lastTime, s = Math.min(e / 1e3, 0.1);
|
|
598
795
|
this.lastTime = t;
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
const
|
|
602
|
-
if (
|
|
603
|
-
|
|
604
|
-
for (let
|
|
605
|
-
this.runPluginSafe(
|
|
796
|
+
const i = this.input.getCurrentTarget();
|
|
797
|
+
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);
|
|
798
|
+
const h = this._activeScope;
|
|
799
|
+
if (h) {
|
|
800
|
+
h.stage.setVisibility(this.resolveStageVisibility()), this.input.isEnabled && h.stage.setNativeCursor(this.resolveCursorState());
|
|
801
|
+
for (let r = 0; r < h.plugins.length; r++)
|
|
802
|
+
this.runPluginSafe(h.plugins[r], e);
|
|
606
803
|
}
|
|
607
|
-
if (this.cleanupCrashedPlugins(), this.input.isEnabled
|
|
608
|
-
const
|
|
609
|
-
this.state.smooth.x =
|
|
610
|
-
const { x:
|
|
611
|
-
(Math.abs(
|
|
804
|
+
if (this.cleanupCrashedPlugins(), this.input.isEnabled) {
|
|
805
|
+
const r = this.state.reducedMotion ? 1e3 : 1 / this.options.smoothness * 2, o = this.state.smooth.x, p = this.state.smooth.y;
|
|
806
|
+
this.state.smooth.x = m(this.state.smooth.x, this.state.target.x, r, s), this.state.smooth.y = m(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 - p) / s) : (this.state.velocity.x = 0, this.state.velocity.y = 0);
|
|
807
|
+
const { x: c, y: a } = this.state.velocity;
|
|
808
|
+
(Math.abs(c) > 0.1 || Math.abs(a) > 0.1) && (this.state.angle = Math.atan2(a, c) * (180 / Math.PI));
|
|
612
809
|
}
|
|
613
810
|
}
|
|
614
811
|
tick = (t) => {
|
|
@@ -627,37 +824,22 @@ class Q {
|
|
|
627
824
|
this._running || (this._running = !0, !document.hidden && (this.lastTime = performance.now(), this.rafId = requestAnimationFrame(this.tick)));
|
|
628
825
|
}
|
|
629
826
|
/**
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
827
|
+
* Adds one or more hover selectors to the current scope. Intended for
|
|
828
|
+
* raw-object plugins during `install`. Plugins written with `definePlugin`
|
|
829
|
+
* should use the `selector` option instead, and consumers setting up a
|
|
830
|
+
* scope should prefer the `hoverSelectors` option at construction.
|
|
633
831
|
*/
|
|
634
832
|
registerHoverTarget(t) {
|
|
635
833
|
const e = this._installingScope ?? this._activeScope ?? this._scopes[0];
|
|
636
834
|
if (e)
|
|
637
835
|
for (const s of t.split(",")) {
|
|
638
|
-
const
|
|
639
|
-
|
|
836
|
+
const i = s.trim();
|
|
837
|
+
i && e.hoverSelectors.add(i);
|
|
640
838
|
}
|
|
641
839
|
}
|
|
642
|
-
/**
|
|
643
|
-
* @deprecated Read from the active scope instead. Exposed for tests and
|
|
644
|
-
* debugging only.
|
|
645
|
-
*/
|
|
646
|
-
get hoverSelectors() {
|
|
647
|
-
const t = this._activeScope ?? this._scopes[0];
|
|
648
|
-
return t ? t.hoverSelectors : /* @__PURE__ */ new Set();
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* @deprecated Read from the active scope instead. Exposed for tests and
|
|
652
|
-
* debugging only.
|
|
653
|
-
*/
|
|
654
|
-
get plugins() {
|
|
655
|
-
const t = this._activeScope ?? this._scopes[0];
|
|
656
|
-
return t ? t.plugins : [];
|
|
657
|
-
}
|
|
658
840
|
}
|
|
659
841
|
export {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
842
|
+
S as DEFAULT_CURSOR_POLICY,
|
|
843
|
+
_ as DEFAULT_HOVER_SELECTORS,
|
|
844
|
+
I as Supermouse
|
|
663
845
|
};
|