@supermousejs/core 2.1.0 → 2.2.0
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 +57 -51
- package/dist/index.d.ts +10 -3
- package/dist/index.mjs +133 -125
- package/dist/index.umd.js +2 -2
- package/package.json +1 -1
- package/src/Supermouse.ts +412 -43
- package/tsconfig.json +9 -9
- package/src/systems/Input.ts +0 -231
- package/src/systems/Stage.ts +0 -126
- package/src/systems/index.ts +0 -2
- package/src/utils/math.ts +0 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,51 +1,57 @@
|
|
|
1
|
-
# @supermousejs/core
|
|
2
|
-
|
|
3
|
-
## 2.
|
|
4
|
-
|
|
5
|
-
### Minor Changes
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
## 2.0.
|
|
24
|
-
|
|
25
|
-
### Patch Changes
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
## 2.0.
|
|
30
|
-
|
|
31
|
-
### Patch Changes
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
## 2.0.
|
|
36
|
-
|
|
37
|
-
### Patch Changes
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
## 2.0.
|
|
42
|
-
|
|
43
|
-
### Patch Changes
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
## 2.0.
|
|
48
|
-
|
|
49
|
-
###
|
|
50
|
-
|
|
51
|
-
-
|
|
1
|
+
# @supermousejs/core
|
|
2
|
+
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f6f44b2: Improved tree-shaking by consolidating subordinate files and helpers into the main module file
|
|
8
|
+
|
|
9
|
+
## 2.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 2590af3: - Refactored engine by removing 200 lines of redundant comments and typedocs, with appropriate re-reference to canon web docs
|
|
14
|
+
- Fixed a framework reactivity cache trap by moving away from WeakMap (computations are light and relatively inexpensive)
|
|
15
|
+
- Fixed double crashing by implementing a `try {} catch {}` safety net for plugin installation
|
|
16
|
+
- Fixed the Input layer not refreshing plugin states (particularly on hover) when DOM content is detached in reactive frameworks with `Node.isConnected`
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 6d70c18: remove legacy package and update supermouse domain in readme
|
|
21
|
+
- 14fb5b6: Updated tsconfig to be reference-compliant with core, utils and zoetrope when required
|
|
22
|
+
|
|
23
|
+
## 2.0.5
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- 67f771b: Add relevant npm metadata to package.json file
|
|
28
|
+
|
|
29
|
+
## 2.0.4
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- 993dc67: Updated supemousejs packages with proper author, license and url descriptors to repo
|
|
34
|
+
|
|
35
|
+
## 2.0.3
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Add keywords to core package
|
|
40
|
+
|
|
41
|
+
## 2.0.2
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- ae219a0: Update READMEs with correct link to documentation
|
|
46
|
+
|
|
47
|
+
## 2.0.1
|
|
48
|
+
|
|
49
|
+
### Patch Changes
|
|
50
|
+
|
|
51
|
+
- Add minimal README.md files to packages
|
|
52
|
+
|
|
53
|
+
## 2.0.0
|
|
54
|
+
|
|
55
|
+
### Major Changes
|
|
56
|
+
|
|
57
|
+
- Initial v2.0.0 release
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const DEFAULT_HOVER_SELECTORS: string[];
|
|
2
2
|
|
|
3
|
+
/* Excluded from this release type: Input */
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* The Interface for interaction state.
|
|
5
7
|
* Plugins should use Module Augmentation to add their specific properties to this interface.
|
|
@@ -69,11 +71,15 @@ export declare interface ShapeState {
|
|
|
69
71
|
borderRadius: number;
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
/* Excluded from this release type: Stage */
|
|
75
|
+
|
|
72
76
|
/**
|
|
73
|
-
* Runtime Loop
|
|
77
|
+
* Supermouse Runtime Loop
|
|
78
|
+
*
|
|
79
|
+
* This class orchestrates the application state, manages the animation loop,
|
|
80
|
+
* and coordinates data flow between the internal systems, and the plugins.
|
|
74
81
|
*
|
|
75
|
-
*
|
|
76
|
-
* and coordinates data flow between the Input system, the Stage system, and the Plugins.
|
|
82
|
+
* @default
|
|
77
83
|
*/
|
|
78
84
|
export declare class Supermouse {
|
|
79
85
|
static readonly version: string;
|
|
@@ -139,6 +145,7 @@ export declare class Supermouse {
|
|
|
139
145
|
* @param plugin - The plugin object to install.
|
|
140
146
|
*/
|
|
141
147
|
use(plugin: SupermousePlugin): this;
|
|
148
|
+
private resetCoords;
|
|
142
149
|
private resetPosition;
|
|
143
150
|
private startLoop;
|
|
144
151
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,78 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const i = d++;
|
|
7
|
-
this.id = `supermouse-style-${i}`, this.scopeClass = `supermouse-scope-${i}`;
|
|
8
|
-
const n = t === document.body;
|
|
9
|
-
this.element = document.createElement("div"), Object.assign(this.element.style, {
|
|
10
|
-
position: n ? "fixed" : "absolute",
|
|
11
|
-
top: "0",
|
|
12
|
-
left: "0",
|
|
13
|
-
width: "100%",
|
|
14
|
-
height: "100%",
|
|
15
|
-
pointerEvents: "none",
|
|
16
|
-
zIndex: "9999",
|
|
17
|
-
opacity: "1",
|
|
18
|
-
transition: "opacity 0.15s ease"
|
|
19
|
-
}), n || window.getComputedStyle(t).position === "static" && (t.style.position = "relative"), t.appendChild(this.element), this.styleTag = document.createElement("style"), this.styleTag.id = this.id, document.head.appendChild(this.styleTag), this.container.classList.add(this.scopeClass), this.hideNativeCursor && this.setNativeCursor("none");
|
|
20
|
-
}
|
|
21
|
-
container;
|
|
22
|
-
hideNativeCursor;
|
|
23
|
-
/** The container element appended to the document. */
|
|
24
|
-
element;
|
|
25
|
-
styleTag;
|
|
26
|
-
id;
|
|
27
|
-
scopeClass;
|
|
28
|
-
currentCursorState = null;
|
|
29
|
-
selectors = /* @__PURE__ */ new Set([
|
|
30
|
-
"a",
|
|
31
|
-
"button",
|
|
32
|
-
"input",
|
|
33
|
-
"textarea",
|
|
34
|
-
"select",
|
|
35
|
-
'[role="button"]',
|
|
36
|
-
"[tabindex]"
|
|
37
|
-
]);
|
|
38
|
-
/**
|
|
39
|
-
* Adds a new CSS selector to the Hide Native Cursor list.
|
|
40
|
-
* Called by `Supermouse` (and subsequently plugins) during install to ensure
|
|
41
|
-
* the native cursor is hidden on their specific interactive targets.
|
|
42
|
-
*/
|
|
43
|
-
addSelector(t) {
|
|
44
|
-
this.selectors.add(t), this.hideNativeCursor && this.updateCursorCSS();
|
|
45
|
-
}
|
|
46
|
-
setVisibility(t) {
|
|
47
|
-
this.element.style.opacity = t ? "1" : "0";
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Toggles the visibility of the native cursor via CSS injection.
|
|
51
|
-
* @param type 'none' to hide, 'auto' to show.
|
|
52
|
-
*/
|
|
53
|
-
setNativeCursor(t) {
|
|
54
|
-
!this.hideNativeCursor && t === "none" || t !== this.currentCursorState && (this.currentCursorState = t, t === "none" ? (this.container.style.cursor = "none", this.updateCursorCSS()) : (this.container.style.cursor = "", this.styleTag.innerText = ""));
|
|
55
|
-
}
|
|
56
|
-
updateCursorCSS() {
|
|
57
|
-
const t = Array.from(this.selectors);
|
|
58
|
-
if (t.length === 0) {
|
|
59
|
-
this.styleTag.innerText = "";
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const e = t.map((i) => `.${this.scopeClass} ${i}`).join(", ");
|
|
63
|
-
this.styleTag.innerText = `
|
|
64
|
-
${e} {
|
|
65
|
-
cursor: none !important;
|
|
66
|
-
}
|
|
67
|
-
`;
|
|
68
|
-
}
|
|
69
|
-
destroy() {
|
|
70
|
-
this.element.remove(), this.styleTag.remove(), this.container.style.cursor = "", this.container.classList.remove(this.scopeClass);
|
|
71
|
-
}
|
|
1
|
+
function c(n, t, e) {
|
|
2
|
+
return n + (t - n) * e;
|
|
3
|
+
}
|
|
4
|
+
function d(n, t, e, i) {
|
|
5
|
+
return c(n, t, 1 - Math.exp(-e * i));
|
|
72
6
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
7
|
+
function p(n, t) {
|
|
8
|
+
return Math.atan2(t, n) * (180 / Math.PI);
|
|
9
|
+
}
|
|
10
|
+
class f {
|
|
11
|
+
constructor(t, e, i, o) {
|
|
12
|
+
this.state = t, this.options = e, this.getHoverSelector = i, this.onEnableChange = o, this.checkDeviceCapability(), this.checkMotionPreference(), this.bindEvents();
|
|
76
13
|
}
|
|
77
14
|
state;
|
|
78
15
|
options;
|
|
@@ -86,23 +23,29 @@ class p {
|
|
|
86
23
|
* Toggled by `Supermouse.enable()`/`disable()` or automatically by device capability checks.
|
|
87
24
|
*/
|
|
88
25
|
isEnabled = !0;
|
|
26
|
+
abortController = new AbortController();
|
|
89
27
|
/**
|
|
90
28
|
* Automatically disables the custom cursor on devices without fine pointer control.
|
|
91
|
-
* Relies on `matchMedia('(pointer: fine)')`.
|
|
92
29
|
*/
|
|
93
30
|
checkDeviceCapability() {
|
|
94
31
|
this.options.autoDisableOnMobile && (this.mediaQueryList = window.matchMedia("(pointer: fine)"), this.updateEnabledState(this.mediaQueryList.matches), this.mediaQueryHandler = (t) => {
|
|
95
32
|
this.updateEnabledState(t.matches);
|
|
96
|
-
}, this.mediaQueryList.addEventListener("change", this.mediaQueryHandler
|
|
33
|
+
}, this.mediaQueryList.addEventListener("change", this.mediaQueryHandler, {
|
|
34
|
+
signal: this.abortController.signal
|
|
35
|
+
}));
|
|
97
36
|
}
|
|
98
37
|
/**
|
|
99
38
|
* Checks for `prefers-reduced-motion`.
|
|
100
39
|
* If true, the core physics engine will switch to instant snapping (high damping) to avoid motion sickness.
|
|
101
40
|
*/
|
|
102
41
|
checkMotionPreference() {
|
|
103
|
-
this.motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)"), this.state.reducedMotion = this.motionQuery.matches, this.motionQuery.addEventListener(
|
|
104
|
-
|
|
105
|
-
|
|
42
|
+
this.motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)"), this.state.reducedMotion = this.motionQuery.matches, this.motionQuery.addEventListener(
|
|
43
|
+
"change",
|
|
44
|
+
(t) => {
|
|
45
|
+
this.state.reducedMotion = t.matches;
|
|
46
|
+
},
|
|
47
|
+
{ signal: this.abortController.signal }
|
|
48
|
+
);
|
|
106
49
|
}
|
|
107
50
|
updateEnabledState(t) {
|
|
108
51
|
this.isEnabled = t, this.onEnableChange(t);
|
|
@@ -114,14 +57,14 @@ class p {
|
|
|
114
57
|
}
|
|
115
58
|
const e = {};
|
|
116
59
|
if (this.options.rules)
|
|
117
|
-
for (const [
|
|
118
|
-
t.matches(
|
|
60
|
+
for (const [o, s] of Object.entries(this.options.rules))
|
|
61
|
+
t.matches(o) && Object.assign(e, s);
|
|
119
62
|
const i = t.dataset;
|
|
120
|
-
for (const
|
|
121
|
-
if (
|
|
122
|
-
const s =
|
|
63
|
+
for (const o in i)
|
|
64
|
+
if (o.startsWith("supermouse")) {
|
|
65
|
+
const s = o.slice(10);
|
|
123
66
|
if (s) {
|
|
124
|
-
const r = s.charAt(0).toLowerCase() + s.slice(1), a = i[
|
|
67
|
+
const r = s.charAt(0).toLowerCase() + s.slice(1), a = i[o];
|
|
125
68
|
a !== void 0 && (e[r] = a === "" ? !0 : a);
|
|
126
69
|
}
|
|
127
70
|
}
|
|
@@ -131,8 +74,8 @@ class p {
|
|
|
131
74
|
if (!this.isEnabled || this.options.autoDisableOnMobile && t.pointerType === "touch") return;
|
|
132
75
|
let e = t.clientX, i = t.clientY;
|
|
133
76
|
if (this.options.container && this.options.container !== document.body) {
|
|
134
|
-
const
|
|
135
|
-
e -=
|
|
77
|
+
const o = this.options.container.getBoundingClientRect();
|
|
78
|
+
e -= o.left, i -= o.top;
|
|
136
79
|
}
|
|
137
80
|
this.state.pointer.x = e, this.state.pointer.y = i, this.state.hasReceivedInput || (this.state.hasReceivedInput = !0, this.state.target.x = this.state.smooth.x = e, this.state.target.y = this.state.smooth.y = i);
|
|
138
81
|
}
|
|
@@ -149,21 +92,21 @@ class p {
|
|
|
149
92
|
this.state.isNative = !0;
|
|
150
93
|
return;
|
|
151
94
|
}
|
|
152
|
-
const i = this.getHoverSelector(),
|
|
153
|
-
|
|
95
|
+
const i = this.getHoverSelector(), o = e.closest(i);
|
|
96
|
+
o && (this.state.isHover = !0, this.state.hoverTarget = o, this.parseDOMInteraction(this.state.hoverTarget));
|
|
154
97
|
const s = this.options.ignoreOnNative;
|
|
155
98
|
if (s) {
|
|
156
99
|
const r = s === !0 || s === "auto" || s === "tag", a = s === !0 || s === "auto" || s === "css";
|
|
157
|
-
let
|
|
100
|
+
let l = !1;
|
|
158
101
|
if (r) {
|
|
159
|
-
const
|
|
160
|
-
(
|
|
102
|
+
const h = e.localName;
|
|
103
|
+
(h === "input" || h === "textarea" || h === "select" || e.isContentEditable) && (l = !0);
|
|
161
104
|
}
|
|
162
|
-
if (!
|
|
163
|
-
const
|
|
164
|
-
["default", "auto", "pointer", "none", "inherit"].includes(
|
|
105
|
+
if (!l && a) {
|
|
106
|
+
const h = window.getComputedStyle(e).cursor;
|
|
107
|
+
["default", "auto", "pointer", "none", "inherit"].includes(h) || (l = !0);
|
|
165
108
|
}
|
|
166
|
-
|
|
109
|
+
l && (this.state.isNative = !0);
|
|
167
110
|
}
|
|
168
111
|
}
|
|
169
112
|
handleMouseOut(t) {
|
|
@@ -178,22 +121,86 @@ class p {
|
|
|
178
121
|
this.state.isHover = !1, this.state.hoverTarget = null, this.state.isNative = !1;
|
|
179
122
|
}
|
|
180
123
|
bindEvents() {
|
|
181
|
-
|
|
124
|
+
const { signal: t } = this.abortController;
|
|
125
|
+
window.addEventListener("pointermove", this.handleMove.bind(this), { passive: !0, signal: t }), window.addEventListener("pointerdown", this.handleDown.bind(this), { passive: !0, signal: t }), window.addEventListener("pointerup", this.handleUp.bind(this), { signal: t }), document.addEventListener("mouseover", this.handleMouseOver.bind(this), { signal: t }), document.addEventListener("mouseout", this.handleMouseOut.bind(this), { signal: t }), document.addEventListener("mouseleave", this.handleWindowLeave.bind(this), { signal: t });
|
|
182
126
|
}
|
|
183
127
|
destroy() {
|
|
184
|
-
this.
|
|
128
|
+
this.abortController.abort();
|
|
185
129
|
}
|
|
186
130
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
131
|
+
let g = 0;
|
|
132
|
+
class v {
|
|
133
|
+
constructor(t = document.body, e) {
|
|
134
|
+
if (this.container = t, this.hideNativeCursor = e, !t || !(t instanceof HTMLElement))
|
|
135
|
+
throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);
|
|
136
|
+
const i = g++;
|
|
137
|
+
this.id = `supermouse-style-${i}`, this.scopeClass = `supermouse-scope-${i}`;
|
|
138
|
+
const o = t === document.body;
|
|
139
|
+
this.element = document.createElement("div"), Object.assign(this.element.style, {
|
|
140
|
+
position: o ? "fixed" : "absolute",
|
|
141
|
+
top: "0",
|
|
142
|
+
left: "0",
|
|
143
|
+
width: "100%",
|
|
144
|
+
height: "100%",
|
|
145
|
+
pointerEvents: "none",
|
|
146
|
+
zIndex: "9999",
|
|
147
|
+
opacity: "1",
|
|
148
|
+
transition: "opacity 0.15s ease"
|
|
149
|
+
}), o || window.getComputedStyle(t).position === "static" && (t.style.position = "relative"), t.appendChild(this.element), this.styleTag = document.createElement("style"), this.styleTag.id = this.id, document.head.appendChild(this.styleTag), this.container.classList.add(this.scopeClass), this.hideNativeCursor && this.setNativeCursor("none");
|
|
150
|
+
}
|
|
151
|
+
container;
|
|
152
|
+
hideNativeCursor;
|
|
153
|
+
/** The container element appended to the document. */
|
|
154
|
+
element;
|
|
155
|
+
styleTag;
|
|
156
|
+
id;
|
|
157
|
+
scopeClass;
|
|
158
|
+
currentCursorState = null;
|
|
159
|
+
selectors = /* @__PURE__ */ new Set([
|
|
160
|
+
"a",
|
|
161
|
+
"button",
|
|
162
|
+
"input",
|
|
163
|
+
"textarea",
|
|
164
|
+
"select",
|
|
165
|
+
'[role="button"]',
|
|
166
|
+
"[tabindex]"
|
|
167
|
+
]);
|
|
168
|
+
/**
|
|
169
|
+
* Adds a new CSS selector to the `selectors` set.
|
|
170
|
+
* Called by `Supermouse` and subsequently plugins during install to ensure
|
|
171
|
+
* the native cursor is hidden on their specific interactive targets.
|
|
172
|
+
*/
|
|
173
|
+
addSelector(t) {
|
|
174
|
+
this.selectors.add(t), this.hideNativeCursor && this.updateCursorCSS();
|
|
175
|
+
}
|
|
176
|
+
setVisibility(t) {
|
|
177
|
+
this.element.style.opacity = t ? "1" : "0";
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Toggles the visibility of the native cursor via CSS injection.
|
|
181
|
+
* @param type 'none' to hide, 'auto' to show.
|
|
182
|
+
*/
|
|
183
|
+
setNativeCursor(t) {
|
|
184
|
+
!this.hideNativeCursor && t === "none" || t !== this.currentCursorState && (this.currentCursorState = t, t === "none" ? (this.container.style.cursor = "none", this.updateCursorCSS()) : (this.container.style.cursor = "", this.styleTag.innerText = ""));
|
|
185
|
+
}
|
|
186
|
+
updateCursorCSS() {
|
|
187
|
+
const t = Array.from(this.selectors);
|
|
188
|
+
if (t.length === 0) {
|
|
189
|
+
this.styleTag.innerText = "";
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const e = t.map((i) => `.${this.scopeClass} ${i}`).join(", ");
|
|
193
|
+
this.styleTag.innerText = `
|
|
194
|
+
${e} {
|
|
195
|
+
cursor: none !important;
|
|
196
|
+
}
|
|
197
|
+
`;
|
|
198
|
+
}
|
|
199
|
+
destroy() {
|
|
200
|
+
this.element.remove(), this.styleTag.remove(), this.container.style.cursor = "", this.container.classList.remove(this.scopeClass);
|
|
201
|
+
}
|
|
195
202
|
}
|
|
196
|
-
const
|
|
203
|
+
const u = { x: -100, y: -100 }, m = [
|
|
197
204
|
"a",
|
|
198
205
|
"button",
|
|
199
206
|
"input",
|
|
@@ -202,8 +209,8 @@ const g = [
|
|
|
202
209
|
"[data-cursor]"
|
|
203
210
|
];
|
|
204
211
|
class y {
|
|
205
|
-
static version = "2.
|
|
206
|
-
version = "2.
|
|
212
|
+
static version = "2.2.0";
|
|
213
|
+
version = "2.2.0";
|
|
207
214
|
state;
|
|
208
215
|
/**
|
|
209
216
|
* Configuration options.
|
|
@@ -248,7 +255,7 @@ class y {
|
|
|
248
255
|
hasReceivedInput: !1,
|
|
249
256
|
shape: null,
|
|
250
257
|
interaction: {}
|
|
251
|
-
}, this.options.hoverSelectors ? this.hoverSelectors = new Set(this.options.hoverSelectors) : this.hoverSelectors = new Set(
|
|
258
|
+
}, this.options.hoverSelectors ? this.hoverSelectors = new Set(this.options.hoverSelectors) : this.hoverSelectors = new Set(m), this.stage = new v(this.options.container, !!this.options.hideCursor), this.hoverSelectors.forEach((e) => this.stage.addSelector(e)), this.input = new f(
|
|
252
259
|
this.state,
|
|
253
260
|
this.options,
|
|
254
261
|
() => Array.from(this.hoverSelectors).join(", "),
|
|
@@ -326,9 +333,11 @@ class y {
|
|
|
326
333
|
use(t) {
|
|
327
334
|
return this.plugins.find((e) => e.name === t.name) ? (console.warn(`[Supermouse] Plugin "${t.name}" already installed.`), this) : (t.isEnabled === void 0 && (t.isEnabled = !0), this.plugins.push(t), this.plugins.sort((e, i) => (e.priority || 0) - (i.priority || 0)), t.install?.(this), this);
|
|
328
335
|
}
|
|
336
|
+
resetCoords() {
|
|
337
|
+
this.state.pointer = { ...u }, this.state.target = { ...u }, this.state.smooth = { ...u }, this.state.velocity = { x: 0, y: 0 }, this.state.angle = 0;
|
|
338
|
+
}
|
|
329
339
|
resetPosition() {
|
|
330
|
-
|
|
331
|
-
this.state.pointer = { ...t }, this.state.target = { ...t }, this.state.smooth = { ...t }, this.state.velocity = { x: 0, y: 0 }, this.state.angle = 0, this.state.hasReceivedInput = !1, this.state.shape = null, this.state.interaction = {};
|
|
340
|
+
this.resetCoords(), this.state.hasReceivedInput = !1, this.state.shape = null, this.state.interaction = {};
|
|
332
341
|
}
|
|
333
342
|
startLoop() {
|
|
334
343
|
this.isRunning || (this.isRunning = !0, this.lastTime = performance.now(), this.tick(this.lastTime));
|
|
@@ -349,7 +358,8 @@ class y {
|
|
|
349
358
|
console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`, i), t.isEnabled = !1;
|
|
350
359
|
try {
|
|
351
360
|
t.onDisable?.(this);
|
|
352
|
-
} catch {
|
|
361
|
+
} catch (o) {
|
|
362
|
+
console.error(`[Supermouse] Failed to execute onDisable for plugin '${t.name}'.`, o);
|
|
353
363
|
}
|
|
354
364
|
}
|
|
355
365
|
}
|
|
@@ -359,23 +369,19 @@ class y {
|
|
|
359
369
|
tick = (t) => {
|
|
360
370
|
const e = t - this.lastTime, i = Math.min(e / 1e3, 0.1);
|
|
361
371
|
this.lastTime = t, this.state.hoverTarget && !this.state.hoverTarget.isConnected && this.input.clearHover();
|
|
362
|
-
const
|
|
363
|
-
if (this.stage.setVisibility(
|
|
372
|
+
const o = this.input.isEnabled && !this.state.isNative && this.state.hasReceivedInput;
|
|
373
|
+
if (this.stage.setVisibility(o), this.input.isEnabled && this.options.hideCursor) {
|
|
364
374
|
let s = "auto";
|
|
365
375
|
this.state.forcedCursor !== null ? s = this.state.forcedCursor : s = this.state.isNative || !this.state.hasReceivedInput ? "auto" : "none", this.stage.setNativeCursor(s);
|
|
366
376
|
}
|
|
377
|
+
this.input.isEnabled ? (this.state.target.x = this.state.pointer.x, this.state.target.y = this.state.pointer.y) : this.resetCoords();
|
|
378
|
+
for (let s = 0; s < this.plugins.length; s++)
|
|
379
|
+
this.runPluginSafe(this.plugins[s], e);
|
|
367
380
|
if (this.input.isEnabled) {
|
|
368
|
-
this.state.target.x = this.state.pointer.x, this.state.target.y = this.state.pointer.y;
|
|
369
|
-
for (let h = 0; h < this.plugins.length; h++)
|
|
370
|
-
this.runPluginSafe(this.plugins[h], e);
|
|
371
381
|
const s = this.state.reducedMotion ? 1e3 : 1 / this.options.smoothness * 2;
|
|
372
|
-
this.state.smooth.x =
|
|
382
|
+
this.state.smooth.x = d(this.state.smooth.x, this.state.target.x, s, i), this.state.smooth.y = d(this.state.smooth.y, this.state.target.y, s, i);
|
|
373
383
|
const r = this.state.target.x - this.state.smooth.x, a = this.state.target.y - this.state.smooth.y;
|
|
374
|
-
this.state.velocity.x = r, this.state.velocity.y = a, (Math.abs(r) > 0.1 || Math.abs(a) > 0.1) && (this.state.angle =
|
|
375
|
-
} else {
|
|
376
|
-
this.state.smooth.x = -100, this.state.smooth.y = -100, this.state.pointer.x = -100, this.state.pointer.y = -100, this.state.velocity.x = 0, this.state.velocity.y = 0;
|
|
377
|
-
for (let s = 0; s < this.plugins.length; s++)
|
|
378
|
-
this.runPluginSafe(this.plugins[s], e);
|
|
384
|
+
this.state.velocity.x = r, this.state.velocity.y = a, (Math.abs(r) > 0.1 || Math.abs(a) > 0.1) && (this.state.angle = p(r, a));
|
|
379
385
|
}
|
|
380
386
|
this.options.autoStart && this.isRunning && (this.rafId = requestAnimationFrame(this.tick));
|
|
381
387
|
};
|
|
@@ -387,6 +393,8 @@ class y {
|
|
|
387
393
|
}
|
|
388
394
|
}
|
|
389
395
|
export {
|
|
390
|
-
|
|
396
|
+
m as DEFAULT_HOVER_SELECTORS,
|
|
397
|
+
f as Input,
|
|
398
|
+
v as Stage,
|
|
391
399
|
y as Supermouse
|
|
392
400
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
(function(l
|
|
1
|
+
(function(n,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(n=typeof globalThis<"u"?globalThis:n||self,l(n.SupermouseCore={}))})(this,(function(n){"use strict";function l(a,t,e){return a+(t-a)*e}function p(a,t,e,i){return l(a,t,1-Math.exp(-e*i))}function m(a,t){return Math.atan2(t,a)*(180/Math.PI)}class f{constructor(t,e,i,o){this.state=t,this.options=e,this.getHoverSelector=i,this.onEnableChange=o,this.checkDeviceCapability(),this.checkMotionPreference(),this.bindEvents()}state;options;getHoverSelector;onEnableChange;mediaQueryList;mediaQueryHandler;motionQuery;isEnabled=!0;abortController=new AbortController;checkDeviceCapability(){this.options.autoDisableOnMobile&&(this.mediaQueryList=window.matchMedia("(pointer: fine)"),this.updateEnabledState(this.mediaQueryList.matches),this.mediaQueryHandler=t=>{this.updateEnabledState(t.matches)},this.mediaQueryList.addEventListener("change",this.mediaQueryHandler,{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.options.resolveInteraction){this.state.interaction=this.options.resolveInteraction(t);return}const e={};if(this.options.rules)for(const[o,s]of Object.entries(this.options.rules))t.matches(o)&&Object.assign(e,s);const i=t.dataset;for(const o in i)if(o.startsWith("supermouse")){const s=o.slice(10);if(s){const h=s.charAt(0).toLowerCase()+s.slice(1),r=i[o];r!==void 0&&(e[h]=r===""?!0:r)}}this.state.interaction=e}handleMove(t){if(!this.isEnabled||this.options.autoDisableOnMobile&&t.pointerType==="touch")return;let e=t.clientX,i=t.clientY;if(this.options.container&&this.options.container!==document.body){const o=this.options.container.getBoundingClientRect();e-=o.left,i-=o.top}this.state.pointer.x=e,this.state.pointer.y=i,this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=e,this.state.target.y=this.state.smooth.y=i)}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(e.closest("[data-supermouse-ignore]")){this.state.isNative=!0;return}const i=this.getHoverSelector(),o=e.closest(i);o&&(this.state.isHover=!0,this.state.hoverTarget=o,this.parseDOMInteraction(this.state.hoverTarget));const s=this.options.ignoreOnNative;if(s){const h=s===!0||s==="auto"||s==="tag",r=s===!0||s==="auto"||s==="css";let d=!1;if(h){const u=e.localName;(u==="input"||u==="textarea"||u==="select"||e.isContentEditable)&&(d=!0)}if(!d&&r){const u=window.getComputedStyle(e).cursor;["default","auto","pointer","none","inherit"].includes(u)||(d=!0)}d&&(this.state.isNative=!0)}}handleMouseOut(t){if(!this.isEnabled)return;const e=t.target;(e===this.state.hoverTarget||e.contains(this.state.hoverTarget))&&(!t.relatedTarget||!this.state.hoverTarget?.contains(t.relatedTarget))&&(this.state.isHover=!1,this.state.hoverTarget=null,this.state.interaction={}),this.state.isNative&&(this.state.isNative=!1)}handleWindowLeave(){this.options.hideOnLeave&&(this.state.hasReceivedInput=!1)}clearHover(){this.state.isHover=!1,this.state.hoverTarget=null,this.state.isNative=!1}bindEvents(){const{signal:t}=this.abortController;window.addEventListener("pointermove",this.handleMove.bind(this),{passive:!0,signal:t}),window.addEventListener("pointerdown",this.handleDown.bind(this),{passive:!0,signal:t}),window.addEventListener("pointerup",this.handleUp.bind(this),{signal:t}),document.addEventListener("mouseover",this.handleMouseOver.bind(this),{signal:t}),document.addEventListener("mouseout",this.handleMouseOut.bind(this),{signal:t}),document.addEventListener("mouseleave",this.handleWindowLeave.bind(this),{signal:t})}destroy(){this.abortController.abort()}}let b=0;class g{constructor(t=document.body,e){if(this.container=t,this.hideNativeCursor=e,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);const i=b++;this.id=`supermouse-style-${i}`,this.scopeClass=`supermouse-scope-${i}`;const o=t===document.body;this.element=document.createElement("div"),Object.assign(this.element.style,{position:o?"fixed":"absolute",top:"0",left:"0",width:"100%",height:"100%",pointerEvents:"none",zIndex:"9999",opacity:"1",transition:"opacity 0.15s ease"}),o||window.getComputedStyle(t).position==="static"&&(t.style.position="relative"),t.appendChild(this.element),this.styleTag=document.createElement("style"),this.styleTag.id=this.id,document.head.appendChild(this.styleTag),this.container.classList.add(this.scopeClass),this.hideNativeCursor&&this.setNativeCursor("none")}container;hideNativeCursor;element;styleTag;id;scopeClass;currentCursorState=null;selectors=new Set(["a","button","input","textarea","select",'[role="button"]',"[tabindex]"]);addSelector(t){this.selectors.add(t),this.hideNativeCursor&&this.updateCursorCSS()}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){!this.hideNativeCursor&&t==="none"||t!==this.currentCursorState&&(this.currentCursorState=t,t==="none"?(this.container.style.cursor="none",this.updateCursorCSS()):(this.container.style.cursor="",this.styleTag.innerText=""))}updateCursorCSS(){const t=Array.from(this.selectors);if(t.length===0){this.styleTag.innerText="";return}const e=t.map(i=>`.${this.scopeClass} ${i}`).join(", ");this.styleTag.innerText=`
|
|
2
2
|
${e} {
|
|
3
3
|
cursor: none !important;
|
|
4
4
|
}
|
|
5
|
-
`}destroy(){this.element.remove(),this.styleTag.remove(),this.container.style.cursor="",this.container.classList.remove(this.scopeClass)}}
|
|
5
|
+
`}destroy(){this.element.remove(),this.styleTag.remove(),this.container.style.cursor="",this.container.classList.remove(this.scopeClass)}}const c={x:-100,y:-100},v=["a","button","input","textarea","[data-hover]","[data-cursor]"];class y{static version="2.2.0";version="2.2.0";state;options;plugins=[];stage;input;rafId=0;lastTime=0;isRunning=!1;hoverSelectors;constructor(t={}){this.options={smoothness:.15,enableTouch:!1,autoDisableOnMobile:!0,ignoreOnNative:"auto",hideCursor:!0,hideOnLeave:!0,autoStart:!0,container:document.body,...t},this.options.container||(this.options.container=document.body),this.state={pointer:{x:-100,y:-100},target:{x:-100,y:-100},smooth:{x:-100,y:-100},velocity:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,forcedCursor:null,hoverTarget:null,reducedMotion:!1,hasReceivedInput:!1,shape:null,interaction:{}},this.options.hoverSelectors?this.hoverSelectors=new Set(this.options.hoverSelectors):this.hoverSelectors=new Set(v),this.stage=new g(this.options.container,!!this.options.hideCursor),this.hoverSelectors.forEach(e=>this.stage.addSelector(e)),this.input=new f(this.state,this.options,()=>Array.from(this.hoverSelectors).join(", "),e=>{e||this.resetPosition()}),this.options.plugins&&this.options.plugins.forEach(e=>this.use(e)),this.init()}getPlugin(t){return this.plugins.find(e=>e.name===t)}get isEnabled(){return this.input.isEnabled}enablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled===!1&&(e.isEnabled=!0,e.onEnable?.(this))}disablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled!==!1&&(e.isEnabled=!1,e.onDisable?.(this))}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}registerHoverTarget(t){this.hoverSelectors.has(t)||(this.hoverSelectors.add(t),this.stage.addSelector(t))}get container(){return this.stage.element}setCursor(t){this.state.forcedCursor=t}init(){this.options.autoStart&&this.startLoop()}enable(){this.input.isEnabled=!0,this.stage.setNativeCursor("none")}disable(){this.input.isEnabled=!1,this.stage.setNativeCursor("auto"),this.resetPosition()}use(t){return this.plugins.find(e=>e.name===t.name)?(console.warn(`[Supermouse] Plugin "${t.name}" already installed.`),this):(t.isEnabled===void 0&&(t.isEnabled=!0),this.plugins.push(t),this.plugins.sort((e,i)=>(e.priority||0)-(i.priority||0)),t.install?.(this),this)}resetCoords(){this.state.pointer={...c},this.state.target={...c},this.state.smooth={...c},this.state.velocity={x:0,y:0},this.state.angle=0}resetPosition(){this.resetCoords(),this.state.hasReceivedInput=!1,this.state.shape=null,this.state.interaction={}}startLoop(){this.isRunning||(this.isRunning=!0,this.lastTime=performance.now(),this.tick(this.lastTime))}step(t){this.tick(t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch(i){console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`,i),t.isEnabled=!1;try{t.onDisable?.(this)}catch(o){console.error(`[Supermouse] Failed to execute onDisable for plugin '${t.name}'.`,o)}}}tick=t=>{const e=t-this.lastTime,i=Math.min(e/1e3,.1);this.lastTime=t,this.state.hoverTarget&&!this.state.hoverTarget.isConnected&&this.input.clearHover();const o=this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput;if(this.stage.setVisibility(o),this.input.isEnabled&&this.options.hideCursor){let s="auto";this.state.forcedCursor!==null?s=this.state.forcedCursor:s=this.state.isNative||!this.state.hasReceivedInput?"auto":"none",this.stage.setNativeCursor(s)}this.input.isEnabled?(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y):this.resetCoords();for(let s=0;s<this.plugins.length;s++)this.runPluginSafe(this.plugins[s],e);if(this.input.isEnabled){const s=this.state.reducedMotion?1e3:1/this.options.smoothness*2;this.state.smooth.x=p(this.state.smooth.x,this.state.target.x,s,i),this.state.smooth.y=p(this.state.smooth.y,this.state.target.y,s,i);const h=this.state.target.x-this.state.smooth.x,r=this.state.target.y-this.state.smooth.y;this.state.velocity.x=h,this.state.velocity.y=r,(Math.abs(h)>.1||Math.abs(r)>.1)&&(this.state.angle=m(h,r))}this.options.autoStart&&this.isRunning&&(this.rafId=requestAnimationFrame(this.tick))};destroy(){this.isRunning=!1,cancelAnimationFrame(this.rafId),this.input.destroy(),this.stage.destroy(),this.plugins.forEach(t=>t.destroy?.(this)),this.plugins=[]}}n.DEFAULT_HOVER_SELECTORS=v,n.Input=f,n.Stage=g,n.Supermouse=y,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}));
|