153 lines
3.6 KiB
TypeScript
153 lines
3.6 KiB
TypeScript
import React from "react";
|
|
import {
|
|
TouchableOpacity,
|
|
Text,
|
|
StyleSheet,
|
|
ActivityIndicator,
|
|
ViewStyle,
|
|
TextStyle,
|
|
StyleProp,
|
|
} from "react-native";
|
|
import { useTheme } from "../contexts/ThemeContext";
|
|
import { fontSize, fontWeight } from "../styles/typography";
|
|
|
|
type ButtonVariant =
|
|
| "primary"
|
|
| "secondary"
|
|
| "tertiary"
|
|
| "danger"
|
|
| "success";
|
|
type ButtonSize = "sm" | "md" | "lg" | "xl";
|
|
|
|
interface MinimalButtonProps {
|
|
title: string;
|
|
onPress: () => void;
|
|
variant?: ButtonVariant;
|
|
size?: ButtonSize;
|
|
loading?: boolean;
|
|
disabled?: boolean;
|
|
style?: StyleProp<ViewStyle>;
|
|
textStyle?: StyleProp<TextStyle>;
|
|
fullWidth?: boolean;
|
|
}
|
|
|
|
export function MinimalButton({
|
|
title,
|
|
onPress,
|
|
variant = "primary",
|
|
size = "md",
|
|
loading = false,
|
|
disabled = false,
|
|
style,
|
|
textStyle,
|
|
fullWidth = false,
|
|
}: MinimalButtonProps) {
|
|
const { colors } = useTheme();
|
|
|
|
const isDisabled = disabled || loading;
|
|
|
|
const getButtonStyle = (): ViewStyle => {
|
|
const baseStyle: ViewStyle = {
|
|
borderRadius: 14,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
opacity: isDisabled ? 0.5 : 1,
|
|
};
|
|
|
|
const sizeStyles: Record<
|
|
ButtonSize,
|
|
{ paddingVertical: number; paddingHorizontal: number }
|
|
> = {
|
|
sm: { paddingVertical: 12, paddingHorizontal: 20 },
|
|
md: { paddingVertical: 16, paddingHorizontal: 28 },
|
|
lg: { paddingVertical: 18, paddingHorizontal: 36 },
|
|
xl: { paddingVertical: 20, paddingHorizontal: 44 },
|
|
};
|
|
|
|
const variantStyles: Record<ButtonVariant, ViewStyle> = {
|
|
primary: {
|
|
backgroundColor: colors.primary,
|
|
shadowColor: colors.primary,
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.3,
|
|
shadowRadius: 8,
|
|
elevation: 4,
|
|
},
|
|
secondary: {
|
|
backgroundColor: "transparent",
|
|
borderWidth: 2,
|
|
borderColor: colors.primary,
|
|
},
|
|
tertiary: {
|
|
backgroundColor: "transparent",
|
|
},
|
|
danger: {
|
|
backgroundColor: colors.danger,
|
|
shadowColor: colors.danger,
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.3,
|
|
shadowRadius: 8,
|
|
elevation: 4,
|
|
},
|
|
success: {
|
|
backgroundColor: colors.success,
|
|
shadowColor: colors.success,
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.3,
|
|
shadowRadius: 8,
|
|
elevation: 4,
|
|
},
|
|
};
|
|
|
|
return {
|
|
...baseStyle,
|
|
...sizeStyles[size],
|
|
...variantStyles[variant],
|
|
...(fullWidth && { width: "100%" }),
|
|
};
|
|
};
|
|
|
|
const getTextStyle = (): TextStyle => {
|
|
const baseTextStyle: TextStyle = {
|
|
fontSize: size === "sm" ? fontSize.sm : fontSize.md,
|
|
fontWeight: fontWeight.bold,
|
|
letterSpacing: 0.5,
|
|
};
|
|
|
|
const variantTextStyles: Record<ButtonVariant, TextStyle> = {
|
|
primary: { color: colors.white },
|
|
secondary: { color: colors.primary },
|
|
tertiary: { color: colors.primary },
|
|
danger: { color: colors.white },
|
|
success: { color: colors.white },
|
|
};
|
|
|
|
return {
|
|
...baseTextStyle,
|
|
...variantTextStyles[variant],
|
|
};
|
|
};
|
|
|
|
return (
|
|
<TouchableOpacity
|
|
style={[getButtonStyle(), style]}
|
|
onPress={onPress}
|
|
disabled={isDisabled}
|
|
activeOpacity={0.85}
|
|
>
|
|
{loading ? (
|
|
<ActivityIndicator
|
|
size="small"
|
|
color={
|
|
variant === "secondary" || variant === "tertiary"
|
|
? colors.primary
|
|
: colors.white
|
|
}
|
|
/>
|
|
) : (
|
|
<Text style={[getTextStyle(), textStyle]}>{title}</Text>
|
|
)}
|
|
</TouchableOpacity>
|
|
);
|
|
}
|