133 lines
2.8 KiB
TypeScript
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,
|
|
},
|
|
});
|