Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { cva, type VariantProps } from "class-variance-authority";
2import { AnimatePresence, motion } from "motion/react";
3import type { ButtonHTMLAttributes, ReactNode } from "react";
4import { forwardRef, memo } from "react";
5import { Spinner } from "@/components/Shared/UI";
6import cn from "@/helpers/cn";
7
8const buttonVariants = cva(
9 "rounded-full font-bold inline-flex items-center justify-center relative overflow-hidden",
10 {
11 compoundVariants: [
12 // Non-outline Primary
13 {
14 class: cn(
15 "text-white hover:text-white active:text-gray-100",
16 "bg-gray-950 hover:bg-gray-800 active:bg-gray-700",
17 "border border-gray-950 hover:border-gray-800 active:border-gray-700",
18 "dark:text-gray-950 dark:hover:text-gray-900 dark:active:text-gray-600",
19 "dark:bg-white dark:hover:bg-gray-200 dark:active:bg-gray-200",
20 "dark:border-white dark:hover:border-gray-100 dark:active:border-gray-200"
21 ),
22 outline: false,
23 variant: "primary"
24 },
25 // Outline Primary
26 {
27 class: cn(
28 "text-gray-950 active:text-gray-500",
29 "border border-gray-300 hover:border-gray-400",
30 "dark:text-white dark:active:text-gray-700",
31 "dark:border-gray-700 dark:hover:border-gray-600"
32 ),
33 outline: true,
34 variant: "primary"
35 }
36 ],
37 defaultVariants: {
38 outline: false,
39 size: "md",
40 variant: "primary"
41 },
42 variants: {
43 outline: { false: "", true: "" },
44 size: { lg: "px-5 py-1.5", md: "px-4 py-1", sm: "px-3 py-0.5 text-sm" },
45 variant: { primary: "" }
46 }
47 }
48);
49
50interface ButtonProps
51 extends ButtonHTMLAttributes<HTMLButtonElement>,
52 VariantProps<typeof buttonVariants> {
53 children?: ReactNode;
54 icon?: ReactNode;
55 loading?: boolean;
56}
57
58const Button = forwardRef<HTMLButtonElement, ButtonProps>(
59 (
60 {
61 children,
62 className,
63 disabled,
64 icon,
65 outline,
66 size,
67 variant,
68 loading,
69 ...rest
70 },
71 ref
72 ) => {
73 return (
74 <button
75 className={buttonVariants({ className, outline, size, variant })}
76 disabled={disabled}
77 ref={ref}
78 type={rest.type}
79 {...rest}
80 >
81 <AnimatePresence mode="wait">
82 <motion.div
83 animate={loading ? "loading" : "idle"}
84 className="flex items-center gap-x-1.5"
85 initial="idle"
86 transition={{ bounce: 0, duration: 0.2, type: "spring" }}
87 variants={{
88 idle: { opacity: 1, y: 0 },
89 loading: { opacity: 0, y: -20 }
90 }}
91 >
92 {icon}
93 {children}
94 </motion.div>
95 {loading && (
96 <motion.div
97 animate={{ opacity: 1, y: 0 }}
98 className="absolute flex items-center justify-center"
99 exit={{ opacity: 0, y: 20 }}
100 initial={{ opacity: 0, y: 20 }}
101 transition={{ bounce: 0, duration: 0.2, type: "spring" }}
102 >
103 <Spinner size="xs" />
104 </motion.div>
105 )}
106 </AnimatePresence>
107 </button>
108 );
109 }
110);
111
112export default memo(Button);