11import * as React from "react" ;
2- import { Slot } from "@radix-ui/react-slot" ;
2+ import { Slot , Slottable } from "@radix-ui/react-slot" ;
33import { cva , type VariantProps } from "class-variance-authority" ;
4-
54import { cn } from "@shared/lib/utils" ;
65
76const buttonVariants = cva (
@@ -20,6 +19,28 @@ const buttonVariants = cva(
2019 destructiveGhost : "text-destructive hover:bg-accent" ,
2120 link : "text-primary underline-offset-4 hover:underline" ,
2221 } ,
22+ effect : {
23+ expandIcon : "group gap-0 relative" ,
24+ ringHover :
25+ "transition-all duration-300 hover:ring-2 hover:ring-primary/90 hover:ring-offset-2" ,
26+ shine :
27+ "before:animate-shine relative overflow-hidden before:absolute before:inset-0 before:rounded-[inherit] before:bg-[linear-gradient(45deg,transparent_25%,rgba(255,255,255,0.5)_50%,transparent_75%,transparent_100%)] before:bg-[length:250%_250%,100%_100%] before:bg-no-repeat background-position_0s_ease" ,
28+ shineHover :
29+ "relative overflow-hidden before:absolute before:inset-0 before:rounded-[inherit] before:bg-[linear-gradient(45deg,transparent_25%,rgba(255,255,255,0.5)_50%,transparent_75%,transparent_100%)] before:bg-[length:250%_250%,100%_100%] before:bg-[position:200%_0,0_0] before:bg-no-repeat before:transition-[background-position_0s_ease] hover:before:bg-[position:-100%_0,0_0] before:duration-1000" ,
30+ shineHoverExpand :
31+ "group gap-0 relative overflow-hidden before:absolute before:inset-0 before:rounded-[inherit] before:bg-[linear-gradient(45deg,transparent_25%,rgba(255,255,255,0.5)_50%,transparent_75%,transparent_100%)] before:bg-[length:250%_250%,100%_100%] before:bg-[position:200%_0,0_0] before:bg-no-repeat before:transition-[background-position_0s_ease] hover:before:bg-[position:-100%_0,0_0] before:duration-1000" ,
32+
33+ gooeyRight :
34+ "relative z-0 overflow-hidden transition-all duration-500 before:absolute before:inset-0 before:-z-10 before:translate-x-[150%] before:translate-y-[150%] before:scale-[2.5] before:rounded-[100%] before:bg-gradient-to-r from-white/40 before:transition-transform before:duration-1000 hover:before:translate-x-[0%] hover:before:translate-y-[0%]" ,
35+ gooeyLeft :
36+ "relative z-0 overflow-hidden transition-all duration-500 after:absolute after:inset-0 after:-z-10 after:translate-x-[-150%] after:translate-y-[150%] after:scale-[2.5] after:rounded-[100%] after:bg-gradient-to-l from-white/40 after:transition-transform after:duration-1000 hover:after:translate-x-[0%] hover:after:translate-y-[0%]" ,
37+ underline :
38+ "relative !no-underline after:absolute after:bg-primary after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-left after:scale-x-100 hover:after:origin-bottom-right hover:after:scale-x-0 after:transition-transform after:ease-in-out after:duration-300" ,
39+ hoverUnderline :
40+ "relative !no-underline after:absolute after:bg-primary after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-right after:scale-x-0 hover:after:origin-bottom-left hover:after:scale-x-100 after:transition-transform after:ease-in-out after:duration-300" ,
41+ gradientSlideShow :
42+ "bg-[size:400%] bg-[linear-gradient(-45deg,var(--gradient-lime),var(--gradient-ocean),var(--gradient-wine),var(--gradient-rust))] animate-gradient-flow" ,
43+ } ,
2344 size : {
2445 default : "h-10 px-4 py-2" ,
2546 sm : "h-9 rounded-md px-3" ,
@@ -35,21 +56,68 @@ const buttonVariants = cva(
3556 }
3657) ;
3758
59+ interface IconProps {
60+ icon : React . ElementType ;
61+ iconPlacement : "left" | "right" ;
62+ }
63+
64+ interface IconRefProps {
65+ icon ?: never ;
66+ iconPlacement ?: undefined ;
67+ }
68+
3869export interface ButtonProps
3970 extends React . ButtonHTMLAttributes < HTMLButtonElement > ,
4071 VariantProps < typeof buttonVariants > {
4172 asChild ?: boolean ;
4273}
4374
44- const Button = React . forwardRef < HTMLButtonElement , ButtonProps > (
45- ( { className, variant, size, asChild = false , ...props } , ref ) => {
75+ export type ButtonIconProps = IconProps | IconRefProps ;
76+
77+ const Button = React . forwardRef <
78+ HTMLButtonElement ,
79+ ButtonProps & ButtonIconProps
80+ > (
81+ (
82+ {
83+ className,
84+ variant,
85+ effect,
86+ size,
87+ icon : Icon ,
88+ iconPlacement,
89+ asChild = false ,
90+ ...props
91+ } ,
92+ ref
93+ ) => {
4694 const Comp = asChild ? Slot : "button" ;
4795 return (
4896 < Comp
49- className = { cn ( buttonVariants ( { variant, size, className } ) ) }
97+ className = { cn ( buttonVariants ( { variant, effect , size, className } ) ) }
5098 ref = { ref }
5199 { ...props }
52- />
100+ >
101+ { Icon &&
102+ iconPlacement === "left" &&
103+ ( effect === "expandIcon" || effect === "shineHoverExpand" ? (
104+ < div className = "group-hover:translate-x-100 w-0 translate-x-[0%] pr-0 opacity-0 transition-all duration-200 group-hover:w-5 group-hover:pr-2 group-hover:opacity-100" >
105+ < Icon />
106+ </ div >
107+ ) : (
108+ < Icon />
109+ ) ) }
110+ < Slottable > { props . children } </ Slottable >
111+ { Icon &&
112+ iconPlacement === "right" &&
113+ ( effect === "expandIcon" || effect === "shineHoverExpand" ? (
114+ < div className = "w-0 translate-x-[100%] pl-0 opacity-0 transition-all duration-200 group-hover:w-5 group-hover:translate-x-0 group-hover:pl-2 group-hover:opacity-100" >
115+ < Icon />
116+ </ div >
117+ ) : (
118+ < Icon />
119+ ) ) }
120+ </ Comp >
53121 ) ;
54122 }
55123) ;
0 commit comments