import React from 'react';
import {
TouchableOpacity,
Text,
StyleSheet,
ActivityIndicator,
View,
type TouchableOpacityProps,
type ViewStyle,
type TextStyle,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { AppColors, BorderRadius, FontSizes, FontWeights, Spacing, Shadows } from '@/constants/theme';
interface ButtonProps extends TouchableOpacityProps {
title: string;
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
loading?: boolean;
fullWidth?: boolean;
icon?: keyof typeof Ionicons.glyphMap;
iconPosition?: 'left' | 'right';
}
export function Button({
title,
variant = 'primary',
size = 'md',
loading = false,
fullWidth = false,
icon,
iconPosition = 'left',
disabled,
style,
...props
}: ButtonProps) {
const isDisabled = disabled || loading;
const buttonStyles: ViewStyle[] = [
styles.base,
styles[variant],
styles[`size_${size}`],
fullWidth && styles.fullWidth,
isDisabled && styles.disabled,
variant === 'primary' && !isDisabled && Shadows.primary,
style as ViewStyle,
];
const textStyles: TextStyle[] = [
styles.text,
styles[`text_${variant}`],
styles[`text_${size}`],
isDisabled && styles.textDisabled,
];
const iconSize = size === 'sm' ? 16 : size === 'lg' ? 22 : 18;
const iconColor = variant === 'primary' || variant === 'danger'
? AppColors.white
: variant === 'secondary'
? AppColors.textPrimary
: AppColors.primary;
const renderContent = () => {
if (loading) {
return (
);
}
return (
{icon && iconPosition === 'left' && (
)}
{title}
{icon && iconPosition === 'right' && (
)}
);
};
return (
{renderContent()}
);
}
const styles = StyleSheet.create({
base: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
borderRadius: BorderRadius.lg,
},
content: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
primary: {
backgroundColor: AppColors.primary,
},
secondary: {
backgroundColor: AppColors.surfaceSecondary,
borderWidth: 1,
borderColor: AppColors.border,
},
outline: {
backgroundColor: 'transparent',
borderWidth: 1.5,
borderColor: AppColors.primary,
},
ghost: {
backgroundColor: 'transparent',
},
danger: {
backgroundColor: AppColors.error,
},
size_sm: {
paddingVertical: Spacing.sm,
paddingHorizontal: Spacing.md,
minHeight: 40,
borderRadius: BorderRadius.md,
},
size_md: {
paddingVertical: Spacing.sm + 4,
paddingHorizontal: Spacing.lg,
minHeight: 48,
},
size_lg: {
paddingVertical: Spacing.md,
paddingHorizontal: Spacing.xl,
minHeight: 56,
borderRadius: BorderRadius.xl,
},
fullWidth: {
width: '100%',
},
disabled: {
opacity: 0.5,
shadowOpacity: 0,
},
text: {
fontWeight: FontWeights.semibold,
letterSpacing: 0.3,
},
text_primary: {
color: AppColors.white,
},
text_secondary: {
color: AppColors.textPrimary,
},
text_outline: {
color: AppColors.primary,
},
text_ghost: {
color: AppColors.primary,
},
text_danger: {
color: AppColors.white,
},
text_sm: {
fontSize: FontSizes.sm,
},
text_md: {
fontSize: FontSizes.base,
},
text_lg: {
fontSize: FontSizes.lg,
},
textDisabled: {
color: AppColors.textDisabled,
},
iconLeft: {
marginRight: Spacing.sm,
},
iconRight: {
marginLeft: Spacing.sm,
},
});