@supermousejs/core 2.2.0 → 2.3.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.
@@ -0,0 +1,13 @@
1
+ Object.defineProperty(window, "matchMedia", {
2
+ writable: true,
3
+ value: (query: string) => ({
4
+ matches: false,
5
+ media: query,
6
+ onchange: null,
7
+ addListener: () => {},
8
+ removeListener: () => {},
9
+ addEventListener: () => {},
10
+ removeEventListener: () => {},
11
+ dispatchEvent: () => false
12
+ })
13
+ });
@@ -0,0 +1,19 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { Supermouse } from "../Supermouse";
3
+
4
+ describe("Supermouse core", () => {
5
+ it("registers and looks up plugins by name", () => {
6
+ const app = new Supermouse();
7
+
8
+ const plugin = {
9
+ name: "test-plugin",
10
+ install() {},
11
+ update() {}
12
+ };
13
+
14
+ app.use(plugin);
15
+
16
+ expect(app.getPlugin("test-plugin")).toBe(plugin);
17
+ expect(app.getPlugin("missing-plugin")).toBeUndefined();
18
+ });
19
+ });
package/src/types.ts CHANGED
@@ -32,21 +32,21 @@ export interface InteractionState {
32
32
  }
33
33
 
34
34
  export interface MouseState {
35
- /** The raw position of the input pointer (mouse/touch). */
35
+ /** The raw position from the latest pointer event, before smoothing is applied. */
36
36
  pointer: MousePosition;
37
- /** The target position the cursor logic wants to reach. */
37
+ /** The current goal position that the core loop is driving toward. */
38
38
  target: MousePosition;
39
39
  /** The smoothed/interpolated position used for rendering. */
40
40
  smooth: MousePosition;
41
- /** The current velocity vector of the smooth position. */
41
+ /** The current movement vector derived from the smoothed state. */
42
42
  velocity: MousePosition;
43
- /** The angle of movement in degrees. Calculated from velocity. */
43
+ /** The current movement angle in degrees, derived from velocity. */
44
44
  angle: number;
45
45
  /** Whether the pointer is currently pressed down. */
46
46
  isDown: boolean;
47
47
  /** Whether the pointer is currently hovering over a registered interactive element. */
48
48
  isHover: boolean;
49
- /** Whether the native cursor is currently forced visible by internal logic (e.g. input elements). */
49
+ /** Whether the runtime has temporarily restored the native cursor due to native-input heuristics. */
50
50
  isNative: boolean;
51
51
  /**
52
52
  * If set, this overrides all auto-detection logic.
@@ -95,20 +95,24 @@ export interface SupermouseOptions {
95
95
  autoDisableOnMobile?: boolean;
96
96
  /**
97
97
  * Strategy for detecting when to fallback to the native cursor.
98
- * - `true` / `'auto'`: Checks both HTML tags and CSS cursor styles (Accurate but slower).
98
+ * - `'auto'`: Checks both HTML tags and CSS cursor styles (Accurate but slower).
99
99
  * - `'tag'`: Checks only semantic tags like <input>, <textarea> (Fastest, prevents layout thrashing).
100
100
  * - `'css'`: Checks only computed CSS cursor styles (Slow, triggers reflow).
101
- * - `false`: Never fallback to native cursor.
101
+ * - `null`: Never fallback to native cursor.
102
+ *
102
103
  * @default 'auto'
103
104
  */
104
- ignoreOnNative?: boolean | NativeIgnoreStrategy;
105
+ ignoreOnNative?: NativeIgnoreStrategy | null;
105
106
  /**
106
- * Whether to hide the native cursor via global CSS injection.
107
+ * Whether to hide the native cursor via scoped CSS injection on the container.
108
+ * When enabled, the stage toggles `cursor: none` on the configured container and
109
+ * on registered hover targets.
107
110
  * @default true
108
111
  */
109
112
  hideCursor?: boolean;
110
113
  /**
111
- * Whether to hide the custom cursor when the mouse leaves the browser window.
114
+ * Whether to hide the custom cursor when the pointer leaves the browser viewport.
115
+ * When enabled the runtime clears the cursor back to an off-screen position to avoid stale hover state.
112
116
  * @default true
113
117
  */
114
118
  hideOnLeave?: boolean;
@@ -128,18 +132,29 @@ export interface SupermouseOptions {
128
132
  autoStart?: boolean;
129
133
  /**
130
134
  * Semantic rules mapping CSS selectors to interaction state.
135
+ * Rules are evaluated against hovered elements and merged into `state.interaction`.
136
+ * Matching data attributes on the same element are also read and can override or enrich the final object.
131
137
  * @example { 'button': { icon: 'pointer' } }
132
138
  */
133
139
  rules?: Record<string, InteractionState>;
134
140
  /**
135
141
  * Custom strategy to resolve interaction state from a hovered element.
136
- * Overrides the default data-attribute scraping.
142
+ * When provided, this callback bypasses the default `rules` + `data-[prefix]-*` scraping and
143
+ * returns the interaction payload directly for the current hover target.
137
144
  */
138
145
  resolveInteraction?: (target: HTMLElement) => InteractionState;
146
+ /**
147
+ * The prefix used for data attributes to store hover metadata.
148
+ * For example, if dataPrefix is "supermouse", then the attribute would be "data-supermouse-*".
149
+ * This allows for multiple instances of Supermouse to coexist without conflicting data attributes.
150
+ * @default "supermouse"
151
+ */
152
+ dataPrefix?: string;
139
153
  }
140
154
 
141
155
  /**
142
156
  * Allows a property to be a static value or a function that returns the value based on state.
157
+ * This is primarily useful for plugin option definitions that should react to the current runtime state.
143
158
  */
144
159
  export type ValueOrGetter<T> = T | ((state: MouseState) => T);
145
160
 
@@ -156,7 +171,7 @@ export interface SupermousePlugin {
156
171
 
157
172
  /** Called when `app.use()` is executed. */
158
173
  install?: (instance: Supermouse) => void;
159
- /** Called on every animation frame. */
174
+ /** Called on every animation frame with the frame delta time in milliseconds. */
160
175
  update?: (instance: Supermouse, deltaTime: number) => void;
161
176
  /** Called when the plugin is removed or the app is destroyed. */
162
177
  destroy?: (instance: Supermouse) => void;
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: "jsdom",
6
+ globals: true,
7
+ setupFiles: ["src/__tests__/setup.ts"],
8
+ include: ["src/**/*.test.ts"]
9
+ }
10
+ });