diff --git a/apps/www/public/llms-full.txt b/apps/www/public/llms-full.txt index 6451aa5cf..40700de19 100644 --- a/apps/www/public/llms-full.txt +++ b/apps/www/public/llms-full.txt @@ -9298,8 +9298,13 @@ Description: A spotlight effect that follows your mouse cursor and highlights bo --- file: magicui/magic-card.tsx --- "use client" -import React, { useCallback, useEffect } from "react" -import { motion, useMotionTemplate, useMotionValue } from "motion/react" +import React, { useCallback, useEffect, useRef } from "react" +import { + animate, + motion, + useMotionTemplate, + useMotionValue, +} from "motion/react" import { cn } from "@/lib/utils" @@ -9322,11 +9327,43 @@ export function MagicCard({ gradientFrom = "#9E7AFF", gradientTo = "#FE8BBB", }: MagicCardProps) { + const ref = useRef(null) + const mouseX = useMotionValue(-gradientSize) const mouseY = useMotionValue(-gradientSize) + const reset = useCallback(() => { - mouseX.set(-gradientSize) - mouseY.set(-gradientSize) + if (!ref.current) return + const rect = ref.current.getBoundingClientRect() + const x = mouseX.get() + const y = mouseY.get() + + const distances = { + left: x, + right: rect.width - x, + top: y, + bottom: rect.height - y, + } + + const closestEdge = Object.entries(distances).reduce( + (closest, [edge, distance]) => + distance < closest.distance ? { edge, distance } : closest, + { edge: "left", distance: distances.left } + ).edge + + switch (closestEdge) { + case "left": + return animate(mouseX, -gradientSize) + case "right": + return animate(mouseX, rect.width + gradientSize) + case "top": + return animate(mouseY, -gradientSize) + case "bottom": + return animate(mouseY, rect.height + gradientSize) + default: + animate(mouseX, -gradientSize) + animate(mouseY, -gradientSize) + } }, [gradientSize, mouseX, mouseY]) const handlePointerMove = useCallback( @@ -9367,27 +9404,28 @@ export function MagicCard({ }, [reset]) return ( -
- -
+ ${gradientTo}, + var(--color-border) 100% + ) border-box + `, + }} + >
{children}
-
+
) } diff --git a/apps/www/public/r/magic-card.json b/apps/www/public/r/magic-card.json index 9b8ecd314..56da3be31 100644 --- a/apps/www/public/r/magic-card.json +++ b/apps/www/public/r/magic-card.json @@ -10,7 +10,7 @@ "files": [ { "path": "registry/magicui/magic-card.tsx", - "content": "\"use client\"\n\nimport React, { useCallback, useEffect } from \"react\"\nimport { motion, useMotionTemplate, useMotionValue } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface MagicCardProps {\n children?: React.ReactNode\n className?: string\n gradientSize?: number\n gradientColor?: string\n gradientOpacity?: number\n gradientFrom?: string\n gradientTo?: string\n}\n\nexport function MagicCard({\n children,\n className,\n gradientSize = 200,\n gradientColor = \"#262626\",\n gradientOpacity = 0.8,\n gradientFrom = \"#9E7AFF\",\n gradientTo = \"#FE8BBB\",\n}: MagicCardProps) {\n const mouseX = useMotionValue(-gradientSize)\n const mouseY = useMotionValue(-gradientSize)\n const reset = useCallback(() => {\n mouseX.set(-gradientSize)\n mouseY.set(-gradientSize)\n }, [gradientSize, mouseX, mouseY])\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent) => {\n const rect = e.currentTarget.getBoundingClientRect()\n mouseX.set(e.clientX - rect.left)\n mouseY.set(e.clientY - rect.top)\n },\n [mouseX, mouseY]\n )\n\n useEffect(() => {\n reset()\n }, [reset])\n\n useEffect(() => {\n const handleGlobalPointerOut = (e: PointerEvent) => {\n if (!e.relatedTarget) {\n reset()\n }\n }\n\n const handleVisibility = () => {\n if (document.visibilityState !== \"visible\") {\n reset()\n }\n }\n\n window.addEventListener(\"pointerout\", handleGlobalPointerOut)\n window.addEventListener(\"blur\", reset)\n document.addEventListener(\"visibilitychange\", handleVisibility)\n\n return () => {\n window.removeEventListener(\"pointerout\", handleGlobalPointerOut)\n window.removeEventListener(\"blur\", reset)\n document.removeEventListener(\"visibilitychange\", handleVisibility)\n }\n }, [reset])\n\n return (\n \n \n
\n \n
{children}
\n
\n )\n}\n", + "content": "\"use client\"\n\nimport React, { useCallback, useEffect, useRef } from \"react\"\nimport {\n animate,\n motion,\n useMotionTemplate,\n useMotionValue,\n} from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface MagicCardProps {\n children?: React.ReactNode\n className?: string\n gradientSize?: number\n gradientColor?: string\n gradientOpacity?: number\n gradientFrom?: string\n gradientTo?: string\n}\n\nexport function MagicCard({\n children,\n className,\n gradientSize = 200,\n gradientColor = \"#262626\",\n gradientOpacity = 0.8,\n gradientFrom = \"#9E7AFF\",\n gradientTo = \"#FE8BBB\",\n}: MagicCardProps) {\n const ref = useRef(null)\n\n const mouseX = useMotionValue(-gradientSize)\n const mouseY = useMotionValue(-gradientSize)\n\n const reset = useCallback(() => {\n if (!ref.current) return\n const rect = ref.current.getBoundingClientRect()\n const x = mouseX.get()\n const y = mouseY.get()\n\n const distances = {\n left: x,\n right: rect.width - x,\n top: y,\n bottom: rect.height - y,\n }\n\n const closestEdge = Object.entries(distances).reduce(\n (closest, [edge, distance]) =>\n distance < closest.distance ? { edge, distance } : closest,\n { edge: \"left\", distance: distances.left }\n ).edge\n\n switch (closestEdge) {\n case \"left\":\n return animate(mouseX, -gradientSize)\n case \"right\":\n return animate(mouseX, rect.width + gradientSize)\n case \"top\":\n return animate(mouseY, -gradientSize)\n case \"bottom\":\n return animate(mouseY, rect.height + gradientSize)\n default:\n animate(mouseX, -gradientSize)\n animate(mouseY, -gradientSize)\n }\n }, [gradientSize, mouseX, mouseY])\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent) => {\n const rect = e.currentTarget.getBoundingClientRect()\n mouseX.set(e.clientX - rect.left)\n mouseY.set(e.clientY - rect.top)\n },\n [mouseX, mouseY]\n )\n\n useEffect(() => {\n reset()\n }, [reset])\n\n useEffect(() => {\n const handleGlobalPointerOut = (e: PointerEvent) => {\n if (!e.relatedTarget) {\n reset()\n }\n }\n\n const handleVisibility = () => {\n if (document.visibilityState !== \"visible\") {\n reset()\n }\n }\n\n window.addEventListener(\"pointerout\", handleGlobalPointerOut)\n window.addEventListener(\"blur\", reset)\n document.addEventListener(\"visibilitychange\", handleVisibility)\n\n return () => {\n window.removeEventListener(\"pointerout\", handleGlobalPointerOut)\n window.removeEventListener(\"blur\", reset)\n document.removeEventListener(\"visibilitychange\", handleVisibility)\n }\n }, [reset])\n\n return (\n \n \n
{children}
\n \n )\n}\n", "type": "registry:ui" } ] diff --git a/apps/www/registry/magicui/magic-card.tsx b/apps/www/registry/magicui/magic-card.tsx index c78a5f87e..5b1c5ed78 100644 --- a/apps/www/registry/magicui/magic-card.tsx +++ b/apps/www/registry/magicui/magic-card.tsx @@ -1,7 +1,12 @@ "use client" -import React, { useCallback, useEffect } from "react" -import { motion, useMotionTemplate, useMotionValue } from "motion/react" +import React, { useCallback, useEffect, useRef } from "react" +import { + animate, + motion, + useMotionTemplate, + useMotionValue, +} from "motion/react" import { cn } from "@/lib/utils" @@ -24,11 +29,43 @@ export function MagicCard({ gradientFrom = "#9E7AFF", gradientTo = "#FE8BBB", }: MagicCardProps) { + const ref = useRef(null) + const mouseX = useMotionValue(-gradientSize) const mouseY = useMotionValue(-gradientSize) + const reset = useCallback(() => { - mouseX.set(-gradientSize) - mouseY.set(-gradientSize) + if (!ref.current) return + const rect = ref.current.getBoundingClientRect() + const x = mouseX.get() + const y = mouseY.get() + + const distances = { + left: x, + right: rect.width - x, + top: y, + bottom: rect.height - y, + } + + const closestEdge = Object.entries(distances).reduce( + (closest, [edge, distance]) => + distance < closest.distance ? { edge, distance } : closest, + { edge: "left", distance: distances.left } + ).edge + + switch (closestEdge) { + case "left": + return animate(mouseX, -gradientSize) + case "right": + return animate(mouseX, rect.width + gradientSize) + case "top": + return animate(mouseY, -gradientSize) + case "bottom": + return animate(mouseY, rect.height + gradientSize) + default: + animate(mouseX, -gradientSize) + animate(mouseY, -gradientSize) + } }, [gradientSize, mouseX, mouseY]) const handlePointerMove = useCallback( @@ -69,27 +106,28 @@ export function MagicCard({ }, [reset]) return ( -
- -
+ ${gradientTo}, + var(--color-border) 100% + ) border-box + `, + }} + >
{children}
-
+
) }