@supermousejs/core 2.4.3 → 2.5.0-beta.1

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/dist/index.umd.js CHANGED
@@ -1,10 +1,2 @@
1
- (function(r,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(r=typeof globalThis<"u"?globalThis:r||self,l(r.SupermouseCore={}))})(this,(function(r){"use strict";const l="2.4.3";function v(a,t,e){return a+(t-a)*e}function c(a,t,e,s){return v(a,t,1-Math.exp(-e*s))}const u={x:-100,y:-100},b=new Set(["input","textarea","select"]),y=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),d=["a","button","input","textarea","[data-hover]","[data-cursor]"];class p{constructor(t,e,s,i){this.state=t,this.options=e,this.getHoverSelector=s,this.onEnableChange=i,this.dataPrefix=this.options.dataPrefix??"supermouse",this.normalizedDataPrefix=this.dataPrefix.toLowerCase(),this.ignoreAttribute=`data-${this.dataPrefix}-ignore`,this.ruleEntries=this.options.rules?Object.entries(this.options.rules):[],this.checkDeviceCapability(),this.checkMotionPreference(),this.setupContainerRectTracking(),this.bindEvents()}state;options;getHoverSelector;onEnableChange;mediaQueryList;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;abortController=new AbortController;nativeTarget=null;hasSeenPointer=!1;isEnabled=!0;containerRect=null;resizeObserver;matchedRules=[];lastParsedTarget=null;ruleEntries;currentTarget=null;checkDeviceCapability(){this.options.autoDisableOnMobile&&(this.mediaQueryList=window.matchMedia("(pointer: fine)"),this.updateEnabledState(this.mediaQueryList.matches),this.mediaQueryList.addEventListener("change",t=>this.updateEnabledState(t.matches),{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)}setupContainerRectTracking(){const t=this.options.container;if(!t||t===document.body)return;const e=()=>{this.containerRect=t.getBoundingClientRect()};e(),window.addEventListener("resize",e,{signal:this.abortController.signal}),window.addEventListener("scroll",e,{passive:!0,signal:this.abortController.signal}),typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(e),this.resizeObserver.observe(t))}parseDOMInteraction(t){if(t!==this.lastParsedTarget){this.lastParsedTarget=t,this.matchedRules=[];for(const[i,n]of this.ruleEntries)this.matchesSelector(t,i)&&this.matchedRules.push({selector:i,rules:n})}const e={};for(const{rules:i}of this.matchedRules)try{const n=typeof i=="function"?i(t):i;if(!n||typeof n!="object")continue;for(const[o,h]of Object.entries(n))e[o]=typeof h=="function"?h(t):h}catch(n){console.error("[Supermouse] Rule threw during evaluation:",n)}const s=this.normalizedDataPrefix;for(const i in t.dataset){if(!i.toLowerCase().startsWith(s))continue;const n=i.slice(s.length);if(!n)continue;const o=t.dataset[i];e[n[0].toLowerCase()+n.slice(1)]=o===""?!0:o}this.state.interaction=e}matchesSelector(t,e){try{if(!/\s/.test(e.trim()))return t.matches(e)}catch{}const s=e.trim().split(/\s+/);if(s.length<2)return!1;const i=s.pop(),n=s.join(" ");if(!i||!n)return!1;try{return t.matches(i)&&!!t.closest(n)}catch{return!1}}isOutsideContainer(t){const{container:e}=this.options;return!!e&&e!==document.body&&!e.contains(t)}resolveComputedCursor(t){return window.getComputedStyle(t).cursor}handleMove=t=>{if(this.options.autoDisableOnMobile&&t.pointerType==="touch"&&!this.options.enableTouch)return;let e=t.clientX,s=t.clientY;const i=this.options.container;i&&this.containerRect&&i!==document.body&&(e-=this.containerRect.left,s-=this.containerRect.top),this.state.pointer.x=e,this.state.pointer.y=s,this.hasSeenPointer=!0,this.isEnabled&&(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(this.isOutsideContainer(e))return;if(this.state.cursorMode==="auto"&&e.closest(`[${this.ignoreAttribute}]`)){this.state.isHover=!1,this.state.hoverTarget=null,this.state.interaction={},this.currentTarget=null,this.lastParsedTarget=null,this.matchedRules=[],this.state.isNative=!0,this.nativeTarget=e;return}if(this.state.isNative=!1,this.nativeTarget=null,this.currentTarget=e,this.parseDOMInteraction(e),this.state.cursorMode!=="auto"){const o=e.closest(this.getHoverSelector());o&&(this.state.isHover=!0,this.state.hoverTarget=o);return}const s=e.closest(this.getHoverSelector());s&&(this.state.isHover=!0,this.state.hoverTarget=s);const i=b.has(e.localName)||e.isContentEditable,n=!y.has(this.resolveComputedCursor(e));(i||n)&&(this.state.isNative=!0,this.nativeTarget=e)};handleMouseOut=t=>{if(!this.isEnabled)return;const e=t.target,s=t.relatedTarget;this.isOutsideContainer(e)||((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.matchedRules=[]))};handleDocumentMouseOut=t=>{this.isEnabled&&t.relatedTarget===null&&this.options.hideOnLeave&&this.handleWindowLeave()};handleWindowLeave=()=>{this.options.hideOnLeave&&(this.state.hasReceivedInput=!1,this.state.pointer={...u})};clearHover(){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.matchedRules=[]}getCurrentTarget(){return this.currentTarget}bindEvents(){const{signal:t}=this.abortController;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});const s=!this.options.container||this.options.container===document.body?document:this.options.container;s.addEventListener("mouseover",this.handleMouseOver,{signal:t}),s.addEventListener("mouseout",this.handleMouseOut,{signal:t}),document.addEventListener("mouseout",this.handleDocumentMouseOut,{signal:t})}destroy(){this.abortController.abort(),this.resizeObserver?.disconnect()}}let C=0;class g{constructor(t=document.body,e=9999){if(this.container=t,this.zIndex=e,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);t.isConnected||console.warn("[Supermouse] container is not attached to the document — stage sizing/positioning will be wrong until it is.");const s=C++;this.id=`supermouse-style-${s}`,this.scopeClass=`supermouse-scope-${s}`,this.hideClass=`supermouse-hide-${s}`;const i=t===document.body;if(this.element=document.createElement("div"),Object.assign(this.element.style,{position:i?"fixed":"absolute",inset:"0px",pointerEvents:"none",zIndex:String(this.zIndex),opacity:"1",transition:"opacity 0.15s ease"}),!i){const n=window.getComputedStyle(t);this.originalContainerPosition=n.position,n.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),this.styleTag=document.createElement("style"),this.styleTag.id=this.id,document.head.appendChild(this.styleTag),this.container.classList.add("supermouse-scope",this.scopeClass),this.updateCursorCSS()}container;zIndex;element;styleTag;id;scopeClass;hideClass;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";selectors=new Set(["a","button","input","textarea","select",'[role="button"]',"[tabindex]"]);addSelectors(t){let e=!1;for(const s of t)s.split(",").forEach(i=>{const n=i.trim();n&&!this.selectors.has(n)&&(this.selectors.add(n),e=!0)});e&&this.updateCursorCSS()}addSelector(t){this.addSelectors([t])}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){t!==this.currentCursorState&&(this.currentCursorState=t,this.container.classList.toggle(this.hideClass,t==="none"),this.container.style.cursor=t==="none"?"none":this.originalContainerCursor)}updateCursorCSS(){const t=Array.from(this.selectors);if(t.length===0){this.styleTag.innerText="";return}const e=`:not(.${this.scopeClass} .supermouse-scope):not(.${this.scopeClass} .supermouse-scope *)`,s=h=>`.${this.scopeClass}.${this.hideClass} ${h}${e} { cursor: none !important; }`,i=t.map(s).join(`
2
- `),n=`.${this.scopeClass}.${this.hideClass} *${e} { cursor: none !important; }`,o=`.${this.scopeClass}.${this.hideClass} { cursor: none !important; }`;this.styleTag.innerText=`
3
- ${o}
4
- ${n}
5
- ${i}
6
- ${s("label")}
7
- ${s("select")}
8
- ${s('input[type="range"]::-webkit-slider-thumb')}
9
- ${s('input[type="range"]::-moz-range-thumb')}
10
- `}destroy(){this.element.remove(),this.styleTag.remove(),this.container.style.cursor=this.originalContainerCursor,this.container.classList.remove("supermouse-scope",this.scopeClass,this.hideClass),this.container!==document.body&&this.originalContainerPosition==="static"&&(this.container.style.position="")}}class S{static version=l;version=l;state;options;plugins=[];_stage;input;rafId=0;lastTime=0;isRunning=!1;isSuspended=!1;visibilityAbortController=new AbortController;hoverSelectors;hoverSelectorString;crashedPlugins=[];constructor(t={}){this.options={smoothness:.15,enableTouch:!1,autoDisableOnMobile:!0,cursor:"auto",hideOnLeave:!0,autoStart:!0,container:document.body,dataPrefix:"supermouse",zIndex:9999,...t},this.state={pointer:{...u},target:{...u},smooth:{...u},velocity:{x:0,y:0},displacement:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,cursorMode:this.options.cursor,hoverTarget:null,reducedMotion:!1,hasReceivedInput:!1,shape:null,interaction:{}},this.hoverSelectors=new Set(this.options.hoverSelectors??d),this.hoverSelectorString=Array.from(this.hoverSelectors).join(", "),this._stage=new g(this.options.container,this.options.zIndex),this._stage.addSelectors(this.hoverSelectors),this.input=new p(this.state,this.options,()=>this.hoverSelectorString,e=>{e||this.reset(!0)}),this.options.plugins?.forEach(e=>this.use(e)),this.bindVisibilityHandling(),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.element&&(e.element.style.display=""),e.onEnable?.(this))}disablePlugin(t){const e=this.getPlugin(t);if(e&&e.isEnabled!==!1){e.isEnabled=!1;const s=()=>{e.element&&(e.element.style.display="none"),e.onDisable?.(this)},i=e.onBeforeDisable?.(this);i&&typeof i.then=="function"?Promise.resolve(i).then(s).catch(n=>{console.error(`[Supermouse] Plugin '${e.name}' onBeforeDisable threw:`,n),s()}):s()}}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.hoverSelectorString=Array.from(this.hoverSelectors).join(", "),this._stage.addSelector(t))}get container(){return this.options.container}get stage(){return this._stage.element}setCursor(t){this.state.cursorMode=t}init(){this.options.autoStart&&this.startLoop()}enable(){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._stage.setNativeCursor(this.resolveCursorState())}disable(){this.input.isEnabled=!1,this._stage.setNativeCursor("auto"),this._stage.setVisibility(!1),this.reset(!0)}suspend(){this.input.isEnabled&&(this.isSuspended=!0,this.input.isEnabled=!1,this.input.clearHover(),this._stage.setVisibility(!1))}resume(){if(this.isSuspended){this.isSuspended=!1,this.input.isEnabled=!0,this.state.hasReceivedInput&&(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());for(let t=this.plugins.length-1;t>=0;t--)this.runPluginSafe(this.plugins[t],0);this._stage.setVisibility(!0)}}use(t){if(this.plugins.some(e=>e.name===t.name))return console.warn(`[Supermouse] Plugin "${t.name}" already installed.`),this;t.isEnabled??=!0;try{t.install?.(this)}catch(e){return console.error(`[Supermouse] Failed to install plugin '${t.name}'.`,e),this}return this.plugins.push(t),this.plugins.sort((e,s)=>(e.priority??0)-(s.priority??0)),this}reset(t=!1){this.state.target={...u},this.state.smooth={...u},this.resetMotion(),this.state.angle=0,t&&(this.state.hasReceivedInput=!1,this.state.shape=null,this.state.interaction={})}startLoop(){this.isRunning||(this.isRunning=!0,!document.hidden&&(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))}start(){this.startLoop()}step(t){this.update(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,this.crashedPlugins.push(t)}}cleanupCrashedPlugins(){if(this.crashedPlugins.length!==0){for(const t of this.crashedPlugins){const e=this.plugins.indexOf(t);e>-1&&this.plugins.splice(e,1);try{t.onDisable?.(this),t.destroy?.(this)}catch(s){console.error(`[Supermouse] Failed to cleanup crashed plugin '${t.name}'.`,s)}t.element?.remove()}this.crashedPlugins=[]}}resolveStageVisibility(){return this.state.cursorMode==="native"?!1:this.state.cursorMode==="both"?this.input.isEnabled&&this.state.hasReceivedInput:this.state.cursorMode==="custom"?this.input.isEnabled&&this.state.hasReceivedInput:this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput}resolveCursorState(){return!this.input.isEnabled||this.state.cursorMode==="both"||this.state.cursorMode==="native"?"auto":this.state.cursorMode==="custom"?"none":this.state.isNative||!this.state.hasReceivedInput?"auto":"none"}resetMotion(){this.state.velocity={x:0,y:0},this.state.displacement={x:0,y:0}}update(t){const e=t-this.lastTime,s=Math.min(e/1e3,.1);this.lastTime=t;const i=this.input.getCurrentTarget();i&&!i.isConnected?this.input.clearHover():i&&this.input.parseDOMInteraction(i),this._stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&this._stage.setNativeCursor(this.resolveCursorState()),this.input.isEnabled&&this.state.hasReceivedInput&&(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y);for(let n=0;n<this.plugins.length;n++)this.runPluginSafe(this.plugins[n],e);if(this.cleanupCrashedPlugins(),this.input.isEnabled){const n=this.state.reducedMotion?1e3:1/this.options.smoothness*2,o=this.state.smooth.x,h=this.state.smooth.y;this.state.smooth.x=c(this.state.smooth.x,this.state.target.x,n,s),this.state.smooth.y=c(this.state.smooth.y,this.state.target.y,n,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-h)/s):(this.state.velocity.x=0,this.state.velocity.y=0);const{x:f,y:m}=this.state.velocity;(Math.abs(f)>.1||Math.abs(m)>.1)&&(this.state.angle=Math.atan2(m,f)*(180/Math.PI))}}tick=t=>{this.update(t),this.isRunning&&(this.rafId=requestAnimationFrame(this.tick))};bindVisibilityHandling(){document.addEventListener("visibilitychange",()=>{this.isRunning&&(document.hidden?cancelAnimationFrame(this.rafId):(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))},{signal:this.visibilityAbortController.signal})}destroy(){this.isRunning=!1,cancelAnimationFrame(this.rafId),this.visibilityAbortController.abort(),this.input.destroy(),this._stage.destroy(),this.plugins.forEach(t=>t.destroy?.(this)),this.plugins=[]}}r.DEFAULT_HOVER_SELECTORS=d,r.Input=p,r.Stage=g,r.Supermouse=S,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(l,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(l=typeof globalThis<"u"?globalThis:l||self,p(l.SupermouseCore={}))})(this,(function(l){"use strict";const p={rules:[{selector:"input",native:!0,hide:!0},{selector:"textarea",native:!0,hide:!0},{selector:"select",native:!0,hide:!0},{selector:"[contenteditable]",native:!0,hide:!0},{selector:"a",native:!1,hide:!0},{selector:"button",native:!1,hide:!0},{selector:'[role="button"]',native:!1,hide:!0},{selector:"[tabindex]",native:!1,hide:!0}]};function w(i){if(!i)return p;if("rules"in i)return i;const t=[],e=new Set(i.native??[]),s=new Set(i.hide??[]),n=new Set([...e,...s]);for(const r of n)t.push({selector:r,native:e.has(r),hide:s.has(r)});return{rules:t}}function A(i){const t=[],e=[];for(const s of i.rules)s.native!==!1&&t.push(s.selector),s.hide!==!1&&e.push(s.selector);return{native:t,hide:e}}let R=0;class O{constructor(t,e){if(this.container=t,!t||!(t instanceof HTMLElement))throw new Error(`[Supermouse] Invalid container: ${t}. Must be an HTMLElement.`);t.isConnected;const s=R++;this.scopeClass=`supermouse-scope-${s}`,this.hideClass=`supermouse-hide-${s}`;const n=t===document.body;if(this.element=document.createElement("div"),Object.assign(this.element.style,{position:n?"fixed":"absolute",inset:"0px",pointerEvents:"none",zIndex:String(e),opacity:"1",transition:"opacity 0.15s ease"}),!n){const r=window.getComputedStyle(t);this.originalContainerPosition=r.position,r.position==="static"&&(t.style.position="relative")}this.originalContainerCursor=t.style.cursor,t.appendChild(this.element),t.classList.add("supermouse-scope",this.scopeClass)}container;element;scopeClass;hideClass;currentCursorState=null;originalContainerPosition="";originalContainerCursor="";get containerElement(){return this.container}getRulePrefix(){return`.${this.scopeClass}.${this.hideClass}`}getExclusion(){return`:not(.${this.scopeClass} .supermouse-scope):not(.${this.scopeClass} .supermouse-scope *)`}setVisibility(t){this.element.style.opacity=t?"1":"0"}setNativeCursor(t){t!==this.currentCursorState&&(this.currentCursorState=t,this.container.classList.toggle(this.hideClass,t==="none"),t==="none"?this.container.style.cursor="none":this.container===document.body?this.container.style.cursor=this.originalContainerCursor:this.container.style.cursor=this.originalContainerCursor||"auto")}destroy(){this.element.remove(),this.container.style.cursor=this.originalContainerCursor,this.container.classList.remove("supermouse-scope",this.scopeClass,this.hideClass),this.container!==document.body&&this.originalContainerPosition==="static"&&(this.container.style.position="")}}class I{constructor(t,e){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;const s=t.cursorPolicy?w(t.cursorPolicy):e.cursorPolicy,n=A(s);this.nativeSelectors=n.native,this.hideSelectors=n.hide,this.stage=new O(t.container,t.zIndex??e.zIndex)}config;stage;hoverSelectors;plugins=[];nativeSelectors;hideSelectors;inheritDataAttributes;name;cursorMode;contains(t){return this.stage.containerElement.contains(t)}get container(){return this.stage.containerElement}get hoverSelectorString(){return Array.from(this.hoverSelectors).join(", ")}get nativeSelectorString(){return this.nativeSelectors.join(", ")}buildRules(){const t=this.stage.getRulePrefix(),e=this.stage.getExclusion(),s=[`${t}${e} { cursor: none !important; }`,`${t} *${e} { cursor: none !important; }`];for(const n of this.hideSelectors)s.push(`${t} ${n}${e} { cursor: none !important; }`);return s.push(`${t} label${e} { cursor: none !important; }`),s.push(`${t} select${e} { cursor: none !important; }`),s.push(`${t} input[type="range"]${e}::-webkit-slider-thumb { cursor: none !important; }`),s.push(`${t} input[type="range"]${e}::-moz-range-thumb { cursor: none !important; }`),s}}const v={x:-100,y:-100},D=new Set(["default","auto","pointer","none","inherit","grab","grabbing"]),x=["a","button","input","textarea","[data-hover]","[data-cursor]"],u=new Map,_=new Map;let m=null,y=!1,S=!1,C=0;function E(i){const t=i.getBoundingClientRect();return{left:t.left,top:t.top,width:t.width,height:t.height}}function T(i){u.set(i,E(i));const t=_.get(i);if(t)for(const e of t)e()}function b(){for(const i of u.keys())T(i)}function $(){m||typeof ResizeObserver>"u"||(m=new ResizeObserver(i=>{for(const t of i){const e=t.target;u.has(e)&&T(e)}}))}function z(){typeof window>"u"||(y||(window.addEventListener("scroll",b,{passive:!0,capture:!0}),y=!0),S||(window.addEventListener("resize",b,{passive:!0}),S=!0))}function k(i,t){return C++,u.has(i)||(u.set(i,E(i)),$(),m?.observe(i),z()),()=>{C--,C===0&&(m?.disconnect(),m=null,u.clear(),_.clear(),y&&(window.removeEventListener("scroll",b,{capture:!0}),y=!1),S&&(window.removeEventListener("resize",b),S=!1))}}function N(i){let t=u.get(i);return t||(t=E(i),u.set(i,t)),t}function H(i,t,e){if(i===document.body)return{x:t,y:e};const s=N(i);return{x:t-s.left,y:e-s.top}}class V{constructor(t,e,s,n){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()}state;options;onEnableChange;onActiveScopeChange;abortController=new AbortController;mediaQueryList;motionQuery;dataPrefix;normalizedDataPrefix;ignoreAttribute;activeScope=null;scopeByContainer=new Map;nativeTarget=null;currentTarget=null;lastParsedTarget=null;ruleEntries;releaseViewport=null;hasSeenPointer=!1;isEnabled=!0;viewportX=0;viewportY=0;cachedChain=[];setScopes(t){this.scopeByContainer.clear();for(const e of t)this.scopeByContainer.set(e.container,e)}setActiveScope(t){t!==this.activeScope&&(this.activeScope=t,this.releaseViewport?.(),this.releaseViewport=t&&t.container!==document.body?k(t.container):null,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))}findScope(t){let e=t;for(;e;){const s=this.scopeByContainer.get(e);if(s)return s;e=e.parentElement}return null}applyPointerToState(){const t=this.activeScope?.container??document.body,e=H(t,this.viewportX,this.viewportY);this.state.pointer.x=e.x,this.state.pointer.y=e.y}checkDeviceCapability(){this.options.autoDisableOnMobile&&(this.mediaQueryList=window.matchMedia("(pointer: fine)"),this.updateEnabledState(this.mediaQueryList.matches),this.mediaQueryList.addEventListener("change",t=>this.updateEnabledState(t.matches),{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){const e=this.activeScope?.container??document.body,s=this.activeScope?.inheritDataAttributes??!0,n=this.normalizedDataPrefix;if(t!==this.lastParsedTarget){this.lastParsedTarget=t,this.cachedChain=[];let o=t;for(;o;){const g=[];for(const[a,h]of this.ruleEntries)this.matchesSelector(o,a)&&g.push({selector:a,rules:h});if(this.cachedChain.push({element:o,matchedRules:g}),!s||o===e)break;const c=o.parentElement;if(!c||!e.contains(c))break;o=c}}const r={};for(const{element:o,matchedRules:g}of this.cachedChain){const c={};for(const{rules:a}of g)try{const h=typeof a=="function"?a(o):a;if(!h||typeof h!="object")continue;for(const[P,f]of Object.entries(h))c[P]=typeof f=="function"?f(o):f}catch{}for(const a in o.dataset){if(!a.toLowerCase().startsWith(n))continue;const h=a.slice(n.length);if(!h)continue;const P=h[0].toLowerCase()+h.slice(1),f=o.dataset[a];c[P]=f==null||f===""?!0:f}for(const[a,h]of Object.entries(c))a in r||(r[a]=h)}this.state.interaction=r}matchesSelector(t,e){try{return t.matches(e)}catch{return!1}}resolveComputedCursor(t){return window.getComputedStyle(t).cursor}handleMove=t=>{this.options.autoDisableOnMobile&&t.pointerType==="touch"&&!this.options.enableTouch||(this.viewportX=t.clientX,this.viewportY=t.clientY,this.hasSeenPointer=!0,this.applyPointerToState(),this.isEnabled&&(this.state.hasReceivedInput||(this.state.hasReceivedInput=!0,this.state.target.x=this.state.smooth.x=this.state.pointer.x,this.state.target.y=this.state.smooth.y=this.state.pointer.y)))};handleDown=()=>{this.isEnabled&&(this.state.isDown=!0)};handleUp=()=>{this.isEnabled&&(this.state.isDown=!1)};handleMouseOver=t=>{if(!this.isEnabled)return;const e=t.target,s=this.findScope(e);if(s&&s!==this.activeScope&&this.setActiveScope(s),!this.activeScope)return;if(this.state.cursorMode==="auto"&&e.closest(`[${this.ignoreAttribute}]`)){this.clearHover(),this.state.isNative=!0,this.nativeTarget=e;return}this.state.isNative=!1,this.nativeTarget=null,this.currentTarget=e,this.parseDOMInteraction(e);const n=e.closest(this.activeScope.hoverSelectorString);if(n&&(this.state.isHover=!0,this.state.hoverTarget=n),this.state.cursorMode==="auto"){if(this.matchesSelector(e,this.activeScope.nativeSelectorString)){this.state.isNative=!0,this.nativeTarget=e;return}(e.isContentEditable||!D.has(this.resolveComputedCursor(e)))&&(this.state.isNative=!0,this.nativeTarget=e)}};handleMouseOut=t=>{if(!this.isEnabled)return;const e=t.target,s=t.relatedTarget;(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={...v})};clearHover(){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=[]}getCurrentTarget(){return this.currentTarget}bindEvents(){const{signal:t}=this.abortController;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})}destroy(){this.abortController.abort(),this.releaseViewport?.(),this.cachedChain=[]}}let d=null;function B(){d||typeof document>"u"||(d=document.createElement("style"),d.id="supermouse-styles",document.head.appendChild(d))}function F(i){B(),d&&(d.textContent=i.join(`
2
+ `))}function U(){d?.remove(),d=null}const M="2.5.0-beta.1";function j(i,t,e){return i+(t-i)*e}function L(i,t,e,s){return j(i,t,1-Math.exp(-e*s))}class Q{static version=M;version=M;state;options;_scopes=[];_activeScope=null;_installingScope=null;scopeByContainer=new Map;input;rafId=0;lastTime=0;visibilityAbortController=new AbortController;crashedPlugins=[];constructor(t={}){this.options={smoothness:.15,enableTouch:!1,autoDisableOnMobile:!0,cursor:"auto",hideOnLeave:!0,autoStart:!0,container:document.body,dataPrefix:"supermouse",zIndex:9999,inheritDataAttributes:!0,...t},this.state={pointer:{...v},target:{...v},smooth:{...v},velocity:{x:0,y:0},displacement:{x:0,y:0},angle:0,isDown:!1,isHover:!1,isNative:!1,cursorMode:this.options.cursor,hoverTarget:null,reducedMotion:!1,hasReceivedInput:!1,shape:null,interaction:{}};const e=this.createScope({container:this.options.container,cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors,cursorPolicy:this.options.cursorPolicy,plugins:this.options.plugins,zIndex:this.options.zIndex});if(this.input=new V(this.state,this.options,s=>{s||this.reset()},s=>this.handleActiveScopeChange(s)),this.input.setScopes(this._scopes),this.input.setActiveScope(e),this.installPlugins(e),this.options.scopes)for(const s of this.options.scopes)this.addScope(s);this.rebuildStylesheet(),this.bindVisibilityHandling(),this.options.autoStart&&this.startLoop()}get container(){return(this._activeScope??this._scopes[0]).container}get stage(){return(this._installingScope??this._activeScope??this._scopes[0]).stage.element}get isEnabled(){return this.input.isEnabled}get isRunning(){return this._running}use(t){return this.installPlugin(this._scopes[0],t),this}getPlugin(t){for(const e of this._scopes){const s=e.plugins.find(n=>n.name===t);if(s)return s}}enablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled===!1&&(e.isEnabled=!0,e.element&&(e.element.style.display=""),e.onEnable?.(this))}disablePlugin(t){const e=this.getPlugin(t);e&&e.isEnabled!==!1&&this.deactivatePlugin(e)}togglePlugin(t){const e=this.getPlugin(t);e&&(e.isEnabled===!1?this.enablePlugin(t):this.disablePlugin(t))}setCursor(t){this._activeScope&&(this._activeScope.cursorMode=t,this.state.cursorMode=t)}addScope(t){const e=this.createScope(t);return this.input.setScopes(this._scopes),this.installPlugins(e),this.rebuildStylesheet(),{name:e.name,container:e.container,remove:()=>this.removeScope(e),setCursor:s=>this.setScopeCursor(e,s)}}enable(){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())}disable(t){this.input.isEnabled=!1,this._activeScope&&(this._activeScope.stage.setNativeCursor("auto"),this._activeScope.stage.setVisibility(!1)),t?.reset&&this.reset()}reset(){this.state.target={...v},this.state.smooth={...v},this.resetMotion(),this.state.angle=0,this.state.hasReceivedInput=!1,this.state.shape=null,this.state.interaction={}}start(){this.startLoop()}step(t){this.update(t)}destroy(){this._running=!1,cancelAnimationFrame(this.rafId),this.visibilityAbortController.abort(),this.input.destroy();for(const t of this._scopes){for(const e of t.plugins)try{e.destroy?.(this)}catch{}t.stage.destroy()}this._scopes=[],this.scopeByContainer.clear(),this._activeScope=null,U()}_running=!1;createScope(t){const e=new I(t,{cursor:this.options.cursor,hoverSelectors:this.options.hoverSelectors??x,cursorPolicy:this.options.cursorPolicy?w(this.options.cursorPolicy):p,zIndex:this.options.zIndex,inheritDataAttributes:this.options.inheritDataAttributes});return this._scopes.push(e),this.scopeByContainer.set(e.container,e),e}removeScope(t){const e=this._scopes.indexOf(t);if(e!==-1){for(const s of t.plugins)try{s.destroy?.(this)}catch{}t.plugins.length=0,t.stage.destroy(),this._scopes.splice(e,1),this.scopeByContainer.delete(t.container),this.input.setScopes(this._scopes),this._activeScope===t&&this.input.setActiveScope(this._scopes[0]??null),this.rebuildStylesheet()}}setScopeCursor(t,e){t.cursorMode=e,t===this._activeScope&&(this.state.cursorMode=e)}installPlugins(t){if(t.config.plugins)for(const e of t.config.plugins)this.installPlugin(t,e)}installPlugin(t,e){if(!t.plugins.some(s=>s.name===e.name)){e.isEnabled??=!0,this._installingScope=t;try{e.install?.(this)}catch{this._installingScope=null;return}this._installingScope=null,t.plugins.push(e),t.plugins.sort((s,n)=>(s.priority??0)-(n.priority??0)),t!==this._activeScope&&(e.isEnabled=!1,e.element&&(e.element.style.display="none"))}}handleActiveScopeChange(t){const e=this._activeScope;if(e!==t){if(e)for(const s of e.plugins)this.deactivatePlugin(s);if(this._activeScope=t,t){this.state.cursorMode=t.cursorMode;for(const s of t.plugins)this.activatePlugin(s)}}}activatePlugin(t){t.isEnabled===!1&&(t.isEnabled=!0,t.element&&(t.element.style.display=""),t.onEnable?.(this))}deactivatePlugin(t){if(t.isEnabled===!1)return;t.isEnabled=!1;const e=()=>{t.element&&(t.element.style.display="none"),t.onDisable?.(this)},s=t.onBeforeDisable?.(this);s&&typeof s.then=="function"?Promise.resolve(s).then(e).catch(n=>{e()}):e()}rebuildStylesheet(){const t=[];for(const e of this._scopes)t.push(...e.buildRules());F(t)}runPluginSafe(t,e){if(t.isEnabled!==!1)try{t.update?.(this,e)}catch{t.isEnabled=!1,this.crashedPlugins.push(t)}}cleanupCrashedPlugins(){if(this.crashedPlugins.length!==0){for(const t of this.crashedPlugins){for(const e of this._scopes){const s=e.plugins.indexOf(t);if(s!==-1){e.plugins.splice(s,1);break}}try{t.onDisable?.(this),t.destroy?.(this)}catch{}t.element?.remove()}this.crashedPlugins=[]}}resolveStageVisibility(){return this.state.cursorMode==="native"?!1:this.state.cursorMode==="custom"||this.state.cursorMode==="both"?this.input.isEnabled&&this.state.hasReceivedInput:this.input.isEnabled&&!this.state.isNative&&this.state.hasReceivedInput}resolveCursorState(){return!this.input.isEnabled||this.state.cursorMode==="native"||this.state.cursorMode==="both"?"auto":this.state.cursorMode==="custom"?"none":this.state.isNative||!this.state.hasReceivedInput?"auto":"none"}resetMotion(){this.state.velocity={x:0,y:0},this.state.displacement={x:0,y:0}}update(t){const e=t-this.lastTime,s=Math.min(e/1e3,.1);this.lastTime=t;const n=this.input.getCurrentTarget();n&&!n.isConnected?this.input.clearHover():n&&this.input.parseDOMInteraction(n);const r=this._activeScope;if(r){r.stage.setVisibility(this.resolveStageVisibility()),this.input.isEnabled&&r.stage.setNativeCursor(this.resolveCursorState());for(let o=0;o<r.plugins.length;o++)this.runPluginSafe(r.plugins[o],e)}if(this.cleanupCrashedPlugins(),this.input.isEnabled&&this.state.hasReceivedInput&&(this.state.target.x=this.state.pointer.x,this.state.target.y=this.state.pointer.y),this.input.isEnabled){const o=this.state.reducedMotion?1e3:1/this.options.smoothness*2,g=this.state.smooth.x,c=this.state.smooth.y;this.state.smooth.x=L(this.state.smooth.x,this.state.target.x,o,s),this.state.smooth.y=L(this.state.smooth.y,this.state.target.y,o,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-g)/s,this.state.velocity.y=(this.state.smooth.y-c)/s):(this.state.velocity.x=0,this.state.velocity.y=0);const{x:a,y:h}=this.state.velocity;(Math.abs(a)>.1||Math.abs(h)>.1)&&(this.state.angle=Math.atan2(h,a)*(180/Math.PI))}}tick=t=>{this.update(t),this._running&&(this.rafId=requestAnimationFrame(this.tick))};bindVisibilityHandling(){document.addEventListener("visibilitychange",()=>{this._running&&(document.hidden?cancelAnimationFrame(this.rafId):(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))},{signal:this.visibilityAbortController.signal})}startLoop(){this._running||(this._running=!0,!document.hidden&&(this.lastTime=performance.now(),this.rafId=requestAnimationFrame(this.tick)))}registerHoverTarget(t){const e=this._installingScope??this._activeScope??this._scopes[0];if(e)for(const s of t.split(",")){const n=s.trim();n&&e.hoverSelectors.add(n)}}get hoverSelectors(){const t=this._activeScope??this._scopes[0];return t?t.hoverSelectors:new Set}get plugins(){const t=this._activeScope??this._scopes[0];return t?t.plugins:[]}}l.DEFAULT_CURSOR_POLICY=p,l.DEFAULT_HOVER_SELECTORS=x,l.Supermouse=Q,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supermousejs/core",
3
- "version": "2.4.3",
3
+ "version": "2.5.0-beta.1",
4
4
  "files": [
5
5
  "dist",
6
6
  "README.md",
@@ -51,6 +51,7 @@
51
51
  "scripts": {
52
52
  "build": "vite build",
53
53
  "test": "vitest",
54
- "test:watch": "vitest --watch"
54
+ "test:watch": "vitest --watch",
55
+ "test:bench": "vitest bench"
55
56
  }
56
57
  }