@@ -13225,16 +13225,11 @@ Description: A customizable, physics-based smooth cursor animation component wit
1322513225--- file: magicui/smooth-cursor.tsx ---
1322613226"use client"
1322713227
13228- import { FC, useEffect, useRef, useState } from "react"
13229- import { motion, useSpring } from "motion/react"
13230-
13231- interface Position {
13232- x: number
13233- y: number
13234- }
13228+ import { JSX } from "react"
13229+ import { SmoothCursor as SmoothCursorComponent } from "smooth-cursor"
1323513230
1323613231export interface SmoothCursorProps {
13237- cursor?: React.ReactNode
13232+ cursor?: JSX.Element
1323813233 springConfig?: {
1323913234 damping: number
1324013235 stiffness: number
@@ -13243,193 +13238,8 @@ export interface SmoothCursorProps {
1324313238 }
1324413239}
1324513240
13246- const DefaultCursorSVG: FC = () => {
13247- return (
13248- <svg
13249- xmlns="http://www.w3.org/2000/svg"
13250- width={50}
13251- height={54}
13252- viewBox="0 0 50 54"
13253- fill="none"
13254- style={{ scale: 0.5 }}
13255- >
13256- <g filter="url(#filter0_d_91_7928)">
13257- <path
13258- d="M42.6817 41.1495L27.5103 6.79925C26.7269 5.02557 24.2082 5.02558 23.3927 6.79925L7.59814 41.1495C6.75833 42.9759 8.52712 44.8902 10.4125 44.1954L24.3757 39.0496C24.8829 38.8627 25.4385 38.8627 25.9422 39.0496L39.8121 44.1954C41.6849 44.8902 43.4884 42.9759 42.6817 41.1495Z"
13259- fill="black"
13260- />
13261- <path
13262- d="M43.7146 40.6933L28.5431 6.34306C27.3556 3.65428 23.5772 3.69516 22.3668 6.32755L6.57226 40.6778C5.3134 43.4156 7.97238 46.298 10.803 45.2549L24.7662 40.109C25.0221 40.0147 25.2999 40.0156 25.5494 40.1082L39.4193 45.254C42.2261 46.2953 44.9254 43.4347 43.7146 40.6933Z"
13263- stroke="white"
13264- strokeWidth={2.25825}
13265- />
13266- </g>
13267- <defs>
13268- <filter
13269- id="filter0_d_91_7928"
13270- x={0.602397}
13271- y={0.952444}
13272- width={49.0584}
13273- height={52.428}
13274- filterUnits="userSpaceOnUse"
13275- colorInterpolationFilters="sRGB"
13276- >
13277- <feFlood floodOpacity={0} result="BackgroundImageFix" />
13278- <feColorMatrix
13279- in="SourceAlpha"
13280- type="matrix"
13281- values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
13282- result="hardAlpha"
13283- />
13284- <feOffset dy={2.25825} />
13285- <feGaussianBlur stdDeviation={2.25825} />
13286- <feComposite in2="hardAlpha" operator="out" />
13287- <feColorMatrix
13288- type="matrix"
13289- values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.08 0"
13290- />
13291- <feBlend
13292- mode="normal"
13293- in2="BackgroundImageFix"
13294- result="effect1_dropShadow_91_7928"
13295- />
13296- <feBlend
13297- mode="normal"
13298- in="SourceGraphic"
13299- in2="effect1_dropShadow_91_7928"
13300- result="shape"
13301- />
13302- </filter>
13303- </defs>
13304- </svg>
13305- )
13306- }
13307-
13308- export function SmoothCursor({
13309- cursor = <DefaultCursorSVG />,
13310- springConfig = {
13311- damping: 45,
13312- stiffness: 400,
13313- mass: 1,
13314- restDelta: 0.001,
13315- },
13316- }: SmoothCursorProps) {
13317- const [isMoving, setIsMoving] = useState(false)
13318- const lastMousePos = useRef<Position>({ x: 0, y: 0 })
13319- const velocity = useRef<Position>({ x: 0, y: 0 })
13320- const lastUpdateTime = useRef(Date.now())
13321- const previousAngle = useRef(0)
13322- const accumulatedRotation = useRef(0)
13323-
13324- const cursorX = useSpring(0, springConfig)
13325- const cursorY = useSpring(0, springConfig)
13326- const rotation = useSpring(0, {
13327- ...springConfig,
13328- damping: 60,
13329- stiffness: 300,
13330- })
13331- const scale = useSpring(1, {
13332- ...springConfig,
13333- stiffness: 500,
13334- damping: 35,
13335- })
13336-
13337- useEffect(() => {
13338- const updateVelocity = (currentPos: Position) => {
13339- const currentTime = Date.now()
13340- const deltaTime = currentTime - lastUpdateTime.current
13341-
13342- if (deltaTime > 0) {
13343- velocity.current = {
13344- x: (currentPos.x - lastMousePos.current.x) / deltaTime,
13345- y: (currentPos.y - lastMousePos.current.y) / deltaTime,
13346- }
13347- }
13348-
13349- lastUpdateTime.current = currentTime
13350- lastMousePos.current = currentPos
13351- }
13352-
13353- const smoothMouseMove = (e: MouseEvent) => {
13354- const currentPos = { x: e.clientX, y: e.clientY }
13355- updateVelocity(currentPos)
13356-
13357- const speed = Math.sqrt(
13358- Math.pow(velocity.current.x, 2) + Math.pow(velocity.current.y, 2)
13359- )
13360-
13361- cursorX.set(currentPos.x)
13362- cursorY.set(currentPos.y)
13363-
13364- if (speed > 0.1) {
13365- const currentAngle =
13366- Math.atan2(velocity.current.y, velocity.current.x) * (180 / Math.PI) +
13367- 90
13368-
13369- let angleDiff = currentAngle - previousAngle.current
13370- if (angleDiff > 180) angleDiff -= 360
13371- if (angleDiff < -180) angleDiff += 360
13372- accumulatedRotation.current += angleDiff
13373- rotation.set(accumulatedRotation.current)
13374- previousAngle.current = currentAngle
13375-
13376- scale.set(0.95)
13377- setIsMoving(true)
13378-
13379- const timeout = setTimeout(() => {
13380- scale.set(1)
13381- setIsMoving(false)
13382- }, 150)
13383-
13384- return () => clearTimeout(timeout)
13385- }
13386- }
13387-
13388- let rafId: number
13389- const throttledMouseMove = (e: MouseEvent) => {
13390- if (rafId) return
13391-
13392- rafId = requestAnimationFrame(() => {
13393- smoothMouseMove(e)
13394- rafId = 0
13395- })
13396- }
13397-
13398- document.body.style.cursor = "none"
13399- window.addEventListener("mousemove", throttledMouseMove)
13400-
13401- return () => {
13402- window.removeEventListener("mousemove", throttledMouseMove)
13403- document.body.style.cursor = "auto"
13404- if (rafId) cancelAnimationFrame(rafId)
13405- }
13406- }, [cursorX, cursorY, rotation, scale])
13407-
13408- return (
13409- <motion.div
13410- style={{
13411- position: "fixed",
13412- left: cursorX,
13413- top: cursorY,
13414- translateX: "-50%",
13415- translateY: "-50%",
13416- rotate: rotation,
13417- scale: scale,
13418- zIndex: 100,
13419- pointerEvents: "none",
13420- willChange: "transform",
13421- }}
13422- initial={{ scale: 0 }}
13423- animate={{ scale: 1 }}
13424- transition={{
13425- type: "spring",
13426- stiffness: 400,
13427- damping: 30,
13428- }}
13429- >
13430- {cursor}
13431- </motion.div>
13432- )
13241+ export function SmoothCursor({ cursor, springConfig }: SmoothCursorProps) {
13242+ return <SmoothCursorComponent cursor={cursor} springConfig={springConfig} />
1343313243}
1343413244
1343513245
0 commit comments