File size: 3,067 Bytes
75fefa7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"use client";

import React from "react";
import { cn } from "@/utils/cn";
import { LucideIcon } from "lucide-react";

interface SlateButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  icon?:
    | LucideIcon
    | React.ComponentType<{
        className?: string;
        isHovered?: boolean;
        isOpen?: boolean;
      }>
    | React.ReactNode;
  iconPosition?: "left" | "right";
  children: React.ReactNode;
  size?: "sm" | "md" | "lg";
  fullWidth?: boolean;
  isLoading?: boolean;
  isOpen?: boolean;
}

export const SlateButton = React.forwardRef<
  HTMLButtonElement,
  SlateButtonProps
>(
  (
    {
      icon: Icon,
      iconPosition = "left",
      children,
      className,
      size = "md",
      fullWidth = false,
      isLoading = false,
      isOpen = false,
      disabled,
      ...props
    },
    ref,
  ) => {
    const [isHovered, setIsHovered] = React.useState(false);

    const sizeClasses = {
      sm: "h-32 px-12 text-body-small gap-6",
      md: "h-40 px-16 text-body-medium gap-8",
      lg: "h-48 px-24 text-body-large gap-10",
    };

    const iconSizes = {
      sm: "w-14 h-14",
      md: "w-16 h-16",
      lg: "w-20 h-20",
    };

    return (
      <button
        ref={ref}
        className={cn(
          // Base styles
          "inline-flex items-center justify-center rounded-12  transition-all",
          // Colors
          "bg-black-alpha-4 text-accent-black",
          "hover:bg-black-alpha-6",
          "active:scale-[0.98]",
          // Border
          // "border-0",
          // Size
          sizeClasses[size],
          // States
          disabled && "opacity-50 cursor-not-allowed",
          isLoading && "cursor-wait",
          // Full width
          fullWidth && "w-full",
          className,
        )}
        disabled={disabled || isLoading}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
        {...props}
      >
        {isLoading ? (
          <div className={cn("animate-spin rounded-full", iconSizes[size])} />
        ) : (
          <>
            {Icon &&
              iconPosition === "left" &&
              (React.isValidElement(Icon) ? (
                Icon
              ) : (
                //@ts-expect-error - Icon component type allows JSX element
                <Icon
                  className={cn(iconSizes[size], "flex-shrink-0")}
                  isHovered={isHovered}
                  isOpen={isOpen}
                />
              ))}
            {children}
            {Icon &&
              iconPosition === "right" &&
              (React.isValidElement(Icon) ? (
                Icon
              ) : (
                //@ts-expect-error - Icon component type allows JSX element
                <Icon
                  className={cn(iconSizes[size], "flex-shrink-0")}
                  isHovered={isHovered}
                  isOpen={isOpen}
                />
              ))}
          </>
        )}
      </button>
    );
  },
);

SlateButton.displayName = "SlateButton";