fristy/src/shared/components/Button.tsx

133 lines
2.8 KiB
TypeScript

import React from 'react';
import {
TouchableOpacity,
Text,
ActivityIndicator,
StyleSheet,
ViewStyle,
TextStyle,
} from 'react-native';
import { COLORS, SPACING, FONT_SIZE, BORDER_RADIUS, SHADOWS } from '@shared/theme';
interface ButtonProps {
title: string;
onPress: () => void;
variant?: 'primary' | 'secondary' | 'outline' | 'danger';
size?: 'sm' | 'md' | 'lg';
loading?: boolean;
disabled?: boolean;
fullWidth?: boolean;
style?: ViewStyle;
textStyle?: TextStyle;
}
export const Button: React.FC<ButtonProps> = ({
title,
onPress,
variant = 'primary',
size = 'md',
loading = false,
disabled = false,
fullWidth = false,
style,
textStyle,
}) => {
const getButtonStyle = (): ViewStyle => {
const baseStyle: ViewStyle = {
...styles.button,
...styles[`button_${size}`],
...(fullWidth && styles.fullWidth),
};
if (disabled || loading) {
return { ...baseStyle, ...styles.disabled };
}
switch (variant) {
case 'primary':
return { ...baseStyle, backgroundColor: COLORS.primary };
case 'secondary':
return { ...baseStyle, backgroundColor: COLORS.secondary };
case 'outline':
return {
...baseStyle,
backgroundColor: 'transparent',
borderWidth: 1,
borderColor: COLORS.primary,
};
case 'danger':
return { ...baseStyle, backgroundColor: COLORS.danger };
default:
return baseStyle;
}
};
const getTextStyle = (): TextStyle => {
const baseTextStyle: TextStyle = {
...styles.text,
...styles[`text_${size}`],
};
if (variant === 'outline') {
return { ...baseTextStyle, color: COLORS.primary };
}
return baseTextStyle;
};
return (
<TouchableOpacity
style={[getButtonStyle(), style]}
onPress={onPress}
disabled={disabled || loading}
activeOpacity={0.7}>
{loading ? (
<ActivityIndicator color="#FFF" size="small" />
) : (
<Text style={[getTextStyle(), textStyle]}>{title}</Text>
)}
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
button: {
alignItems: 'center',
justifyContent: 'center',
borderRadius: BORDER_RADIUS.md,
...SHADOWS.sm,
},
button_sm: {
paddingVertical: SPACING.sm,
paddingHorizontal: SPACING.md,
},
button_md: {
paddingVertical: SPACING.md,
paddingHorizontal: SPACING.lg,
},
button_lg: {
paddingVertical: SPACING.lg,
paddingHorizontal: SPACING.xl,
},
text: {
color: '#FFF',
fontWeight: '600',
},
text_sm: {
fontSize: FONT_SIZE.sm,
},
text_md: {
fontSize: FONT_SIZE.md,
},
text_lg: {
fontSize: FONT_SIZE.lg,
},
fullWidth: {
width: '100%',
},
disabled: {
backgroundColor: COLORS.border,
opacity: 0.6,
},
});