@supermousejs/core 2.0.0 → 2.0.2
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 +12 -0
- package/README.md +31 -0
- package/dist/index.mjs +2 -2
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
- package/tsconfig.json +15 -15
- package/vite.config.ts +32 -32
package/CHANGELOG.md
CHANGED
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
# @supermousejs/core
|
|
3
|
+
|
|
4
|
+
The high-performance runtime engine for **Supermouse v2**.
|
|
5
|
+
|
|
6
|
+
It separates cursor **intent** (input, physics, logic) from **rendering** (visuals), exposing a deterministic plugin pipeline.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pnpm add @supermousejs/core
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Basic Usage
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { Supermouse } from '@supermousejs/core';
|
|
18
|
+
// Import visuals separately to keep bundle size low
|
|
19
|
+
import { Dot } from '@supermousejs/dot';
|
|
20
|
+
|
|
21
|
+
const app = new Supermouse({
|
|
22
|
+
smoothness: 0.15, // 0-1 (Physics damping)
|
|
23
|
+
hideCursor: true, // Auto-hide native cursor
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
app.use(Dot({ size: 8, color: '#f59e0b' }));
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Documentation
|
|
30
|
+
|
|
31
|
+
Full documentation and interactive playground available at [supermouse](https://supermouse.vercel.app) or [check out the repo](https://github.com/Whitestar14/supermouse-js).
|
package/dist/index.mjs
CHANGED
package/dist/index.umd.js
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
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)}}class v{constructor(t,e,s,n){this.state=t,this.options=e,this.getHoverSelector=s,this.onEnableChange=n,this.checkDeviceCapability(),this.checkMotionPreference(),this.bindEvents()}mediaQueryList;mediaQueryHandler;motionQuery;isEnabled=!0;interactionCache=new WeakMap;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))}checkMotionPreference(){this.motionQuery=window.matchMedia("(prefer-reduced-motion: reduce)"),this.state.reducedMotion=this.motionQuery.matches,this.motionQuery.addEventListener("change",t=>{this.state.reducedMotion=t.matches})}updateEnabledState(t){this.isEnabled=t,this.onEnableChange(t)}parseDOMInteraction(t){if(this.options.resolveInteraction){this.state.interaction=this.options.resolveInteraction(t);return}if(this.interactionCache.has(t)){this.state.interaction=this.interactionCache.get(t);return}const e={};if(this.options.rules)for(const[n,i]of Object.entries(this.options.rules))t.matches(n)&&Object.assign(e,i);const s=t.dataset;for(const n in s)if(n.startsWith("supermouse")){const i=n.slice(10);if(i){const l=i.charAt(0).toLowerCase()+i.slice(1),r=s[n];e[l]=r===""?!0:r}}this.interactionCache.set(t,e),this.state.interaction=e}handleMove=t=>{if(!this.isEnabled||this.options.autoDisableOnMobile&&t.pointerType==="touch")return;let e=t.clientX,s=t.clientY;if(this.options.container&&this.options.container!==document.body){const n=this.options.container.getBoundingClientRect();e-=n.left,s-=n.top}this.state.pointer.x=e,this.state.pointer.y=s,this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=e,this.state.target.y=this.state.smooth.y=s)};handleDown=()=>{this.isEnabled&&(this.state.isDown=!0)};handleUp=()=>{this.isEnabled&&(this.state.isDown=!1)};handleMouseOver=t=>{if(!this.isEnabled)return;const e=t.target;if(e.closest("[data-supermouse-ignore]")){this.state.isNative=!0;return}const s=this.getHoverSelector(),n=e.closest(s);n&&(this.state.isHover=!0,this.state.hoverTarget=n,this.parseDOMInteraction(this.state.hoverTarget));const i=this.options.ignoreOnNative;if(i){const l=i===!0||i==="auto"||i==="tag",r=i===!0||i==="auto"||i==="css";let h=!1;if(l){const a=e.localName;(a==="input"||a==="textarea"||a==="select"||e.isContentEditable)&&(h=!0)}if(!h&&r){const a=window.getComputedStyle(e).cursor;["default","auto","pointer","none","inherit"].includes(a)||(h=!0)}h&&(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)};bindEvents(){window.addEventListener("pointermove",this.handleMove,{passive:!0}),window.addEventListener("pointerdown",this.handleDown,{passive:!0}),window.addEventListener("pointerup",this.handleUp),document.addEventListener("mouseover",this.handleMouseOver),document.addEventListener("mouseout",this.handleMouseOut),document.addEventListener("mouseleave",this.handleWindowLeave)}destroy(){this.mediaQueryList&&this.mediaQueryHandler&&this.mediaQueryList.removeEventListener("change",this.mediaQueryHandler),window.removeEventListener("pointermove",this.handleMove),window.removeEventListener("pointerdown",this.handleDown),window.removeEventListener("pointerup",this.handleUp),document.removeEventListener("mouseover",this.handleMouseOver),document.removeEventListener("mouseout",this.handleMouseOut),document.removeEventListener("mouseleave",this.handleWindowLeave)}}function m(o,t,e){return o+(t-o)*e}function c(o,t,e,s){return m(o,t,1-Math.exp(-e*s))}function g(o,t){return Math.atan2(t,o)*(180/Math.PI)}const p=["a","button","input","textarea","[data-hover]","[data-cursor]"];class y{static version="2.0.
|
|
5
|
+
`}destroy(){this.element.remove(),this.styleTag.remove(),this.container.style.cursor="",this.container.classList.remove(this.scopeClass)}}class v{constructor(t,e,s,n){this.state=t,this.options=e,this.getHoverSelector=s,this.onEnableChange=n,this.checkDeviceCapability(),this.checkMotionPreference(),this.bindEvents()}mediaQueryList;mediaQueryHandler;motionQuery;isEnabled=!0;interactionCache=new WeakMap;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))}checkMotionPreference(){this.motionQuery=window.matchMedia("(prefer-reduced-motion: reduce)"),this.state.reducedMotion=this.motionQuery.matches,this.motionQuery.addEventListener("change",t=>{this.state.reducedMotion=t.matches})}updateEnabledState(t){this.isEnabled=t,this.onEnableChange(t)}parseDOMInteraction(t){if(this.options.resolveInteraction){this.state.interaction=this.options.resolveInteraction(t);return}if(this.interactionCache.has(t)){this.state.interaction=this.interactionCache.get(t);return}const e={};if(this.options.rules)for(const[n,i]of Object.entries(this.options.rules))t.matches(n)&&Object.assign(e,i);const s=t.dataset;for(const n in s)if(n.startsWith("supermouse")){const i=n.slice(10);if(i){const l=i.charAt(0).toLowerCase()+i.slice(1),r=s[n];e[l]=r===""?!0:r}}this.interactionCache.set(t,e),this.state.interaction=e}handleMove=t=>{if(!this.isEnabled||this.options.autoDisableOnMobile&&t.pointerType==="touch")return;let e=t.clientX,s=t.clientY;if(this.options.container&&this.options.container!==document.body){const n=this.options.container.getBoundingClientRect();e-=n.left,s-=n.top}this.state.pointer.x=e,this.state.pointer.y=s,this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=e,this.state.target.y=this.state.smooth.y=s)};handleDown=()=>{this.isEnabled&&(this.state.isDown=!0)};handleUp=()=>{this.isEnabled&&(this.state.isDown=!1)};handleMouseOver=t=>{if(!this.isEnabled)return;const e=t.target;if(e.closest("[data-supermouse-ignore]")){this.state.isNative=!0;return}const s=this.getHoverSelector(),n=e.closest(s);n&&(this.state.isHover=!0,this.state.hoverTarget=n,this.parseDOMInteraction(this.state.hoverTarget));const i=this.options.ignoreOnNative;if(i){const l=i===!0||i==="auto"||i==="tag",r=i===!0||i==="auto"||i==="css";let h=!1;if(l){const a=e.localName;(a==="input"||a==="textarea"||a==="select"||e.isContentEditable)&&(h=!0)}if(!h&&r){const a=window.getComputedStyle(e).cursor;["default","auto","pointer","none","inherit"].includes(a)||(h=!0)}h&&(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)};bindEvents(){window.addEventListener("pointermove",this.handleMove,{passive:!0}),window.addEventListener("pointerdown",this.handleDown,{passive:!0}),window.addEventListener("pointerup",this.handleUp),document.addEventListener("mouseover",this.handleMouseOver),document.addEventListener("mouseout",this.handleMouseOut),document.addEventListener("mouseleave",this.handleWindowLeave)}destroy(){this.mediaQueryList&&this.mediaQueryHandler&&this.mediaQueryList.removeEventListener("change",this.mediaQueryHandler),window.removeEventListener("pointermove",this.handleMove),window.removeEventListener("pointerdown",this.handleDown),window.removeEventListener("pointerup",this.handleUp),document.removeEventListener("mouseover",this.handleMouseOver),document.removeEventListener("mouseout",this.handleMouseOut),document.removeEventListener("mouseleave",this.handleWindowLeave)}}function m(o,t,e){return o+(t-o)*e}function c(o,t,e,s){return m(o,t,1-Math.exp(-e*s))}function g(o,t){return Math.atan2(t,o)*(180/Math.PI)}const p=["a","button","input","textarea","[data-hover]","[data-cursor]"];class y{static version="2.0.2";version="2.0.2";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(p),this.stage=new f(this.options.container,!!this.options.hideCursor),this.hoverSelectors.forEach(e=>this.stage.addSelector(e)),this.input=new v(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,s)=>(e.priority||0)-(s.priority||0)),t.install?.(this),this)}resetPosition(){const t={x:-100,y:-100};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={}}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(s){console.error(`[Supermouse] Plugin '${t.name}' crashed and has been disabled.`,s),t.isEnabled=!1,t.onDisable?.(this)}}tick=t=>{const e=t-this.lastTime,s=Math.min(e/1e3,.1);this.lastTime=t;const n=this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput;if(this.stage.setVisibility(n),this.input.isEnabled&&this.options.hideCursor){let i="auto";this.state.forcedCursor!==null?i=this.state.forcedCursor:i=this.state.isNative||!this.state.hasReceivedInput?"auto":"none",this.stage.setNativeCursor(i)}if(this.input.isEnabled){this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y;for(let a=0;a<this.plugins.length;a++)this.runPluginSafe(this.plugins[a],e);const i=this.options.smoothness,l=this.state.reducedMotion?1e3:1/i*2;this.state.smooth.x=c(this.state.smooth.x,this.state.target.x,l,s),this.state.smooth.y=c(this.state.smooth.y,this.state.target.y,l,s);const r=this.state.target.x-this.state.smooth.x,h=this.state.target.y-this.state.smooth.y;this.state.velocity.x=r,this.state.velocity.y=h,(Math.abs(r)>.1||Math.abs(h)>.1)&&(this.state.angle=g(r,h))}else{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;for(let i=0;i<this.plugins.length;i++)this.runPluginSafe(this.plugins[i],e)}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=[]}}u.DEFAULT_HOVER_SELECTORS=p,u.Supermouse=y,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
package/tsconfig.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"include": [
|
|
4
|
-
"src"
|
|
5
|
-
],
|
|
6
|
-
"compilerOptions": {
|
|
7
|
-
"outDir": "dist",
|
|
8
|
-
"baseUrl": ".",
|
|
9
|
-
"forceConsistentCasingInFileNames": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"noUnusedLocals": true,
|
|
12
|
-
"noImplicitAny": true,
|
|
13
|
-
"noImplicitReturns": true,
|
|
14
|
-
"paths": {}
|
|
15
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"include": [
|
|
4
|
+
"src"
|
|
5
|
+
],
|
|
6
|
+
"compilerOptions": {
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"baseUrl": ".",
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"noUnusedLocals": true,
|
|
12
|
+
"noImplicitAny": true,
|
|
13
|
+
"noImplicitReturns": true,
|
|
14
|
+
"paths": {}
|
|
15
|
+
}
|
|
16
16
|
}
|
package/vite.config.ts
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import dts from 'vite-plugin-dts';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { readFileSync } from 'fs';
|
|
6
|
-
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = path.dirname(__filename);
|
|
9
|
-
|
|
10
|
-
const pkg = JSON.parse(readFileSync(path.resolve(__dirname, 'package.json'), 'utf-8'));
|
|
11
|
-
|
|
12
|
-
export default defineConfig({
|
|
13
|
-
define: {
|
|
14
|
-
__VERSION__: JSON.stringify(pkg.version)
|
|
15
|
-
},
|
|
16
|
-
build: {
|
|
17
|
-
lib: {
|
|
18
|
-
entry: path.resolve(__dirname, 'src/index.ts'),
|
|
19
|
-
name: 'SupermouseCore',
|
|
20
|
-
fileName: (format) => format === 'es' ? 'index.mjs' : 'index.umd.js',
|
|
21
|
-
},
|
|
22
|
-
rollupOptions: {
|
|
23
|
-
external: [],
|
|
24
|
-
output: {
|
|
25
|
-
globals: {
|
|
26
|
-
'@supermousejs/core': 'SupermouseCore'
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
plugins: [dts({ rollupTypes: true })]
|
|
32
|
-
});
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import dts from 'vite-plugin-dts';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
const pkg = JSON.parse(readFileSync(path.resolve(__dirname, 'package.json'), 'utf-8'));
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
define: {
|
|
14
|
+
__VERSION__: JSON.stringify(pkg.version)
|
|
15
|
+
},
|
|
16
|
+
build: {
|
|
17
|
+
lib: {
|
|
18
|
+
entry: path.resolve(__dirname, 'src/index.ts'),
|
|
19
|
+
name: 'SupermouseCore',
|
|
20
|
+
fileName: (format) => format === 'es' ? 'index.mjs' : 'index.umd.js',
|
|
21
|
+
},
|
|
22
|
+
rollupOptions: {
|
|
23
|
+
external: [],
|
|
24
|
+
output: {
|
|
25
|
+
globals: {
|
|
26
|
+
'@supermousejs/core': 'SupermouseCore'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
plugins: [dts({ rollupTypes: true })]
|
|
32
|
+
});
|