@izhann/react-cursor-fx
Version:
Interactive cursor effects for React and Next.js applications — zero runtime dependencies
4 lines (3 loc) • 11 kB
JavaScript
"use client";
;var e=require("react/jsx-runtime"),t=require("react");const r=()=>{const[e,r]=t.useState({x:0,y:0}),[n,s]=t.useState(!1),o=t.useRef(null);return t.useEffect((()=>{s(!0);const e=e=>{null===o.current&&(o.current=requestAnimationFrame((()=>{r({x:e.clientX,y:e.clientY}),o.current=null})))};return window.addEventListener("mousemove",e),()=>{window.removeEventListener("mousemove",e),null!==o.current&&cancelAnimationFrame(o.current)}}),[]),n?e:{x:0,y:0}},n={default:{width:24,height:24,scale:1,shape:"circle",color:"rgba(255, 255, 255, 0.8)",opacity:1,borderColor:"rgba(0, 0, 0, 0)",borderWidth:0,borderStyle:"solid",label:"",fontSize:"12px",fontWeight:"bold",labelColor:"#000",transition:{stiffness:800,damping:80,mass:1}}},s=t.createContext({cursorState:Object.assign(Object.assign({},n.default),{variant:"default"}),setCursorVariant:()=>{},config:n,mousePosition:{x:0,y:0},resetCursorToDefault:()=>{},setGlobalCursorVariant:()=>{},clearGlobalCursorVariant:()=>{}}),o=()=>t.useContext(s);function a(e,t,r,n,s,o,a){const i=(-n*(e-r)-s*t)/o;return[e+t*a+.5*i*a*a,t+i*a]}"function"==typeof SuppressedError&&SuppressedError;const i=({variant:e,onEnter:r,onLeave:n})=>{const{setCursorVariant:s,resetCursorToDefault:a}=o(),i=t.useRef(null),u=t.useRef(!1);t.useEffect((()=>()=>{i.current&&clearTimeout(i.current)}),[]);return{onMouseEnter:()=>{i.current&&(clearTimeout(i.current),i.current=null),u.current=!0,s(e,"push"),null==r||r()},onMouseLeave:e=>{var t,r;u.current=!1;const o=e.relatedTarget;o&&((null===(t=o.hasAttribute)||void 0===t?void 0:t.call(o,"data-cursor-target"))||(null===(r=o.closest)||void 0===r?void 0:r.call(o,"[data-cursor-target]")))||s("","pop"),i.current=setTimeout((()=>{u.current||a()}),0),null==n||n()},onFocus:()=>{i.current&&(clearTimeout(i.current),i.current=null),u.current=!0,s(e,"push"),null==r||r()},onBlur:()=>{u.current=!1,s("","pop"),i.current=setTimeout((()=>{u.current||a()}),0),null==n||n()},"data-cursor-target":!0}};exports.Cursor=({zIndex:r=9999,showOnTouch:n=!1,trailLength:s=10})=>{const{cursorState:i,mousePosition:u}=o(),[c,l]=t.useState(!1),[d,f]=t.useState(!1),[m,h]=t.useState(!1),v=t.useRef(null),p=t.useRef([]),x=t.useRef({x:0,y:0,vx:0,vy:0}),g=t.useRef({x:0,y:0}),b=t.useRef(null),y=t.useRef(null),w=t.useRef({stiffness:800,damping:80,mass:1}),E=t.useRef(!1);if(t.useEffect((()=>{var e,t,r,n,s,o;w.current={stiffness:null!==(t=null===(e=i.transition)||void 0===e?void 0:e.stiffness)&&void 0!==t?t:800,damping:null!==(n=null===(r=i.transition)||void 0===r?void 0:r.damping)&&void 0!==n?n:80,mass:null!==(o=null===(s=i.transition)||void 0===s?void 0:s.mass)&&void 0!==o?o:1}}),[i.transition]),t.useEffect((()=>{const e=e=>{g.current={x:e.clientX,y:e.clientY},p.current=[{x:e.clientX,y:e.clientY},...p.current.slice(0,s-1)]};return window.addEventListener("mousemove",e,{passive:!0}),()=>window.removeEventListener("mousemove",e)}),[s]),t.useEffect((()=>{const e=t=>{if(null!==y.current)if(E.current){const{x:e,y:t}=g.current;x.current={x:e,y:t,vx:0,vy:0},v.current&&(v.current.style.transform=`translate(${e}px, ${t}px)`)}else{const e=Math.min((t-y.current)/1e3,.064),{stiffness:r,damping:n,mass:s}=w.current,{x:o,y:i,vx:u,vy:c}=x.current,{x:l,y:d}=g.current,[f,m]=a(o,u,l,r,n,s,e),[h,p]=a(i,c,d,r,n,s,e);x.current={x:f,y:h,vx:m,vy:p},v.current&&(v.current.style.transform=`translate(${f}px, ${h}px)`)}y.current=t,b.current=requestAnimationFrame(e)};return b.current=requestAnimationFrame(e),()=>{null!==b.current&&cancelAnimationFrame(b.current)}}),[]),t.useEffect((()=>{const e=window.matchMedia("(pointer: coarse)");f(e.matches);const t=window.matchMedia("(prefers-reduced-motion: reduce)");E.current=t.matches,h(t.matches);const r=e=>{E.current=e.matches,h(e.matches)};t.addEventListener("change",r);const n=setTimeout((()=>l(!0)),50);return()=>{t.removeEventListener("change",r),clearTimeout(n)}}),[]),d&&!n)return null;const{width:C=24,height:R=24,scale:S=1,shape:L="circle",color:T="rgba(255, 255, 255, 0.8)",opacity:j=1,borderColor:A="rgba(0, 0, 0, 0)",borderWidth:O=0,borderStyle:P="solid",mixBlendMode:z="normal",label:M,fontSize:V="12px",fontWeight:F="bold",labelColor:k="#000",customElement:q,innerElements:$,borderRadius:I}=i,W="circle"===L?"50%":"square"===L?`${null!=I?I:0}px`:"0",G="custom"===L?"transparent":T,X=m?"none":"width 0.2s ease, height 0.2s ease, border-radius 0.2s ease, background-color 0.2s ease, border-color 0.2s ease, opacity 0.2s ease, transform 0.15s ease";return e.jsx("div",{ref:v,"aria-hidden":"true",style:{position:"fixed",left:0,top:0,zIndex:r,pointerEvents:"none",opacity:c?1:0,willChange:"transform",mixBlendMode:z},children:e.jsxs("div",{style:{width:C,height:R,borderRadius:W,backgroundColor:G,opacity:j,borderColor:A,borderWidth:O,borderStyle:P,display:"flex",justifyContent:"center",alignItems:"center",transform:`translate(-50%, -50%) scale(${S})`,transition:X,willChange:"width, height, background-color, transform"},children:["custom"===L&&q,M&&e.jsx("div",{style:{fontSize:V,fontWeight:F,color:k,textAlign:"center",userSelect:"none",whiteSpace:"nowrap",pointerEvents:"none"},children:M}),null==$?void 0:$.map(((t,r)=>{const n=p.current[Math.min(r+1,p.current.length-1)]||u,s=u.x-n.x,o=u.y-n.y;return e.jsx("div",{style:{position:"absolute",left:"50%",top:"50%",transform:`translate(calc(-50% + ${.5*-s}px), calc(-50% + ${.5*-o}px))`,transition:m?"none":"transform 0.12s ease"},children:t.element},`inner-${r}`)}))]})})},exports.CursorClickEffect=({size:r=50,duration:n=600,color:s="rgba(255, 255, 255, 0.8)",strokeWidth:o=2,zIndex:a=9997})=>{const i=t.useRef(null),u=t.useRef([]),c=t.useRef(0),l=t.useRef(null);return t.useEffect((()=>{const e=i.current;if(!e)return;const t=e.getContext("2d");if(!t)return;const a=()=>{e.width=window.innerWidth,e.height=window.innerHeight};a(),window.addEventListener("resize",a,{passive:!0});const d=e=>{u.current.push({x:e.clientX,y:e.clientY,startTime:performance.now(),id:c.current++})};window.addEventListener("click",d);const f=a=>{t.clearRect(0,0,e.width,e.height),u.current=u.current.filter((e=>{const i=a-e.startTime;if(i>=n)return!1;const u=i/n,c=1-Math.pow(1-u,3),l=r/2*c,d=1-u;return t.beginPath(),t.arc(e.x,e.y,l,0,2*Math.PI),t.strokeStyle=s,t.globalAlpha=d,t.lineWidth=o,t.stroke(),!0})),t.globalAlpha=1,l.current=requestAnimationFrame(f)};return l.current=requestAnimationFrame(f),()=>{window.removeEventListener("resize",a),window.removeEventListener("click",d),null!==l.current&&cancelAnimationFrame(l.current)}}),[s,n,r,o]),e.jsx("canvas",{ref:i,"aria-hidden":"true",style:{position:"fixed",top:0,left:0,pointerEvents:"none",zIndex:a}})},exports.CursorProvider=({children:o,config:a=n,hideNativeCursor:i=!0})=>{var u;const c=r(),[l,d]=t.useState(["default"]),f=t.useRef(Date.now()),m=t.useRef(null),[h,v]=t.useState(null),p=()=>{d(["default"])};t.useEffect((()=>{const e=e=>{f.current=Date.now(),m.current&&(clearTimeout(m.current),m.current=null);const t=document.elementFromPoint(e.clientX,e.clientY);t&&(t.hasAttribute("data-cursor-target")||t.closest("[data-cursor-target]"))||"default"===l[l.length-1]||(m.current=setTimeout((()=>{const t=document.elementFromPoint(e.clientX,e.clientY);(!t||!t.hasAttribute("data-cursor-target")&&!t.closest("[data-cursor-target]"))&&p()}),0))};return document.addEventListener("mousemove",e,{passive:!0}),()=>{document.removeEventListener("mousemove",e),m.current&&clearTimeout(m.current)}}),[l]);const x=null!=h?h:l[l.length-1],g=null!==(u=a[x])&&void 0!==u?u:a.default,b=Object.assign(Object.assign({},g),{variant:x});return t.useEffect((()=>{if(i){const e=document.createElement("style");return e.textContent='\n body, a, button, [role="button"], * {\n cursor: none !important;\n }\n ',document.head.appendChild(e),()=>{document.head.removeChild(e)}}}),[i]),e.jsx(s.Provider,{value:{cursorState:b,setCursorVariant:(e,t="push")=>{m.current&&(clearTimeout(m.current),m.current=null),"reset"===t?d(["default"]):"push"===t?(e=>{d((t=>[...t,e]))})(e):d((e=>{const t=[...e];return t.pop(),t.length?t:["default"]}))},resetCursorToDefault:p,config:a,mousePosition:c,setGlobalCursorVariant:v,clearGlobalCursorVariant:()=>v(null)},children:o})},exports.CursorTarget=function(t){var{as:r,children:n,variant:s,onEnter:o,onLeave:a}=t,u=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var s=0;for(n=Object.getOwnPropertySymbols(e);s<n.length;s++)t.indexOf(n[s])<0&&Object.prototype.propertyIsEnumerable.call(e,n[s])&&(r[n[s]]=e[n[s]])}return r}(t,["as","children","variant","onEnter","onLeave"]);const c=null!=r?r:"div",l=i({variant:s,onEnter:o,onLeave:a});return e.jsx(c,Object.assign({},u,l,{"data-cursor-variant":s,children:n}))},exports.CursorTrail=({count:r=12,color:n="rgba(255, 255, 255, 0.6)",size:s=8,zIndex:a=9998})=>{const{cursorState:i}=o(),u=t.useRef(null),c=t.useRef({x:0,y:0}),l=t.useRef([]),d=t.useRef(null),f=t.useRef(i.variant);return t.useEffect((()=>{f.current=i.variant}),[i.variant]),t.useEffect((()=>{const e=u.current;if(!e)return;const t=e.getContext("2d");if(!t)return;const o=()=>{e.width=window.innerWidth,e.height=window.innerHeight};o(),window.addEventListener("resize",o,{passive:!0});const a=e=>{c.current={x:e.clientX,y:e.clientY}};window.addEventListener("mousemove",a,{passive:!0});const i=()=>{l.current=[Object.assign({},c.current),...l.current].slice(0,r),t.clearRect(0,0,e.width,e.height),l.current.forEach(((e,o)=>{const a=o/r,i=.7*(1-a),u=s/2*(1-.5*a);t.beginPath(),t.arc(e.x,e.y,Math.max(u,.5),0,2*Math.PI),t.globalAlpha=i,t.fillStyle=n,t.fill()})),t.globalAlpha=1,d.current=requestAnimationFrame(i)};return d.current=requestAnimationFrame(i),()=>{window.removeEventListener("resize",o),window.removeEventListener("mousemove",a),null!==d.current&&cancelAnimationFrame(d.current)}}),[r,n,s]),e.jsx("canvas",{ref:u,"aria-hidden":"true",style:{position:"fixed",top:0,left:0,pointerEvents:"none",zIndex:a}})},exports.useCursor=i,exports.useCursorVariant=()=>{const{setCursorVariant:e,resetCursorToDefault:r,setGlobalCursorVariant:n,clearGlobalCursorVariant:s}=o();return{setVariant:t.useCallback((t=>{e(t,"push")}),[e]),resetVariant:t.useCallback((()=>{r()}),[r]),setGlobalVariant:t.useCallback((e=>{null==n||n(e)}),[n]),clearGlobalVariant:t.useCallback((()=>{null==s||s()}),[s])}},exports.useMagnetic=function({strength:e=.35,distance:r=80}={}){const n=t.useRef(null),{mousePosition:s}=o();return t.useEffect((()=>{const t=n.current;if(!t)return;const o=t.getBoundingClientRect(),a=o.left+o.width/2,i=o.top+o.height/2,u=s.x-a,c=s.y-i,l=Math.sqrt(u*u+c*c);if(l<r){const n=(1-l/r)*e;t.style.transform=`translate(${u*n}px, ${c*n}px)`,t.style.transition="transform 0.08s linear"}else t.style.transform="translate(0px, 0px)",t.style.transition="transform 0.4s ease"}),[s,e,r]),t.useEffect((()=>()=>{n.current&&(n.current.style.transform="",n.current.style.transition="")}),[]),n},exports.useMousePosition=r;
//# sourceMappingURL=index.js.map