diff --git a/__registry__/index.tsx b/__registry__/index.tsx index 735a94942..9681d5392 100644 --- a/__registry__/index.tsx +++ b/__registry__/index.tsx @@ -203,7 +203,7 @@ export const Index: Record = { "script-copy-btn": { name: "script-copy-btn", type: "registry:ui", - registryDependencies: undefined, + registryDependencies: ["button"], files: ["registry/default/magicui/script-copy-btn.tsx"], component: React.lazy( () => import("@/registry/default/magicui/script-copy-btn.tsx"), @@ -281,7 +281,7 @@ export const Index: Record = { "bento-grid": { name: "bento-grid", type: "registry:ui", - registryDependencies: undefined, + registryDependencies: ["button"], files: ["registry/default/magicui/bento-grid.tsx"], component: React.lazy( () => import("@/registry/default/magicui/bento-grid.tsx"), @@ -648,7 +648,7 @@ export const Index: Record = { confetti: { name: "confetti", type: "registry:ui", - registryDependencies: undefined, + registryDependencies: ["button"], files: ["registry/default/magicui/confetti.tsx"], component: React.lazy( () => import("@/registry/default/magicui/confetti.tsx"), diff --git a/app/(marketing)/showcase/page.tsx b/app/(marketing)/showcase/page.tsx index 71a299d17..63691414d 100644 --- a/app/(marketing)/showcase/page.tsx +++ b/app/(marketing)/showcase/page.tsx @@ -1,9 +1,9 @@ import { allShowcases } from "content-collections"; import { ShowcaseCard } from "@/components/sections/showcase"; -import BlurFade from "@/registry/default/magicui/blur-fade"; +import { BlurFade } from "@/registry/default/magicui/blur-fade"; -export default async function Page() { +export default function Page() { return (

diff --git a/components/mdx-components.tsx b/components/mdx-components.tsx index 082da0aad..30162f5d4 100644 --- a/components/mdx-components.tsx +++ b/components/mdx-components.tsx @@ -11,7 +11,7 @@ import { import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Event } from "@/lib/events"; import { cn } from "@/lib/utils"; -import TweetCard from "@/registry/default/magicui/tweet-card"; +import { TweetCard } from "@/registry/default/magicui/tweet-card"; import { useMDXComponent } from "@content-collections/mdx/react"; import Image from "next/image"; import Link from "next/link"; diff --git a/components/sections/showcase.tsx b/components/sections/showcase.tsx index 16e78211b..434c1cafe 100644 --- a/components/sections/showcase.tsx +++ b/components/sections/showcase.tsx @@ -2,7 +2,7 @@ import { ChevronRightIcon } from "@radix-ui/react-icons"; import { allShowcases } from "content-collections"; import Link from "next/link"; -import Marquee from "@/registry/default/magicui/marquee"; +import { Marquee } from "@/registry/default/magicui/marquee"; export interface ShowcaseCardProps { title: string; diff --git a/components/sections/testimonials.tsx b/components/sections/testimonials.tsx index 9f8d38ab6..c66902741 100644 --- a/components/sections/testimonials.tsx +++ b/components/sections/testimonials.tsx @@ -1,5 +1,5 @@ -import Marquee from "@/registry/default/magicui/marquee"; -import TweetCard from "@/registry/default/magicui/tweet-card"; +import { Marquee } from "@/registry/default/magicui/marquee"; +import { TweetCard } from "@/registry/default/magicui/tweet-card"; const tweets = [ "https://x.com/chronark_/status/1754781648262967323", diff --git a/components/sidebar-cta.tsx b/components/sidebar-cta.tsx index fd2e6663f..0f3393f12 100644 --- a/components/sidebar-cta.tsx +++ b/components/sidebar-cta.tsx @@ -4,7 +4,7 @@ import { ChevronRight } from "lucide-react"; import Link from "next/link"; import posthog from "posthog-js"; -import AnimatedShinyText from "@/registry/default/magicui/animated-shiny-text"; +import { AnimatedShinyText } from "@/registry/default/magicui/animated-shiny-text"; import { TextAnimate } from "@/registry/default/magicui/text-animate"; export default function SidebarCTA() { diff --git a/components/site-header.tsx b/components/site-header.tsx index 486e22581..ef97d6d05 100644 --- a/components/site-header.tsx +++ b/components/site-header.tsx @@ -9,7 +9,7 @@ import { ModeToggle } from "@/components/mode-toggle"; import { buttonVariants } from "@/components/ui/button"; import { siteConfig } from "@/config/site"; import { cn } from "@/lib/utils"; -import NumberTicker from "@/registry/default/magicui/number-ticker"; +import { NumberTicker } from "@/registry/default/magicui/number-ticker"; export async function SiteHeader() { let stars = 300; // Default value diff --git a/public/r/index.json b/public/r/index.json index 8a9d2eaf8..c49f9b470 100644 --- a/public/r/index.json +++ b/public/r/index.json @@ -167,9 +167,6 @@ { "name": "morphing-text", "type": "registry:ui", - "dependencies": [ - "motion" - ], "files": [ { "path": "magicui/morphing-text.tsx", @@ -290,9 +287,6 @@ { "name": "flickering-grid", "type": "registry:ui", - "dependencies": [ - "motion" - ], "files": [ { "path": "magicui/flickering-grid.tsx", @@ -335,6 +329,9 @@ "shiki", "next-themes" ], + "registryDependencies": [ + "button" + ], "files": [ { "path": "magicui/script-copy-btn.tsx", @@ -386,8 +383,7 @@ "name": "globe", "type": "registry:ui", "dependencies": [ - "cobe", - "react-spring" + "cobe" ], "files": [ { @@ -471,6 +467,9 @@ "dependencies": [ "@radix-ui/react-icons" ], + "registryDependencies": [ + "button" + ], "files": [ { "path": "magicui/bento-grid.tsx", @@ -948,6 +947,9 @@ "canvas-confetti", "@types/canvas-confetti" ], + "registryDependencies": [ + "button" + ], "files": [ { "path": "magicui/confetti.tsx", @@ -1141,9 +1143,6 @@ { "name": "interactive-hover-button", "type": "registry:ui", - "dependencies": [ - "lucide-react" - ], "files": [ { "path": "magicui/interactive-hover-button.tsx", diff --git a/public/r/styles/default/animated-circular-progress-bar.json b/public/r/styles/default/animated-circular-progress-bar.json index 43fcb71c0..c9df30414 100644 --- a/public/r/styles/default/animated-circular-progress-bar.json +++ b/public/r/styles/default/animated-circular-progress-bar.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/animated-circular-progress-bar.tsx", - "content": "import { cn } from \"@/lib/utils\";\n\ninterface Props {\n max: number;\n value: number;\n min: number;\n gaugePrimaryColor: string;\n gaugeSecondaryColor: string;\n className?: string;\n}\n\nexport default function AnimatedCircularProgressBar({\n max = 100,\n min = 0,\n value = 0,\n gaugePrimaryColor,\n gaugeSecondaryColor,\n className,\n}: Props) {\n const circumference = 2 * Math.PI * 45;\n const percentPx = circumference / 100;\n const currentPercent = Math.round(((value - min) / (max - min)) * 100);\n\n return (\n \n \n {currentPercent <= 90 && currentPercent >= 0 && (\n \n )}\n \n \n \n {currentPercent}\n \n \n );\n}\n", + "content": "import { cn } from \"@/lib/utils\";\n\ninterface AnimatedCircularProgressBarProps {\n max: number;\n value: number;\n min: number;\n gaugePrimaryColor: string;\n gaugeSecondaryColor: string;\n className?: string;\n}\n\nexport function AnimatedCircularProgressBar({\n max = 100,\n min = 0,\n value = 0,\n gaugePrimaryColor,\n gaugeSecondaryColor,\n className,\n}: AnimatedCircularProgressBarProps) {\n const circumference = 2 * Math.PI * 45;\n const percentPx = circumference / 100;\n const currentPercent = Math.round(((value - min) / (max - min)) * 100);\n\n return (\n \n \n {currentPercent <= 90 && currentPercent >= 0 && (\n \n )}\n \n \n \n {currentPercent}\n \n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/animated-gradient-text.json b/public/r/styles/default/animated-gradient-text.json index 9b1542696..d67090487 100644 --- a/public/r/styles/default/animated-gradient-text.json +++ b/public/r/styles/default/animated-gradient-text.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/animated-gradient-text.tsx", - "content": "import { ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport default function AnimatedGradientText({\n children,\n className,\n}: {\n children: ReactNode;\n className?: string;\n}) {\n return (\n \n \n\n {children}\n \n );\n}\n", + "content": "import { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface AnimatedGradientTextProps\n extends ComponentPropsWithoutRef<\"div\"> {\n children: ReactNode;\n}\n\nexport function AnimatedGradientText({\n children,\n className,\n ...props\n}: AnimatedGradientTextProps) {\n return (\n \n \n\n {children}\n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/animated-grid-pattern.json b/public/r/styles/default/animated-grid-pattern.json index 25c76b36c..865bdb812 100644 --- a/public/r/styles/default/animated-grid-pattern.json +++ b/public/r/styles/default/animated-grid-pattern.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/animated-grid-pattern.tsx", - "content": "\"use client\";\n\nimport { motion } from \"motion/react\";\nimport { useEffect, useId, useRef, useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface AnimatedGridPatternProps {\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n strokeDasharray?: any;\n numSquares?: number;\n className?: string;\n maxOpacity?: number;\n duration?: number;\n repeatDelay?: number;\n}\n\nexport default function AnimatedGridPattern({\n width = 40,\n height = 40,\n x = -1,\n y = -1,\n strokeDasharray = 0,\n numSquares = 50,\n className,\n maxOpacity = 0.5,\n duration = 4,\n repeatDelay = 0.5,\n ...props\n}: AnimatedGridPatternProps) {\n const id = useId();\n const containerRef = useRef(null);\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 });\n const [squares, setSquares] = useState(() => generateSquares(numSquares));\n\n function getPos() {\n return [\n Math.floor((Math.random() * dimensions.width) / width),\n Math.floor((Math.random() * dimensions.height) / height),\n ];\n }\n\n // Adjust the generateSquares function to return objects with an id, x, and y\n function generateSquares(count: number) {\n return Array.from({ length: count }, (_, i) => ({\n id: i,\n pos: getPos(),\n }));\n }\n\n // Function to update a single square's position\n const updateSquarePosition = (id: number) => {\n setSquares((currentSquares) =>\n currentSquares.map((sq) =>\n sq.id === id\n ? {\n ...sq,\n pos: getPos(),\n }\n : sq,\n ),\n );\n };\n\n // Update squares to animate in\n useEffect(() => {\n if (dimensions.width && dimensions.height) {\n setSquares(generateSquares(numSquares));\n }\n }, [dimensions, numSquares]);\n\n // Resize observer to update container dimensions\n useEffect(() => {\n const resizeObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n setDimensions({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n });\n\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current);\n }\n\n return () => {\n if (containerRef.current) {\n resizeObserver.unobserve(containerRef.current);\n }\n };\n }, [containerRef]);\n\n return (\n \n \n \n \n \n \n \n \n {squares.map(({ pos: [x, y], id }, index) => (\n updateSquarePosition(id)}\n key={`${x}-${y}-${index}`}\n width={width - 1}\n height={height - 1}\n x={x * width + 1}\n y={y * height + 1}\n fill=\"currentColor\"\n strokeWidth=\"0\"\n />\n ))}\n \n \n );\n}\n", + "content": "\"use client\";\n\nimport { motion } from \"motion/react\";\nimport {\n ComponentPropsWithoutRef,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface AnimatedGridPatternProps\n extends ComponentPropsWithoutRef<\"svg\"> {\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n strokeDasharray?: any;\n numSquares?: number;\n maxOpacity?: number;\n duration?: number;\n repeatDelay?: number;\n}\n\nexport function AnimatedGridPattern({\n width = 40,\n height = 40,\n x = -1,\n y = -1,\n strokeDasharray = 0,\n numSquares = 50,\n className,\n maxOpacity = 0.5,\n duration = 4,\n repeatDelay = 0.5,\n ...props\n}: AnimatedGridPatternProps) {\n const id = useId();\n const containerRef = useRef(null);\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 });\n const [squares, setSquares] = useState(() => generateSquares(numSquares));\n\n function getPos() {\n return [\n Math.floor((Math.random() * dimensions.width) / width),\n Math.floor((Math.random() * dimensions.height) / height),\n ];\n }\n\n // Adjust the generateSquares function to return objects with an id, x, and y\n function generateSquares(count: number) {\n return Array.from({ length: count }, (_, i) => ({\n id: i,\n pos: getPos(),\n }));\n }\n\n // Function to update a single square's position\n const updateSquarePosition = (id: number) => {\n setSquares((currentSquares) =>\n currentSquares.map((sq) =>\n sq.id === id\n ? {\n ...sq,\n pos: getPos(),\n }\n : sq,\n ),\n );\n };\n\n // Update squares to animate in\n useEffect(() => {\n if (dimensions.width && dimensions.height) {\n setSquares(generateSquares(numSquares));\n }\n }, [dimensions, numSquares]);\n\n // Resize observer to update container dimensions\n useEffect(() => {\n const resizeObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n setDimensions({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n });\n\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current);\n }\n\n return () => {\n if (containerRef.current) {\n resizeObserver.unobserve(containerRef.current);\n }\n };\n }, [containerRef]);\n\n return (\n \n \n \n \n \n \n \n \n {squares.map(({ pos: [x, y], id }, index) => (\n updateSquarePosition(id)}\n key={`${x}-${y}-${index}`}\n width={width - 1}\n height={height - 1}\n x={x * width + 1}\n y={y * height + 1}\n fill=\"currentColor\"\n strokeWidth=\"0\"\n />\n ))}\n \n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/animated-list.json b/public/r/styles/default/animated-list.json index 50a502f6b..b345672cc 100644 --- a/public/r/styles/default/animated-list.json +++ b/public/r/styles/default/animated-list.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/animated-list.tsx", - "content": "\"use client\";\n\nimport { AnimatePresence, motion } from \"motion/react\";\nimport React, { useEffect, useMemo, useState } from \"react\";\n\nexport interface AnimatedListProps {\n className?: string;\n children: React.ReactNode;\n delay?: number;\n}\n\nexport const AnimatedList = React.memo(\n ({ className, children, delay = 1000 }: AnimatedListProps) => {\n const [index, setIndex] = useState(0);\n const childrenArray = useMemo(\n () => React.Children.toArray(children),\n [children],\n );\n\n useEffect(() => {\n if (index < childrenArray.length - 1) {\n const timeout = setTimeout(() => {\n setIndex((prevIndex) => prevIndex + 1);\n }, delay);\n\n return () => clearTimeout(timeout);\n }\n }, [index, delay, childrenArray.length]);\n\n const itemsToShow = useMemo(() => {\n const result = childrenArray.slice(0, index + 1).reverse();\n return result;\n }, [index, childrenArray]);\n\n return (\n
\n \n {itemsToShow.map((item) => (\n \n {item}\n \n ))}\n \n
\n );\n },\n);\n\nAnimatedList.displayName = \"AnimatedList\";\n\nexport function AnimatedListItem({ children }: { children: React.ReactNode }) {\n const animations = {\n initial: { scale: 0, opacity: 0 },\n animate: { scale: 1, opacity: 1, originY: 0 },\n exit: { scale: 0, opacity: 0 },\n transition: { type: \"spring\", stiffness: 350, damping: 40 },\n };\n\n return (\n \n {children}\n \n );\n}\n", + "content": "\"use client\";\n\nimport { AnimatePresence, motion } from \"motion/react\";\nimport React, {\n ComponentPropsWithoutRef,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\n\nexport function AnimatedListItem({ children }: { children: React.ReactNode }) {\n const animations = {\n initial: { scale: 0, opacity: 0 },\n animate: { scale: 1, opacity: 1, originY: 0 },\n exit: { scale: 0, opacity: 0 },\n transition: { type: \"spring\", stiffness: 350, damping: 40 },\n };\n\n return (\n \n {children}\n \n );\n}\n\nexport interface AnimatedListProps extends ComponentPropsWithoutRef<\"div\"> {\n children: React.ReactNode;\n delay?: number;\n}\n\nexport const AnimatedList = React.memo(\n ({ children, className, delay = 1000, ...props }: AnimatedListProps) => {\n const [index, setIndex] = useState(0);\n const childrenArray = useMemo(\n () => React.Children.toArray(children),\n [children],\n );\n\n useEffect(() => {\n if (index < childrenArray.length - 1) {\n const timeout = setTimeout(() => {\n setIndex((prevIndex) => prevIndex + 1);\n }, delay);\n\n return () => clearTimeout(timeout);\n }\n }, [index, delay, childrenArray.length]);\n\n const itemsToShow = useMemo(() => {\n const result = childrenArray.slice(0, index + 1).reverse();\n return result;\n }, [index, childrenArray]);\n\n return (\n \n \n {itemsToShow.map((item) => (\n \n {item}\n \n ))}\n \n \n );\n },\n);\n\nAnimatedList.displayName = \"AnimatedList\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/animated-shiny-text.json b/public/r/styles/default/animated-shiny-text.json index 718a24d19..84c5bcdbf 100644 --- a/public/r/styles/default/animated-shiny-text.json +++ b/public/r/styles/default/animated-shiny-text.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/animated-shiny-text.tsx", - "content": "import { CSSProperties, FC, ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface AnimatedShinyTextProps {\n children: ReactNode;\n className?: string;\n shimmerWidth?: number;\n}\n\nconst AnimatedShinyText: FC = ({\n children,\n className,\n shimmerWidth = 100,\n}) => {\n return (\n \n {children}\n

\n );\n};\n\nexport default AnimatedShinyText;\n", + "content": "import { ComponentPropsWithoutRef, CSSProperties, FC } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface AnimatedShinyTextProps\n extends ComponentPropsWithoutRef<\"span\"> {\n shimmerWidth?: number;\n}\n\nexport const AnimatedShinyText: FC = ({\n children,\n className,\n shimmerWidth = 100,\n ...props\n}) => {\n return (\n \n {children}\n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/animated-subscribe-button.json b/public/r/styles/default/animated-subscribe-button.json index fb26aba15..063c83934 100644 --- a/public/r/styles/default/animated-subscribe-button.json +++ b/public/r/styles/default/animated-subscribe-button.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/animated-subscribe-button.tsx", - "content": "\"use client\";\n\nimport { HTMLMotionProps } from \"motion/react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport React, { useState } from \"react\";\n\ninterface AnimatedSubscribeButtonProps extends HTMLMotionProps<\"button\"> {\n buttonColor: string;\n buttonTextColor?: string;\n subscribeStatus: boolean;\n initialText: React.ReactElement | string;\n changeText: React.ReactElement | string;\n ref?: React.Ref;\n}\n\nexport const AnimatedSubscribeButton = React.forwardRef<\n HTMLButtonElement,\n AnimatedSubscribeButtonProps\n>(\n (\n {\n buttonColor,\n subscribeStatus,\n buttonTextColor,\n changeText,\n initialText,\n onClick,\n ...props\n },\n ref\n ) => {\n const [isSubscribed, setIsSubscribed] = useState(subscribeStatus);\n\n return (\n \n {isSubscribed ? (\n ) => {\n setIsSubscribed(false);\n onClick?.(e);\n }}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n {...props}\n >\n \n {changeText}\n \n \n ) : (\n {\n setIsSubscribed(true);\n onClick?.(e);\n }}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n {...props}\n >\n \n {initialText}\n \n \n )}\n \n );\n }\n);\n\nAnimatedSubscribeButton.displayName = \"AnimatedSubscribeButton\";\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { HTMLMotionProps } from \"motion/react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport React, { useState } from \"react\";\n\ninterface AnimatedSubscribeButtonProps\n extends Omit, \"ref\"> {\n subscribeStatus?: boolean;\n children: React.ReactNode;\n className?: string;\n}\n\nexport const AnimatedSubscribeButton = React.forwardRef<\n HTMLButtonElement,\n AnimatedSubscribeButtonProps\n>(\n (\n { subscribeStatus = false, onClick, className, children, ...props },\n ref,\n ) => {\n const [isSubscribed, setIsSubscribed] = useState(subscribeStatus);\n\n if (\n React.Children.count(children) !== 2 ||\n !React.Children.toArray(children).every(\n (child) => React.isValidElement(child) && child.type === \"span\",\n )\n ) {\n throw new Error(\n \"AnimatedSubscribeButton expects two children, both of which must be elements.\",\n );\n }\n\n const childrenArray = React.Children.toArray(children);\n const initialChild = childrenArray[0];\n const changeChild = childrenArray[1];\n\n return (\n \n {isSubscribed ? (\n ) => {\n setIsSubscribed(false);\n onClick?.(e);\n }}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n {...props}\n >\n \n {changeChild} {/* Use children for subscribed state */}\n \n \n ) : (\n {\n setIsSubscribed(true);\n onClick?.(e);\n }}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n {...props}\n >\n \n {initialChild} {/* Use children for unsubscribed state */}\n \n \n )}\n \n );\n },\n);\n\nAnimatedSubscribeButton.displayName = \"AnimatedSubscribeButton\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/avatar-circles.json b/public/r/styles/default/avatar-circles.json index 4957e0ea7..1a026669c 100644 --- a/public/r/styles/default/avatar-circles.json +++ b/public/r/styles/default/avatar-circles.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/avatar-circles.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface Avatar {\n imageUrl: string;\n profileUrl: string;\n}\ninterface AvatarCirclesProps {\n className?: string;\n numPeople?: number;\n avatarUrls: Avatar[];\n}\n\nconst AvatarCircles = ({\n numPeople,\n className,\n avatarUrls,\n}: AvatarCirclesProps) => {\n return (\n
\n {avatarUrls.map((url, index) => (\n \n \n \n ))}\n {(numPeople ?? 0) > 0 && (\n \n +{numPeople}\n \n )}\n
\n );\n};\n\nexport default AvatarCircles;\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface Avatar {\n imageUrl: string;\n profileUrl: string;\n}\ninterface AvatarCirclesProps {\n className?: string;\n numPeople?: number;\n avatarUrls: Avatar[];\n}\n\nexport const AvatarCircles = ({\n numPeople,\n className,\n avatarUrls,\n}: AvatarCirclesProps) => {\n return (\n
\n {avatarUrls.map((url, index) => (\n \n \n \n ))}\n {(numPeople ?? 0) > 0 && (\n \n +{numPeople}\n \n )}\n
\n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/bento-grid.json b/public/r/styles/default/bento-grid.json index 8e36e073d..985bea33c 100644 --- a/public/r/styles/default/bento-grid.json +++ b/public/r/styles/default/bento-grid.json @@ -4,10 +4,13 @@ "dependencies": [ "@radix-ui/react-icons" ], + "registryDependencies": [ + "button" + ], "files": [ { "path": "magicui/bento-grid.tsx", - "content": "import { ReactNode } from \"react\";\nimport { ArrowRightIcon } from \"@radix-ui/react-icons\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\ntype BentoGridProps = {\n children: ReactNode;\n className?: string;\n};\n\ntype BentoCardProps = {\n name: string;\n className: string;\n background: ReactNode;\n Icon: React.ElementType;\n description: string;\n href: string;\n cta: string;\n};\n\nconst BentoGrid = ({ children, className }: BentoGridProps) => {\n return (\n \n {children}\n \n );\n};\n\nconst BentoCard = ({\n name,\n className,\n background,\n Icon,\n description,\n href,\n cta,\n}: BentoCardProps) => (\n \n
{background}
\n
\n \n

\n {name}\n

\n

{description}

\n
\n\n \n \n \n
\n
\n);\n\nexport { BentoCard, BentoGrid };\n", + "content": "import { ArrowRightIcon } from \"@radix-ui/react-icons\";\nimport { ComponentPropsWithoutRef, ReactNode } from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ninterface BentoGridProps extends ComponentPropsWithoutRef<\"div\"> {\n children: ReactNode;\n className?: string;\n}\n\ninterface BentoCardProps extends ComponentPropsWithoutRef<\"div\"> {\n name: string;\n className: string;\n background: ReactNode;\n Icon: React.ElementType;\n description: string;\n href: string;\n cta: string;\n}\n\nconst BentoGrid = ({ children, className, ...props }: BentoGridProps) => {\n return (\n \n {children}\n \n );\n};\n\nconst BentoCard = ({\n name,\n className,\n background,\n Icon,\n description,\n href,\n cta,\n ...props\n}: BentoCardProps) => (\n \n
{background}
\n
\n \n

\n {name}\n

\n

{description}

\n
\n\n \n \n \n
\n
\n);\n\nexport { BentoCard, BentoGrid };\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/blur-fade.json b/public/r/styles/default/blur-fade.json index b0fd6aa11..2ffc1abc7 100644 --- a/public/r/styles/default/blur-fade.json +++ b/public/r/styles/default/blur-fade.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/blur-fade.tsx", - "content": "\"use client\";\n\nimport { useRef } from \"react\";\nimport {\n AnimatePresence,\n motion,\n useInView,\n UseInViewOptions,\n Variants,\n} from \"motion/react\";\n\ntype MarginType = UseInViewOptions[\"margin\"];\n\ninterface BlurFadeProps {\n children: React.ReactNode;\n className?: string;\n variant?: {\n hidden: { y: number };\n visible: { y: number };\n };\n duration?: number;\n delay?: number;\n offset?: number;\n direction?: \"up\" | \"down\" | \"left\" | \"right\";\n inView?: boolean;\n inViewMargin?: MarginType;\n blur?: string;\n}\n\nexport default function BlurFade({\n children,\n className,\n variant,\n duration = 0.4,\n delay = 0,\n offset = 6,\n direction = \"down\",\n inView = false,\n inViewMargin = \"-50px\",\n blur = \"6px\",\n}: BlurFadeProps) {\n const ref = useRef(null);\n const inViewResult = useInView(ref, { once: true, margin: inViewMargin });\n const isInView = !inView || inViewResult;\n const defaultVariants: Variants = {\n hidden: {\n [direction === \"left\" || direction === \"right\" ? \"x\" : \"y\"]:\n direction === \"right\" || direction === \"down\" ? -offset : offset,\n opacity: 0,\n filter: `blur(${blur})`,\n },\n visible: {\n [direction === \"left\" || direction === \"right\" ? \"x\" : \"y\"]: 0,\n opacity: 1,\n filter: `blur(0px)`,\n },\n };\n const combinedVariants = variant || defaultVariants;\n return (\n \n \n {children}\n \n \n );\n}\n", + "content": "\"use client\";\n\nimport {\n AnimatePresence,\n motion,\n useInView,\n UseInViewOptions,\n Variants,\n} from \"motion/react\";\nimport { useRef } from \"react\";\n\ntype MarginType = UseInViewOptions[\"margin\"];\n\ninterface BlurFadeProps {\n children: React.ReactNode;\n className?: string;\n variant?: {\n hidden: { y: number };\n visible: { y: number };\n };\n duration?: number;\n delay?: number;\n offset?: number;\n direction?: \"up\" | \"down\" | \"left\" | \"right\";\n inView?: boolean;\n inViewMargin?: MarginType;\n blur?: string;\n}\n\nexport function BlurFade({\n children,\n className,\n variant,\n duration = 0.4,\n delay = 0,\n offset = 6,\n direction = \"down\",\n inView = false,\n inViewMargin = \"-50px\",\n blur = \"6px\",\n}: BlurFadeProps) {\n const ref = useRef(null);\n const inViewResult = useInView(ref, { once: true, margin: inViewMargin });\n const isInView = !inView || inViewResult;\n const defaultVariants: Variants = {\n hidden: {\n [direction === \"left\" || direction === \"right\" ? \"x\" : \"y\"]:\n direction === \"right\" || direction === \"down\" ? -offset : offset,\n opacity: 0,\n filter: `blur(${blur})`,\n },\n visible: {\n [direction === \"left\" || direction === \"right\" ? \"x\" : \"y\"]: 0,\n opacity: 1,\n filter: `blur(0px)`,\n },\n };\n const combinedVariants = variant || defaultVariants;\n return (\n \n \n {children}\n \n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/border-beam.json b/public/r/styles/default/border-beam.json index e232331a9..af7b73664 100644 --- a/public/r/styles/default/border-beam.json +++ b/public/r/styles/default/border-beam.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/border-beam.tsx", - "content": "import { cn } from \"@/lib/utils\";\n\ninterface BorderBeamProps {\n className?: string;\n size?: number;\n duration?: number;\n borderWidth?: number;\n anchor?: number;\n colorFrom?: string;\n colorTo?: string;\n delay?: number;\n}\n\nexport const BorderBeam = ({\n className,\n size = 200,\n duration = 15,\n anchor = 90,\n borderWidth = 1.5,\n colorFrom = \"#ffaa40\",\n colorTo = \"#9c40ff\",\n delay = 0,\n}: BorderBeamProps) => {\n return (\n \n );\n};\n", + "content": "import { cn } from \"@/lib/utils\";\nimport { ComponentPropsWithoutRef } from \"react\";\n\ninterface BorderBeamProps extends ComponentPropsWithoutRef<\"div\"> {\n size?: number;\n duration?: number;\n borderWidth?: number;\n anchor?: number;\n colorFrom?: string;\n colorTo?: string;\n delay?: number;\n}\n\nexport const BorderBeam = ({\n className,\n size = 200,\n duration = 15,\n anchor = 90,\n borderWidth = 1.5,\n colorFrom = \"#ffaa40\",\n colorTo = \"#9c40ff\",\n delay = 0,\n ...props\n}: BorderBeamProps) => {\n return (\n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/box-reveal.json b/public/r/styles/default/box-reveal.json index 04d23e7cd..255fcbbf5 100644 --- a/public/r/styles/default/box-reveal.json +++ b/public/r/styles/default/box-reveal.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/box-reveal.tsx", - "content": "\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { motion, useAnimation, useInView } from \"motion/react\";\n\ninterface BoxRevealProps {\n children: JSX.Element;\n width?: \"fit-content\" | \"100%\";\n boxColor?: string;\n duration?: number;\n}\n\nexport const BoxReveal = ({\n children,\n width = \"fit-content\",\n boxColor,\n duration,\n}: BoxRevealProps) => {\n const mainControls = useAnimation();\n const slideControls = useAnimation();\n\n const ref = useRef(null);\n const isInView = useInView(ref, { once: true });\n\n useEffect(() => {\n if (isInView) {\n slideControls.start(\"visible\");\n mainControls.start(\"visible\");\n } else {\n slideControls.start(\"hidden\");\n mainControls.start(\"hidden\");\n }\n }, [isInView, mainControls, slideControls]);\n\n return (\n
\n \n {children}\n \n\n \n
\n );\n};\n\nexport default BoxReveal;\n", + "content": "\"use client\";\n\nimport { motion, useAnimation, useInView } from \"motion/react\";\nimport { useEffect, useRef } from \"react\";\n\ninterface BoxRevealProps {\n children: JSX.Element;\n width?: \"fit-content\" | \"100%\";\n boxColor?: string;\n duration?: number;\n}\n\nexport const BoxReveal = ({\n children,\n width = \"fit-content\",\n boxColor = \"#5046e6\",\n duration,\n}: BoxRevealProps) => {\n const mainControls = useAnimation();\n const slideControls = useAnimation();\n\n const ref = useRef(null);\n const isInView = useInView(ref, { once: true });\n\n useEffect(() => {\n if (isInView) {\n slideControls.start(\"visible\");\n mainControls.start(\"visible\");\n } else {\n slideControls.start(\"hidden\");\n mainControls.start(\"hidden\");\n }\n }, [isInView, mainControls, slideControls]);\n\n return (\n
\n \n {children}\n \n\n \n
\n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/client-tweet-card.json b/public/r/styles/default/client-tweet-card.json index cd24018e0..828dd2878 100644 --- a/public/r/styles/default/client-tweet-card.json +++ b/public/r/styles/default/client-tweet-card.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/client-tweet-card.tsx", - "content": "\"use client\";\n\nimport { TweetProps, useTweet } from \"react-tweet\";\n\nimport {\n MagicTweet,\n TweetNotFound,\n TweetSkeleton,\n} from \"@/registry/default/magicui/tweet-card\";\n\nconst ClientTweetCard = ({\n id,\n apiUrl,\n fallback = ,\n components,\n fetchOptions,\n onError,\n ...props\n}: TweetProps & { className?: string }) => {\n const { data, error, isLoading } = useTweet(id, apiUrl, fetchOptions);\n\n if (isLoading) return fallback;\n if (error || !data) {\n const NotFound = components?.TweetNotFound || TweetNotFound;\n return ;\n }\n\n return ;\n};\n\nexport default ClientTweetCard;\n", + "content": "\"use client\";\n\nimport { TweetProps, useTweet } from \"react-tweet\";\n\nimport {\n MagicTweet,\n TweetNotFound,\n TweetSkeleton,\n} from \"@/registry/default/magicui/tweet-card\";\n\nexport const ClientTweetCard = ({\n id,\n apiUrl,\n fallback = ,\n components,\n fetchOptions,\n onError,\n ...props\n}: TweetProps & { className?: string }) => {\n const { data, error, isLoading } = useTweet(id, apiUrl, fetchOptions);\n\n if (isLoading) return fallback;\n if (error || !data) {\n const NotFound = components?.TweetNotFound || TweetNotFound;\n return ;\n }\n\n return ;\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/confetti.json b/public/r/styles/default/confetti.json index 22172ee2f..08d33356b 100644 --- a/public/r/styles/default/confetti.json +++ b/public/r/styles/default/confetti.json @@ -5,10 +5,13 @@ "canvas-confetti", "@types/canvas-confetti" ], + "registryDependencies": [ + "button" + ], "files": [ { "path": "magicui/confetti.tsx", - "content": "import type { ReactNode } from \"react\";\nimport React, {\n createContext,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n} from \"react\";\nimport type {\n GlobalOptions as ConfettiGlobalOptions,\n CreateTypes as ConfettiInstance,\n Options as ConfettiOptions,\n} from \"canvas-confetti\";\nimport confetti from \"canvas-confetti\";\n\nimport { Button, ButtonProps } from \"@/components/ui/button\";\n\ntype Api = {\n fire: (options?: ConfettiOptions) => void;\n};\n\ntype Props = React.ComponentPropsWithRef<\"canvas\"> & {\n options?: ConfettiOptions;\n globalOptions?: ConfettiGlobalOptions;\n manualstart?: boolean;\n children?: ReactNode;\n};\n\nexport type ConfettiRef = Api | null;\n\nconst ConfettiContext = createContext({} as Api);\n\n// Define component first\nconst ConfettiComponent = forwardRef((props, ref) => {\n const {\n options,\n globalOptions = { resize: true, useWorker: true },\n manualstart = false,\n children,\n ...rest\n } = props;\n const instanceRef = useRef(null);\n\n const canvasRef = useCallback(\n (node: HTMLCanvasElement) => {\n if (node !== null) {\n if (instanceRef.current) return;\n instanceRef.current = confetti.create(node, {\n ...globalOptions,\n resize: true,\n });\n } else {\n if (instanceRef.current) {\n instanceRef.current.reset();\n instanceRef.current = null;\n }\n }\n },\n [globalOptions],\n );\n\n const fire = useCallback(\n async (opts = {}) => {\n try {\n await instanceRef.current?.({ ...options, ...opts });\n } catch (error) {\n console.error(\"Confetti error:\", error);\n }\n },\n [options],\n );\n\n const api = useMemo(\n () => ({\n fire,\n }),\n [fire],\n );\n\n useImperativeHandle(ref, () => api, [api]);\n\n useEffect(() => {\n if (!manualstart) {\n (async () => {\n try {\n await fire();\n } catch (error) {\n console.error(\"Confetti effect error:\", error);\n }\n })();\n }\n }, [manualstart, fire]);\n\n return (\n \n \n {children}\n \n );\n});\n\n// Set display name immediately\nConfettiComponent.displayName = \"Confetti\";\n\n// Export as Confetti\nexport const Confetti = ConfettiComponent;\n\ninterface ConfettiButtonProps extends ButtonProps {\n options?: ConfettiOptions &\n ConfettiGlobalOptions & { canvas?: HTMLCanvasElement };\n children?: React.ReactNode;\n}\n\nconst ConfettiButtonComponent = ({\n options,\n children,\n ...props\n}: ConfettiButtonProps) => {\n const handleClick = async (event: React.MouseEvent) => {\n try {\n const rect = event.currentTarget.getBoundingClientRect();\n const x = rect.left + rect.width / 2;\n const y = rect.top + rect.height / 2;\n await confetti({\n ...options,\n origin: {\n x: x / window.innerWidth,\n y: y / window.innerHeight,\n },\n });\n } catch (error) {\n console.error(\"Confetti button error:\", error);\n }\n };\n\n return (\n \n );\n};\n\nConfettiButtonComponent.displayName = \"ConfettiButton\";\n\nexport const ConfettiButton = ConfettiButtonComponent;\n\nexport default Confetti;\n", + "content": "import type {\n GlobalOptions as ConfettiGlobalOptions,\n CreateTypes as ConfettiInstance,\n Options as ConfettiOptions,\n} from \"canvas-confetti\";\nimport confetti from \"canvas-confetti\";\nimport type { ReactNode } from \"react\";\nimport React, {\n createContext,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n} from \"react\";\n\nimport { Button, ButtonProps } from \"@/components/ui/button\";\n\ntype Api = {\n fire: (options?: ConfettiOptions) => void;\n};\n\ntype Props = React.ComponentPropsWithRef<\"canvas\"> & {\n options?: ConfettiOptions;\n globalOptions?: ConfettiGlobalOptions;\n manualstart?: boolean;\n children?: ReactNode;\n};\n\nexport type ConfettiRef = Api | null;\n\nconst ConfettiContext = createContext({} as Api);\n\n// Define component first\nconst ConfettiComponent = forwardRef((props, ref) => {\n const {\n options,\n globalOptions = { resize: true, useWorker: true },\n manualstart = false,\n children,\n ...rest\n } = props;\n const instanceRef = useRef(null);\n\n const canvasRef = useCallback(\n (node: HTMLCanvasElement) => {\n if (node !== null) {\n if (instanceRef.current) return;\n instanceRef.current = confetti.create(node, {\n ...globalOptions,\n resize: true,\n });\n } else {\n if (instanceRef.current) {\n instanceRef.current.reset();\n instanceRef.current = null;\n }\n }\n },\n [globalOptions],\n );\n\n const fire = useCallback(\n async (opts = {}) => {\n try {\n await instanceRef.current?.({ ...options, ...opts });\n } catch (error) {\n console.error(\"Confetti error:\", error);\n }\n },\n [options],\n );\n\n const api = useMemo(\n () => ({\n fire,\n }),\n [fire],\n );\n\n useImperativeHandle(ref, () => api, [api]);\n\n useEffect(() => {\n if (!manualstart) {\n (async () => {\n try {\n await fire();\n } catch (error) {\n console.error(\"Confetti effect error:\", error);\n }\n })();\n }\n }, [manualstart, fire]);\n\n return (\n \n \n {children}\n \n );\n});\n\n// Set display name immediately\nConfettiComponent.displayName = \"Confetti\";\n\n// Export as Confetti\nexport const Confetti = ConfettiComponent;\n\ninterface ConfettiButtonProps extends ButtonProps {\n options?: ConfettiOptions &\n ConfettiGlobalOptions & { canvas?: HTMLCanvasElement };\n children?: React.ReactNode;\n}\n\nconst ConfettiButtonComponent = ({\n options,\n children,\n ...props\n}: ConfettiButtonProps) => {\n const handleClick = async (event: React.MouseEvent) => {\n try {\n const rect = event.currentTarget.getBoundingClientRect();\n const x = rect.left + rect.width / 2;\n const y = rect.top + rect.height / 2;\n await confetti({\n ...options,\n origin: {\n x: x / window.innerWidth,\n y: y / window.innerHeight,\n },\n });\n } catch (error) {\n console.error(\"Confetti button error:\", error);\n }\n };\n\n return (\n \n );\n};\n\nConfettiButtonComponent.displayName = \"ConfettiButton\";\n\nexport const ConfettiButton = ConfettiButtonComponent;\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/dot-pattern.json b/public/r/styles/default/dot-pattern.json index edd4796a1..ca945fdba 100644 --- a/public/r/styles/default/dot-pattern.json +++ b/public/r/styles/default/dot-pattern.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/dot-pattern.tsx", - "content": "import { useId } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface DotPatternProps {\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n cx?: number;\n cy?: number;\n cr?: number;\n className?: string;\n [key: string]: unknown;\n}\nexport function DotPattern({\n width = 16,\n height = 16,\n x = 0,\n y = 0,\n cx = 1,\n cy = 1,\n cr = 1,\n className,\n ...props\n}: DotPatternProps) {\n const id = useId();\n\n return (\n \n \n \n \n \n \n \n \n );\n}\n\nexport default DotPattern;\n", + "content": "import { useId } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface DotPatternProps extends React.SVGProps {\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n cx?: number;\n cy?: number;\n cr?: number;\n className?: string;\n [key: string]: unknown;\n}\nexport function DotPattern({\n width = 16,\n height = 16,\n x = 0,\n y = 0,\n cx = 1,\n cy = 1,\n cr = 1,\n className,\n ...props\n}: DotPatternProps) {\n const id = useId();\n\n return (\n \n \n \n \n \n \n \n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/flickering-grid.json b/public/r/styles/default/flickering-grid.json index 7fff24769..9a518812b 100644 --- a/public/r/styles/default/flickering-grid.json +++ b/public/r/styles/default/flickering-grid.json @@ -1,13 +1,10 @@ { "name": "flickering-grid", "type": "registry:ui", - "dependencies": [ - "motion" - ], "files": [ { "path": "magicui/flickering-grid.tsx", - "content": "\"use client\";\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\ninterface FlickeringGridProps {\n squareSize?: number;\n gridGap?: number;\n flickerChance?: number;\n color?: string;\n width?: number;\n height?: number;\n className?: string;\n\n maxOpacity?: number;\n}\n\nconst FlickeringGrid: React.FC = ({\n squareSize = 4,\n gridGap = 6,\n flickerChance = 0.3,\n color = \"rgb(0, 0, 0)\",\n width,\n height,\n className,\n maxOpacity = 0.3,\n}) => {\n const canvasRef = useRef(null);\n const containerRef = useRef(null);\n const [isInView, setIsInView] = useState(false);\n const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });\n\n const memoizedColor = useMemo(() => {\n const toRGBA = (color: string) => {\n if (typeof window === \"undefined\") {\n return `rgba(0, 0, 0,`;\n }\n const canvas = document.createElement(\"canvas\");\n canvas.width = canvas.height = 1;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return \"rgba(255, 0, 0,\";\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, 1, 1);\n const [r, g, b] = Array.from(ctx.getImageData(0, 0, 1, 1).data);\n return `rgba(${r}, ${g}, ${b},`;\n };\n return toRGBA(color);\n }, [color]);\n\n const setupCanvas = useCallback(\n (canvas: HTMLCanvasElement, width: number, height: number) => {\n const dpr = window.devicePixelRatio || 1;\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n const cols = Math.floor(width / (squareSize + gridGap));\n const rows = Math.floor(height / (squareSize + gridGap));\n\n const squares = new Float32Array(cols * rows);\n for (let i = 0; i < squares.length; i++) {\n squares[i] = Math.random() * maxOpacity;\n }\n\n return { cols, rows, squares, dpr };\n },\n [squareSize, gridGap, maxOpacity],\n );\n\n const updateSquares = useCallback(\n (squares: Float32Array, deltaTime: number) => {\n for (let i = 0; i < squares.length; i++) {\n if (Math.random() < flickerChance * deltaTime) {\n squares[i] = Math.random() * maxOpacity;\n }\n }\n },\n [flickerChance, maxOpacity],\n );\n\n const drawGrid = useCallback(\n (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n cols: number,\n rows: number,\n squares: Float32Array,\n dpr: number,\n ) => {\n ctx.clearRect(0, 0, width, height);\n ctx.fillStyle = \"transparent\";\n ctx.fillRect(0, 0, width, height);\n\n for (let i = 0; i < cols; i++) {\n for (let j = 0; j < rows; j++) {\n const opacity = squares[i * rows + j];\n ctx.fillStyle = `${memoizedColor}${opacity})`;\n ctx.fillRect(\n i * (squareSize + gridGap) * dpr,\n j * (squareSize + gridGap) * dpr,\n squareSize * dpr,\n squareSize * dpr,\n );\n }\n }\n },\n [memoizedColor, squareSize, gridGap],\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n let animationFrameId: number;\n let gridParams: ReturnType;\n\n const updateCanvasSize = () => {\n const newWidth = width || container.clientWidth;\n const newHeight = height || container.clientHeight;\n setCanvasSize({ width: newWidth, height: newHeight });\n gridParams = setupCanvas(canvas, newWidth, newHeight);\n };\n\n updateCanvasSize();\n\n let lastTime = 0;\n const animate = (time: number) => {\n if (!isInView) return;\n\n const deltaTime = (time - lastTime) / 1000;\n lastTime = time;\n\n updateSquares(gridParams.squares, deltaTime);\n drawGrid(\n ctx,\n canvas.width,\n canvas.height,\n gridParams.cols,\n gridParams.rows,\n gridParams.squares,\n gridParams.dpr,\n );\n animationFrameId = requestAnimationFrame(animate);\n };\n\n const resizeObserver = new ResizeObserver(() => {\n updateCanvasSize();\n });\n\n resizeObserver.observe(container);\n\n const intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n setIsInView(entry.isIntersecting);\n },\n { threshold: 0 },\n );\n\n intersectionObserver.observe(canvas);\n\n if (isInView) {\n animationFrameId = requestAnimationFrame(animate);\n }\n\n return () => {\n cancelAnimationFrame(animationFrameId);\n resizeObserver.disconnect();\n intersectionObserver.disconnect();\n };\n }, [setupCanvas, updateSquares, drawGrid, width, height, isInView]);\n\n return (\n
\n \n
\n );\n};\n\nexport default FlickeringGrid;\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\ninterface FlickeringGridProps extends React.HTMLAttributes {\n squareSize?: number;\n gridGap?: number;\n flickerChance?: number;\n color?: string;\n width?: number;\n height?: number;\n className?: string;\n maxOpacity?: number;\n}\n\nexport const FlickeringGrid: React.FC = ({\n squareSize = 4,\n gridGap = 6,\n flickerChance = 0.3,\n color = \"rgb(0, 0, 0)\",\n width,\n height,\n className,\n maxOpacity = 0.3,\n ...props\n}) => {\n const canvasRef = useRef(null);\n const containerRef = useRef(null);\n const [isInView, setIsInView] = useState(false);\n const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });\n\n const memoizedColor = useMemo(() => {\n const toRGBA = (color: string) => {\n if (typeof window === \"undefined\") {\n return `rgba(0, 0, 0,`;\n }\n const canvas = document.createElement(\"canvas\");\n canvas.width = canvas.height = 1;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return \"rgba(255, 0, 0,\";\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, 1, 1);\n const [r, g, b] = Array.from(ctx.getImageData(0, 0, 1, 1).data);\n return `rgba(${r}, ${g}, ${b},`;\n };\n return toRGBA(color);\n }, [color]);\n\n const setupCanvas = useCallback(\n (canvas: HTMLCanvasElement, width: number, height: number) => {\n const dpr = window.devicePixelRatio || 1;\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n const cols = Math.floor(width / (squareSize + gridGap));\n const rows = Math.floor(height / (squareSize + gridGap));\n\n const squares = new Float32Array(cols * rows);\n for (let i = 0; i < squares.length; i++) {\n squares[i] = Math.random() * maxOpacity;\n }\n\n return { cols, rows, squares, dpr };\n },\n [squareSize, gridGap, maxOpacity],\n );\n\n const updateSquares = useCallback(\n (squares: Float32Array, deltaTime: number) => {\n for (let i = 0; i < squares.length; i++) {\n if (Math.random() < flickerChance * deltaTime) {\n squares[i] = Math.random() * maxOpacity;\n }\n }\n },\n [flickerChance, maxOpacity],\n );\n\n const drawGrid = useCallback(\n (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n cols: number,\n rows: number,\n squares: Float32Array,\n dpr: number,\n ) => {\n ctx.clearRect(0, 0, width, height);\n ctx.fillStyle = \"transparent\";\n ctx.fillRect(0, 0, width, height);\n\n for (let i = 0; i < cols; i++) {\n for (let j = 0; j < rows; j++) {\n const opacity = squares[i * rows + j];\n ctx.fillStyle = `${memoizedColor}${opacity})`;\n ctx.fillRect(\n i * (squareSize + gridGap) * dpr,\n j * (squareSize + gridGap) * dpr,\n squareSize * dpr,\n squareSize * dpr,\n );\n }\n }\n },\n [memoizedColor, squareSize, gridGap],\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const container = containerRef.current;\n if (!canvas || !container) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n let animationFrameId: number;\n let gridParams: ReturnType;\n\n const updateCanvasSize = () => {\n const newWidth = width || container.clientWidth;\n const newHeight = height || container.clientHeight;\n setCanvasSize({ width: newWidth, height: newHeight });\n gridParams = setupCanvas(canvas, newWidth, newHeight);\n };\n\n updateCanvasSize();\n\n let lastTime = 0;\n const animate = (time: number) => {\n if (!isInView) return;\n\n const deltaTime = (time - lastTime) / 1000;\n lastTime = time;\n\n updateSquares(gridParams.squares, deltaTime);\n drawGrid(\n ctx,\n canvas.width,\n canvas.height,\n gridParams.cols,\n gridParams.rows,\n gridParams.squares,\n gridParams.dpr,\n );\n animationFrameId = requestAnimationFrame(animate);\n };\n\n const resizeObserver = new ResizeObserver(() => {\n updateCanvasSize();\n });\n\n resizeObserver.observe(container);\n\n const intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n setIsInView(entry.isIntersecting);\n },\n { threshold: 0 },\n );\n\n intersectionObserver.observe(canvas);\n\n if (isInView) {\n animationFrameId = requestAnimationFrame(animate);\n }\n\n return () => {\n cancelAnimationFrame(animationFrameId);\n resizeObserver.disconnect();\n intersectionObserver.disconnect();\n };\n }, [setupCanvas, updateSquares, drawGrid, width, height, isInView]);\n\n return (\n \n \n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/flip-text.json b/public/r/styles/default/flip-text.json index 5d03e0929..7fcefe739 100644 --- a/public/r/styles/default/flip-text.json +++ b/public/r/styles/default/flip-text.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/flip-text.tsx", - "content": "\"use client\";\n\nimport { AnimatePresence, motion, Variants } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface FlipTextProps {\n word: string;\n duration?: number;\n delayMultiple?: number;\n framerProps?: Variants;\n className?: string;\n}\n\nexport default function FlipText({\n word,\n duration = 0.5,\n delayMultiple = 0.08,\n framerProps = {\n hidden: { rotateX: -90, opacity: 0 },\n visible: { rotateX: 0, opacity: 1 },\n },\n className,\n}: FlipTextProps) {\n return (\n
\n \n {word.split(\"\").map((char, i) => (\n \n {char}\n \n ))}\n \n
\n );\n}\n", + "content": "\"use client\";\n\nimport { AnimatePresence, motion, Variants } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface FlipTextProps {\n word: string;\n duration?: number;\n delayMultiple?: number;\n framerProps?: Variants;\n className?: string;\n}\n\nexport function FlipText({\n word,\n duration = 0.5,\n delayMultiple = 0.08,\n framerProps = {\n hidden: { rotateX: -90, opacity: 0 },\n visible: { rotateX: 0, opacity: 1 },\n },\n className,\n}: FlipTextProps) {\n return (\n
\n \n {word.split(\"\").map((char, i) => (\n \n {char}\n \n ))}\n \n
\n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/globe.json b/public/r/styles/default/globe.json index 2843c1265..a6a58a34f 100644 --- a/public/r/styles/default/globe.json +++ b/public/r/styles/default/globe.json @@ -2,13 +2,12 @@ "name": "globe", "type": "registry:ui", "dependencies": [ - "cobe", - "react-spring" + "cobe" ], "files": [ { "path": "magicui/globe.tsx", - "content": "\"use client\";\n\nimport createGlobe, { COBEOptions } from \"cobe\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst GLOBE_CONFIG: COBEOptions = {\n width: 800,\n height: 800,\n onRender: () => {},\n devicePixelRatio: 2,\n phi: 0,\n theta: 0.3,\n dark: 0,\n diffuse: 0.4,\n mapSamples: 16000,\n mapBrightness: 1.2,\n baseColor: [1, 1, 1],\n markerColor: [251 / 255, 100 / 255, 21 / 255],\n glowColor: [1, 1, 1],\n markers: [\n { location: [14.5995, 120.9842], size: 0.03 },\n { location: [19.076, 72.8777], size: 0.1 },\n { location: [23.8103, 90.4125], size: 0.05 },\n { location: [30.0444, 31.2357], size: 0.07 },\n { location: [39.9042, 116.4074], size: 0.08 },\n { location: [-23.5505, -46.6333], size: 0.1 },\n { location: [19.4326, -99.1332], size: 0.1 },\n { location: [40.7128, -74.006], size: 0.1 },\n { location: [34.6937, 135.5022], size: 0.05 },\n { location: [41.0082, 28.9784], size: 0.06 },\n ],\n};\n\nexport default function Globe({\n className,\n config = GLOBE_CONFIG,\n}: {\n className?: string;\n config?: COBEOptions;\n}) {\n let phi = 0;\n let width = 0;\n const canvasRef = useRef(null);\n const pointerInteracting = useRef(null);\n const pointerInteractionMovement = useRef(0);\n const [r, setR] = useState(0);\n\n const updatePointerInteraction = (value: any) => {\n pointerInteracting.current = value;\n if (canvasRef.current) {\n canvasRef.current.style.cursor = value ? \"grabbing\" : \"grab\";\n }\n };\n\n const updateMovement = (clientX: any) => {\n if (pointerInteracting.current !== null) {\n const delta = clientX - pointerInteracting.current;\n pointerInteractionMovement.current = delta;\n setR(delta / 200);\n }\n };\n\n const onRender = useCallback(\n (state: Record) => {\n if (!pointerInteracting.current) phi += 0.005;\n state.phi = phi + r;\n state.width = width * 2;\n state.height = width * 2;\n },\n [r],\n );\n\n const onResize = () => {\n if (canvasRef.current) {\n width = canvasRef.current.offsetWidth;\n }\n };\n\n useEffect(() => {\n window.addEventListener(\"resize\", onResize);\n onResize();\n\n const globe = createGlobe(canvasRef.current!, {\n ...config,\n width: width * 2,\n height: width * 2,\n onRender,\n });\n\n setTimeout(() => (canvasRef.current!.style.opacity = \"1\"));\n return () => globe.destroy();\n }, []);\n\n return (\n \n \n updatePointerInteraction(\n e.clientX - pointerInteractionMovement.current,\n )\n }\n onPointerUp={() => updatePointerInteraction(null)}\n onPointerOut={() => updatePointerInteraction(null)}\n onMouseMove={(e) => updateMovement(e.clientX)}\n onTouchMove={(e) =>\n e.touches[0] && updateMovement(e.touches[0].clientX)\n }\n />\n \n );\n}\n", + "content": "\"use client\";\n\nimport createGlobe, { COBEOptions } from \"cobe\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst GLOBE_CONFIG: COBEOptions = {\n width: 800,\n height: 800,\n onRender: () => {},\n devicePixelRatio: 2,\n phi: 0,\n theta: 0.3,\n dark: 0,\n diffuse: 0.4,\n mapSamples: 16000,\n mapBrightness: 1.2,\n baseColor: [1, 1, 1],\n markerColor: [251 / 255, 100 / 255, 21 / 255],\n glowColor: [1, 1, 1],\n markers: [\n { location: [14.5995, 120.9842], size: 0.03 },\n { location: [19.076, 72.8777], size: 0.1 },\n { location: [23.8103, 90.4125], size: 0.05 },\n { location: [30.0444, 31.2357], size: 0.07 },\n { location: [39.9042, 116.4074], size: 0.08 },\n { location: [-23.5505, -46.6333], size: 0.1 },\n { location: [19.4326, -99.1332], size: 0.1 },\n { location: [40.7128, -74.006], size: 0.1 },\n { location: [34.6937, 135.5022], size: 0.05 },\n { location: [41.0082, 28.9784], size: 0.06 },\n ],\n};\n\nexport function Globe({\n className,\n config = GLOBE_CONFIG,\n}: {\n className?: string;\n config?: COBEOptions;\n}) {\n let phi = 0;\n let width = 0;\n const canvasRef = useRef(null);\n const pointerInteracting = useRef(null);\n const pointerInteractionMovement = useRef(0);\n const [r, setR] = useState(0);\n\n const updatePointerInteraction = (value: any) => {\n pointerInteracting.current = value;\n if (canvasRef.current) {\n canvasRef.current.style.cursor = value ? \"grabbing\" : \"grab\";\n }\n };\n\n const updateMovement = (clientX: any) => {\n if (pointerInteracting.current !== null) {\n const delta = clientX - pointerInteracting.current;\n pointerInteractionMovement.current = delta;\n setR(delta / 200);\n }\n };\n\n const onRender = useCallback(\n (state: Record) => {\n if (!pointerInteracting.current) phi += 0.005;\n state.phi = phi + r;\n state.width = width * 2;\n state.height = width * 2;\n },\n [r],\n );\n\n const onResize = () => {\n if (canvasRef.current) {\n width = canvasRef.current.offsetWidth;\n }\n };\n\n useEffect(() => {\n window.addEventListener(\"resize\", onResize);\n onResize();\n\n const globe = createGlobe(canvasRef.current!, {\n ...config,\n width: width * 2,\n height: width * 2,\n onRender,\n });\n\n setTimeout(() => (canvasRef.current!.style.opacity = \"1\"));\n return () => globe.destroy();\n }, []);\n\n return (\n \n \n updatePointerInteraction(\n e.clientX - pointerInteractionMovement.current,\n )\n }\n onPointerUp={() => updatePointerInteraction(null)}\n onPointerOut={() => updatePointerInteraction(null)}\n onMouseMove={(e) => updateMovement(e.clientX)}\n onTouchMove={(e) =>\n e.touches[0] && updateMovement(e.touches[0].clientX)\n }\n />\n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/grid-pattern.json b/public/r/styles/default/grid-pattern.json index e0b1b0534..933d7f1e0 100644 --- a/public/r/styles/default/grid-pattern.json +++ b/public/r/styles/default/grid-pattern.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/grid-pattern.tsx", - "content": "import { useId } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface GridPatternProps {\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n squares?: Array<[x: number, y: number]>;\n strokeDasharray?: string;\n className?: string;\n [key: string]: unknown;\n}\n\nexport function GridPattern({\n width = 40,\n height = 40,\n x = -1,\n y = -1,\n strokeDasharray = \"0\",\n squares,\n className,\n ...props\n}: GridPatternProps) {\n const id = useId();\n\n return (\n \n \n \n \n \n \n \n {squares && (\n \n {squares.map(([x, y]) => (\n \n ))}\n \n )}\n \n );\n}\n\nexport default GridPattern;\n", + "content": "import { useId } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface GridPatternProps extends React.SVGProps {\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n squares?: Array<[x: number, y: number]>;\n strokeDasharray?: string;\n className?: string;\n [key: string]: unknown;\n}\n\nexport function GridPattern({\n width = 40,\n height = 40,\n x = -1,\n y = -1,\n strokeDasharray = \"0\",\n squares,\n className,\n ...props\n}: GridPatternProps) {\n const id = useId();\n\n return (\n \n \n \n \n \n \n \n {squares && (\n \n {squares.map(([x, y]) => (\n \n ))}\n \n )}\n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/hyper-text.json b/public/r/styles/default/hyper-text.json index 00dd49b9e..325d6bc07 100644 --- a/public/r/styles/default/hyper-text.json +++ b/public/r/styles/default/hyper-text.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/hyper-text.tsx", - "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion, MotionProps } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\n\ntype CharacterSet = string[] | readonly string[];\n\ninterface HyperTextProps extends MotionProps {\n /** The text content to be animated */\n children: string;\n /** Optional className for styling */\n className?: string;\n /** Duration of the animation in milliseconds */\n duration?: number;\n /** Delay before animation starts in milliseconds */\n delay?: number;\n /** Component to render as - defaults to div */\n as?: React.ElementType;\n /** Whether to start animation when element comes into view */\n startOnView?: boolean;\n /** Whether to trigger animation on hover */\n animateOnHover?: boolean;\n /** Custom character set for scramble effect. Defaults to uppercase alphabet */\n characterSet?: CharacterSet;\n}\n\nconst DEFAULT_CHARACTER_SET = Object.freeze(\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\".split(\"\"),\n) as readonly string[];\n\nconst getRandomInt = (max: number): number => Math.floor(Math.random() * max);\n\nexport default function HyperText({\n children,\n className,\n duration = 800,\n delay = 0,\n as: Component = \"div\",\n startOnView = false,\n animateOnHover = true,\n characterSet = DEFAULT_CHARACTER_SET,\n ...props\n}: HyperTextProps) {\n const MotionComponent = motion.create(Component, {\n forwardMotionProps: true,\n });\n\n const [displayText, setDisplayText] = useState(() =>\n children.split(\"\"),\n );\n const [isAnimating, setIsAnimating] = useState(false);\n const iterationCount = useRef(0);\n const elementRef = useRef(null);\n\n const handleAnimationTrigger = () => {\n if (animateOnHover && !isAnimating) {\n iterationCount.current = 0;\n setIsAnimating(true);\n }\n };\n\n // Handle animation start based on view or delay\n useEffect(() => {\n if (!startOnView) {\n const startTimeout = setTimeout(() => {\n setIsAnimating(true);\n }, delay);\n return () => clearTimeout(startTimeout);\n }\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setTimeout(() => {\n setIsAnimating(true);\n }, delay);\n observer.disconnect();\n }\n },\n { threshold: 0.1, rootMargin: \"-30% 0px -30% 0px\" },\n );\n\n if (elementRef.current) {\n observer.observe(elementRef.current);\n }\n\n return () => observer.disconnect();\n }, [delay, startOnView]);\n\n // Handle scramble animation\n useEffect(() => {\n if (!isAnimating) return;\n\n const intervalDuration = duration / (children.length * 10);\n const maxIterations = children.length;\n\n const interval = setInterval(() => {\n if (iterationCount.current < maxIterations) {\n setDisplayText((currentText) =>\n currentText.map((letter, index) =>\n letter === \" \"\n ? letter\n : index <= iterationCount.current\n ? children[index]\n : characterSet[getRandomInt(characterSet.length)],\n ),\n );\n iterationCount.current = iterationCount.current + 0.1;\n } else {\n setIsAnimating(false);\n clearInterval(interval);\n }\n }, intervalDuration);\n\n return () => clearInterval(interval);\n }, [children, duration, isAnimating, characterSet]);\n\n return (\n \n \n {displayText.map((letter, index) => (\n \n {letter.toUpperCase()}\n \n ))}\n \n \n );\n}\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion, MotionProps } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\n\ntype CharacterSet = string[] | readonly string[];\n\ninterface HyperTextProps extends MotionProps {\n /** The text content to be animated */\n children: string;\n /** Optional className for styling */\n className?: string;\n /** Duration of the animation in milliseconds */\n duration?: number;\n /** Delay before animation starts in milliseconds */\n delay?: number;\n /** Component to render as - defaults to div */\n as?: React.ElementType;\n /** Whether to start animation when element comes into view */\n startOnView?: boolean;\n /** Whether to trigger animation on hover */\n animateOnHover?: boolean;\n /** Custom character set for scramble effect. Defaults to uppercase alphabet */\n characterSet?: CharacterSet;\n}\n\nconst DEFAULT_CHARACTER_SET = Object.freeze(\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\".split(\"\"),\n) as readonly string[];\n\nconst getRandomInt = (max: number): number => Math.floor(Math.random() * max);\n\nexport function HyperText({\n children,\n className,\n duration = 800,\n delay = 0,\n as: Component = \"div\",\n startOnView = false,\n animateOnHover = true,\n characterSet = DEFAULT_CHARACTER_SET,\n ...props\n}: HyperTextProps) {\n const MotionComponent = motion.create(Component, {\n forwardMotionProps: true,\n });\n\n const [displayText, setDisplayText] = useState(() =>\n children.split(\"\"),\n );\n const [isAnimating, setIsAnimating] = useState(false);\n const iterationCount = useRef(0);\n const elementRef = useRef(null);\n\n const handleAnimationTrigger = () => {\n if (animateOnHover && !isAnimating) {\n iterationCount.current = 0;\n setIsAnimating(true);\n }\n };\n\n // Handle animation start based on view or delay\n useEffect(() => {\n if (!startOnView) {\n const startTimeout = setTimeout(() => {\n setIsAnimating(true);\n }, delay);\n return () => clearTimeout(startTimeout);\n }\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setTimeout(() => {\n setIsAnimating(true);\n }, delay);\n observer.disconnect();\n }\n },\n { threshold: 0.1, rootMargin: \"-30% 0px -30% 0px\" },\n );\n\n if (elementRef.current) {\n observer.observe(elementRef.current);\n }\n\n return () => observer.disconnect();\n }, [delay, startOnView]);\n\n // Handle scramble animation\n useEffect(() => {\n if (!isAnimating) return;\n\n const intervalDuration = duration / (children.length * 10);\n const maxIterations = children.length;\n\n const interval = setInterval(() => {\n if (iterationCount.current < maxIterations) {\n setDisplayText((currentText) =>\n currentText.map((letter, index) =>\n letter === \" \"\n ? letter\n : index <= iterationCount.current\n ? children[index]\n : characterSet[getRandomInt(characterSet.length)],\n ),\n );\n iterationCount.current = iterationCount.current + 0.1;\n } else {\n setIsAnimating(false);\n clearInterval(interval);\n }\n }, intervalDuration);\n\n return () => clearInterval(interval);\n }, [children, duration, isAnimating, characterSet]);\n\n return (\n \n \n {displayText.map((letter, index) => (\n \n {letter.toUpperCase()}\n \n ))}\n \n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/interactive-hover-button.json b/public/r/styles/default/interactive-hover-button.json index 0c488f690..d7f5cec2d 100644 --- a/public/r/styles/default/interactive-hover-button.json +++ b/public/r/styles/default/interactive-hover-button.json @@ -1,13 +1,12 @@ { "name": "interactive-hover-button", "type": "registry:ui", - "dependencies": ["lucide-react"], "files": [ { "path": "magicui/interactive-hover-button.tsx", - "content": "import React from \"react\";\nimport { ArrowRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface InteractiveHoverButtonProps\n extends React.ButtonHTMLAttributes {\n text?: string;\n}\n\nconst InteractiveHoverButton = React.forwardRef<\n HTMLButtonElement,\n InteractiveHoverButtonProps\n>(({ text = \"Button\", className, ...props }, ref) => {\n return (\n \n \n {text}\n \n
\n {text}\n \n
\n
\n \n );\n});\n\nInteractiveHoverButton.displayName = \"InteractiveHoverButton\";\n\nexport default InteractiveHoverButton;\n", + "content": "import React from \"react\";\nimport { ArrowRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface InteractiveHoverButtonProps\n extends React.ButtonHTMLAttributes {}\n\nexport const InteractiveHoverButton = React.forwardRef<\n HTMLButtonElement,\n InteractiveHoverButtonProps\n>(({ children, className, ...props }, ref) => {\n return (\n \n
\n
\n \n {children}\n \n
\n
\n {children}\n \n
\n \n );\n});\n\nInteractiveHoverButton.displayName = \"InteractiveHoverButton\";\n", "type": "registry:ui", "target": "" } ] -} +} \ No newline at end of file diff --git a/public/r/styles/default/marquee.json b/public/r/styles/default/marquee.json index 10514cdc4..6c47cd9eb 100644 --- a/public/r/styles/default/marquee.json +++ b/public/r/styles/default/marquee.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/marquee.tsx", - "content": "import { cn } from \"@/lib/utils\";\nimport { ComponentPropsWithoutRef } from \"react\";\n\ninterface MarqueeProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * Optional CSS class name to apply custom styles\n */\n className?: string;\n /**\n * Whether to reverse the animation direction\n * @default false\n */\n reverse?: boolean;\n /**\n * Whether to pause the animation on hover\n * @default false\n */\n pauseOnHover?: boolean;\n /**\n * Content to be displayed in the marquee\n */\n children: React.ReactNode;\n /**\n * Whether to animate vertically instead of horizontally\n * @default false\n */\n vertical?: boolean;\n /**\n * Number of times to repeat the content\n * @default 4\n */\n repeat?: number;\n}\n\nexport default function Marquee({\n className,\n reverse = false,\n pauseOnHover = false,\n children,\n vertical = false,\n repeat = 4,\n ...props\n}: MarqueeProps) {\n return (\n \n {Array(repeat)\n .fill(0)\n .map((_, i) => (\n \n {children}\n \n ))}\n \n );\n}\n", + "content": "import { cn } from \"@/lib/utils\";\nimport { ComponentPropsWithoutRef } from \"react\";\n\ninterface MarqueeProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * Optional CSS class name to apply custom styles\n */\n className?: string;\n /**\n * Whether to reverse the animation direction\n * @default false\n */\n reverse?: boolean;\n /**\n * Whether to pause the animation on hover\n * @default false\n */\n pauseOnHover?: boolean;\n /**\n * Content to be displayed in the marquee\n */\n children: React.ReactNode;\n /**\n * Whether to animate vertically instead of horizontally\n * @default false\n */\n vertical?: boolean;\n /**\n * Number of times to repeat the content\n * @default 4\n */\n repeat?: number;\n}\n\nexport function Marquee({\n className,\n reverse = false,\n pauseOnHover = false,\n children,\n vertical = false,\n repeat = 4,\n ...props\n}: MarqueeProps) {\n return (\n \n {Array(repeat)\n .fill(0)\n .map((_, i) => (\n \n {children}\n \n ))}\n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/morphing-text.json b/public/r/styles/default/morphing-text.json index 3514e79cb..c347a5fe5 100644 --- a/public/r/styles/default/morphing-text.json +++ b/public/r/styles/default/morphing-text.json @@ -1,13 +1,10 @@ { "name": "morphing-text", "type": "registry:ui", - "dependencies": [ - "motion" - ], "files": [ { "path": "magicui/morphing-text.tsx", - "content": "\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst morphTime = 1.5;\nconst cooldownTime = 0.5;\n\nconst useMorphingText = (texts: string[]) => {\n const textIndexRef = useRef(0);\n const morphRef = useRef(0);\n const cooldownRef = useRef(0);\n const timeRef = useRef(new Date());\n\n const text1Ref = useRef(null);\n const text2Ref = useRef(null);\n\n const setStyles = useCallback(\n (fraction: number) => {\n const [current1, current2] = [text1Ref.current, text2Ref.current];\n if (!current1 || !current2) return;\n\n current2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;\n current2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;\n\n const invertedFraction = 1 - fraction;\n current1.style.filter = `blur(${Math.min(8 / invertedFraction - 8, 100)}px)`;\n current1.style.opacity = `${Math.pow(invertedFraction, 0.4) * 100}%`;\n\n current1.textContent = texts[textIndexRef.current % texts.length];\n current2.textContent = texts[(textIndexRef.current + 1) % texts.length];\n },\n [texts],\n );\n\n const doMorph = useCallback(() => {\n morphRef.current -= cooldownRef.current;\n cooldownRef.current = 0;\n\n let fraction = morphRef.current / morphTime;\n\n if (fraction > 1) {\n cooldownRef.current = cooldownTime;\n fraction = 1;\n }\n\n setStyles(fraction);\n\n if (fraction === 1) {\n textIndexRef.current++;\n }\n }, [setStyles]);\n\n const doCooldown = useCallback(() => {\n morphRef.current = 0;\n const [current1, current2] = [text1Ref.current, text2Ref.current];\n if (current1 && current2) {\n current2.style.filter = \"none\";\n current2.style.opacity = \"100%\";\n current1.style.filter = \"none\";\n current1.style.opacity = \"0%\";\n }\n }, []);\n\n useEffect(() => {\n let animationFrameId: number;\n\n const animate = () => {\n animationFrameId = requestAnimationFrame(animate);\n\n const newTime = new Date();\n const dt = (newTime.getTime() - timeRef.current.getTime()) / 1000;\n timeRef.current = newTime;\n\n cooldownRef.current -= dt;\n\n if (cooldownRef.current <= 0) doMorph();\n else doCooldown();\n };\n\n animate();\n return () => {\n cancelAnimationFrame(animationFrameId);\n };\n }, [doMorph, doCooldown]);\n\n return { text1Ref, text2Ref };\n};\n\ninterface MorphingTextProps {\n className?: string;\n texts: string[];\n}\n\nconst Texts: React.FC> = ({ texts }) => {\n const { text1Ref, text2Ref } = useMorphingText(texts);\n return (\n <>\n \n \n \n );\n};\n\nconst SvgFilters: React.FC = () => (\n \n \n \n \n \n \n \n);\n\nconst MorphingText: React.FC = ({ texts, className }) => (\n \n \n \n \n);\n\nexport default MorphingText;\n", + "content": "\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst morphTime = 1.5;\nconst cooldownTime = 0.5;\n\nconst useMorphingText = (texts: string[]) => {\n const textIndexRef = useRef(0);\n const morphRef = useRef(0);\n const cooldownRef = useRef(0);\n const timeRef = useRef(new Date());\n\n const text1Ref = useRef(null);\n const text2Ref = useRef(null);\n\n const setStyles = useCallback(\n (fraction: number) => {\n const [current1, current2] = [text1Ref.current, text2Ref.current];\n if (!current1 || !current2) return;\n\n current2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;\n current2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;\n\n const invertedFraction = 1 - fraction;\n current1.style.filter = `blur(${Math.min(8 / invertedFraction - 8, 100)}px)`;\n current1.style.opacity = `${Math.pow(invertedFraction, 0.4) * 100}%`;\n\n current1.textContent = texts[textIndexRef.current % texts.length];\n current2.textContent = texts[(textIndexRef.current + 1) % texts.length];\n },\n [texts],\n );\n\n const doMorph = useCallback(() => {\n morphRef.current -= cooldownRef.current;\n cooldownRef.current = 0;\n\n let fraction = morphRef.current / morphTime;\n\n if (fraction > 1) {\n cooldownRef.current = cooldownTime;\n fraction = 1;\n }\n\n setStyles(fraction);\n\n if (fraction === 1) {\n textIndexRef.current++;\n }\n }, [setStyles]);\n\n const doCooldown = useCallback(() => {\n morphRef.current = 0;\n const [current1, current2] = [text1Ref.current, text2Ref.current];\n if (current1 && current2) {\n current2.style.filter = \"none\";\n current2.style.opacity = \"100%\";\n current1.style.filter = \"none\";\n current1.style.opacity = \"0%\";\n }\n }, []);\n\n useEffect(() => {\n let animationFrameId: number;\n\n const animate = () => {\n animationFrameId = requestAnimationFrame(animate);\n\n const newTime = new Date();\n const dt = (newTime.getTime() - timeRef.current.getTime()) / 1000;\n timeRef.current = newTime;\n\n cooldownRef.current -= dt;\n\n if (cooldownRef.current <= 0) doMorph();\n else doCooldown();\n };\n\n animate();\n return () => {\n cancelAnimationFrame(animationFrameId);\n };\n }, [doMorph, doCooldown]);\n\n return { text1Ref, text2Ref };\n};\n\ninterface MorphingTextProps {\n className?: string;\n texts: string[];\n}\n\nconst Texts: React.FC> = ({ texts }) => {\n const { text1Ref, text2Ref } = useMorphingText(texts);\n return (\n <>\n \n \n \n );\n};\n\nconst SvgFilters: React.FC = () => (\n \n \n \n \n \n \n \n);\n\nexport const MorphingText: React.FC = ({\n texts,\n className,\n}) => (\n \n \n \n \n);\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/neon-gradient-card.json b/public/r/styles/default/neon-gradient-card.json index 62be7fa4f..29271d6c0 100644 --- a/public/r/styles/default/neon-gradient-card.json +++ b/public/r/styles/default/neon-gradient-card.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/neon-gradient-card.tsx", - "content": "\"use client\";\n\nimport {\n CSSProperties,\n ReactElement,\n ReactNode,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface NeonColorsProps {\n firstColor: string;\n secondColor: string;\n}\n\ninterface NeonGradientCardProps {\n /**\n * @default
\n * @type ReactElement\n * @description\n * The component to be rendered as the card\n * */\n as?: ReactElement;\n /**\n * @default \"\"\n * @type string\n * @description\n * The className of the card\n */\n className?: string;\n\n /**\n * @default \"\"\n * @type ReactNode\n * @description\n * The children of the card\n * */\n children?: ReactNode;\n\n /**\n * @default 5\n * @type number\n * @description\n * The size of the border in pixels\n * */\n borderSize?: number;\n\n /**\n * @default 20\n * @type number\n * @description\n * The size of the radius in pixels\n * */\n borderRadius?: number;\n\n /**\n * @default \"{ firstColor: '#ff00aa', secondColor: '#00FFF1' }\"\n * @type string\n * @description\n * The colors of the neon gradient\n * */\n neonColors?: NeonColorsProps;\n\n [key: string]: any;\n}\n\nconst NeonGradientCard: React.FC = ({\n className,\n children,\n borderSize = 2,\n borderRadius = 20,\n neonColors = {\n firstColor: \"#ff00aa\",\n secondColor: \"#00FFF1\",\n },\n ...props\n}) => {\n const containerRef = useRef(null);\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 });\n\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const { offsetWidth, offsetHeight } = containerRef.current;\n setDimensions({ width: offsetWidth, height: offsetHeight });\n }\n };\n\n updateDimensions();\n window.addEventListener(\"resize\", updateDimensions);\n\n return () => {\n window.removeEventListener(\"resize\", updateDimensions);\n };\n }, []);\n\n useEffect(() => {\n if (containerRef.current) {\n const { offsetWidth, offsetHeight } = containerRef.current;\n setDimensions({ width: offsetWidth, height: offsetHeight });\n }\n }, [children]);\n\n return (\n \n \n {children}\n
\n \n );\n};\n\nexport { NeonGradientCard };\n", + "content": "\"use client\";\n\nimport {\n CSSProperties,\n ReactElement,\n ReactNode,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface NeonColorsProps {\n firstColor: string;\n secondColor: string;\n}\n\ninterface NeonGradientCardProps {\n /**\n * @default
\n * @type ReactElement\n * @description\n * The component to be rendered as the card\n * */\n as?: ReactElement;\n /**\n * @default \"\"\n * @type string\n * @description\n * The className of the card\n */\n className?: string;\n\n /**\n * @default \"\"\n * @type ReactNode\n * @description\n * The children of the card\n * */\n children?: ReactNode;\n\n /**\n * @default 5\n * @type number\n * @description\n * The size of the border in pixels\n * */\n borderSize?: number;\n\n /**\n * @default 20\n * @type number\n * @description\n * The size of the radius in pixels\n * */\n borderRadius?: number;\n\n /**\n * @default \"{ firstColor: '#ff00aa', secondColor: '#00FFF1' }\"\n * @type string\n * @description\n * The colors of the neon gradient\n * */\n neonColors?: NeonColorsProps;\n\n [key: string]: any;\n}\n\nexport const NeonGradientCard: React.FC = ({\n className,\n children,\n borderSize = 2,\n borderRadius = 20,\n neonColors = {\n firstColor: \"#ff00aa\",\n secondColor: \"#00FFF1\",\n },\n ...props\n}) => {\n const containerRef = useRef(null);\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 });\n\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const { offsetWidth, offsetHeight } = containerRef.current;\n setDimensions({ width: offsetWidth, height: offsetHeight });\n }\n };\n\n updateDimensions();\n window.addEventListener(\"resize\", updateDimensions);\n\n return () => {\n window.removeEventListener(\"resize\", updateDimensions);\n };\n }, []);\n\n useEffect(() => {\n if (containerRef.current) {\n const { offsetWidth, offsetHeight } = containerRef.current;\n setDimensions({ width: offsetWidth, height: offsetHeight });\n }\n }, [children]);\n\n return (\n \n \n {children}\n
\n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/number-ticker.json b/public/r/styles/default/number-ticker.json index 6dce0756b..125193319 100644 --- a/public/r/styles/default/number-ticker.json +++ b/public/r/styles/default/number-ticker.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/number-ticker.tsx", - "content": "\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useInView, useMotionValue, useSpring } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport default function NumberTicker({\n value,\n direction = \"up\",\n delay = 0,\n className,\n decimalPlaces = 0,\n}: {\n value: number;\n direction?: \"up\" | \"down\";\n className?: string;\n delay?: number; // delay in s\n decimalPlaces?: number;\n}) {\n const ref = useRef(null);\n const motionValue = useMotionValue(direction === \"down\" ? value : 0);\n const springValue = useSpring(motionValue, {\n damping: 60,\n stiffness: 100,\n });\n const isInView = useInView(ref, { once: true, margin: \"0px\" });\n\n useEffect(() => {\n isInView &&\n setTimeout(() => {\n motionValue.set(direction === \"down\" ? 0 : value);\n }, delay * 1000);\n }, [motionValue, isInView, delay, value, direction]);\n\n useEffect(\n () =>\n springValue.on(\"change\", (latest) => {\n if (ref.current) {\n ref.current.textContent = Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: decimalPlaces,\n maximumFractionDigits: decimalPlaces,\n }).format(Number(latest.toFixed(decimalPlaces)));\n }\n }),\n [springValue, decimalPlaces],\n );\n\n return (\n \n );\n}\n", + "content": "\"use client\";\n\nimport { useInView, useMotionValue, useSpring } from \"motion/react\";\nimport { ComponentPropsWithoutRef, useEffect, useRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface NumberTickerProps extends ComponentPropsWithoutRef<\"span\"> {\n value: number;\n direction?: \"up\" | \"down\";\n delay?: number; // delay in s\n decimalPlaces?: number;\n}\n\nexport function NumberTicker({\n value,\n direction = \"up\",\n delay = 0,\n className,\n decimalPlaces = 0,\n ...props\n}: NumberTickerProps) {\n const ref = useRef(null);\n const motionValue = useMotionValue(direction === \"down\" ? value : 0);\n const springValue = useSpring(motionValue, {\n damping: 60,\n stiffness: 100,\n });\n const isInView = useInView(ref, { once: true, margin: \"0px\" });\n\n useEffect(() => {\n isInView &&\n setTimeout(() => {\n motionValue.set(direction === \"down\" ? 0 : value);\n }, delay * 1000);\n }, [motionValue, isInView, delay, value, direction]);\n\n useEffect(\n () =>\n springValue.on(\"change\", (latest) => {\n if (ref.current) {\n ref.current.textContent = Intl.NumberFormat(\"en-US\", {\n minimumFractionDigits: decimalPlaces,\n maximumFractionDigits: decimalPlaces,\n }).format(Number(latest.toFixed(decimalPlaces)));\n }\n }),\n [springValue, decimalPlaces],\n );\n\n return (\n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/particles.json b/public/r/styles/default/particles.json index 6f1b2ccdc..b44543442 100644 --- a/public/r/styles/default/particles.json +++ b/public/r/styles/default/particles.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/particles.tsx", - "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\ninterface MousePosition {\n x: number;\n y: number;\n}\n\nfunction MousePosition(): MousePosition {\n const [mousePosition, setMousePosition] = useState({\n x: 0,\n y: 0,\n });\n\n useEffect(() => {\n const handleMouseMove = (event: MouseEvent) => {\n setMousePosition({ x: event.clientX, y: event.clientY });\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n };\n }, []);\n\n return mousePosition;\n}\n\ninterface ParticlesProps {\n className?: string;\n quantity?: number;\n staticity?: number;\n ease?: number;\n size?: number;\n refresh?: boolean;\n color?: string;\n vx?: number;\n vy?: number;\n}\n\nfunction hexToRgb(hex: string): number[] {\n hex = hex.replace(\"#\", \"\");\n\n if (hex.length === 3) {\n hex = hex\n .split(\"\")\n .map((char) => char + char)\n .join(\"\");\n }\n\n const hexInt = parseInt(hex, 16);\n const red = (hexInt >> 16) & 255;\n const green = (hexInt >> 8) & 255;\n const blue = hexInt & 255;\n return [red, green, blue];\n}\n\ntype Circle = {\n x: number;\n y: number;\n translateX: number;\n translateY: number;\n size: number;\n alpha: number;\n targetAlpha: number;\n dx: number;\n dy: number;\n magnetism: number;\n};\n\nconst Particles: React.FC = ({\n className = \"\",\n quantity = 100,\n staticity = 50,\n ease = 50,\n size = 0.4,\n refresh = false,\n color = \"#ffffff\",\n vx = 0,\n vy = 0,\n}) => {\n const canvasRef = useRef(null);\n const canvasContainerRef = useRef(null);\n const context = useRef(null);\n const circles = useRef([]);\n const mousePosition = MousePosition();\n const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });\n const dpr = typeof window !== \"undefined\" ? window.devicePixelRatio : 1;\n const rafID = useRef(null);\n const resizeTimeout = useRef();\n\n useEffect(() => {\n if (canvasRef.current) {\n context.current = canvasRef.current.getContext(\"2d\");\n }\n initCanvas();\n animate();\n\n const handleResize = () => {\n if (resizeTimeout.current) {\n clearTimeout(resizeTimeout.current);\n }\n resizeTimeout.current = setTimeout(() => {\n initCanvas();\n }, 200);\n };\n\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n if (rafID.current != null) {\n window.cancelAnimationFrame(rafID.current);\n }\n if (resizeTimeout.current) {\n clearTimeout(resizeTimeout.current);\n }\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [color]);\n\n useEffect(() => {\n onMouseMove();\n }, [mousePosition.x, mousePosition.y]);\n\n useEffect(() => {\n initCanvas();\n }, [refresh]);\n\n const initCanvas = () => {\n resizeCanvas();\n drawParticles();\n };\n\n const onMouseMove = () => {\n if (canvasRef.current) {\n const rect = canvasRef.current.getBoundingClientRect();\n const { w, h } = canvasSize.current;\n const x = mousePosition.x - rect.left - w / 2;\n const y = mousePosition.y - rect.top - h / 2;\n const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;\n if (inside) {\n mouse.current.x = x;\n mouse.current.y = y;\n }\n }\n };\n\n const resizeCanvas = () => {\n if (canvasContainerRef.current && canvasRef.current && context.current) {\n canvasSize.current.w = canvasContainerRef.current.offsetWidth;\n canvasSize.current.h = canvasContainerRef.current.offsetHeight;\n\n canvasRef.current.width = canvasSize.current.w * dpr;\n canvasRef.current.height = canvasSize.current.h * dpr;\n canvasRef.current.style.width = `${canvasSize.current.w}px`;\n canvasRef.current.style.height = `${canvasSize.current.h}px`;\n context.current.scale(dpr, dpr);\n\n // Clear existing particles and create new ones with exact quantity\n circles.current = [];\n for (let i = 0; i < quantity; i++) {\n const circle = circleParams();\n drawCircle(circle);\n }\n }\n };\n\n const circleParams = (): Circle => {\n const x = Math.floor(Math.random() * canvasSize.current.w);\n const y = Math.floor(Math.random() * canvasSize.current.h);\n const translateX = 0;\n const translateY = 0;\n const pSize = Math.floor(Math.random() * 2) + size;\n const alpha = 0;\n const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1));\n const dx = (Math.random() - 0.5) * 0.1;\n const dy = (Math.random() - 0.5) * 0.1;\n const magnetism = 0.1 + Math.random() * 4;\n return {\n x,\n y,\n translateX,\n translateY,\n size: pSize,\n alpha,\n targetAlpha,\n dx,\n dy,\n magnetism,\n };\n };\n\n const rgb = hexToRgb(color);\n\n const drawCircle = (circle: Circle, update = false) => {\n if (context.current) {\n const { x, y, translateX, translateY, size, alpha } = circle;\n context.current.translate(translateX, translateY);\n context.current.beginPath();\n context.current.arc(x, y, size, 0, 2 * Math.PI);\n context.current.fillStyle = `rgba(${rgb.join(\", \")}, ${alpha})`;\n context.current.fill();\n context.current.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (!update) {\n circles.current.push(circle);\n }\n }\n };\n\n const clearContext = () => {\n if (context.current) {\n context.current.clearRect(\n 0,\n 0,\n canvasSize.current.w,\n canvasSize.current.h,\n );\n }\n };\n\n const drawParticles = () => {\n clearContext();\n const particleCount = quantity;\n for (let i = 0; i < particleCount; i++) {\n const circle = circleParams();\n drawCircle(circle);\n }\n };\n\n const remapValue = (\n value: number,\n start1: number,\n end1: number,\n start2: number,\n end2: number,\n ): number => {\n const remapped =\n ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;\n return remapped > 0 ? remapped : 0;\n };\n\n const animate = () => {\n clearContext();\n circles.current.forEach((circle: Circle, i: number) => {\n // Handle the alpha value\n const edge = [\n circle.x + circle.translateX - circle.size, // distance from left edge\n canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge\n circle.y + circle.translateY - circle.size, // distance from top edge\n canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge\n ];\n const closestEdge = edge.reduce((a, b) => Math.min(a, b));\n const remapClosestEdge = parseFloat(\n remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),\n );\n if (remapClosestEdge > 1) {\n circle.alpha += 0.02;\n if (circle.alpha > circle.targetAlpha) {\n circle.alpha = circle.targetAlpha;\n }\n } else {\n circle.alpha = circle.targetAlpha * remapClosestEdge;\n }\n circle.x += circle.dx + vx;\n circle.y += circle.dy + vy;\n circle.translateX +=\n (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /\n ease;\n circle.translateY +=\n (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /\n ease;\n\n drawCircle(circle, true);\n\n // circle gets out of the canvas\n if (\n circle.x < -circle.size ||\n circle.x > canvasSize.current.w + circle.size ||\n circle.y < -circle.size ||\n circle.y > canvasSize.current.h + circle.size\n ) {\n // remove the circle from the array\n circles.current.splice(i, 1);\n // create a new circle\n const newCircle = circleParams();\n drawCircle(newCircle);\n }\n });\n rafID.current = window.requestAnimationFrame(animate);\n };\n\n return (\n \n \n \n );\n};\n\nexport default Particles;\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport React, {\n ComponentPropsWithoutRef,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\ninterface MousePosition {\n x: number;\n y: number;\n}\n\nfunction MousePosition(): MousePosition {\n const [mousePosition, setMousePosition] = useState({\n x: 0,\n y: 0,\n });\n\n useEffect(() => {\n const handleMouseMove = (event: MouseEvent) => {\n setMousePosition({ x: event.clientX, y: event.clientY });\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n };\n }, []);\n\n return mousePosition;\n}\n\ninterface ParticlesProps extends ComponentPropsWithoutRef<\"div\"> {\n className?: string;\n quantity?: number;\n staticity?: number;\n ease?: number;\n size?: number;\n refresh?: boolean;\n color?: string;\n vx?: number;\n vy?: number;\n}\n\nfunction hexToRgb(hex: string): number[] {\n hex = hex.replace(\"#\", \"\");\n\n if (hex.length === 3) {\n hex = hex\n .split(\"\")\n .map((char) => char + char)\n .join(\"\");\n }\n\n const hexInt = parseInt(hex, 16);\n const red = (hexInt >> 16) & 255;\n const green = (hexInt >> 8) & 255;\n const blue = hexInt & 255;\n return [red, green, blue];\n}\n\ntype Circle = {\n x: number;\n y: number;\n translateX: number;\n translateY: number;\n size: number;\n alpha: number;\n targetAlpha: number;\n dx: number;\n dy: number;\n magnetism: number;\n};\n\nexport const Particles: React.FC = ({\n className = \"\",\n quantity = 100,\n staticity = 50,\n ease = 50,\n size = 0.4,\n refresh = false,\n color = \"#ffffff\",\n vx = 0,\n vy = 0,\n ...props\n}) => {\n const canvasRef = useRef(null);\n const canvasContainerRef = useRef(null);\n const context = useRef(null);\n const circles = useRef([]);\n const mousePosition = MousePosition();\n const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });\n const dpr = typeof window !== \"undefined\" ? window.devicePixelRatio : 1;\n const rafID = useRef(null);\n const resizeTimeout = useRef();\n\n useEffect(() => {\n if (canvasRef.current) {\n context.current = canvasRef.current.getContext(\"2d\");\n }\n initCanvas();\n animate();\n\n const handleResize = () => {\n if (resizeTimeout.current) {\n clearTimeout(resizeTimeout.current);\n }\n resizeTimeout.current = setTimeout(() => {\n initCanvas();\n }, 200);\n };\n\n window.addEventListener(\"resize\", handleResize);\n\n return () => {\n if (rafID.current != null) {\n window.cancelAnimationFrame(rafID.current);\n }\n if (resizeTimeout.current) {\n clearTimeout(resizeTimeout.current);\n }\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [color]);\n\n useEffect(() => {\n onMouseMove();\n }, [mousePosition.x, mousePosition.y]);\n\n useEffect(() => {\n initCanvas();\n }, [refresh]);\n\n const initCanvas = () => {\n resizeCanvas();\n drawParticles();\n };\n\n const onMouseMove = () => {\n if (canvasRef.current) {\n const rect = canvasRef.current.getBoundingClientRect();\n const { w, h } = canvasSize.current;\n const x = mousePosition.x - rect.left - w / 2;\n const y = mousePosition.y - rect.top - h / 2;\n const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;\n if (inside) {\n mouse.current.x = x;\n mouse.current.y = y;\n }\n }\n };\n\n const resizeCanvas = () => {\n if (canvasContainerRef.current && canvasRef.current && context.current) {\n canvasSize.current.w = canvasContainerRef.current.offsetWidth;\n canvasSize.current.h = canvasContainerRef.current.offsetHeight;\n\n canvasRef.current.width = canvasSize.current.w * dpr;\n canvasRef.current.height = canvasSize.current.h * dpr;\n canvasRef.current.style.width = `${canvasSize.current.w}px`;\n canvasRef.current.style.height = `${canvasSize.current.h}px`;\n context.current.scale(dpr, dpr);\n\n // Clear existing particles and create new ones with exact quantity\n circles.current = [];\n for (let i = 0; i < quantity; i++) {\n const circle = circleParams();\n drawCircle(circle);\n }\n }\n };\n\n const circleParams = (): Circle => {\n const x = Math.floor(Math.random() * canvasSize.current.w);\n const y = Math.floor(Math.random() * canvasSize.current.h);\n const translateX = 0;\n const translateY = 0;\n const pSize = Math.floor(Math.random() * 2) + size;\n const alpha = 0;\n const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1));\n const dx = (Math.random() - 0.5) * 0.1;\n const dy = (Math.random() - 0.5) * 0.1;\n const magnetism = 0.1 + Math.random() * 4;\n return {\n x,\n y,\n translateX,\n translateY,\n size: pSize,\n alpha,\n targetAlpha,\n dx,\n dy,\n magnetism,\n };\n };\n\n const rgb = hexToRgb(color);\n\n const drawCircle = (circle: Circle, update = false) => {\n if (context.current) {\n const { x, y, translateX, translateY, size, alpha } = circle;\n context.current.translate(translateX, translateY);\n context.current.beginPath();\n context.current.arc(x, y, size, 0, 2 * Math.PI);\n context.current.fillStyle = `rgba(${rgb.join(\", \")}, ${alpha})`;\n context.current.fill();\n context.current.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (!update) {\n circles.current.push(circle);\n }\n }\n };\n\n const clearContext = () => {\n if (context.current) {\n context.current.clearRect(\n 0,\n 0,\n canvasSize.current.w,\n canvasSize.current.h,\n );\n }\n };\n\n const drawParticles = () => {\n clearContext();\n const particleCount = quantity;\n for (let i = 0; i < particleCount; i++) {\n const circle = circleParams();\n drawCircle(circle);\n }\n };\n\n const remapValue = (\n value: number,\n start1: number,\n end1: number,\n start2: number,\n end2: number,\n ): number => {\n const remapped =\n ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;\n return remapped > 0 ? remapped : 0;\n };\n\n const animate = () => {\n clearContext();\n circles.current.forEach((circle: Circle, i: number) => {\n // Handle the alpha value\n const edge = [\n circle.x + circle.translateX - circle.size, // distance from left edge\n canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge\n circle.y + circle.translateY - circle.size, // distance from top edge\n canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge\n ];\n const closestEdge = edge.reduce((a, b) => Math.min(a, b));\n const remapClosestEdge = parseFloat(\n remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),\n );\n if (remapClosestEdge > 1) {\n circle.alpha += 0.02;\n if (circle.alpha > circle.targetAlpha) {\n circle.alpha = circle.targetAlpha;\n }\n } else {\n circle.alpha = circle.targetAlpha * remapClosestEdge;\n }\n circle.x += circle.dx + vx;\n circle.y += circle.dy + vy;\n circle.translateX +=\n (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /\n ease;\n circle.translateY +=\n (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /\n ease;\n\n drawCircle(circle, true);\n\n // circle gets out of the canvas\n if (\n circle.x < -circle.size ||\n circle.x > canvasSize.current.w + circle.size ||\n circle.y < -circle.size ||\n circle.y > canvasSize.current.h + circle.size\n ) {\n // remove the circle from the array\n circles.current.splice(i, 1);\n // create a new circle\n const newCircle = circleParams();\n drawCircle(newCircle);\n }\n });\n rafID.current = window.requestAnimationFrame(animate);\n };\n\n return (\n \n \n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/pulsating-button.json b/public/r/styles/default/pulsating-button.json index 79ba9cadc..2b77162b1 100644 --- a/public/r/styles/default/pulsating-button.json +++ b/public/r/styles/default/pulsating-button.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/pulsating-button.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface PulsatingButtonProps\n extends React.ButtonHTMLAttributes {\n pulseColor?: string;\n duration?: string;\n}\n\nexport const PulsatingButton = React.forwardRef<\n HTMLButtonElement,\n PulsatingButtonProps\n>(\n (\n {\n className,\n children,\n pulseColor = \"#0096ff\",\n duration = \"1.5s\",\n ...props\n },\n ref,\n ) => {\n return (\n \n
{children}
\n
\n \n );\n },\n);\n\nPulsatingButton.displayName = \"PulsatingButton\";\n", + "content": "import React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface PulsatingButtonProps\n extends React.ButtonHTMLAttributes {\n pulseColor?: string;\n duration?: string;\n}\n\nexport const PulsatingButton = React.forwardRef<\n HTMLButtonElement,\n PulsatingButtonProps\n>(\n (\n {\n className,\n children,\n pulseColor = \"#0096ff\",\n duration = \"1.5s\",\n ...props\n },\n ref,\n ) => {\n return (\n \n
{children}
\n
\n \n );\n },\n);\n\nPulsatingButton.displayName = \"PulsatingButton\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/rainbow-button.json b/public/r/styles/default/rainbow-button.json index b117e8b09..8421f148d 100644 --- a/public/r/styles/default/rainbow-button.json +++ b/public/r/styles/default/rainbow-button.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/rainbow-button.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface RainbowButtonProps\n extends React.ButtonHTMLAttributes {}\n\nexport const RainbowButton = React.forwardRef<\n HTMLButtonElement,\n RainbowButtonProps\n>(({ children, className, ...props }, ref) => {\n return (\n \n {children}\n \n );\n});\n\nRainbowButton.displayName = \"RainbowButton\";\n", + "content": "import React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface RainbowButtonProps\n extends React.ButtonHTMLAttributes {}\n\nexport const RainbowButton = React.forwardRef<\n HTMLButtonElement,\n RainbowButtonProps\n>(({ children, className, ...props }, ref) => {\n return (\n \n {children}\n \n );\n});\n\nRainbowButton.displayName = \"RainbowButton\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/retro-grid.json b/public/r/styles/default/retro-grid.json index 1fb4689c5..9f56780c6 100644 --- a/public/r/styles/default/retro-grid.json +++ b/public/r/styles/default/retro-grid.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/retro-grid.tsx", - "content": "import { cn } from \"@/lib/utils\";\n\ninterface RetroGridProps extends React.HTMLAttributes {\n /**\n * Additional CSS classes to apply to the grid container\n */\n className?: string;\n /**\n * Rotation angle of the grid in degrees\n * @default 65\n */\n angle?: number;\n /**\n * Grid cell size in pixels\n * @default 60\n */\n cellSize?: number;\n /**\n * Grid opacity value between 0 and 1\n * @default 0.5\n */\n opacity?: number;\n /**\n * Grid line color in light mode\n * @default \"gray\"\n */\n lightLineColor?: string;\n /**\n * Grid line color in dark mode\n * @default \"gray\"\n */\n darkLineColor?: string;\n}\n\nexport default function RetroGrid({\n className,\n angle = 65,\n cellSize = 60,\n opacity = 0.5,\n lightLineColor = \"gray\",\n darkLineColor = \"gray\",\n ...props\n}: RetroGridProps) {\n const gridStyles = {\n \"--grid-angle\": `${angle}deg`,\n \"--cell-size\": `${cellSize}px`,\n \"--opacity\": opacity,\n \"--light-line\": lightLineColor,\n \"--dark-line\": darkLineColor,\n } as React.CSSProperties;\n\n return (\n \n
\n
\n
\n\n
\n
\n );\n}\n", + "content": "import { cn } from \"@/lib/utils\";\n\ninterface RetroGridProps extends React.HTMLAttributes {\n /**\n * Additional CSS classes to apply to the grid container\n */\n className?: string;\n /**\n * Rotation angle of the grid in degrees\n * @default 65\n */\n angle?: number;\n /**\n * Grid cell size in pixels\n * @default 60\n */\n cellSize?: number;\n /**\n * Grid opacity value between 0 and 1\n * @default 0.5\n */\n opacity?: number;\n /**\n * Grid line color in light mode\n * @default \"gray\"\n */\n lightLineColor?: string;\n /**\n * Grid line color in dark mode\n * @default \"gray\"\n */\n darkLineColor?: string;\n}\n\nexport function RetroGrid({\n className,\n angle = 65,\n cellSize = 60,\n opacity = 0.5,\n lightLineColor = \"gray\",\n darkLineColor = \"gray\",\n ...props\n}: RetroGridProps) {\n const gridStyles = {\n \"--grid-angle\": `${angle}deg`,\n \"--cell-size\": `${cellSize}px`,\n \"--opacity\": opacity,\n \"--light-line\": lightLineColor,\n \"--dark-line\": darkLineColor,\n } as React.CSSProperties;\n\n return (\n \n
\n
\n
\n\n
\n
\n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/ripple.json b/public/r/styles/default/ripple.json index be086362c..8da11229b 100644 --- a/public/r/styles/default/ripple.json +++ b/public/r/styles/default/ripple.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/ripple.tsx", - "content": "import React, { CSSProperties } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface RippleProps {\n mainCircleSize?: number;\n mainCircleOpacity?: number;\n numCircles?: number;\n className?: string;\n}\n\nconst Ripple = React.memo(function Ripple({\n mainCircleSize = 210,\n mainCircleOpacity = 0.24,\n numCircles = 8,\n className,\n}: RippleProps) {\n return (\n \n {Array.from({ length: numCircles }, (_, i) => {\n const size = mainCircleSize + i * 70;\n const opacity = mainCircleOpacity - i * 0.03;\n const animationDelay = `${i * 0.06}s`;\n const borderStyle = i === numCircles - 1 ? \"dashed\" : \"solid\";\n const borderOpacity = 5 + i * 5;\n\n return (\n \n );\n })}\n
\n );\n});\n\nRipple.displayName = \"Ripple\";\n\nexport default Ripple;\n", + "content": "import React, { ComponentPropsWithoutRef, CSSProperties } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface RippleProps extends ComponentPropsWithoutRef<\"div\"> {\n mainCircleSize?: number;\n mainCircleOpacity?: number;\n numCircles?: number;\n}\n\nexport const Ripple = React.memo(function Ripple({\n mainCircleSize = 210,\n mainCircleOpacity = 0.24,\n numCircles = 8,\n className,\n ...props\n}: RippleProps) {\n return (\n \n {Array.from({ length: numCircles }, (_, i) => {\n const size = mainCircleSize + i * 70;\n const opacity = mainCircleOpacity - i * 0.03;\n const animationDelay = `${i * 0.06}s`;\n const borderStyle = i === numCircles - 1 ? \"dashed\" : \"solid\";\n const borderOpacity = 5 + i * 5;\n\n return (\n \n );\n })}\n
\n );\n});\n\nRipple.displayName = \"Ripple\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/safari.json b/public/r/styles/default/safari.json index 2cd64fe40..c80101a6e 100644 --- a/public/r/styles/default/safari.json +++ b/public/r/styles/default/safari.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/safari.tsx", - "content": "import { SVGProps } from \"react\";\n\ntype SafariMode = \"default\" | \"simple\";\nexport interface SafariProps extends SVGProps {\n url?: string;\n imageSrc?: string;\n videoSrc?: string;\n width?: number;\n height?: number;\n mode?: SafariMode;\n}\n\nexport default function Safari({\n imageSrc,\n videoSrc,\n url,\n width = 1203,\n height = 753,\n mode = \"default\",\n ...props\n}: SafariProps) {\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {url}\n \n \n {mode === \"default\" ? (\n <>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ) : null}\n {imageSrc && (\n \n )}\n {videoSrc && (\n \n \n \n )}\n \n \n \n \n \n \n \n \n \n \n );\n}\n", + "content": "import { SVGProps } from \"react\";\n\ntype SafariMode = \"default\" | \"simple\";\n\nexport interface SafariProps extends SVGProps {\n url?: string;\n imageSrc?: string;\n videoSrc?: string;\n width?: number;\n height?: number;\n mode?: SafariMode;\n}\n\nexport default function Safari({\n imageSrc,\n videoSrc,\n url,\n width = 1203,\n height = 753,\n mode = \"default\",\n ...props\n}: SafariProps) {\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {url}\n \n \n {mode === \"default\" ? (\n <>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ) : null}\n {imageSrc && (\n \n )}\n {videoSrc && (\n \n \n \n )}\n \n \n \n \n \n \n \n \n \n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/scratch-to-reveal.json b/public/r/styles/default/scratch-to-reveal.json index 9eda84844..f5ced0c5b 100644 --- a/public/r/styles/default/scratch-to-reveal.json +++ b/public/r/styles/default/scratch-to-reveal.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/scratch-to-reveal.tsx", - "content": "import { cn } from \"@/lib/utils\";\nimport React, { useRef, useEffect, useState } from \"react\";\nimport { motion, useAnimation } from \"motion/react\";\n\ninterface ScratchToRevealProps {\n children: React.ReactNode;\n width: number;\n height: number;\n minScratchPercentage?: number;\n className?: string;\n onComplete?: () => void;\n gradientColors?: [string, string, string];\n}\n\nconst ScratchToReveal: React.FC = ({\n width,\n height,\n minScratchPercentage = 50,\n onComplete,\n children,\n className,\n gradientColors = [\"#A97CF8\", \"#F38CB8\", \"#FDCC92\"],\n}) => {\n const canvasRef = useRef(null);\n const [isScratching, setIsScratching] = useState(false);\n const [isComplete, setIsComplete] = useState(false);\n\n const controls = useAnimation();\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext(\"2d\");\n if (canvas && ctx) {\n ctx.fillStyle = \"#ccc\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n const gradient = ctx.createLinearGradient(\n 0,\n 0,\n canvas.width,\n canvas.height,\n );\n gradient.addColorStop(0, gradientColors[0]);\n gradient.addColorStop(0.5, gradientColors[1]);\n gradient.addColorStop(1, gradientColors[2]);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n }\n }, [gradientColors]);\n\n useEffect(() => {\n const handleDocumentMouseMove = (event: MouseEvent) => {\n if (!isScratching) return;\n scratch(event.clientX, event.clientY);\n };\n\n const handleDocumentTouchMove = (event: TouchEvent) => {\n if (!isScratching) return;\n const touch = event.touches[0];\n scratch(touch.clientX, touch.clientY);\n };\n\n const handleDocumentMouseUp = () => {\n setIsScratching(false);\n checkCompletion();\n };\n\n const handleDocumentTouchEnd = () => {\n setIsScratching(false);\n checkCompletion();\n };\n\n document.addEventListener(\"mousedown\", handleDocumentMouseMove);\n document.addEventListener(\"mousemove\", handleDocumentMouseMove);\n document.addEventListener(\"touchstart\", handleDocumentTouchMove);\n document.addEventListener(\"touchmove\", handleDocumentTouchMove);\n document.addEventListener(\"mouseup\", handleDocumentMouseUp);\n document.addEventListener(\"touchend\", handleDocumentTouchEnd);\n document.addEventListener(\"touchcancel\", handleDocumentTouchEnd);\n\n return () => {\n document.removeEventListener(\"mousedown\", handleDocumentMouseMove);\n document.removeEventListener(\"mousemove\", handleDocumentMouseMove);\n document.removeEventListener(\"touchstart\", handleDocumentTouchMove);\n document.removeEventListener(\"touchmove\", handleDocumentTouchMove);\n document.removeEventListener(\"mouseup\", handleDocumentMouseUp);\n document.removeEventListener(\"touchend\", handleDocumentTouchEnd);\n document.removeEventListener(\"touchcancel\", handleDocumentTouchEnd);\n };\n }, [isScratching]);\n\n const handleMouseDown = () => setIsScratching(true);\n\n const handleTouchStart = () => setIsScratching(true);\n\n const scratch = (clientX: number, clientY: number) => {\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext(\"2d\");\n if (canvas && ctx) {\n const rect = canvas.getBoundingClientRect();\n const x = clientX - rect.left + 16;\n const y = clientY - rect.top + 16;\n ctx.globalCompositeOperation = \"destination-out\";\n ctx.beginPath();\n ctx.arc(x, y, 30, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const startAnimation = async () => {\n await controls.start({\n scale: [1, 1.5, 1],\n rotate: [0, 10, -10, 10, -10, 0],\n transition: { duration: 0.5 },\n });\n\n // Call onComplete after animation finishes\n if (onComplete) {\n onComplete();\n }\n };\n\n const checkCompletion = () => {\n if (isComplete) return;\n\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext(\"2d\");\n if (canvas && ctx) {\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const pixels = imageData.data;\n const totalPixels = pixels.length / 4;\n let clearPixels = 0;\n\n for (let i = 3; i < pixels.length; i += 4) {\n if (pixels[i] === 0) clearPixels++;\n }\n\n const percentage = (clearPixels / totalPixels) * 100;\n\n if (percentage >= minScratchPercentage) {\n setIsComplete(true);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n startAnimation();\n }\n }\n };\n\n return (\n \n \n {children}\n \n );\n};\n\nexport default ScratchToReveal;\n", + "content": "import { cn } from \"@/lib/utils\";\nimport { motion, useAnimation } from \"motion/react\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\ninterface ScratchToRevealProps {\n children: React.ReactNode;\n width: number;\n height: number;\n minScratchPercentage?: number;\n className?: string;\n onComplete?: () => void;\n gradientColors?: [string, string, string];\n}\n\nexport const ScratchToReveal: React.FC = ({\n width,\n height,\n minScratchPercentage = 50,\n onComplete,\n children,\n className,\n gradientColors = [\"#A97CF8\", \"#F38CB8\", \"#FDCC92\"],\n}) => {\n const canvasRef = useRef(null);\n const [isScratching, setIsScratching] = useState(false);\n const [isComplete, setIsComplete] = useState(false);\n\n const controls = useAnimation();\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext(\"2d\");\n if (canvas && ctx) {\n ctx.fillStyle = \"#ccc\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n const gradient = ctx.createLinearGradient(\n 0,\n 0,\n canvas.width,\n canvas.height,\n );\n gradient.addColorStop(0, gradientColors[0]);\n gradient.addColorStop(0.5, gradientColors[1]);\n gradient.addColorStop(1, gradientColors[2]);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n }\n }, [gradientColors]);\n\n useEffect(() => {\n const handleDocumentMouseMove = (event: MouseEvent) => {\n if (!isScratching) return;\n scratch(event.clientX, event.clientY);\n };\n\n const handleDocumentTouchMove = (event: TouchEvent) => {\n if (!isScratching) return;\n const touch = event.touches[0];\n scratch(touch.clientX, touch.clientY);\n };\n\n const handleDocumentMouseUp = () => {\n setIsScratching(false);\n checkCompletion();\n };\n\n const handleDocumentTouchEnd = () => {\n setIsScratching(false);\n checkCompletion();\n };\n\n document.addEventListener(\"mousedown\", handleDocumentMouseMove);\n document.addEventListener(\"mousemove\", handleDocumentMouseMove);\n document.addEventListener(\"touchstart\", handleDocumentTouchMove);\n document.addEventListener(\"touchmove\", handleDocumentTouchMove);\n document.addEventListener(\"mouseup\", handleDocumentMouseUp);\n document.addEventListener(\"touchend\", handleDocumentTouchEnd);\n document.addEventListener(\"touchcancel\", handleDocumentTouchEnd);\n\n return () => {\n document.removeEventListener(\"mousedown\", handleDocumentMouseMove);\n document.removeEventListener(\"mousemove\", handleDocumentMouseMove);\n document.removeEventListener(\"touchstart\", handleDocumentTouchMove);\n document.removeEventListener(\"touchmove\", handleDocumentTouchMove);\n document.removeEventListener(\"mouseup\", handleDocumentMouseUp);\n document.removeEventListener(\"touchend\", handleDocumentTouchEnd);\n document.removeEventListener(\"touchcancel\", handleDocumentTouchEnd);\n };\n }, [isScratching]);\n\n const handleMouseDown = () => setIsScratching(true);\n\n const handleTouchStart = () => setIsScratching(true);\n\n const scratch = (clientX: number, clientY: number) => {\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext(\"2d\");\n if (canvas && ctx) {\n const rect = canvas.getBoundingClientRect();\n const x = clientX - rect.left + 16;\n const y = clientY - rect.top + 16;\n ctx.globalCompositeOperation = \"destination-out\";\n ctx.beginPath();\n ctx.arc(x, y, 30, 0, Math.PI * 2);\n ctx.fill();\n }\n };\n\n const startAnimation = async () => {\n await controls.start({\n scale: [1, 1.5, 1],\n rotate: [0, 10, -10, 10, -10, 0],\n transition: { duration: 0.5 },\n });\n\n // Call onComplete after animation finishes\n if (onComplete) {\n onComplete();\n }\n };\n\n const checkCompletion = () => {\n if (isComplete) return;\n\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext(\"2d\");\n if (canvas && ctx) {\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const pixels = imageData.data;\n const totalPixels = pixels.length / 4;\n let clearPixels = 0;\n\n for (let i = 3; i < pixels.length; i += 4) {\n if (pixels[i] === 0) clearPixels++;\n }\n\n const percentage = (clearPixels / totalPixels) * 100;\n\n if (percentage >= minScratchPercentage) {\n setIsComplete(true);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n startAnimation();\n }\n }\n };\n\n return (\n \n \n {children}\n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/script-copy-btn.json b/public/r/styles/default/script-copy-btn.json index 4ae15f5c7..c32243e1e 100644 --- a/public/r/styles/default/script-copy-btn.json +++ b/public/r/styles/default/script-copy-btn.json @@ -6,10 +6,13 @@ "shiki", "next-themes" ], + "registryDependencies": [ + "button" + ], "files": [ { "path": "magicui/script-copy-btn.tsx", - "content": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { motion } from \"motion/react\";\nimport { Check, Copy } from \"lucide-react\";\nimport { useTheme } from \"next-themes\";\nimport { HTMLAttributes, useEffect, useState } from \"react\";\nimport { codeToHtml } from \"shiki\";\n\ninterface ScriptCopyBtnProps extends HTMLAttributes {\n showMultiplePackageOptions?: boolean;\n codeLanguage: string;\n lightTheme: string;\n darkTheme: string;\n commandMap: Record;\n className?: string;\n}\n\nexport default function ScriptCopyBtn({\n showMultiplePackageOptions = true,\n codeLanguage,\n lightTheme,\n darkTheme,\n commandMap,\n className,\n}: ScriptCopyBtnProps) {\n const packageManagers = Object.keys(commandMap);\n const [packageManager, setPackageManager] = useState(packageManagers[0]);\n const [copied, setCopied] = useState(false);\n const [highlightedCode, setHighlightedCode] = useState(\"\");\n const { theme } = useTheme();\n const command = commandMap[packageManager];\n\n useEffect(() => {\n async function loadHighlightedCode() {\n try {\n const highlighted = await codeToHtml(command, {\n lang: codeLanguage,\n themes: {\n light: lightTheme,\n dark: darkTheme,\n },\n defaultColor: theme === \"dark\" ? \"dark\" : \"light\",\n });\n setHighlightedCode(highlighted);\n } catch (error) {\n console.error(\"Error highlighting code:\", error);\n setHighlightedCode(`
${command}
`);\n }\n }\n\n loadHighlightedCode();\n }, [command, theme, codeLanguage, lightTheme, darkTheme]);\n\n const copyToClipboard = () => {\n navigator.clipboard.writeText(command);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n return (\n \n
\n
\n {showMultiplePackageOptions && (\n
\n
\n {packageManagers.map((pm, index) => (\n
\n {index > 0 && (\n
\n )}\n setPackageManager(pm)}\n >\n {pm}\n {packageManager === pm && (\n \n )}\n \n
\n ))}\n
\n
\n )}\n
\n
\n
\n {highlightedCode ? (\n pre]:overflow-x-auto [&>pre]:rounded-md [&>pre]:p-2 [&>pre]:px-4 [&>pre]:font-mono ${\n theme === \"dark\" ? \"dark\" : \"light\"\n }`}\n dangerouslySetInnerHTML={{ __html: highlightedCode }}\n />\n ) : (\n
\n                {command}\n              
\n )}\n
\n \n {copied ? \"Copied\" : \"Copy\"}\n \n \n \n
\n
\n
\n );\n}\n", + "content": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { Check, Copy } from \"lucide-react\";\nimport { motion } from \"motion/react\";\nimport { useTheme } from \"next-themes\";\nimport { HTMLAttributes, useEffect, useState } from \"react\";\nimport { codeToHtml } from \"shiki\";\n\ninterface ScriptCopyBtnProps extends HTMLAttributes {\n showMultiplePackageOptions?: boolean;\n codeLanguage: string;\n lightTheme: string;\n darkTheme: string;\n commandMap: Record;\n className?: string;\n}\n\nexport function ScriptCopyBtn({\n showMultiplePackageOptions = true,\n codeLanguage,\n lightTheme,\n darkTheme,\n commandMap,\n className,\n}: ScriptCopyBtnProps) {\n const packageManagers = Object.keys(commandMap);\n const [packageManager, setPackageManager] = useState(packageManagers[0]);\n const [copied, setCopied] = useState(false);\n const [highlightedCode, setHighlightedCode] = useState(\"\");\n const { theme } = useTheme();\n const command = commandMap[packageManager];\n\n useEffect(() => {\n async function loadHighlightedCode() {\n try {\n const highlighted = await codeToHtml(command, {\n lang: codeLanguage,\n themes: {\n light: lightTheme,\n dark: darkTheme,\n },\n defaultColor: theme === \"dark\" ? \"dark\" : \"light\",\n });\n setHighlightedCode(highlighted);\n } catch (error) {\n console.error(\"Error highlighting code:\", error);\n setHighlightedCode(`
${command}
`);\n }\n }\n\n loadHighlightedCode();\n }, [command, theme, codeLanguage, lightTheme, darkTheme]);\n\n const copyToClipboard = () => {\n navigator.clipboard.writeText(command);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n return (\n \n
\n
\n {showMultiplePackageOptions && (\n
\n
\n {packageManagers.map((pm, index) => (\n
\n {index > 0 && (\n
\n )}\n setPackageManager(pm)}\n >\n {pm}\n {packageManager === pm && (\n \n )}\n \n
\n ))}\n
\n
\n )}\n
\n
\n
\n {highlightedCode ? (\n pre]:overflow-x-auto [&>pre]:rounded-md [&>pre]:p-2 [&>pre]:px-4 [&>pre]:font-mono ${\n theme === \"dark\" ? \"dark\" : \"light\"\n }`}\n dangerouslySetInnerHTML={{ __html: highlightedCode }}\n />\n ) : (\n
\n                {command}\n              
\n )}\n
\n \n {copied ? \"Copied\" : \"Copy\"}\n \n \n \n
\n
\n
\n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/scroll-progress.json b/public/r/styles/default/scroll-progress.json index d77eef3d3..9417bf62c 100644 --- a/public/r/styles/default/scroll-progress.json +++ b/public/r/styles/default/scroll-progress.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/scroll-progress.tsx", - "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, useScroll, useSpring } from \"motion/react\";\n\ninterface ScrollProgressProps {\n className?: string;\n}\n\nexport default function ScrollProgress({ className }: ScrollProgressProps) {\n const { scrollYProgress } = useScroll();\n\n const scaleX = useSpring(scrollYProgress, {\n stiffness: 200,\n damping: 50,\n restDelta: 0.001,\n });\n\n return (\n \n );\n}\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, MotionProps, useScroll, useSpring } from \"motion/react\";\nimport React from \"react\";\ninterface ScrollProgressProps\n extends Omit, keyof MotionProps> {}\n\nexport const ScrollProgress = React.forwardRef<\n HTMLDivElement,\n ScrollProgressProps\n>(({ className, ...props }, ref) => {\n const { scrollYProgress } = useScroll();\n\n const scaleX = useSpring(scrollYProgress, {\n stiffness: 200,\n damping: 50,\n restDelta: 0.001,\n });\n\n return (\n \n );\n});\n\nScrollProgress.displayName = \"ScrollProgress\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/shimmer-button.json b/public/r/styles/default/shimmer-button.json index d05fe9e9f..7583713d1 100644 --- a/public/r/styles/default/shimmer-button.json +++ b/public/r/styles/default/shimmer-button.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/shimmer-button.tsx", - "content": "import React, { CSSProperties } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface ShimmerButtonProps\n extends React.ButtonHTMLAttributes {\n shimmerColor?: string;\n shimmerSize?: string;\n borderRadius?: string;\n shimmerDuration?: string;\n background?: string;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport const ShimmerButton = React.forwardRef<\n HTMLButtonElement,\n ShimmerButtonProps\n>(\n (\n {\n shimmerColor = \"#ffffff\",\n shimmerSize = \"0.05em\",\n shimmerDuration = \"3s\",\n borderRadius = \"100px\",\n background = \"rgba(0, 0, 0, 1)\",\n className,\n children,\n ...props\n },\n ref\n ) => {\n return (\n \n {/* spark container */}\n \n {/* spark */}\n
\n {/* spark before */}\n
\n
\n
\n {children}\n\n {/* Highlight */}\n \n\n {/* backdrop */}\n \n \n );\n }\n);\n\nShimmerButton.displayName = \"ShimmerButton\";\n", + "content": "import React, { CSSProperties, ComponentPropsWithoutRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface ShimmerButtonProps extends ComponentPropsWithoutRef<\"button\"> {\n shimmerColor?: string;\n shimmerSize?: string;\n borderRadius?: string;\n shimmerDuration?: string;\n background?: string;\n className?: string;\n children?: React.ReactNode;\n}\n\nexport const ShimmerButton = React.forwardRef<\n HTMLButtonElement,\n ShimmerButtonProps\n>(\n (\n {\n shimmerColor = \"#ffffff\",\n shimmerSize = \"0.05em\",\n shimmerDuration = \"3s\",\n borderRadius = \"100px\",\n background = \"rgba(0, 0, 0, 1)\",\n className,\n children,\n ...props\n },\n ref,\n ) => {\n return (\n \n {/* spark container */}\n \n {/* spark */}\n
\n {/* spark before */}\n
\n
\n
\n {children}\n\n {/* Highlight */}\n \n\n {/* backdrop */}\n \n \n );\n },\n);\n\nShimmerButton.displayName = \"ShimmerButton\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/shine-border.json b/public/r/styles/default/shine-border.json index cb8469fcb..369020a92 100644 --- a/public/r/styles/default/shine-border.json +++ b/public/r/styles/default/shine-border.json @@ -4,7 +4,7 @@ "files": [ { "path": "magicui/shine-border.tsx", - "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype TColorProp = string | string[];\n\ninterface ShineBorderProps {\n borderRadius?: number;\n borderWidth?: number;\n duration?: number;\n color?: TColorProp;\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * @name Shine Border\n * @description It is an animated background border effect component with easy to use and configurable props.\n * @param borderRadius defines the radius of the border.\n * @param borderWidth defines the width of the border.\n * @param duration defines the animation duration to be applied on the shining border\n * @param color a string or string array to define border color.\n * @param className defines the class name to be applied to the component\n * @param children contains react node elements.\n */\nexport default function ShineBorder({\n borderRadius = 8,\n borderWidth = 1,\n duration = 14,\n color = \"#000000\",\n className,\n children,\n}: ShineBorderProps) {\n return (\n \n
\n {children}\n
\n );\n}\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype TColorProp = string | string[];\n\ninterface ShineBorderProps {\n borderRadius?: number;\n borderWidth?: number;\n duration?: number;\n color?: TColorProp;\n className?: string;\n children: React.ReactNode;\n}\n\n/**\n * @name Shine Border\n * @description It is an animated background border effect component with easy to use and configurable props.\n * @param borderRadius defines the radius of the border.\n * @param borderWidth defines the width of the border.\n * @param duration defines the animation duration to be applied on the shining border\n * @param color a string or string array to define border color.\n * @param className defines the class name to be applied to the component\n * @param children contains react node elements.\n */\nexport function ShineBorder({\n borderRadius = 8,\n borderWidth = 1,\n duration = 14,\n color = \"#000000\",\n className,\n children,\n}: ShineBorderProps) {\n return (\n \n \n {children}\n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/shiny-button.json b/public/r/styles/default/shiny-button.json index 1a6fd807c..d8bad36b9 100644 --- a/public/r/styles/default/shiny-button.json +++ b/public/r/styles/default/shiny-button.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/shiny-button.tsx", - "content": "\"use client\";\n\nimport React from \"react\";\nimport {\n motion,\n type AnimationProps,\n type HTMLMotionProps,\n} from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\nconst animationProps = {\n initial: { \"--x\": \"100%\", scale: 0.8 },\n animate: { \"--x\": \"-100%\", scale: 1 },\n whileTap: { scale: 0.95 },\n transition: {\n repeat: Infinity,\n repeatType: \"loop\",\n repeatDelay: 1,\n type: \"spring\",\n stiffness: 20,\n damping: 15,\n mass: 2,\n scale: {\n type: \"spring\",\n stiffness: 200,\n damping: 5,\n mass: 0.5,\n },\n },\n} as AnimationProps;\n\ninterface ShinyButtonProps extends HTMLMotionProps<\"button\"> {\n children: React.ReactNode;\n className?: string;\n ref?: React.Ref;\n}\n\nexport const ShinyButton = React.forwardRef<\n HTMLButtonElement,\n ShinyButtonProps\n>(({ children, className, ...props }, ref) => {\n return (\n \n \n {children}\n
\n \n \n );\n});\n\nShinyButton.displayName = \"ShinyButton\";\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, MotionProps, type AnimationProps } from \"motion/react\";\nimport React from \"react\";\n\nconst animationProps = {\n initial: { \"--x\": \"100%\", scale: 0.8 },\n animate: { \"--x\": \"-100%\", scale: 1 },\n whileTap: { scale: 0.95 },\n transition: {\n repeat: Infinity,\n repeatType: \"loop\",\n repeatDelay: 1,\n type: \"spring\",\n stiffness: 20,\n damping: 15,\n mass: 2,\n scale: {\n type: \"spring\",\n stiffness: 200,\n damping: 5,\n mass: 0.5,\n },\n },\n} as AnimationProps;\n\ninterface ShinyButtonProps\n extends Omit, keyof MotionProps>,\n MotionProps {\n children: React.ReactNode;\n className?: string;\n}\n\nexport const ShinyButton = React.forwardRef<\n HTMLButtonElement,\n ShinyButtonProps\n>(({ children, className, ...props }, ref) => {\n return (\n \n \n {children}\n \n \n \n );\n});\n\nShinyButton.displayName = \"ShinyButton\";\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/sparkles-text.json b/public/r/styles/default/sparkles-text.json index c360e3da4..3c2a1fb2f 100644 --- a/public/r/styles/default/sparkles-text.json +++ b/public/r/styles/default/sparkles-text.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/sparkles-text.tsx", - "content": "\"use client\";\n\nimport { CSSProperties, ReactElement, useEffect, useState } from \"react\";\nimport { motion } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface Sparkle {\n id: string;\n x: string;\n y: string;\n color: string;\n delay: number;\n scale: number;\n lifespan: number;\n}\n\ninterface SparklesTextProps {\n /**\n * @default
\n * @type ReactElement\n * @description\n * The component to be rendered as the text\n * */\n as?: ReactElement;\n\n /**\n * @default \"\"\n * @type string\n * @description\n * The className of the text\n */\n className?: string;\n\n /**\n * @required\n * @type string\n * @description\n * The text to be displayed\n * */\n text: string;\n\n /**\n * @default 10\n * @type number\n * @description\n * The count of sparkles\n * */\n sparklesCount?: number;\n\n /**\n * @default \"{first: '#9E7AFF', second: '#FE8BBB'}\"\n * @type string\n * @description\n * The colors of the sparkles\n * */\n colors?: {\n first: string;\n second: string;\n };\n}\n\nconst SparklesText: React.FC = ({\n text,\n colors = { first: \"#9E7AFF\", second: \"#FE8BBB\" },\n className,\n sparklesCount = 10,\n ...props\n}) => {\n const [sparkles, setSparkles] = useState([]);\n\n useEffect(() => {\n const generateStar = (): Sparkle => {\n const starX = `${Math.random() * 100}%`;\n const starY = `${Math.random() * 100}%`;\n const color = Math.random() > 0.5 ? colors.first : colors.second;\n const delay = Math.random() * 2;\n const scale = Math.random() * 1 + 0.3;\n const lifespan = Math.random() * 10 + 5;\n const id = `${starX}-${starY}-${Date.now()}`;\n return { id, x: starX, y: starY, color, delay, scale, lifespan };\n };\n\n const initializeStars = () => {\n const newSparkles = Array.from({ length: sparklesCount }, generateStar);\n setSparkles(newSparkles);\n };\n\n const updateStars = () => {\n setSparkles((currentSparkles) =>\n currentSparkles.map((star) => {\n if (star.lifespan <= 0) {\n return generateStar();\n } else {\n return { ...star, lifespan: star.lifespan - 0.1 };\n }\n }),\n );\n };\n\n initializeStars();\n const interval = setInterval(updateStars, 100);\n\n return () => clearInterval(interval);\n }, [colors.first, colors.second, sparklesCount]);\n\n return (\n \n \n {sparkles.map((sparkle) => (\n \n ))}\n {text}\n \n
\n );\n};\n\nconst Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => {\n return (\n \n \n \n );\n};\n\nexport default SparklesText;\n", + "content": "\"use client\";\n\nimport { motion } from \"motion/react\";\nimport { CSSProperties, ReactElement, useEffect, useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface Sparkle {\n id: string;\n x: string;\n y: string;\n color: string;\n delay: number;\n scale: number;\n lifespan: number;\n}\n\nconst Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => {\n return (\n \n \n \n );\n};\n\ninterface SparklesTextProps {\n /**\n * @default
\n * @type ReactElement\n * @description\n * The component to be rendered as the text\n * */\n as?: ReactElement;\n\n /**\n * @default \"\"\n * @type string\n * @description\n * The className of the text\n */\n className?: string;\n\n /**\n * @required\n * @type string\n * @description\n * The text to be displayed\n * */\n text: string;\n\n /**\n * @default 10\n * @type number\n * @description\n * The count of sparkles\n * */\n sparklesCount?: number;\n\n /**\n * @default \"{first: '#9E7AFF', second: '#FE8BBB'}\"\n * @type string\n * @description\n * The colors of the sparkles\n * */\n colors?: {\n first: string;\n second: string;\n };\n}\n\nexport const SparklesText: React.FC = ({\n text,\n colors = { first: \"#9E7AFF\", second: \"#FE8BBB\" },\n className,\n sparklesCount = 10,\n ...props\n}) => {\n const [sparkles, setSparkles] = useState([]);\n\n useEffect(() => {\n const generateStar = (): Sparkle => {\n const starX = `${Math.random() * 100}%`;\n const starY = `${Math.random() * 100}%`;\n const color = Math.random() > 0.5 ? colors.first : colors.second;\n const delay = Math.random() * 2;\n const scale = Math.random() * 1 + 0.3;\n const lifespan = Math.random() * 10 + 5;\n const id = `${starX}-${starY}-${Date.now()}`;\n return { id, x: starX, y: starY, color, delay, scale, lifespan };\n };\n\n const initializeStars = () => {\n const newSparkles = Array.from({ length: sparklesCount }, generateStar);\n setSparkles(newSparkles);\n };\n\n const updateStars = () => {\n setSparkles((currentSparkles) =>\n currentSparkles.map((star) => {\n if (star.lifespan <= 0) {\n return generateStar();\n } else {\n return { ...star, lifespan: star.lifespan - 0.1 };\n }\n }),\n );\n };\n\n initializeStars();\n const interval = setInterval(updateStars, 100);\n\n return () => clearInterval(interval);\n }, [colors.first, colors.second, sparklesCount]);\n\n return (\n \n \n {sparkles.map((sparkle) => (\n \n ))}\n {text}\n \n
\n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/text-reveal.json b/public/r/styles/default/text-reveal.json index 4a71a248d..a55fdaca4 100644 --- a/public/r/styles/default/text-reveal.json +++ b/public/r/styles/default/text-reveal.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/text-reveal.tsx", - "content": "\"use client\";\n\nimport { FC, ReactNode, useRef } from \"react\";\nimport { motion, MotionValue, useScroll, useTransform } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface TextRevealByWordProps {\n text: string;\n className?: string;\n}\n\nexport const TextRevealByWord: FC = ({\n text,\n className,\n}) => {\n const targetRef = useRef(null);\n\n const { scrollYProgress } = useScroll({\n target: targetRef,\n });\n const words = text.split(\" \");\n\n return (\n
\n \n \n {words.map((word, i) => {\n const start = i / words.length;\n const end = start + 1 / words.length;\n return (\n \n {word}\n \n );\n })}\n

\n
\n \n );\n};\n\ninterface WordProps {\n children: ReactNode;\n progress: MotionValue;\n range: [number, number];\n}\n\nconst Word: FC = ({ children, progress, range }) => {\n const opacity = useTransform(progress, range, [0, 1]);\n return (\n \n {children}\n \n {children}\n \n \n );\n};\n\nexport default TextRevealByWord;\n", + "content": "\"use client\";\n\nimport { motion, MotionValue, useScroll, useTransform } from \"motion/react\";\nimport { ComponentPropsWithoutRef, FC, ReactNode, useRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface TextRevealProps extends ComponentPropsWithoutRef<\"div\"> {\n text: string;\n}\n\nexport const TextReveal: FC = ({ text, className }) => {\n const targetRef = useRef(null);\n\n const { scrollYProgress } = useScroll({\n target: targetRef,\n });\n const words = text.split(\" \");\n\n return (\n
\n \n \n {words.map((word, i) => {\n const start = i / words.length;\n const end = start + 1 / words.length;\n return (\n \n {word}\n \n );\n })}\n

\n
\n \n );\n};\n\ninterface WordProps {\n children: ReactNode;\n progress: MotionValue;\n range: [number, number];\n}\n\nconst Word: FC = ({ children, progress, range }) => {\n const opacity = useTransform(progress, range, [0, 1]);\n return (\n \n {children}\n \n {children}\n \n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/tweet-card.json b/public/r/styles/default/tweet-card.json index 7f6e42e80..c6967c602 100644 --- a/public/r/styles/default/tweet-card.json +++ b/public/r/styles/default/tweet-card.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/tweet-card.tsx", - "content": "import { Suspense } from \"react\";\nimport {\n enrichTweet,\n type EnrichedTweet,\n type TweetProps,\n type TwitterComponents,\n} from \"react-tweet\";\nimport { getTweet, type Tweet } from \"react-tweet/api\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface TwitterIconProps {\n className?: string;\n [key: string]: unknown;\n}\nconst Twitter = ({ className, ...props }: TwitterIconProps) => (\n \n \n \n \n \n \n);\n\nconst Verified = ({ className, ...props }: TwitterIconProps) => (\n \n \n \n \n \n);\n\nexport const truncate = (str: string | null, length: number) => {\n if (!str || str.length <= length) return str;\n return `${str.slice(0, length - 3)}...`;\n};\n\nconst Skeleton = ({\n className,\n ...props\n}: React.HTMLAttributes) => {\n return (\n
\n );\n};\n\nexport const TweetSkeleton = ({\n className,\n ...props\n}: {\n className?: string;\n [key: string]: unknown;\n}) => (\n \n
\n \n \n
\n \n
\n);\n\nexport const TweetNotFound = ({\n className,\n ...props\n}: {\n className?: string;\n [key: string]: unknown;\n}) => (\n \n

Tweet not found

\n \n);\n\nexport const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n
\n \n \n \n
\n \n {truncate(tweet.user.name, 20)}\n {tweet.user.verified ||\n (tweet.user.is_blue_verified && (\n \n ))}\n \n
\n \n @{truncate(tweet.user.screen_name, 16)}\n \n
\n
\n
\n \n Link to tweet\n \n \n
\n);\n\nexport const TweetBody = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n {tweet.entities.map((entity, idx) => {\n switch (entity.type) {\n case \"url\":\n case \"symbol\":\n case \"hashtag\":\n case \"mention\":\n return (\n \n {entity.text}\n \n );\n case \"text\":\n return (\n \n );\n }\n })}\n
\n);\n\nexport const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n {tweet.video && (\n \n \n Your browser does not support the video tag.\n \n )}\n {tweet.photos && (\n
\n
\n {tweet.photos.map((photo) => (\n \n ))}\n
\n
\n )}\n {!tweet.video &&\n !tweet.photos &&\n // @ts-ignore\n tweet?.card?.binding_values?.thumbnail_image_large?.image_value.url && (\n \n )}\n
\n);\n\nexport const MagicTweet = ({\n tweet,\n components,\n className,\n ...props\n}: {\n tweet: Tweet;\n components?: TwitterComponents;\n className?: string;\n}) => {\n const enrichedTweet = enrichTweet(tweet);\n return (\n \n \n \n \n
\n );\n};\n\n/**\n * TweetCard (Server Side Only)\n */\nexport const TweetCard = async ({\n id,\n components,\n fallback = ,\n onError,\n ...props\n}: TweetProps & {\n className?: string;\n}) => {\n const tweet = id\n ? await getTweet(id).catch((err) => {\n if (onError) {\n onError(err);\n } else {\n console.error(err);\n }\n })\n : undefined;\n\n if (!tweet) {\n const NotFound = components?.TweetNotFound || TweetNotFound;\n return ;\n }\n\n return (\n \n \n \n );\n};\n\nexport default TweetCard;\n", + "content": "import { Suspense } from \"react\";\nimport {\n enrichTweet,\n type EnrichedTweet,\n type TweetProps,\n type TwitterComponents,\n} from \"react-tweet\";\nimport { getTweet, type Tweet } from \"react-tweet/api\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface TwitterIconProps {\n className?: string;\n [key: string]: unknown;\n}\nconst Twitter = ({ className, ...props }: TwitterIconProps) => (\n \n \n \n \n \n \n);\n\nconst Verified = ({ className, ...props }: TwitterIconProps) => (\n \n \n \n \n \n);\n\nexport const truncate = (str: string | null, length: number) => {\n if (!str || str.length <= length) return str;\n return `${str.slice(0, length - 3)}...`;\n};\n\nconst Skeleton = ({\n className,\n ...props\n}: React.HTMLAttributes) => {\n return (\n
\n );\n};\n\nexport const TweetSkeleton = ({\n className,\n ...props\n}: {\n className?: string;\n [key: string]: unknown;\n}) => (\n \n
\n \n \n
\n \n
\n);\n\nexport const TweetNotFound = ({\n className,\n ...props\n}: {\n className?: string;\n [key: string]: unknown;\n}) => (\n \n

Tweet not found

\n
\n);\n\nexport const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n
\n \n \n \n
\n \n {truncate(tweet.user.name, 20)}\n {tweet.user.verified ||\n (tweet.user.is_blue_verified && (\n \n ))}\n \n
\n \n @{truncate(tweet.user.screen_name, 16)}\n \n
\n
\n
\n \n Link to tweet\n \n \n
\n);\n\nexport const TweetBody = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n {tweet.entities.map((entity, idx) => {\n switch (entity.type) {\n case \"url\":\n case \"symbol\":\n case \"hashtag\":\n case \"mention\":\n return (\n \n {entity.text}\n \n );\n case \"text\":\n return (\n \n );\n }\n })}\n
\n);\n\nexport const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => (\n
\n {tweet.video && (\n \n \n Your browser does not support the video tag.\n \n )}\n {tweet.photos && (\n
\n
\n {tweet.photos.map((photo) => (\n \n ))}\n
\n
\n )}\n {!tweet.video &&\n !tweet.photos &&\n // @ts-ignore\n tweet?.card?.binding_values?.thumbnail_image_large?.image_value.url && (\n \n )}\n
\n);\n\nexport const MagicTweet = ({\n tweet,\n components,\n className,\n ...props\n}: {\n tweet: Tweet;\n components?: TwitterComponents;\n className?: string;\n}) => {\n const enrichedTweet = enrichTweet(tweet);\n return (\n \n \n \n \n
\n );\n};\n\n/**\n * TweetCard (Server Side Only)\n */\nexport const TweetCard = async ({\n id,\n components,\n fallback = ,\n onError,\n ...props\n}: TweetProps & {\n className?: string;\n}) => {\n const tweet = id\n ? await getTweet(id).catch((err) => {\n if (onError) {\n onError(err);\n } else {\n console.error(err);\n }\n })\n : undefined;\n\n if (!tweet) {\n const NotFound = components?.TweetNotFound || TweetNotFound;\n return ;\n }\n\n return (\n \n \n \n );\n};\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/typing-animation.json b/public/r/styles/default/typing-animation.json index 34bbcaadf..e898a6f9a 100644 --- a/public/r/styles/default/typing-animation.json +++ b/public/r/styles/default/typing-animation.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/typing-animation.tsx", - "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, MotionProps } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\n\ninterface TypingAnimationProps extends MotionProps {\n children: string;\n className?: string;\n duration?: number;\n delay?: number;\n as?: React.ElementType;\n startOnView?: boolean;\n}\n\nexport default function TypingAnimation({\n children,\n className,\n duration = 100,\n delay = 0,\n as: Component = \"div\",\n startOnView = false,\n ...props\n}: TypingAnimationProps) {\n const MotionComponent = motion.create(Component, {\n forwardMotionProps: true,\n });\n\n const [displayedText, setDisplayedText] = useState(\"\");\n const [started, setStarted] = useState(false);\n const elementRef = useRef(null);\n\n useEffect(() => {\n if (!startOnView) {\n const startTimeout = setTimeout(() => {\n setStarted(true);\n }, delay);\n return () => clearTimeout(startTimeout);\n }\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setTimeout(() => {\n setStarted(true);\n }, delay);\n observer.disconnect();\n }\n },\n { threshold: 0.1 },\n );\n\n if (elementRef.current) {\n observer.observe(elementRef.current);\n }\n\n return () => observer.disconnect();\n }, [delay, startOnView]);\n\n useEffect(() => {\n if (!started) return;\n\n let i = 0;\n const typingEffect = setInterval(() => {\n if (i < children.length) {\n setDisplayedText(children.substring(0, i + 1));\n i++;\n } else {\n clearInterval(typingEffect);\n }\n }, duration);\n\n return () => {\n clearInterval(typingEffect);\n };\n }, [children, duration, started]);\n\n return (\n \n {displayedText}\n \n );\n}\n", + "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { motion, MotionProps } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\n\ninterface TypingAnimationProps extends MotionProps {\n children: string;\n className?: string;\n duration?: number;\n delay?: number;\n as?: React.ElementType;\n startOnView?: boolean;\n}\n\nexport function TypingAnimation({\n children,\n className,\n duration = 100,\n delay = 0,\n as: Component = \"div\",\n startOnView = false,\n ...props\n}: TypingAnimationProps) {\n const MotionComponent = motion.create(Component, {\n forwardMotionProps: true,\n });\n\n const [displayedText, setDisplayedText] = useState(\"\");\n const [started, setStarted] = useState(false);\n const elementRef = useRef(null);\n\n useEffect(() => {\n if (!startOnView) {\n const startTimeout = setTimeout(() => {\n setStarted(true);\n }, delay);\n return () => clearTimeout(startTimeout);\n }\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setTimeout(() => {\n setStarted(true);\n }, delay);\n observer.disconnect();\n }\n },\n { threshold: 0.1 },\n );\n\n if (elementRef.current) {\n observer.observe(elementRef.current);\n }\n\n return () => observer.disconnect();\n }, [delay, startOnView]);\n\n useEffect(() => {\n if (!started) return;\n\n let i = 0;\n const typingEffect = setInterval(() => {\n if (i < children.length) {\n setDisplayedText(children.substring(0, i + 1));\n i++;\n } else {\n clearInterval(typingEffect);\n }\n }, duration);\n\n return () => {\n clearInterval(typingEffect);\n };\n }, [children, duration, started]);\n\n return (\n \n {displayedText}\n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/public/r/styles/default/word-rotate.json b/public/r/styles/default/word-rotate.json index ab2469a3d..7e00b1a36 100644 --- a/public/r/styles/default/word-rotate.json +++ b/public/r/styles/default/word-rotate.json @@ -7,7 +7,7 @@ "files": [ { "path": "magicui/word-rotate.tsx", - "content": "\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { AnimatePresence, motion, MotionProps } from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface WordRotateProps {\n words: string[];\n duration?: number;\n framerProps?: MotionProps;\n className?: string;\n}\n\nexport default function WordRotate({\n words,\n duration = 2500,\n framerProps = {\n initial: { opacity: 0, y: -50 },\n animate: { opacity: 1, y: 0 },\n exit: { opacity: 0, y: 50 },\n transition: { duration: 0.25, ease: \"easeOut\" },\n },\n className,\n}: WordRotateProps) {\n const [index, setIndex] = useState(0);\n\n useEffect(() => {\n const interval = setInterval(() => {\n setIndex((prevIndex) => (prevIndex + 1) % words.length);\n }, duration);\n\n // Clean up interval on unmount\n return () => clearInterval(interval);\n }, [words, duration]);\n\n return (\n
\n \n \n {words[index]}\n \n \n
\n );\n}\n", + "content": "\"use client\";\n\nimport { AnimatePresence, motion, MotionProps } from \"motion/react\";\nimport { useEffect, useState } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface WordRotateProps {\n words: string[];\n duration?: number;\n motionProps?: MotionProps;\n className?: string;\n}\n\nexport function WordRotate({\n words,\n duration = 2500,\n motionProps = {\n initial: { opacity: 0, y: -50 },\n animate: { opacity: 1, y: 0 },\n exit: { opacity: 0, y: 50 },\n transition: { duration: 0.25, ease: \"easeOut\" },\n },\n className,\n}: WordRotateProps) {\n const [index, setIndex] = useState(0);\n\n useEffect(() => {\n const interval = setInterval(() => {\n setIndex((prevIndex) => (prevIndex + 1) % words.length);\n }, duration);\n\n // Clean up interval on unmount\n return () => clearInterval(interval);\n }, [words, duration]);\n\n return (\n
\n \n \n {words[index]}\n \n \n
\n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/registry/default/example/animated-circular-progress-bar-demo.tsx b/registry/default/example/animated-circular-progress-bar-demo.tsx index 973cb1c77..7b67729ef 100644 --- a/registry/default/example/animated-circular-progress-bar-demo.tsx +++ b/registry/default/example/animated-circular-progress-bar-demo.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; -import AnimatedCircularProgressBar from "@/registry/default/magicui/animated-circular-progress-bar"; +import { AnimatedCircularProgressBar } from "@/registry/default/magicui/animated-circular-progress-bar"; export default function AnimatedCircularProgressBarDemo() { const [value, setValue] = useState(0); diff --git a/registry/default/example/animated-gradient-text-demo.tsx b/registry/default/example/animated-gradient-text-demo.tsx index bed4d77f2..5c78185c1 100644 --- a/registry/default/example/animated-gradient-text-demo.tsx +++ b/registry/default/example/animated-gradient-text-demo.tsx @@ -1,7 +1,7 @@ import { ChevronRight } from "lucide-react"; import { cn } from "@/lib/utils"; -import AnimatedGradientText from "@/registry/default/magicui/animated-gradient-text"; +import { AnimatedGradientText } from "@/registry/default/magicui/animated-gradient-text"; export default async function AnimatedGradientTextDemo() { return ( diff --git a/registry/default/example/animated-grid-pattern-demo.tsx b/registry/default/example/animated-grid-pattern-demo.tsx index c064e619a..8810d96b6 100644 --- a/registry/default/example/animated-grid-pattern-demo.tsx +++ b/registry/default/example/animated-grid-pattern-demo.tsx @@ -1,5 +1,5 @@ import { cn } from "@/lib/utils"; -import AnimatedGridPattern from "@/registry/default/magicui/animated-grid-pattern"; +import { AnimatedGridPattern } from "@/registry/default/magicui/animated-grid-pattern"; export default function AnimatedGridPatternDemo() { return ( diff --git a/registry/default/example/animated-list-demo.tsx b/registry/default/example/animated-list-demo.tsx index 237a914de..a065e8f8c 100644 --- a/registry/default/example/animated-list-demo.tsx +++ b/registry/default/example/animated-list-demo.tsx @@ -90,7 +90,7 @@ export default function AnimatedListDemo({ return (
diff --git a/registry/default/example/animated-shiny-text-demo.tsx b/registry/default/example/animated-shiny-text-demo.tsx index dd1120671..3171c7b0b 100644 --- a/registry/default/example/animated-shiny-text-demo.tsx +++ b/registry/default/example/animated-shiny-text-demo.tsx @@ -1,9 +1,9 @@ import { ArrowRightIcon } from "@radix-ui/react-icons"; import { cn } from "@/lib/utils"; -import AnimatedShinyText from "@/registry/default/magicui/animated-shiny-text"; +import { AnimatedShinyText } from "@/registry/default/magicui/animated-shiny-text"; -export default async function AnimatedShinyTextDemo() { +export default function AnimatedShinyTextDemo() { return (
{ const isLandscape = i % 2 === 0; diff --git a/registry/default/example/blur-fade-text-demo.tsx b/registry/default/example/blur-fade-text-demo.tsx index 8e6e2f067..fa5a76940 100644 --- a/registry/default/example/blur-fade-text-demo.tsx +++ b/registry/default/example/blur-fade-text-demo.tsx @@ -1,4 +1,4 @@ -import BlurFade from "@/registry/default/magicui/blur-fade"; +import { BlurFade } from "@/registry/default/magicui/blur-fade"; export default function BlurFadeTextDemo() { return ( diff --git a/registry/default/example/box-reveal-demo.tsx b/registry/default/example/box-reveal-demo.tsx index 68e0d7228..4cd71947d 100644 --- a/registry/default/example/box-reveal-demo.tsx +++ b/registry/default/example/box-reveal-demo.tsx @@ -1,7 +1,7 @@ import { Button } from "@/components/ui/button"; -import BoxReveal from "@/registry/default/magicui/box-reveal"; +import { BoxReveal } from "@/registry/default/magicui/box-reveal"; -export default async function BoxRevealDemo() { +export default function BoxRevealDemo() { return (
diff --git a/registry/default/example/confetti-demo.tsx b/registry/default/example/confetti-demo.tsx index b786888e7..478019bf0 100644 --- a/registry/default/example/confetti-demo.tsx +++ b/registry/default/example/confetti-demo.tsx @@ -2,8 +2,10 @@ import { useRef } from "react"; -import type { ConfettiRef } from "@/registry/default/magicui/confetti"; -import Confetti from "@/registry/default/magicui/confetti"; +import { + Confetti, + type ConfettiRef, +} from "@/registry/default/magicui/confetti"; export default function ConfettiDemo() { const confettiRef = useRef(null); diff --git a/registry/default/example/flickering-grid-demo.tsx b/registry/default/example/flickering-grid-demo.tsx index 1186ca9d3..c617caa41 100644 --- a/registry/default/example/flickering-grid-demo.tsx +++ b/registry/default/example/flickering-grid-demo.tsx @@ -1,10 +1,10 @@ -import FlickeringGrid from "@/registry/default/magicui/flickering-grid"; +import { FlickeringGrid } from "@/registry/default/magicui/flickering-grid"; export default function FlickeringGridDemo() { return ( -
+
+
Hover Me!; diff --git a/registry/default/example/marquee-3d.tsx b/registry/default/example/marquee-3d.tsx index 6f2c29993..a6a5a81fb 100644 --- a/registry/default/example/marquee-3d.tsx +++ b/registry/default/example/marquee-3d.tsx @@ -1,4 +1,4 @@ -import Marquee from "@/registry/default/magicui/marquee"; +import { Marquee } from "@/registry/default/magicui/marquee"; const logos = [ { diff --git a/registry/default/example/marquee-demo-vertical.tsx b/registry/default/example/marquee-demo-vertical.tsx index 23fd8dac2..498e914b8 100644 --- a/registry/default/example/marquee-demo-vertical.tsx +++ b/registry/default/example/marquee-demo-vertical.tsx @@ -1,5 +1,5 @@ import { cn } from "@/lib/utils"; -import Marquee from "@/registry/default/magicui/marquee"; +import { Marquee } from "@/registry/default/magicui/marquee"; const reviews = [ { diff --git a/registry/default/example/marquee-demo.tsx b/registry/default/example/marquee-demo.tsx index 33c707bc4..de2bdbc4b 100644 --- a/registry/default/example/marquee-demo.tsx +++ b/registry/default/example/marquee-demo.tsx @@ -1,5 +1,5 @@ import { cn } from "@/lib/utils"; -import Marquee from "@/registry/default/magicui/marquee"; +import { Marquee } from "@/registry/default/magicui/marquee"; const reviews = [ { diff --git a/registry/default/example/marquee-logos.tsx b/registry/default/example/marquee-logos.tsx index 3cc1e43d5..837189aa5 100644 --- a/registry/default/example/marquee-logos.tsx +++ b/registry/default/example/marquee-logos.tsx @@ -1,5 +1,5 @@ import { cn } from "@/lib/utils"; -import Marquee from "@/registry/default/magicui/marquee"; +import { Marquee } from "@/registry/default/magicui/marquee"; const logos = [ { diff --git a/registry/default/example/morphing-text-demo.tsx b/registry/default/example/morphing-text-demo.tsx index d2f45afcb..703d5237a 100644 --- a/registry/default/example/morphing-text-demo.tsx +++ b/registry/default/example/morphing-text-demo.tsx @@ -1,4 +1,4 @@ -import MorphingText from "@/registry/default/magicui/morphing-text"; +import { MorphingText } from "@/registry/default/magicui/morphing-text"; const texts = [ "Hello", diff --git a/registry/default/example/number-ticker-decimal-demo.tsx b/registry/default/example/number-ticker-decimal-demo.tsx index fb6d8c122..af982c842 100644 --- a/registry/default/example/number-ticker-decimal-demo.tsx +++ b/registry/default/example/number-ticker-decimal-demo.tsx @@ -1,9 +1,11 @@ -import NumberTicker from "@/registry/default/magicui/number-ticker"; +import { NumberTicker } from "@/registry/default/magicui/number-ticker"; export default function NumberTickerDemo() { return ( -

- -

+ ); } diff --git a/registry/default/example/number-ticker-demo.tsx b/registry/default/example/number-ticker-demo.tsx index 16e0847d0..91ba3e4f7 100644 --- a/registry/default/example/number-ticker-demo.tsx +++ b/registry/default/example/number-ticker-demo.tsx @@ -1,9 +1,10 @@ -import NumberTicker from "@/registry/default/magicui/number-ticker"; +import { NumberTicker } from "@/registry/default/magicui/number-ticker"; export default function NumberTickerDemo() { return ( -

- -

+ ); } diff --git a/registry/default/example/particles-demo.tsx b/registry/default/example/particles-demo.tsx index 1fd8517ea..2e7f38170 100644 --- a/registry/default/example/particles-demo.tsx +++ b/registry/default/example/particles-demo.tsx @@ -3,7 +3,7 @@ import { useTheme } from "next-themes"; import { useEffect, useState } from "react"; -import Particles from "@/registry/default/magicui/particles"; +import { Particles } from "@/registry/default/magicui/particles"; export default function ParticlesDemo() { const { resolvedTheme } = useTheme(); diff --git a/registry/default/example/retro-grid-demo.tsx b/registry/default/example/retro-grid-demo.tsx index ff4fe0897..618cec35c 100644 --- a/registry/default/example/retro-grid-demo.tsx +++ b/registry/default/example/retro-grid-demo.tsx @@ -1,6 +1,6 @@ "use client"; -import RetroGrid from "@/registry/default/magicui/retro-grid"; +import { RetroGrid } from "@/registry/default/magicui/retro-grid"; export default function RetroGridDemo() { return ( diff --git a/registry/default/example/ripple-demo.tsx b/registry/default/example/ripple-demo.tsx index 4f89b4c45..682f15100 100644 --- a/registry/default/example/ripple-demo.tsx +++ b/registry/default/example/ripple-demo.tsx @@ -1,4 +1,4 @@ -import Ripple from "@/registry/default/magicui/ripple"; +import { Ripple } from "@/registry/default/magicui/ripple"; export default function RippleDemo() { return ( diff --git a/registry/default/example/scratch-to-reveal-demo.tsx b/registry/default/example/scratch-to-reveal-demo.tsx index 18b051c66..e7c067d02 100644 --- a/registry/default/example/scratch-to-reveal-demo.tsx +++ b/registry/default/example/scratch-to-reveal-demo.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import ScratchToReveal from "@/components/magicui/scratch-to-reveal"; +import { ScratchToReveal } from "@/registry/default/magicui/scratch-to-reveal"; const ScratchToRevealDemo = () => { const handleComplete = () => { @@ -7,18 +6,16 @@ const ScratchToRevealDemo = () => { }; return ( -
- -

😎

-
-
+ +

😎

+
); }; diff --git a/registry/default/example/script-copy-btn-demo.tsx b/registry/default/example/script-copy-btn-demo.tsx index 5b4da0ade..acfd3e4e3 100644 --- a/registry/default/example/script-copy-btn-demo.tsx +++ b/registry/default/example/script-copy-btn-demo.tsx @@ -1,4 +1,4 @@ -import ScriptCopyBtn from "@/registry/default/magicui/script-copy-btn"; +import { ScriptCopyBtn } from "@/registry/default/magicui/script-copy-btn"; export default function ScriptCopyBtnDemo() { const customCommandMap = { @@ -8,14 +8,12 @@ export default function ScriptCopyBtnDemo() { bun: "bun x shadcn@latest add button", }; return ( - <> - - + ); } diff --git a/registry/default/example/scroll-progress-demo.tsx b/registry/default/example/scroll-progress-demo.tsx index cb05b66d5..1f4dc76ab 100644 --- a/registry/default/example/scroll-progress-demo.tsx +++ b/registry/default/example/scroll-progress-demo.tsx @@ -1,6 +1,6 @@ -import ScrollProgress from "@/registry/default/magicui/scroll-progress"; +import { ScrollProgress } from "@/registry/default/magicui/scroll-progress"; -const ScrollProgressDemo = () => { +export default function ScrollProgressDemo() { return (
@@ -15,6 +15,4 @@ const ScrollProgressDemo = () => {

); -}; - -export default ScrollProgressDemo; +} diff --git a/registry/default/example/shine-border-demo-2.tsx b/registry/default/example/shine-border-demo-2.tsx index b3313543d..7e6437b70 100644 --- a/registry/default/example/shine-border-demo-2.tsx +++ b/registry/default/example/shine-border-demo-2.tsx @@ -1,6 +1,6 @@ import { useTheme } from "next-themes"; -import ShineBorder from "@/registry/default/magicui/shine-border"; +import { ShineBorder } from "@/registry/default/magicui/shine-border"; export default function ShineBorderDemo() { const theme = useTheme(); diff --git a/registry/default/example/shine-border-demo.tsx b/registry/default/example/shine-border-demo.tsx index 2af53c1be..2c48e2d75 100644 --- a/registry/default/example/shine-border-demo.tsx +++ b/registry/default/example/shine-border-demo.tsx @@ -1,4 +1,4 @@ -import ShineBorder from "@/registry/default/magicui/shine-border"; +import { ShineBorder } from "@/registry/default/magicui/shine-border"; export default function ShineBorderDemo() { return ( diff --git a/registry/default/example/sparkles-text-demo.tsx b/registry/default/example/sparkles-text-demo.tsx index 57dbd9be0..9db7c8b6e 100644 --- a/registry/default/example/sparkles-text-demo.tsx +++ b/registry/default/example/sparkles-text-demo.tsx @@ -1,4 +1,4 @@ -import SparklesText from "@/registry/default/magicui/sparkles-text"; +import { SparklesText } from "@/registry/default/magicui/sparkles-text"; export default function SparklesTextDemo() { return ; diff --git a/registry/default/example/text-reveal-demo.tsx b/registry/default/example/text-reveal-demo.tsx index bef4f001c..d47232e6f 100644 --- a/registry/default/example/text-reveal-demo.tsx +++ b/registry/default/example/text-reveal-demo.tsx @@ -1,4 +1,4 @@ -import TextReveal from "@/registry/default/magicui/text-reveal"; +import { TextReveal } from "@/registry/default/magicui/text-reveal"; export default function TextRevealDemo() { return ( diff --git a/registry/default/example/tweet-card-demo.tsx b/registry/default/example/tweet-card-demo.tsx index c6223c0eb..0b8a72705 100644 --- a/registry/default/example/tweet-card-demo.tsx +++ b/registry/default/example/tweet-card-demo.tsx @@ -1,4 +1,4 @@ -import ClientTweetCard from "@/registry/default/magicui/client-tweet-card"; +import { ClientTweetCard } from "@/registry/default/magicui/client-tweet-card"; /** * (Server Side Only) diff --git a/registry/default/example/tweet-card-images.tsx b/registry/default/example/tweet-card-images.tsx index 1ee4a8bd7..2984539ac 100644 --- a/registry/default/example/tweet-card-images.tsx +++ b/registry/default/example/tweet-card-images.tsx @@ -1,5 +1,5 @@ -import ClientTweetCard from "@/registry/default/magicui/client-tweet-card"; +import { ClientTweetCard } from "@/registry/default/magicui/client-tweet-card"; -export default async function TweetImages() { +export default function TweetImages() { return ; } diff --git a/registry/default/example/tweet-card-meta-preview.tsx b/registry/default/example/tweet-card-meta-preview.tsx index 3b87e30f3..31a2f1ed1 100644 --- a/registry/default/example/tweet-card-meta-preview.tsx +++ b/registry/default/example/tweet-card-meta-preview.tsx @@ -1,4 +1,4 @@ -import ClientTweetCard from "@/registry/default/magicui/client-tweet-card"; +import { ClientTweetCard } from "@/registry/default/magicui/client-tweet-card"; export default function TweetMetaPreview() { return ; diff --git a/registry/default/example/typing-animation-demo.tsx b/registry/default/example/typing-animation-demo.tsx index dae36ac9e..54fb584b1 100644 --- a/registry/default/example/typing-animation-demo.tsx +++ b/registry/default/example/typing-animation-demo.tsx @@ -1,4 +1,4 @@ -import TypingAnimation from "@/registry/default/magicui/typing-animation"; +import { TypingAnimation } from "@/registry/default/magicui/typing-animation"; export default function TypingAnimationDemo() { return Typing Animation; diff --git a/registry/default/example/word-rotate-demo.tsx b/registry/default/example/word-rotate-demo.tsx index 011394e49..446803ab2 100644 --- a/registry/default/example/word-rotate-demo.tsx +++ b/registry/default/example/word-rotate-demo.tsx @@ -1,4 +1,4 @@ -import WordRotate from "@/registry/default/magicui/word-rotate"; +import { WordRotate } from "@/registry/default/magicui/word-rotate"; export default function WordRotateDemo() { return ( diff --git a/registry/default/magicui/animated-circular-progress-bar.tsx b/registry/default/magicui/animated-circular-progress-bar.tsx index 979644be5..a9823e367 100644 --- a/registry/default/magicui/animated-circular-progress-bar.tsx +++ b/registry/default/magicui/animated-circular-progress-bar.tsx @@ -1,6 +1,6 @@ import { cn } from "@/lib/utils"; -interface Props { +interface AnimatedCircularProgressBarProps { max: number; value: number; min: number; @@ -9,14 +9,14 @@ interface Props { className?: string; } -export default function AnimatedCircularProgressBar({ +export function AnimatedCircularProgressBar({ max = 100, min = 0, value = 0, gaugePrimaryColor, gaugeSecondaryColor, className, -}: Props) { +}: AnimatedCircularProgressBarProps) { const circumference = 2 * Math.PI * 45; const percentPx = circumference / 100; const currentPercent = Math.round(((value - min) / (max - min)) * 100); diff --git a/registry/default/magicui/animated-gradient-text.tsx b/registry/default/magicui/animated-gradient-text.tsx index 19b0e6281..adfcab89b 100644 --- a/registry/default/magicui/animated-gradient-text.tsx +++ b/registry/default/magicui/animated-gradient-text.tsx @@ -1,20 +1,24 @@ -import { ReactNode } from "react"; +import { ComponentPropsWithoutRef, ReactNode } from "react"; import { cn } from "@/lib/utils"; -export default function AnimatedGradientText({ +export interface AnimatedGradientTextProps + extends ComponentPropsWithoutRef<"div"> { + children: ReactNode; +} + +export function AnimatedGradientText({ children, className, -}: { - children: ReactNode; - className?: string; -}) { + ...props +}: AnimatedGradientTextProps) { return (
{ width?: number; height?: number; x?: number; y?: number; strokeDasharray?: any; numSquares?: number; - className?: string; maxOpacity?: number; duration?: number; repeatDelay?: number; } -export default function AnimatedGridPattern({ +export function AnimatedGridPattern({ width = 40, height = 40, x = -1, diff --git a/registry/default/magicui/animated-list.tsx b/registry/default/magicui/animated-list.tsx index 66a730bf5..26a65a3db 100644 --- a/registry/default/magicui/animated-list.tsx +++ b/registry/default/magicui/animated-list.tsx @@ -1,16 +1,35 @@ "use client"; import { AnimatePresence, motion } from "motion/react"; -import React, { useEffect, useMemo, useState } from "react"; +import React, { + ComponentPropsWithoutRef, + useEffect, + useMemo, + useState, +} from "react"; -export interface AnimatedListProps { - className?: string; +export function AnimatedListItem({ children }: { children: React.ReactNode }) { + const animations = { + initial: { scale: 0, opacity: 0 }, + animate: { scale: 1, opacity: 1, originY: 0 }, + exit: { scale: 0, opacity: 0 }, + transition: { type: "spring", stiffness: 350, damping: 40 }, + }; + + return ( + + {children} + + ); +} + +export interface AnimatedListProps extends ComponentPropsWithoutRef<"div"> { children: React.ReactNode; delay?: number; } export const AnimatedList = React.memo( - ({ className, children, delay = 1000 }: AnimatedListProps) => { + ({ children, className, delay = 1000, ...props }: AnimatedListProps) => { const [index, setIndex] = useState(0); const childrenArray = useMemo( () => React.Children.toArray(children), @@ -33,7 +52,10 @@ export const AnimatedList = React.memo( }, [index, childrenArray]); return ( -
+
{itemsToShow.map((item) => ( @@ -47,18 +69,3 @@ export const AnimatedList = React.memo( ); AnimatedList.displayName = "AnimatedList"; - -export function AnimatedListItem({ children }: { children: React.ReactNode }) { - const animations = { - initial: { scale: 0, opacity: 0 }, - animate: { scale: 1, opacity: 1, originY: 0 }, - exit: { scale: 0, opacity: 0 }, - transition: { type: "spring", stiffness: 350, damping: 40 }, - }; - - return ( - - {children} - - ); -} diff --git a/registry/default/magicui/animated-shiny-text.tsx b/registry/default/magicui/animated-shiny-text.tsx index f55fd208a..7a8506bae 100644 --- a/registry/default/magicui/animated-shiny-text.tsx +++ b/registry/default/magicui/animated-shiny-text.tsx @@ -1,20 +1,20 @@ -import { CSSProperties, FC, ReactNode } from "react"; +import { ComponentPropsWithoutRef, CSSProperties, FC } from "react"; import { cn } from "@/lib/utils"; -interface AnimatedShinyTextProps { - children: ReactNode; - className?: string; +export interface AnimatedShinyTextProps + extends ComponentPropsWithoutRef<"span"> { shimmerWidth?: number; } -const AnimatedShinyText: FC = ({ +export const AnimatedShinyText: FC = ({ children, className, shimmerWidth = 100, + ...props }) => { return ( -

= ({ className, )} + {...props} > {children} -

+ ); }; - -export default AnimatedShinyText; diff --git a/registry/default/magicui/avatar-circles.tsx b/registry/default/magicui/avatar-circles.tsx index ae93f0471..ac1da3537 100644 --- a/registry/default/magicui/avatar-circles.tsx +++ b/registry/default/magicui/avatar-circles.tsx @@ -1,8 +1,6 @@ /* eslint-disable @next/next/no-img-element */ "use client"; -import React from "react"; - import { cn } from "@/lib/utils"; interface Avatar { @@ -15,7 +13,7 @@ interface AvatarCirclesProps { avatarUrls: Avatar[]; } -const AvatarCircles = ({ +export const AvatarCircles = ({ numPeople, className, avatarUrls, @@ -50,5 +48,3 @@ const AvatarCircles = ({
); }; - -export default AvatarCircles; diff --git a/registry/default/magicui/bento-grid.tsx b/registry/default/magicui/bento-grid.tsx index bd207b667..7b30ca257 100644 --- a/registry/default/magicui/bento-grid.tsx +++ b/registry/default/magicui/bento-grid.tsx @@ -1,15 +1,15 @@ -import { ReactNode } from "react"; import { ArrowRightIcon } from "@radix-ui/react-icons"; +import { ComponentPropsWithoutRef, ReactNode } from "react"; -import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; -type BentoGridProps = { +interface BentoGridProps extends ComponentPropsWithoutRef<"div"> { children: ReactNode; className?: string; -}; +} -type BentoCardProps = { +interface BentoCardProps extends ComponentPropsWithoutRef<"div"> { name: string; className: string; background: ReactNode; @@ -17,15 +17,16 @@ type BentoCardProps = { description: string; href: string; cta: string; -}; +} -const BentoGrid = ({ children, className }: BentoGridProps) => { +const BentoGrid = ({ children, className, ...props }: BentoGridProps) => { return (
{children}
@@ -40,6 +41,7 @@ const BentoCard = ({ description, href, cta, + ...props }: BentoCardProps) => (
{background}
diff --git a/registry/default/magicui/blur-fade.tsx b/registry/default/magicui/blur-fade.tsx index 8aa618591..0d3361b20 100644 --- a/registry/default/magicui/blur-fade.tsx +++ b/registry/default/magicui/blur-fade.tsx @@ -1,6 +1,5 @@ "use client"; -import { useRef } from "react"; import { AnimatePresence, motion, @@ -8,6 +7,7 @@ import { UseInViewOptions, Variants, } from "motion/react"; +import { useRef } from "react"; type MarginType = UseInViewOptions["margin"]; @@ -27,7 +27,7 @@ interface BlurFadeProps { blur?: string; } -export default function BlurFade({ +export function BlurFade({ children, className, variant, diff --git a/registry/default/magicui/border-beam.tsx b/registry/default/magicui/border-beam.tsx index a7203078f..97ac5b017 100644 --- a/registry/default/magicui/border-beam.tsx +++ b/registry/default/magicui/border-beam.tsx @@ -1,7 +1,7 @@ import { cn } from "@/lib/utils"; +import { ComponentPropsWithoutRef } from "react"; -interface BorderBeamProps { - className?: string; +interface BorderBeamProps extends ComponentPropsWithoutRef<"div"> { size?: number; duration?: number; borderWidth?: number; @@ -20,6 +20,7 @@ export const BorderBeam = ({ colorFrom = "#ffaa40", colorTo = "#9c40ff", delay = 0, + ...props }: BorderBeamProps) => { return (
); }; diff --git a/registry/default/magicui/box-reveal.tsx b/registry/default/magicui/box-reveal.tsx index 03e67fc27..9f9bcdee4 100644 --- a/registry/default/magicui/box-reveal.tsx +++ b/registry/default/magicui/box-reveal.tsx @@ -1,7 +1,7 @@ "use client"; -import { useEffect, useRef } from "react"; import { motion, useAnimation, useInView } from "motion/react"; +import { useEffect, useRef } from "react"; interface BoxRevealProps { children: JSX.Element; @@ -13,7 +13,7 @@ interface BoxRevealProps { export const BoxReveal = ({ children, width = "fit-content", - boxColor, + boxColor = "#5046e6", duration, }: BoxRevealProps) => { const mainControls = useAnimation(); @@ -61,11 +61,9 @@ export const BoxReveal = ({ left: 0, right: 0, zIndex: 20, - background: boxColor ? boxColor : "#5046e6", + background: boxColor, }} />
); }; - -export default BoxReveal; diff --git a/registry/default/magicui/client-tweet-card.tsx b/registry/default/magicui/client-tweet-card.tsx index a7a3d4d45..214c888d4 100644 --- a/registry/default/magicui/client-tweet-card.tsx +++ b/registry/default/magicui/client-tweet-card.tsx @@ -8,7 +8,7 @@ import { TweetSkeleton, } from "@/registry/default/magicui/tweet-card"; -const ClientTweetCard = ({ +export const ClientTweetCard = ({ id, apiUrl, fallback = , @@ -27,5 +27,3 @@ const ClientTweetCard = ({ return ; }; - -export default ClientTweetCard; diff --git a/registry/default/magicui/confetti.tsx b/registry/default/magicui/confetti.tsx index 49f85277f..161255fc5 100644 --- a/registry/default/magicui/confetti.tsx +++ b/registry/default/magicui/confetti.tsx @@ -1,3 +1,9 @@ +import type { + GlobalOptions as ConfettiGlobalOptions, + CreateTypes as ConfettiInstance, + Options as ConfettiOptions, +} from "canvas-confetti"; +import confetti from "canvas-confetti"; import type { ReactNode } from "react"; import React, { createContext, @@ -8,12 +14,6 @@ import React, { useMemo, useRef, } from "react"; -import type { - GlobalOptions as ConfettiGlobalOptions, - CreateTypes as ConfettiInstance, - Options as ConfettiOptions, -} from "canvas-confetti"; -import confetti from "canvas-confetti"; import { Button, ButtonProps } from "@/components/ui/button"; @@ -145,5 +145,3 @@ const ConfettiButtonComponent = ({ ConfettiButtonComponent.displayName = "ConfettiButton"; export const ConfettiButton = ConfettiButtonComponent; - -export default Confetti; diff --git a/registry/default/magicui/dot-pattern.tsx b/registry/default/magicui/dot-pattern.tsx index da83cd1db..a1e79fab7 100644 --- a/registry/default/magicui/dot-pattern.tsx +++ b/registry/default/magicui/dot-pattern.tsx @@ -2,7 +2,7 @@ import { useId } from "react"; import { cn } from "@/lib/utils"; -interface DotPatternProps { +interface DotPatternProps extends React.SVGProps { width?: number; height?: number; x?: number; @@ -52,5 +52,3 @@ export function DotPattern({ ); } - -export default DotPattern; diff --git a/registry/default/magicui/flickering-grid.tsx b/registry/default/magicui/flickering-grid.tsx index 60e55d6f9..f303d4d48 100644 --- a/registry/default/magicui/flickering-grid.tsx +++ b/registry/default/magicui/flickering-grid.tsx @@ -1,5 +1,6 @@ "use client"; +import { cn } from "@/lib/utils"; import React, { useCallback, useEffect, @@ -8,7 +9,7 @@ import React, { useState, } from "react"; -interface FlickeringGridProps { +interface FlickeringGridProps extends React.HTMLAttributes { squareSize?: number; gridGap?: number; flickerChance?: number; @@ -16,11 +17,10 @@ interface FlickeringGridProps { width?: number; height?: number; className?: string; - maxOpacity?: number; } -const FlickeringGrid: React.FC = ({ +export const FlickeringGrid: React.FC = ({ squareSize = 4, gridGap = 6, flickerChance = 0.3, @@ -29,6 +29,7 @@ const FlickeringGrid: React.FC = ({ height, className, maxOpacity = 0.3, + ...props }) => { const canvasRef = useRef(null); const containerRef = useRef(null); @@ -180,7 +181,11 @@ const FlickeringGrid: React.FC = ({ }, [setupCanvas, updateSquares, drawGrid, width, height, isInView]); return ( -
+
= ({
); }; - -export default FlickeringGrid; diff --git a/registry/default/magicui/flip-text.tsx b/registry/default/magicui/flip-text.tsx index 7b1116dfc..c1a132af0 100644 --- a/registry/default/magicui/flip-text.tsx +++ b/registry/default/magicui/flip-text.tsx @@ -12,7 +12,7 @@ interface FlipTextProps { className?: string; } -export default function FlipText({ +export function FlipText({ word, duration = 0.5, delayMultiple = 0.08, diff --git a/registry/default/magicui/globe.tsx b/registry/default/magicui/globe.tsx index 480b6498d..4bb7f9050 100644 --- a/registry/default/magicui/globe.tsx +++ b/registry/default/magicui/globe.tsx @@ -33,7 +33,7 @@ const GLOBE_CONFIG: COBEOptions = { ], }; -export default function Globe({ +export function Globe({ className, config = GLOBE_CONFIG, }: { diff --git a/registry/default/magicui/grid-pattern.tsx b/registry/default/magicui/grid-pattern.tsx index 150e6ac6c..6840f45f8 100644 --- a/registry/default/magicui/grid-pattern.tsx +++ b/registry/default/magicui/grid-pattern.tsx @@ -2,7 +2,7 @@ import { useId } from "react"; import { cn } from "@/lib/utils"; -interface GridPatternProps { +interface GridPatternProps extends React.SVGProps { width?: number; height?: number; x?: number; @@ -68,5 +68,3 @@ export function GridPattern({ ); } - -export default GridPattern; diff --git a/registry/default/magicui/hyper-text.tsx b/registry/default/magicui/hyper-text.tsx index ec78d669e..0a33c4222 100644 --- a/registry/default/magicui/hyper-text.tsx +++ b/registry/default/magicui/hyper-text.tsx @@ -31,7 +31,7 @@ const DEFAULT_CHARACTER_SET = Object.freeze( const getRandomInt = (max: number): number => Math.floor(Math.random() * max); -export default function HyperText({ +export function HyperText({ children, className, duration = 800, diff --git a/registry/default/magicui/marquee.tsx b/registry/default/magicui/marquee.tsx index 6f087fef9..fa9c129ba 100644 --- a/registry/default/magicui/marquee.tsx +++ b/registry/default/magicui/marquee.tsx @@ -32,7 +32,7 @@ interface MarqueeProps extends ComponentPropsWithoutRef<"div"> { repeat?: number; } -export default function Marquee({ +export function Marquee({ className, reverse = false, pauseOnHover = false, diff --git a/registry/default/magicui/morphing-text.tsx b/registry/default/magicui/morphing-text.tsx index 78266fbb9..68907ca2a 100644 --- a/registry/default/magicui/morphing-text.tsx +++ b/registry/default/magicui/morphing-text.tsx @@ -130,7 +130,10 @@ const SvgFilters: React.FC = () => ( ); -const MorphingText: React.FC = ({ texts, className }) => ( +export const MorphingText: React.FC = ({ + texts, + className, +}) => (
= ({ texts, className }) => (
); - -export default MorphingText; diff --git a/registry/default/magicui/neon-gradient-card.tsx b/registry/default/magicui/neon-gradient-card.tsx index 319278913..1a2a76b04 100644 --- a/registry/default/magicui/neon-gradient-card.tsx +++ b/registry/default/magicui/neon-gradient-card.tsx @@ -67,7 +67,7 @@ interface NeonGradientCardProps { [key: string]: any; } -const NeonGradientCard: React.FC = ({ +export const NeonGradientCard: React.FC = ({ className, children, borderSize = 2, @@ -147,5 +147,3 @@ const NeonGradientCard: React.FC = ({
); }; - -export { NeonGradientCard }; diff --git a/registry/default/magicui/number-ticker.tsx b/registry/default/magicui/number-ticker.tsx index f69d0bf97..a70be7b33 100644 --- a/registry/default/magicui/number-ticker.tsx +++ b/registry/default/magicui/number-ticker.tsx @@ -1,23 +1,25 @@ "use client"; -import { useEffect, useRef } from "react"; import { useInView, useMotionValue, useSpring } from "motion/react"; +import { ComponentPropsWithoutRef, useEffect, useRef } from "react"; import { cn } from "@/lib/utils"; -export default function NumberTicker({ +interface NumberTickerProps extends ComponentPropsWithoutRef<"span"> { + value: number; + direction?: "up" | "down"; + delay?: number; // delay in s + decimalPlaces?: number; +} + +export function NumberTicker({ value, direction = "up", delay = 0, className, decimalPlaces = 0, -}: { - value: number; - direction?: "up" | "down"; - className?: string; - delay?: number; // delay in s - decimalPlaces?: number; -}) { + ...props +}: NumberTickerProps) { const ref = useRef(null); const motionValue = useMotionValue(direction === "down" ? value : 0); const springValue = useSpring(motionValue, { @@ -48,11 +50,12 @@ export default function NumberTicker({ return ( ); } diff --git a/registry/default/magicui/particles.tsx b/registry/default/magicui/particles.tsx index 688c7c07f..ff6719ab1 100644 --- a/registry/default/magicui/particles.tsx +++ b/registry/default/magicui/particles.tsx @@ -1,7 +1,12 @@ "use client"; import { cn } from "@/lib/utils"; -import React, { useEffect, useRef, useState } from "react"; +import React, { + ComponentPropsWithoutRef, + useEffect, + useRef, + useState, +} from "react"; interface MousePosition { x: number; @@ -29,7 +34,7 @@ function MousePosition(): MousePosition { return mousePosition; } -interface ParticlesProps { +interface ParticlesProps extends ComponentPropsWithoutRef<"div"> { className?: string; quantity?: number; staticity?: number; @@ -71,7 +76,7 @@ type Circle = { magnetism: number; }; -const Particles: React.FC = ({ +export const Particles: React.FC = ({ className = "", quantity = 100, staticity = 50, @@ -81,6 +86,7 @@ const Particles: React.FC = ({ color = "#ffffff", vx = 0, vy = 0, + ...props }) => { const canvasRef = useRef(null); const canvasContainerRef = useRef(null); @@ -299,10 +305,9 @@ const Particles: React.FC = ({ className={cn("pointer-events-none", className)} ref={canvasContainerRef} aria-hidden="true" + {...props} >
); }; - -export default Particles; diff --git a/registry/default/magicui/retro-grid.tsx b/registry/default/magicui/retro-grid.tsx index 04fe5ed67..9a72d4352 100644 --- a/registry/default/magicui/retro-grid.tsx +++ b/registry/default/magicui/retro-grid.tsx @@ -32,7 +32,7 @@ interface RetroGridProps extends React.HTMLAttributes { darkLineColor?: string; } -export default function RetroGrid({ +export function RetroGrid({ className, angle = 65, cellSize = 60, diff --git a/registry/default/magicui/ripple.tsx b/registry/default/magicui/ripple.tsx index 0b9f66bce..02ed975b1 100644 --- a/registry/default/magicui/ripple.tsx +++ b/registry/default/magicui/ripple.tsx @@ -1,26 +1,27 @@ -import React, { CSSProperties } from "react"; +import React, { ComponentPropsWithoutRef, CSSProperties } from "react"; import { cn } from "@/lib/utils"; -interface RippleProps { +interface RippleProps extends ComponentPropsWithoutRef<"div"> { mainCircleSize?: number; mainCircleOpacity?: number; numCircles?: number; - className?: string; } -const Ripple = React.memo(function Ripple({ +export const Ripple = React.memo(function Ripple({ mainCircleSize = 210, mainCircleOpacity = 0.24, numCircles = 8, className, + ...props }: RippleProps) { return (
{Array.from({ length: numCircles }, (_, i) => { const size = mainCircleSize + i * 70; @@ -32,7 +33,7 @@ const Ripple = React.memo(function Ripple({ return (
= ({ +export const ScratchToReveal: React.FC = ({ width, height, minScratchPercentage = 50, @@ -167,5 +167,3 @@ const ScratchToReveal: React.FC = ({ ); }; - -export default ScratchToReveal; diff --git a/registry/default/magicui/script-copy-btn.tsx b/registry/default/magicui/script-copy-btn.tsx index fbc8137b1..58bf2b9e1 100644 --- a/registry/default/magicui/script-copy-btn.tsx +++ b/registry/default/magicui/script-copy-btn.tsx @@ -2,8 +2,8 @@ import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; -import { motion } from "motion/react"; import { Check, Copy } from "lucide-react"; +import { motion } from "motion/react"; import { useTheme } from "next-themes"; import { HTMLAttributes, useEffect, useState } from "react"; import { codeToHtml } from "shiki"; @@ -17,7 +17,7 @@ interface ScriptCopyBtnProps extends HTMLAttributes { className?: string; } -export default function ScriptCopyBtn({ +export function ScriptCopyBtn({ showMultiplePackageOptions = true, codeLanguage, lightTheme, diff --git a/registry/default/magicui/scroll-progress.tsx b/registry/default/magicui/scroll-progress.tsx index c883361b7..63cad7d81 100644 --- a/registry/default/magicui/scroll-progress.tsx +++ b/registry/default/magicui/scroll-progress.tsx @@ -1,13 +1,15 @@ "use client"; import { cn } from "@/lib/utils"; -import { motion, useScroll, useSpring } from "motion/react"; +import { motion, MotionProps, useScroll, useSpring } from "motion/react"; +import React from "react"; +interface ScrollProgressProps + extends Omit, keyof MotionProps> {} -interface ScrollProgressProps { - className?: string; -} - -export default function ScrollProgress({ className }: ScrollProgressProps) { +export const ScrollProgress = React.forwardRef< + HTMLDivElement, + ScrollProgressProps +>(({ className, ...props }, ref) => { const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { @@ -18,6 +20,7 @@ export default function ScrollProgress({ className }: ScrollProgressProps) { return ( ); -} +}); + +ScrollProgress.displayName = "ScrollProgress"; diff --git a/registry/default/magicui/shimmer-button.tsx b/registry/default/magicui/shimmer-button.tsx index dc7364187..c217800cb 100644 --- a/registry/default/magicui/shimmer-button.tsx +++ b/registry/default/magicui/shimmer-button.tsx @@ -1,9 +1,8 @@ -import React, { CSSProperties } from "react"; +import React, { CSSProperties, ComponentPropsWithoutRef } from "react"; import { cn } from "@/lib/utils"; -export interface ShimmerButtonProps - extends React.ButtonHTMLAttributes { +export interface ShimmerButtonProps extends ComponentPropsWithoutRef<"button"> { shimmerColor?: string; shimmerSize?: string; borderRadius?: string; diff --git a/registry/default/magicui/shine-border.tsx b/registry/default/magicui/shine-border.tsx index 53b12a85a..fcde11a0e 100644 --- a/registry/default/magicui/shine-border.tsx +++ b/registry/default/magicui/shine-border.tsx @@ -23,7 +23,7 @@ interface ShineBorderProps { * @param className defines the class name to be applied to the component * @param children contains react node elements. */ -export default function ShineBorder({ +export function ShineBorder({ borderRadius = 8, borderWidth = 1, duration = 14, @@ -53,7 +53,7 @@ export default function ShineBorder({ "--background-radial-gradient": `radial-gradient(transparent,transparent, ${color instanceof Array ? color.join(",") : color},transparent,transparent)`, } as React.CSSProperties } - className={`pointer-events-none before:bg-shine-size before:absolute before:inset-0 before:size-full before:rounded-[--border-radius] before:p-[--border-width] before:will-change-[background-position] before:content-[""] before:![-webkit-mask-composite:xor] before:![mask-composite:exclude] before:[background-image:--background-radial-gradient] before:[background-size:300%_300%] before:[mask:--mask-linear-gradient] motion-safe:before:animate-shine`} + className={`before:bg-shine-size pointer-events-none before:absolute before:inset-0 before:size-full before:rounded-[--border-radius] before:p-[--border-width] before:will-change-[background-position] before:content-[""] before:![-webkit-mask-composite:xor] before:![mask-composite:exclude] before:[background-image:--background-radial-gradient] before:[background-size:300%_300%] before:[mask:--mask-linear-gradient] motion-safe:before:animate-shine`} >
{children}
diff --git a/registry/default/magicui/shiny-button.tsx b/registry/default/magicui/shiny-button.tsx index 9d4ba5ffc..73b5f017c 100644 --- a/registry/default/magicui/shiny-button.tsx +++ b/registry/default/magicui/shiny-button.tsx @@ -1,12 +1,8 @@ "use client"; -import React from "react"; -import { - motion, - type AnimationProps, - type HTMLMotionProps, -} from "motion/react"; import { cn } from "@/lib/utils"; +import { motion, MotionProps, type AnimationProps } from "motion/react"; +import React from "react"; const animationProps = { initial: { "--x": "100%", scale: 0.8 }, @@ -29,7 +25,9 @@ const animationProps = { }, } as AnimationProps; -interface ShinyButtonProps extends Omit, "ref"> { +interface ShinyButtonProps + extends Omit, keyof MotionProps>, + MotionProps { children: React.ReactNode; className?: string; } diff --git a/registry/default/magicui/sparkles-text.tsx b/registry/default/magicui/sparkles-text.tsx index 99d296385..4ab2baa34 100644 --- a/registry/default/magicui/sparkles-text.tsx +++ b/registry/default/magicui/sparkles-text.tsx @@ -1,7 +1,7 @@ "use client"; -import { CSSProperties, ReactElement, useEffect, useState } from "react"; import { motion } from "motion/react"; +import { CSSProperties, ReactElement, useEffect, useState } from "react"; import { cn } from "@/lib/utils"; @@ -15,6 +15,30 @@ interface Sparkle { lifespan: number; } +const Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => { + return ( + + + + ); +}; + interface SparklesTextProps { /** * @default
@@ -60,7 +84,7 @@ interface SparklesTextProps { }; } -const SparklesText: React.FC = ({ +export const SparklesText: React.FC = ({ text, colors = { first: "#9E7AFF", second: "#FE8BBB" }, className, @@ -124,29 +148,3 @@ const SparklesText: React.FC = ({
); }; - -const Sparkle: React.FC = ({ id, x, y, color, delay, scale }) => { - return ( - - - - ); -}; - -export default SparklesText; diff --git a/registry/default/magicui/text-reveal.tsx b/registry/default/magicui/text-reveal.tsx index 08edc1632..ef05225cf 100644 --- a/registry/default/magicui/text-reveal.tsx +++ b/registry/default/magicui/text-reveal.tsx @@ -1,19 +1,15 @@ "use client"; -import { FC, ReactNode, useRef } from "react"; import { motion, MotionValue, useScroll, useTransform } from "motion/react"; +import { ComponentPropsWithoutRef, FC, ReactNode, useRef } from "react"; import { cn } from "@/lib/utils"; -interface TextRevealByWordProps { +export interface TextRevealProps extends ComponentPropsWithoutRef<"div"> { text: string; - className?: string; } -export const TextRevealByWord: FC = ({ - text, - className, -}) => { +export const TextReveal: FC = ({ text, className }) => { const targetRef = useRef(null); const { scrollYProgress } = useScroll({ @@ -69,5 +65,3 @@ const Word: FC = ({ children, progress, range }) => { ); }; - -export default TextRevealByWord; diff --git a/registry/default/magicui/tweet-card.tsx b/registry/default/magicui/tweet-card.tsx index 405938e3e..0f720db1a 100644 --- a/registry/default/magicui/tweet-card.tsx +++ b/registry/default/magicui/tweet-card.tsx @@ -280,5 +280,3 @@ export const TweetCard = async ({ ); }; - -export default TweetCard; diff --git a/registry/default/magicui/typing-animation.tsx b/registry/default/magicui/typing-animation.tsx index 506813faf..62ce90a4c 100644 --- a/registry/default/magicui/typing-animation.tsx +++ b/registry/default/magicui/typing-animation.tsx @@ -13,7 +13,7 @@ interface TypingAnimationProps extends MotionProps { startOnView?: boolean; } -export default function TypingAnimation({ +export function TypingAnimation({ children, className, duration = 100, diff --git a/registry/default/magicui/word-rotate.tsx b/registry/default/magicui/word-rotate.tsx index 3282f7f8e..17be594e8 100644 --- a/registry/default/magicui/word-rotate.tsx +++ b/registry/default/magicui/word-rotate.tsx @@ -1,21 +1,21 @@ "use client"; -import { useEffect, useState } from "react"; import { AnimatePresence, motion, MotionProps } from "motion/react"; +import { useEffect, useState } from "react"; import { cn } from "@/lib/utils"; interface WordRotateProps { words: string[]; duration?: number; - framerProps?: MotionProps; + motionProps?: MotionProps; className?: string; } -export default function WordRotate({ +export function WordRotate({ words, duration = 2500, - framerProps = { + motionProps = { initial: { opacity: 0, y: -50 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 50 }, @@ -40,7 +40,7 @@ export default function WordRotate({ {words[index]} diff --git a/registry/registry-ui.ts b/registry/registry-ui.ts index 8c8cad875..b337cd8fc 100644 --- a/registry/registry-ui.ts +++ b/registry/registry-ui.ts @@ -94,7 +94,6 @@ export const ui: Registry = [ { name: "morphing-text", type: "registry:ui", - dependencies: ["motion"], files: ["magicui/morphing-text.tsx"], }, { @@ -173,7 +172,6 @@ export const ui: Registry = [ { name: "flickering-grid", type: "registry:ui", - dependencies: ["motion"], files: ["magicui/flickering-grid.tsx"], }, { @@ -192,6 +190,7 @@ export const ui: Registry = [ name: "script-copy-btn", type: "registry:ui", dependencies: ["motion", "shiki", "next-themes"], + registryDependencies: ["button"], files: ["magicui/script-copy-btn.tsx"], }, { @@ -225,7 +224,7 @@ export const ui: Registry = [ { name: "globe", type: "registry:ui", - dependencies: ["cobe", "react-spring"], + dependencies: ["cobe"], files: ["magicui/globe.tsx"], }, { @@ -284,6 +283,7 @@ export const ui: Registry = [ name: "bento-grid", type: "registry:ui", dependencies: ["@radix-ui/react-icons"], + registryDependencies: ["button"], files: ["magicui/bento-grid.tsx"], }, { @@ -586,6 +586,7 @@ export const ui: Registry = [ name: "confetti", type: "registry:ui", dependencies: ["canvas-confetti", "@types/canvas-confetti"], + registryDependencies: ["button"], files: ["magicui/confetti.tsx"], }, { @@ -717,7 +718,6 @@ export const ui: Registry = [ { name: "interactive-hover-button", type: "registry:ui", - dependencies: ["lucide-react"], files: ["magicui/interactive-hover-button.tsx"], }, ];