@supermousejs/core 2.2.0 → 2.4.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 +44 -0
- package/dist/index.d.ts +113 -127
- package/dist/index.mjs +329 -228
- package/dist/index.umd.js +10 -5
- package/package.json +4 -3
- package/src/Supermouse.ts +953 -708
- package/src/__tests__/core.spec.ts +291 -0
- package/src/__tests__/cursor-mode.spec.ts +109 -0
- package/src/__tests__/input.spec.ts +261 -0
- package/src/__tests__/integration.spec.ts +121 -0
- package/src/__tests__/lifecycle.spec.ts +199 -0
- package/src/__tests__/nested-instance.spec.ts +51 -0
- package/src/__tests__/plugin.spec.ts +130 -0
- package/src/__tests__/setup.ts +21 -0
- package/src/__tests__/stage.spec.ts +235 -0
- package/src/__tests__/suspend-resume.spec.ts +50 -0
- package/src/types.ts +165 -168
- package/vitest.config.ts +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# @supermousejs/core
|
|
2
2
|
|
|
3
|
+
## 2.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 53b7276: This release stabilises the core after experimental work, keeping the best improvements while reverting the approach that caused cursor flickering.
|
|
8
|
+
- `zIndex` option – customise the stage’s z‑index (default `9999`).
|
|
9
|
+
- `cacheCursorStyle` option – opt‑in per‑element caching of computed `cursor` values, with `clearStyleCache()` to invalidate.
|
|
10
|
+
- `suspend()` / `resume()` – temporarily yield to another Supermouse instance without tearing down the current one.
|
|
11
|
+
- `hasSeenPointer` flag – enables `enable()` to snap the cursor to the live pointer instantly, no more off‑screen sweep.
|
|
12
|
+
- Nested‑instance CSS exclusion – scoped stylesheets now automatically prevent outer instance cursor rules from leaking into nested containers.
|
|
13
|
+
- `enable()` now respects any active `forcedCursor` override.
|
|
14
|
+
- `disable()` always restores the native cursor.
|
|
15
|
+
- `clearHover()` now resets `isNative` and `nativeTarget` to prevent stale state.
|
|
16
|
+
- Plugin crash handling: crashing plugins are removed after the frame with full cleanup (`onDisable` → `destroy` → element removal).
|
|
17
|
+
- `enablePlugin` / `disablePlugin` now hide/show the plugin’s DOM element (if it exposes an `element` property) and call lifecycle hooks.
|
|
18
|
+
- `reset()` no longer wipes `state.pointer`, so `enable()` can always snap to the last known position.
|
|
19
|
+
- Native‑cursor suppression now uses a class‑toggled CSS approach with additional rules for `<label>`, `<select>`, and range slider thumbs.
|
|
20
|
+
- `handleMouseOut` clears `isNative` only when truly leaving the native element, preventing flicker when moving within native controls.
|
|
21
|
+
- Animation loop pauses when the tab is hidden and resumes on focus.
|
|
22
|
+
- `Stage` warns if the container is not attached to the DOM yet.
|
|
23
|
+
- Original container `cursor` style is restored on destroy.
|
|
24
|
+
- Various other stability and edge‑case fixes.
|
|
25
|
+
|
|
26
|
+
- 0cd6a04: - Unified cursor modes to reduce api surface by replacing cursor and hideCursor with single cursor option, decouple interaction parsing causing bugs
|
|
27
|
+
- Cache rule entries and hover selector string to reduce per-frame work.
|
|
28
|
+
- Suspend/resume no longer toggle native cursor state. this is an identified multi-scope limitation.
|
|
29
|
+
- ab3cad2: Enhanced supermouse containerization and added options for caching computed cursor styles
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- 36d5366: Added proper description messages to package meta
|
|
34
|
+
- 4fc5aed: Added forward-compatible `onBeforeDisable` hook for plugins in preparation for architecture rewrite in v2.5
|
|
35
|
+
|
|
36
|
+
## 2.3.0
|
|
37
|
+
|
|
38
|
+
### Minor Changes
|
|
39
|
+
|
|
40
|
+
- 8dc8e06: cleanup and robustness pass: better case-insensitive data-\* handling, safer plugin lifecycle behavior, more reliable cursor restoration, and a more consistent reset/update flow
|
|
41
|
+
- 600de13: added `dataPrefix` option for customizable data attribute handling, added a `start()` public method to manually start the raf loop and enhanced supermouse's resistance to bugs
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- b72e264: Renamed `setCursor` to `setNativeCursor` for simplicity and removed redundant checks on `ignoreOnNative`
|
|
46
|
+
|
|
3
47
|
## 2.2.0
|
|
4
48
|
|
|
5
49
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
/** Default selectors that trigger `state.isHover`. Override with `hoverSelectors`. */
|
|
1
2
|
export declare const DEFAULT_HOVER_SELECTORS: string[];
|
|
2
3
|
|
|
3
4
|
/* Excluded from this release type: Input */
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* Interaction state consumed by plugins.
|
|
8
|
+
* Extend via module augmentation for type safety.
|
|
8
9
|
*
|
|
9
10
|
* @example
|
|
10
11
|
* declare module '@supermousejs/core' {
|
|
@@ -15,10 +16,7 @@ export declare const DEFAULT_HOVER_SELECTORS: string[];
|
|
|
15
16
|
* }
|
|
16
17
|
*/
|
|
17
18
|
export declare interface InteractionState {
|
|
18
|
-
/**
|
|
19
|
-
* Allow arbitrary keys for rapid prototyping.
|
|
20
|
-
* For type safety, use module augmentation to define expected keys.
|
|
21
|
-
*/
|
|
19
|
+
/** Arbitrary keys allowed for quick prototyping. */
|
|
22
20
|
[key: string]: any;
|
|
23
21
|
}
|
|
24
22
|
|
|
@@ -28,42 +26,49 @@ export declare interface MousePosition {
|
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
export declare interface MouseState {
|
|
31
|
-
/**
|
|
29
|
+
/** Raw pointer position from the latest event (before smoothing). */
|
|
32
30
|
pointer: MousePosition;
|
|
33
|
-
/**
|
|
31
|
+
/** Goal position the core loop drives toward. */
|
|
34
32
|
target: MousePosition;
|
|
35
|
-
/**
|
|
33
|
+
/** Smoothed position used for rendering. */
|
|
36
34
|
smooth: MousePosition;
|
|
37
|
-
/**
|
|
35
|
+
/** Movement vector derived from smoothed state. */
|
|
38
36
|
velocity: MousePosition;
|
|
39
|
-
/**
|
|
37
|
+
/** Remaining distance to target. */
|
|
38
|
+
displacement: MousePosition;
|
|
39
|
+
/** Movement angle in degrees. */
|
|
40
40
|
angle: number;
|
|
41
|
-
/**
|
|
41
|
+
/** Pointer is pressed down. */
|
|
42
42
|
isDown: boolean;
|
|
43
|
-
/**
|
|
43
|
+
/** Hovering over a registered interactive element. */
|
|
44
44
|
isHover: boolean;
|
|
45
|
-
/**
|
|
45
|
+
/** Native cursor temporarily restored due to native-input heuristics. */
|
|
46
46
|
isNative: boolean;
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
* 'none' = Force Custom Cursor (Hide Native)
|
|
51
|
-
* null = Let the Core decide based on isNative/isHover
|
|
52
|
-
*/
|
|
53
|
-
forcedCursor: "auto" | "none" | null;
|
|
54
|
-
/** The DOM element currently being hovered, if any. */
|
|
47
|
+
/** Current cursor mode: auto, custom, native, or both. */
|
|
48
|
+
cursorMode: "auto" | "custom" | "native" | "both";
|
|
49
|
+
/** Currently hovered DOM element, if any. */
|
|
55
50
|
hoverTarget: HTMLElement | null;
|
|
56
|
-
/**
|
|
51
|
+
/** User has `prefers-reduced-motion` enabled. */
|
|
57
52
|
reducedMotion: boolean;
|
|
58
|
-
/**
|
|
53
|
+
/** At least one valid input coordinate received. */
|
|
59
54
|
hasReceivedInput: boolean;
|
|
60
|
-
/**
|
|
55
|
+
/** Geometric shape the cursor should conform to. */
|
|
61
56
|
shape: ShapeState | null;
|
|
62
|
-
/** Centralized store for hover metadata from data attributes. */
|
|
57
|
+
/** Centralized store for hover metadata from data attributes and rules. */
|
|
63
58
|
interaction: InteractionState;
|
|
64
59
|
}
|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
/**
|
|
62
|
+
* The subset of `SupermouseOptions` guaranteed to have a concrete value once
|
|
63
|
+
* the constructor has merged user input over the defaults.
|
|
64
|
+
*/
|
|
65
|
+
declare type ResolvedOptions = SupermouseOptions & Required<Pick<SupermouseOptions, "smoothness" | "enableTouch" | "autoDisableOnMobile" | "cursor" | "hideOnLeave" | "autoStart" | "container" | "dataPrefix" | "zIndex">>;
|
|
66
|
+
|
|
67
|
+
export declare type RuleDefinition = RuleSet | ((el: HTMLElement) => RuleSet);
|
|
68
|
+
|
|
69
|
+
export declare type RuleSet = Record<string, RuleValue | ((el: HTMLElement) => RuleValue)>;
|
|
70
|
+
|
|
71
|
+
export declare type RuleValue = string | boolean | number;
|
|
67
72
|
|
|
68
73
|
export declare interface ShapeState {
|
|
69
74
|
width: number;
|
|
@@ -74,100 +79,78 @@ export declare interface ShapeState {
|
|
|
74
79
|
/* Excluded from this release type: Stage */
|
|
75
80
|
|
|
76
81
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* This class orchestrates the application state, manages the animation loop,
|
|
80
|
-
* and coordinates data flow between the internal systems, and the plugins.
|
|
81
|
-
*
|
|
82
|
-
* @default
|
|
82
|
+
* Orchestrates state, animation loop, and plugin lifecycle.
|
|
83
83
|
*/
|
|
84
84
|
export declare class Supermouse {
|
|
85
85
|
static readonly version: string;
|
|
86
86
|
readonly version: string;
|
|
87
87
|
state: MouseState;
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
*/
|
|
91
|
-
options: SupermouseOptions;
|
|
88
|
+
/** Configuration options, fully resolved with defaults applied. */
|
|
89
|
+
options: ResolvedOptions;
|
|
92
90
|
private plugins;
|
|
93
|
-
private
|
|
91
|
+
private _stage;
|
|
94
92
|
private input;
|
|
95
93
|
private rafId;
|
|
96
94
|
private lastTime;
|
|
97
95
|
private isRunning;
|
|
96
|
+
private isSuspended;
|
|
97
|
+
private visibilityAbortController;
|
|
98
98
|
private hoverSelectors;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
*
|
|
102
|
-
* @param options - Global configuration options.
|
|
103
|
-
* @throws Will throw if running in a non-browser environment (window/document undefined).
|
|
104
|
-
*/
|
|
99
|
+
private hoverSelectorString;
|
|
100
|
+
private crashedPlugins;
|
|
105
101
|
constructor(options?: SupermouseOptions);
|
|
106
|
-
/**
|
|
107
|
-
* Retrieves a registered plugin instance by its unique name.
|
|
108
|
-
*/
|
|
102
|
+
/** Look up a registered plugin by name. */
|
|
109
103
|
getPlugin(name: string): SupermousePlugin | undefined;
|
|
110
|
-
/**
|
|
111
|
-
* Returns whether the cursor system is currently enabled (processing input).
|
|
112
|
-
*/
|
|
104
|
+
/** Whether the instance is not disabled/suspended and is processing input. */
|
|
113
105
|
get isEnabled(): boolean;
|
|
114
|
-
/**
|
|
115
|
-
* Enables a specific plugin by name.
|
|
116
|
-
* Triggers the `onEnable` lifecycle hook of the plugin.
|
|
117
|
-
*/
|
|
106
|
+
/** Enable a plugin by name. */
|
|
118
107
|
enablePlugin(name: string): void;
|
|
119
|
-
/**
|
|
120
|
-
* Disables a specific plugin by name.
|
|
121
|
-
* Triggers the `onDisable` lifecycle hook.
|
|
122
|
-
*/
|
|
108
|
+
/** Disable a plugin by name and hide its element. */
|
|
123
109
|
disablePlugin(name: string): void;
|
|
124
|
-
/**
|
|
125
|
-
* Toggles the enabled state of a plugin.
|
|
126
|
-
*/
|
|
110
|
+
/** Toggle a plugin's enabled state by name. */
|
|
127
111
|
togglePlugin(name: string): void;
|
|
112
|
+
/** Add a selector to hover detection and cursor suppression. */
|
|
128
113
|
registerHoverTarget(selector: string): void;
|
|
129
|
-
/**
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
get
|
|
133
|
-
/**
|
|
134
|
-
|
|
135
|
-
*
|
|
136
|
-
* @param type 'auto' (Show Native), 'none' (Hide Native), or null (Resume Auto-detection)
|
|
137
|
-
*/
|
|
138
|
-
setCursor(type: "auto" | "none" | null): void;
|
|
114
|
+
/** The DOM element the instance is scoped to. */
|
|
115
|
+
get container(): HTMLElement;
|
|
116
|
+
/** The stage element that plugins append their visuals into. */
|
|
117
|
+
get stage(): HTMLDivElement;
|
|
118
|
+
/** Set the current cursor mode. */
|
|
119
|
+
setCursor(mode: "auto" | "custom" | "native" | "both"): void;
|
|
139
120
|
private init;
|
|
121
|
+
/** Re‑enable input processing and re‑apply cursor state. */
|
|
140
122
|
enable(): void;
|
|
123
|
+
/** Disable input processing and restore native cursor. */
|
|
141
124
|
disable(): void;
|
|
142
|
-
/**
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
125
|
+
/** Temporarily yield to a scoped instance. */
|
|
126
|
+
suspend(): void;
|
|
127
|
+
/** Resume from `suspend()`. */
|
|
128
|
+
resume(): void;
|
|
129
|
+
/** Register a new plugin. */
|
|
147
130
|
use(plugin: SupermousePlugin): this;
|
|
148
|
-
|
|
149
|
-
private
|
|
131
|
+
/** Reset physics; optionally clear all input state. */
|
|
132
|
+
private reset;
|
|
150
133
|
private startLoop;
|
|
151
|
-
/**
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
* @param time Current timestamp in milliseconds.
|
|
155
|
-
*/
|
|
134
|
+
/** Start the animation loop. */
|
|
135
|
+
start(): void;
|
|
136
|
+
/** Manually step the animation loop. */
|
|
156
137
|
step(time: number): void;
|
|
157
138
|
private runPluginSafe;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
139
|
+
private cleanupCrashedPlugins;
|
|
140
|
+
private resolveStageVisibility;
|
|
141
|
+
private resolveCursorState;
|
|
142
|
+
private resetMotion;
|
|
143
|
+
private update;
|
|
161
144
|
private tick;
|
|
162
|
-
/**
|
|
163
|
-
|
|
164
|
-
|
|
145
|
+
/** Pause rAF loop when tab hidden; resume on visible. */
|
|
146
|
+
private bindVisibilityHandling;
|
|
147
|
+
/** Destroy the instance, freeing all resources. */
|
|
165
148
|
destroy(): void;
|
|
166
149
|
}
|
|
167
150
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
*/
|
|
151
|
+
export declare type SupermouseInstance = Supermouse;
|
|
152
|
+
|
|
153
|
+
/** Configuration options for the Supermouse constructor. */
|
|
171
154
|
export declare interface SupermouseOptions {
|
|
172
155
|
/**
|
|
173
156
|
* The interpolation factor (0 to 1). Lower is smoother/slower.
|
|
@@ -190,21 +173,16 @@ export declare interface SupermouseOptions {
|
|
|
190
173
|
*/
|
|
191
174
|
autoDisableOnMobile?: boolean;
|
|
192
175
|
/**
|
|
193
|
-
*
|
|
194
|
-
* - `
|
|
195
|
-
* - `
|
|
196
|
-
* - `
|
|
197
|
-
* - `
|
|
198
|
-
* @default
|
|
199
|
-
*/
|
|
200
|
-
ignoreOnNative?: boolean | NativeIgnoreStrategy;
|
|
201
|
-
/**
|
|
202
|
-
* Whether to hide the native cursor via global CSS injection.
|
|
203
|
-
* @default true
|
|
176
|
+
* Overall cursor mode.
|
|
177
|
+
* - `"auto"`: use built-in heuristic to decide per element.
|
|
178
|
+
* - `"custom"`: always show custom cursor, hide native.
|
|
179
|
+
* - `"native"`: always show native cursor, hide custom.
|
|
180
|
+
* - `"both"`: always show custom cursor **and** native cursor together (no suppression).
|
|
181
|
+
* @default "auto"
|
|
204
182
|
*/
|
|
205
|
-
|
|
183
|
+
cursor?: "auto" | "custom" | "native" | "both";
|
|
206
184
|
/**
|
|
207
|
-
* Whether to hide the custom cursor when the
|
|
185
|
+
* Whether to hide the custom cursor when the pointer leaves the browser viewport.
|
|
208
186
|
* @default true
|
|
209
187
|
*/
|
|
210
188
|
hideOnLeave?: boolean;
|
|
@@ -224,41 +202,49 @@ export declare interface SupermouseOptions {
|
|
|
224
202
|
autoStart?: boolean;
|
|
225
203
|
/**
|
|
226
204
|
* Semantic rules mapping CSS selectors to interaction state.
|
|
205
|
+
* Rules are evaluated against hovered elements and merged into `state.interaction`.
|
|
227
206
|
* @example { 'button': { icon: 'pointer' } }
|
|
228
207
|
*/
|
|
229
|
-
rules?: Record<string,
|
|
208
|
+
rules?: Record<string, RuleDefinition>;
|
|
230
209
|
/**
|
|
231
|
-
*
|
|
232
|
-
*
|
|
210
|
+
* The prefix used for data attributes to store hover metadata.
|
|
211
|
+
* @default "supermouse"
|
|
233
212
|
*/
|
|
234
|
-
|
|
213
|
+
dataPrefix?: string;
|
|
214
|
+
/**
|
|
215
|
+
* The `z-index` applied to the cursor stage element.
|
|
216
|
+
* @default 9999
|
|
217
|
+
*/
|
|
218
|
+
zIndex?: number;
|
|
235
219
|
}
|
|
236
220
|
|
|
237
|
-
/**
|
|
238
|
-
* Interface for defining a Supermouse Plugin.
|
|
239
|
-
*/
|
|
221
|
+
/** Interface for defining a Supermouse plugin. */
|
|
240
222
|
export declare interface SupermousePlugin {
|
|
241
|
-
/** Unique
|
|
223
|
+
/** Unique plugin name. */
|
|
242
224
|
name: string;
|
|
243
|
-
/** Execution priority
|
|
225
|
+
/** Execution priority; lower runs first. */
|
|
244
226
|
priority?: number;
|
|
245
|
-
/** If false, update() will not be called. */
|
|
227
|
+
/** If false, `update()` will not be called. */
|
|
246
228
|
isEnabled?: boolean;
|
|
229
|
+
/** Root DOM element, if any. Hidden when plugin disabled. */
|
|
230
|
+
element?: HTMLElement | SVGElement;
|
|
247
231
|
/** Called when `app.use()` is executed. */
|
|
248
|
-
install?: (instance:
|
|
249
|
-
/** Called
|
|
250
|
-
update?: (instance:
|
|
251
|
-
/** Called when
|
|
252
|
-
destroy?: (instance:
|
|
253
|
-
/** Called when
|
|
254
|
-
onEnable?: (instance:
|
|
255
|
-
/** Called when
|
|
256
|
-
onDisable?: (instance:
|
|
232
|
+
install?: (instance: SupermouseInstance) => void;
|
|
233
|
+
/** Called every animation frame with delta time in ms. */
|
|
234
|
+
update?: (instance: SupermouseInstance, deltaTime: number) => void;
|
|
235
|
+
/** Called when plugin removed or instance destroyed. */
|
|
236
|
+
destroy?: (instance: SupermouseInstance) => void;
|
|
237
|
+
/** Called when plugin enabled via `.enablePlugin()`. */
|
|
238
|
+
onEnable?: (instance: SupermouseInstance) => void;
|
|
239
|
+
/** Called when plugin disabled via `.disablePlugin()`. */
|
|
240
|
+
onDisable?: (instance: SupermouseInstance) => void;
|
|
241
|
+
/**
|
|
242
|
+
* Called before the plugin is disabled.
|
|
243
|
+
*/
|
|
244
|
+
onBeforeDisable?(instance: SupermouseInstance): void | Promise<void>;
|
|
257
245
|
}
|
|
258
246
|
|
|
259
|
-
/**
|
|
260
|
-
* Allows a property to be a static value or a function that returns the value based on state.
|
|
261
|
-
*/
|
|
247
|
+
/** Static value or function that returns a value based on state. */
|
|
262
248
|
export declare type ValueOrGetter<T> = T | ((state: MouseState) => T);
|
|
263
249
|
|
|
264
250
|
export { }
|