UNPKG

xlibs-components

Version:

Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications

120 lines (119 loc) 7.71 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { cva } from "class-variance-authority"; import { cn } from '../../lib/utils.js'; import { motion, AnimatePresence } from "motion/react"; const unifiedButtonVariants = cva("inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 relative overflow-hidden group font-sans", { variants: { variant: { default: "btn-primary shadow-lg hover:shadow-xl transform hover:-translate-y-0.5", destructive: "btn-destructive shadow-lg hover:shadow-xl transform hover:-translate-y-0.5", outline: "btn-outline shadow-sm hover:shadow-md transform hover:-translate-y-0.5", secondary: "btn-secondary shadow-lg hover:shadow-xl transform hover:-translate-y-0.5", ghost: "text-foreground hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", success: "btn-success shadow-lg hover:shadow-xl transform hover:-translate-y-0.5", warning: "btn-warning shadow-lg hover:shadow-xl transform hover:-translate-y-0.5", info: "btn-info shadow-lg hover:shadow-xl transform hover:-translate-y-0.5", magic: "bg-gradient-to-r from-primary via-chart-2 to-chart-3 text-primary-foreground shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 hover:scale-105", glass: "backdrop-blur-sm border border-border bg-card/50 hover:bg-card/80 hover:text-card-foreground shadow-lg hover:shadow-xl transform hover:-translate-y-0.5", neon: "bg-primary text-primary-foreground shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 border border-primary/50 hover:border-primary shadow-[0_0_20px_rgba(var(--primary),0.3)] hover:shadow-[0_0_30px_rgba(var(--primary),0.5)]", shiny: "bg-gradient-to-r from-primary to-chart-2 text-primary-foreground shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 relative overflow-hidden", pulsating: "btn-primary shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 animate-pulse", interactive: "btn-primary shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 hover:scale-105", subscribe: "btn-primary shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-300", }, size: { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", magic: "h-12 px-6 py-3 text-base", xl: "h-14 px-10 py-4 text-lg", }, effect: { none: "", ripple: "relative overflow-hidden", shine: "relative overflow-hidden", pulse: "animate-pulse", glow: "shadow-[0_0_20px_rgba(var(--primary),0.3)] hover:shadow-[0_0_30px_rgba(var(--primary),0.5)]", float: "animate-float", scale: "hover:scale-105", bounce: "hover:animate-bounce", } }, defaultVariants: { variant: "default", size: "default", effect: "none", }, }); const UnifiedButton = React.forwardRef(({ className, variant, size, effect, asChild = false, loading = false, ripple = false, shine = false, pulse = false, glow = false, float = false, scale = false, bounce = false, children, ...props }, ref) => { // Filter out custom props to prevent them from being passed to DOM const domProps = { ...props }; delete domProps.ripple; delete domProps.shine; delete domProps.pulse; delete domProps.glow; delete domProps.float; delete domProps.scale; delete domProps.bounce; const Comp = asChild ? Slot : "button"; const [ripples, setRipples] = React.useState([]); const [isShining, setIsShining] = React.useState(false); const [isSubscribed, setIsSubscribed] = React.useState(false); // Determine effect based on variant and props const activeEffect = React.useMemo(() => { if (effect !== "none") return effect; if (ripple) return "ripple"; if (shine || variant === "shiny") return "shine"; if (pulse || variant === "pulsating") return "pulse"; if (glow || variant === "neon") return "glow"; if (float) return "float"; if (scale || variant === "interactive") return "scale"; if (bounce) return "bounce"; return "none"; }, [effect, ripple, shine, pulse, glow, float, scale, bounce, variant]); const handleClick = (event) => { if (ripple || activeEffect === "ripple") { const rect = event.currentTarget.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const id = Date.now(); setRipples(prev => [...prev, { id, x, y }]); setTimeout(() => { setRipples(prev => prev.filter(ripple => ripple.id !== id)); }, 600); } if (variant === "subscribe") { setIsSubscribed(!isSubscribed); } if (shine || activeEffect === "shine") { setIsShining(true); setTimeout(() => setIsShining(false), 600); } }; return (_jsxs(Comp, { className: cn(unifiedButtonVariants({ variant, size, effect: activeEffect, className })), ref: ref, onClick: handleClick, disabled: loading || domProps.disabled, ...domProps, children: [loading && (_jsx("div", { className: "mr-2 h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" })), _jsx(AnimatePresence, { mode: "wait", children: variant === "subscribe" ? (_jsx(motion.span, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2 }, className: "font-sans", children: isSubscribed ? "Subscribed" : "Subscribe" }, isSubscribed ? "subscribed" : "subscribe")) : (_jsx("span", { className: "font-sans", children: children })) }), (ripple || activeEffect === "ripple") && ripples.map((ripple) => (_jsx(motion.span, { className: "absolute rounded-full bg-white/30", initial: { scale: 0, opacity: 1 }, animate: { scale: 4, opacity: 0 }, transition: { duration: 0.6 }, style: { left: ripple.x - 10, top: ripple.y - 10, width: 20, height: 20, } }, ripple.id))), (shine || activeEffect === "shine" || variant === "shiny") && (_jsx(motion.div, { className: "absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent", initial: { x: "-100%" }, animate: { x: isShining ? "100%" : "-100%" }, transition: { duration: 0.6, ease: "easeInOut" } })), variant === "magic" && (_jsx("div", { className: "absolute inset-0 rounded-lg bg-gradient-to-r from-primary/20 via-chart-2/20 to-chart-3/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300" })), (variant === "interactive" || activeEffect === "scale") && (_jsx(motion.div, { className: "absolute inset-0 bg-white/10 rounded-lg", initial: { scale: 0, opacity: 0 }, whileHover: { scale: 1, opacity: 1 }, transition: { duration: 0.2 } }))] })); }); UnifiedButton.displayName = "UnifiedButton"; export { UnifiedButton, unifiedButtonVariants };