70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import { LoaderPinwheel } from "lucide-react";
|
|
|
|
type PrimaryButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
loading?: boolean;
|
|
children: React.ReactNode;
|
|
};
|
|
|
|
export default function PrimaryButton({ children, loading, className, onClick }: PrimaryButtonProps) {
|
|
return (
|
|
<button
|
|
onClick={onClick}
|
|
className={cn(
|
|
"bg-primary grid w-full place-items-center overflow-hidden rounded-xl px-4 py-2 text-white hover:scale-102 active:scale-98",
|
|
className
|
|
)}
|
|
>
|
|
<AnimatePresence mode="wait">
|
|
{loading ? (
|
|
<motion.div
|
|
key={"loading"}
|
|
initial={{
|
|
opacity: 0,
|
|
x: -80,
|
|
}}
|
|
animate={{
|
|
opacity: 1,
|
|
x: 0,
|
|
}}
|
|
exit={{
|
|
opacity: 0,
|
|
x: -80,
|
|
}}
|
|
transition={{
|
|
duration: 0.2,
|
|
}}
|
|
>
|
|
<LoaderPinwheel className="animate-spin" />
|
|
</motion.div>
|
|
) : (
|
|
<motion.div
|
|
key="content"
|
|
initial={{
|
|
opacity: 0,
|
|
x: 80,
|
|
}}
|
|
animate={{
|
|
opacity: 1,
|
|
x: 0,
|
|
}}
|
|
exit={{
|
|
opacity: 0,
|
|
x: 80,
|
|
}}
|
|
transition={{
|
|
duration: 0.2,
|
|
}}
|
|
className="flex items-center justify-center gap-2"
|
|
>
|
|
{children}
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</button>
|
|
);
|
|
}
|