@alexandretav/aleui 1.0.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export { Accordion } from './accordion';
2
+ export type { AccordionProps, AccordionItemProps } from './accordion';
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+
3
+ export interface AeroBubbleProps {
4
+ size?: 'sm' | 'md' | 'lg' | 'xl';
5
+ color?: 'cyan' | 'blue' | 'lime' | 'sky';
6
+ className?: string;
7
+ }
8
+
9
+ const sizeClasses = {
10
+ sm: 'w-12 h-12',
11
+ md: 'w-20 h-20',
12
+ lg: 'w-32 h-32',
13
+ xl: 'w-48 h-48',
14
+ };
15
+
16
+ const colorClasses = {
17
+ cyan: 'bg-gradient-to-br from-cyan-300/40 to-cyan-500/20',
18
+ blue: 'bg-gradient-to-br from-blue-300/40 to-blue-500/20',
19
+ lime: 'bg-gradient-to-br from-lime-300/40 to-lime-500/20',
20
+ sky: 'bg-gradient-to-br from-sky-300/40 to-sky-500/20',
21
+ };
22
+
23
+ export const AeroBubble: React.FC<AeroBubbleProps> = ({
24
+ size = 'md',
25
+ color = 'cyan',
26
+ className = '',
27
+ }) => {
28
+ return (
29
+ <div
30
+ className={`
31
+ ${sizeClasses[size]}
32
+ ${colorClasses[color]}
33
+ rounded-full
34
+ backdrop-blur-sm
35
+ border border-white/30
36
+ shadow-[0_8px_32px_0_rgba(31,38,135,0.37)]
37
+ relative
38
+ overflow-hidden
39
+ ${className}
40
+ `}
41
+ >
42
+ {/* Shine effect */}
43
+ <div className="absolute inset-0 bg-gradient-to-br from-white/40 via-transparent to-transparent rounded-full"></div>
44
+
45
+ {/* Inner glow */}
46
+ <div className="absolute bottom-2 right-2 w-1/3 h-1/3 bg-white/30 rounded-full blur-md"></div>
47
+ </div>
48
+ );
49
+ };
50
+
51
+ export default AeroBubble;
@@ -0,0 +1,2 @@
1
+ export { AeroBubble } from './aero-bubble';
2
+ export type { AeroBubbleProps } from './aero-bubble';
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { getAeroClasses, AeroVariantType } from '@/theme/glass';
3
+
4
+ export interface AeroButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: AeroVariantType;
6
+ size?: 'sm' | 'md' | 'lg';
7
+ fullWidth?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const sizeClasses = {
12
+ sm: 'px-4 py-2 text-sm',
13
+ md: 'px-6 py-3 text-base',
14
+ lg: 'px-8 py-4 text-lg',
15
+ };
16
+
17
+ export const AeroButton: React.FC<AeroButtonProps> = ({
18
+ variant = 'light',
19
+ size = 'md',
20
+ fullWidth = false,
21
+ children,
22
+ className = '',
23
+ disabled = false,
24
+ ...props
25
+ }) => {
26
+ const aeroClasses = getAeroClasses(variant, 'rounded-lg');
27
+ const sizeClass = sizeClasses[size];
28
+ const widthClass = fullWidth ? 'w-full' : '';
29
+ const disabledClass = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';
30
+
31
+ return (
32
+ <button
33
+ className={`
34
+ ${aeroClasses}
35
+ ${sizeClass}
36
+ ${widthClass}
37
+ ${disabledClass}
38
+ font-medium text-white
39
+ ${className}
40
+ `}
41
+ disabled={disabled}
42
+ {...props}
43
+ >
44
+ {children}
45
+ </button>
46
+ );
47
+ };
48
+
49
+ export default AeroButton;
@@ -0,0 +1,2 @@
1
+ export { AeroButton } from './aero-button';
2
+ export type { AeroButtonProps } from './aero-button';
@@ -0,0 +1,83 @@
1
+ "use client"
2
+
3
+ import React from 'react'
4
+ import { motion } from 'framer-motion';
5
+ import { cn } from '@/utils';
6
+
7
+ const animation = {
8
+ initial: { "--x": "-100%", scale: 1 },
9
+ animate: { "--x": "-100%", scale: 1 },
10
+ whileHover: { scale: 1.05 },
11
+ whileTap: { scale: 0.95 },
12
+ }
13
+
14
+ const sizeClasses = {
15
+ sm: 'px-4 py-2 text-sm',
16
+ md: 'px-6 py-3 text-base',
17
+ lg: 'px-8 py-4 text-lg',
18
+ };
19
+
20
+ interface ShinyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
21
+ size?: 'sm' | 'md' | 'lg';
22
+ fullWidth?: boolean;
23
+ children: React.ReactNode;
24
+ onClick?: () => void;
25
+ }
26
+
27
+ export const ShinyButton: React.FC<ShinyButtonProps> = ({
28
+ onClick,
29
+ size = 'md',
30
+ fullWidth = false,
31
+ className = '',
32
+ children,
33
+ disabled = false,
34
+ }) => {
35
+ const sizeClass = sizeClasses[size];
36
+ const widthClass = fullWidth ? 'w-full' : '';
37
+
38
+ return (
39
+ <motion.button
40
+ {...animation}
41
+ onClick={onClick}
42
+ disabled={disabled}
43
+ className={cn(
44
+ "relative rounded-xl overflow-hidden font-medium",
45
+ sizeClass,
46
+ widthClass,
47
+ "bg-gradient-to-br from-cyan-400/30 via-blue-400/25 to-cyan-500/30",
48
+ "backdrop-blur-lg border-2 border-cyan-300/40",
49
+ "shadow-[0_0_30px_rgba(0,206,209,0.4),inset_0_0_20px_rgba(255,255,255,0.1)]",
50
+ "hover:shadow-[0_0_50px_rgba(0,206,209,0.6),inset_0_0_30px_rgba(255,255,255,0.2)]",
51
+ "hover:border-cyan-300/60",
52
+ "transition-all duration-300",
53
+ disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
54
+ className,
55
+ )}
56
+ >
57
+ {/* Shine effect */}
58
+ <motion.span
59
+ className="absolute inset-0 z-0"
60
+ animate={{
61
+ x: ["0%", "200%"],
62
+ }}
63
+ transition={{
64
+ duration: 3,
65
+ repeat: Infinity,
66
+ ease: "linear",
67
+ }}
68
+ style={{
69
+ background: "linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%)",
70
+ width: "50%",
71
+ }}
72
+ />
73
+
74
+ {/* Inner glow */}
75
+ <span className="absolute inset-0 bg-gradient-to-t from-transparent via-white/5 to-white/10 z-0" />
76
+
77
+ {/* Text */}
78
+ <span className="relative z-10 text-white font-semibold drop-shadow-[0_2px_8px_rgba(0,0,0,0.5)]">
79
+ {children}
80
+ </span>
81
+ </motion.button>
82
+ );
83
+ };
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { getAeroClasses, AeroVariantType } from '@/theme/glass';
3
+
4
+ export interface AeroCardProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ variant?: AeroVariantType;
6
+ padding?: 'none' | 'sm' | 'md' | 'lg';
7
+ enableInteractions?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const paddingClasses = {
12
+ none: '',
13
+ sm: 'p-4',
14
+ md: 'p-6',
15
+ lg: 'p-8',
16
+ };
17
+
18
+ export const AeroCard: React.FC<AeroCardProps> = ({
19
+ variant = 'light',
20
+ padding = 'md',
21
+ enableInteractions = false,
22
+ children,
23
+ className = '',
24
+ ...props
25
+ }) => {
26
+ const aeroClasses = getAeroClasses(variant, 'rounded-xl', enableInteractions);
27
+ const paddingClass = paddingClasses[padding];
28
+
29
+ return (
30
+ <div
31
+ className={`
32
+ ${aeroClasses}
33
+ ${paddingClass}
34
+ ${className}
35
+ `}
36
+ {...props}
37
+ >
38
+ {children}
39
+ </div>
40
+ );
41
+ };
42
+
43
+ export default AeroCard;
@@ -0,0 +1,2 @@
1
+ export { AeroCard } from './aero-card';
2
+ export type { AeroCardProps } from './aero-card';
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { getAeroClasses, AeroVariantType } from '@/theme/glass';
3
+
4
+ export interface AeroInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
5
+ variant?: AeroVariantType;
6
+ label?: string;
7
+ fullWidth?: boolean;
8
+ }
9
+
10
+ export const AeroInput: React.FC<AeroInputProps> = ({
11
+ variant = 'light',
12
+ label,
13
+ fullWidth = false,
14
+ className = '',
15
+ ...props
16
+ }) => {
17
+ const aeroClasses = getAeroClasses(variant, 'rounded-lg');
18
+ const widthClass = fullWidth ? 'w-full' : '';
19
+
20
+ return (
21
+ <div className={`flex flex-col gap-2 ${widthClass}`}>
22
+ {label && (
23
+ <label className="text-white/90 text-sm font-medium">
24
+ {label}
25
+ </label>
26
+ )}
27
+ <input
28
+ className={`
29
+ ${aeroClasses}
30
+ px-4 py-3
31
+ ${widthClass}
32
+ text-white placeholder-white/50
33
+ ${className}
34
+ `}
35
+ {...props}
36
+ />
37
+ </div>
38
+ );
39
+ };
40
+
41
+ export default AeroInput;
@@ -0,0 +1,2 @@
1
+ export { AeroInput } from './aero-input';
2
+ export type { AeroInputProps } from './aero-input';
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { getGlassClasses, GlassVariantType } from '@/theme/glass';
3
+
4
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: GlassVariantType;
6
+ size?: 'sm' | 'md' | 'lg';
7
+ fullWidth?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const sizeClasses = {
12
+ sm: 'px-4 py-2 text-sm',
13
+ md: 'px-6 py-3 text-base',
14
+ lg: 'px-8 py-4 text-lg',
15
+ };
16
+
17
+
18
+ export const Button: React.FC<ButtonProps> = ({
19
+ variant = 'light',
20
+ size = 'md',
21
+ fullWidth = false,
22
+ children,
23
+ className = '',
24
+ disabled = false,
25
+ ...props
26
+ }) => {
27
+ const glassClasses = getGlassClasses(variant);
28
+ const sizeClass = sizeClasses[size];
29
+ const widthClass = fullWidth ? 'w-full' : '';
30
+ const disabledClass = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';
31
+
32
+ return (
33
+ <button
34
+ className={`
35
+ ${glassClasses}
36
+ ${sizeClass}
37
+ ${widthClass}
38
+ ${disabledClass}
39
+ font-medium text-white
40
+ ${className}
41
+ `}
42
+ disabled={disabled}
43
+ {...props}
44
+ >
45
+ {children}
46
+ </button>
47
+ );
48
+ };
49
+
50
+ export default Button;
@@ -0,0 +1,2 @@
1
+ export { Button } from './button';
2
+ export type { ButtonProps } from './button';
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { getGlassClasses, GlassVariantType } from '@/theme/glass';
3
+
4
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ variant?: GlassVariantType;
6
+ padding?: 'none' | 'sm' | 'md' | 'lg';
7
+ enableInteractions?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const paddingClasses = {
12
+ none: '',
13
+ sm: 'p-4',
14
+ md: 'p-6',
15
+ lg: 'p-8',
16
+ };
17
+
18
+ export const Card: React.FC<CardProps> = ({
19
+ variant = 'light',
20
+ padding = 'md',
21
+ enableInteractions = false,
22
+ children,
23
+ className = '',
24
+ ...props
25
+ }) => {
26
+ const glassClasses = getGlassClasses(variant, undefined, enableInteractions);
27
+ const paddingClass = paddingClasses[padding];
28
+
29
+ return (
30
+ <div
31
+ className={`
32
+ ${glassClasses}
33
+ ${paddingClass}
34
+ ${className}
35
+ `}
36
+ {...props}
37
+ >
38
+ {children}
39
+ </div>
40
+ );
41
+ };
42
+
43
+ export default Card;
@@ -0,0 +1,2 @@
1
+ export { Card } from './card';
2
+ export type { CardProps } from './card';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Glassmorphism UI Component Library
3
+ * Export all components from a single entry point
4
+ */
5
+
6
+ export { Button } from './button';
7
+ export type { ButtonProps } from './button';
8
+
9
+ export { Card } from './card';
10
+ export type { CardProps } from './card';
11
+
12
+ export { Input } from './input';
13
+ export type { InputProps } from './input';
14
+
15
+ export { Modal } from './modal';
16
+ export type { ModalProps } from './modal';
17
+
18
+ export { AeroBubble } from './aero-bubble';
19
+ export type { AeroBubbleProps } from './aero-bubble';
20
+
21
+ export { Accordion } from './accordion';
22
+ export type { AccordionProps, AccordionItemProps } from './accordion';
23
+
24
+ export {
25
+ getGlassClasses,
26
+ getAeroClasses,
27
+ glassVariants,
28
+ aeroVariants,
29
+ } from '@/theme/glass';
30
+ export type { GlassVariantType, AeroVariantType } from '@/theme/glass';
@@ -0,0 +1,2 @@
1
+ export { Input } from './input';
2
+ export type { InputProps } from './input';
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { getGlassClasses, GlassVariantType } from '@/theme/glass';
3
+
4
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
5
+ variant?: GlassVariantType;
6
+ fullWidth?: boolean;
7
+ label?: string;
8
+ }
9
+
10
+ export const Input: React.FC<InputProps> = ({
11
+ variant = 'light',
12
+ fullWidth = false,
13
+ label,
14
+ className = '',
15
+ id,
16
+ ...props
17
+ }) => {
18
+ const glassClasses = getGlassClasses(variant);
19
+ const widthClass = fullWidth ? 'w-full' : '';
20
+ const inputId = id || label?.toLowerCase().replace(/\s+/g, '-');
21
+
22
+ return (
23
+ <div className={`flex flex-col gap-2 ${widthClass}`}>
24
+ {label && (
25
+ <label
26
+ htmlFor={inputId}
27
+ className="text-white text-sm font-medium pl-1"
28
+ >
29
+ {label}
30
+ </label>
31
+ )}
32
+ <input
33
+ id={inputId}
34
+ className={`
35
+ ${glassClasses}
36
+ ${widthClass}
37
+ px-4 py-3
38
+ text-white placeholder-white/50
39
+ transition-all duration-300
40
+ focus:outline-none focus:ring-2 focus:ring-white/50
41
+ ${className}
42
+ `}
43
+ {...props}
44
+ />
45
+ </div>
46
+ );
47
+ };
48
+
49
+ export default Input;
@@ -0,0 +1,2 @@
1
+ export { Modal } from './modal';
2
+ export type { ModalProps } from './modal';
@@ -0,0 +1,82 @@
1
+ import React from 'react';
2
+ import { getGlassClasses, GlassVariantType } from '@/theme/glass';
3
+
4
+ export interface ModalProps {
5
+ isOpen: boolean;
6
+ onClose: () => void;
7
+ variant?: GlassVariantType;
8
+ title?: string;
9
+ children: React.ReactNode;
10
+ size?: 'sm' | 'md' | 'lg' | 'xl';
11
+ }
12
+
13
+ const sizeClasses = {
14
+ sm: 'max-w-sm',
15
+ md: 'max-w-md',
16
+ lg: 'max-w-lg',
17
+ xl: 'max-w-xl',
18
+ };
19
+
20
+ export const Modal: React.FC<ModalProps> = ({
21
+ isOpen,
22
+ onClose,
23
+ variant = 'medium',
24
+ title,
25
+ children,
26
+ size = 'md',
27
+ }) => {
28
+ if (!isOpen) return null;
29
+
30
+ const glassClasses = getGlassClasses(variant);
31
+ const sizeClass = sizeClasses[size];
32
+
33
+ return (
34
+ <div
35
+ className="fixed inset-0 z-50 flex items-center justify-center p-4 animate-fadeIn"
36
+ onClick={onClose}
37
+ >
38
+ {/* Backdrop */}
39
+ <div className="absolute inset-0 bg-black/50 backdrop-blur-sm" />
40
+
41
+ {/* Modal */}
42
+ <div
43
+ className={`
44
+ ${glassClasses}
45
+ ${sizeClass}
46
+ w-full p-6 relative z-10
47
+ animate-scaleIn
48
+ `}
49
+ onClick={(e) => e.stopPropagation()}
50
+ >
51
+ {/* Header */}
52
+ {title && (
53
+ <div className="flex items-center justify-between mb-4">
54
+ <h2 className="text-2xl font-bold text-white">{title}</h2>
55
+ <button
56
+ onClick={onClose}
57
+ className="text-white/70 hover:text-white transition-colors p-1"
58
+ aria-label="Close modal"
59
+ >
60
+ <svg
61
+ className="w-6 h-6"
62
+ fill="none"
63
+ strokeLinecap="round"
64
+ strokeLinejoin="round"
65
+ strokeWidth="2"
66
+ viewBox="0 0 24 24"
67
+ stroke="currentColor"
68
+ >
69
+ <path d="M6 18L18 6M6 6l12 12" />
70
+ </svg>
71
+ </button>
72
+ </div>
73
+ )}
74
+
75
+ {/* Content */}
76
+ <div className="text-white">{children}</div>
77
+ </div>
78
+ </div>
79
+ );
80
+ };
81
+
82
+ export default Modal;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Glassmorphism Theme Configuration
3
+ * Define reusable glassmorphism styles and variants
4
+ */
5
+
6
+ export interface GlassVariant {
7
+ background: string;
8
+ backdropBlur: string;
9
+ border: string;
10
+ shadow: string;
11
+ hover: string;
12
+ focus: string;
13
+ }
14
+
15
+ export interface AeroVariant {
16
+ background: string;
17
+ backdropBlur: string;
18
+ border: string;
19
+ shadow: string;
20
+ hover: string;
21
+ focus: string;
22
+ }
23
+
24
+ // Traditional Glassmorphism styles
25
+ export const glassVariants = {
26
+ light: {
27
+ background: 'bg-white/5',
28
+ backdropBlur: 'backdrop-blur-[2px]',
29
+ border: 'border border-white/15',
30
+ shadow: 'shadow-lg',
31
+ hover: 'hover:bg-white/10 hover:shadow-xl',
32
+ focus: 'focus:outline-none focus:ring-2 focus:ring-white/10',
33
+ },
34
+ medium: {
35
+ background: 'bg-white/20',
36
+ backdropBlur: 'backdrop-blur-lg',
37
+ border: 'border border-white/30',
38
+ shadow: 'shadow-xl',
39
+ hover: 'hover:bg-white/30 hover:shadow-2xl',
40
+ focus: 'focus:outline-none focus:ring-2 focus:ring-white/50',
41
+ },
42
+ dark: {
43
+ background: 'bg-black/20',
44
+ backdropBlur: 'backdrop-blur-md',
45
+ border: 'border border-white/10',
46
+ shadow: 'shadow-lg',
47
+ hover: 'hover:bg-black/30 hover:shadow-xl',
48
+ focus: 'focus:outline-none focus:ring-2 focus:ring-white/40',
49
+ },
50
+ colored: {
51
+ background: 'bg-gradient-to-br from-white/20 to-white/10',
52
+ backdropBlur: 'backdrop-blur-xl',
53
+ border: 'border border-white/25',
54
+ shadow: 'shadow-2xl',
55
+ hover: 'hover:from-white/30 hover:to-white/20 hover:shadow-[0_8px_32px_0_rgba(255,255,255,0.37)]',
56
+ focus: 'focus:outline-none focus:ring-2 focus:ring-white/60',
57
+ },
58
+ } as const;
59
+
60
+ // Frutiger Aero specific styles
61
+ export const aeroVariants = {
62
+ light: {
63
+ background: 'bg-gradient-to-br from-cyan-400/20 to-blue-400/10',
64
+ backdropBlur: 'backdrop-blur-md',
65
+ border: 'border border-cyan-300/30',
66
+ shadow: 'shadow-aero',
67
+ hover: 'hover:from-cyan-400/30 hover:to-blue-400/20 hover:shadow-aero-lg',
68
+ focus: 'focus:outline-none focus:ring-2 focus:ring-cyan-300/50',
69
+ },
70
+ medium: {
71
+ background: 'bg-gradient-to-br from-sky-400/25 to-cyan-400/15',
72
+ backdropBlur: 'backdrop-blur-lg',
73
+ border: 'border border-sky-300/40',
74
+ shadow: 'shadow-aero-lg',
75
+ hover: 'hover:from-sky-400/35 hover:to-cyan-400/25 hover:shadow-[0_8px_32px_0_rgba(56,189,248,0.37)]',
76
+ focus: 'focus:outline-none focus:ring-2 focus:ring-sky-300/60',
77
+ },
78
+ dark: {
79
+ background: 'bg-gradient-to-br from-blue-500/30 to-cyan-500/20',
80
+ backdropBlur: 'backdrop-blur-md',
81
+ border: 'border border-blue-300/30',
82
+ shadow: 'shadow-aero',
83
+ hover: 'hover:from-blue-500/40 hover:to-cyan-500/30 hover:shadow-aero-lg',
84
+ focus: 'focus:outline-none focus:ring-2 focus:ring-blue-300/50',
85
+ },
86
+ colored: {
87
+ background: 'bg-gradient-to-br from-lime-400/25 via-cyan-400/20 to-blue-400/15',
88
+ backdropBlur: 'backdrop-blur-xl',
89
+ border: 'border border-lime-300/35',
90
+ shadow: 'shadow-aero-lg',
91
+ hover: 'hover:from-lime-400/35 hover:via-cyan-400/30 hover:to-blue-400/25 hover:shadow-[0_8px_32px_0_rgba(163,230,53,0.37)]',
92
+ focus: 'focus:outline-none focus:ring-2 focus:ring-lime-300/60',
93
+ },
94
+ } as const;
95
+
96
+ export type GlassVariantType = keyof typeof glassVariants;
97
+ export type AeroVariantType = keyof typeof aeroVariants;
98
+
99
+ /**
100
+ * Generate glassmorphism class string
101
+ */
102
+ export const getGlassClasses = (
103
+ variant: GlassVariantType = 'light',
104
+ rounded: string = 'rounded-xl',
105
+ includeInteractions: boolean = true
106
+ ): string => {
107
+ const v = glassVariants[variant];
108
+ const interactions = includeInteractions ? `transition-all duration-300 ${v.hover} ${v.focus} active:scale-95` : '';
109
+ return `${v.background} ${v.backdropBlur} ${v.border} ${v.shadow} ${rounded} ${interactions}`;
110
+ };
111
+
112
+ /**
113
+ * Generate Frutiger Aero class string
114
+ */
115
+ export const getAeroClasses = (
116
+ variant: AeroVariantType = 'light',
117
+ rounded: string = 'rounded-xl',
118
+ includeInteractions: boolean = true
119
+ ): string => {
120
+ const v = aeroVariants[variant];
121
+ const interactions = includeInteractions ? `transition-all duration-300 ${v.hover} ${v.focus} active:scale-95` : '';
122
+ return `${v.background} ${v.backdropBlur} ${v.border} ${v.shadow} ${rounded} ${interactions}`;
123
+ };
124
+