91 lines
2.0 KiB
TypeScript
91 lines
2.0 KiB
TypeScript
import {
|
|
ActivityIndicator,
|
|
Pressable,
|
|
StyleSheet,
|
|
Text,
|
|
type PressableProps,
|
|
} from 'react-native';
|
|
import { useAppearance } from '@/src/context/AppearanceContext';
|
|
|
|
type Variant = 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
|
|
interface ButtonProps extends Omit<PressableProps, 'style'> {
|
|
title: string;
|
|
loading?: boolean;
|
|
variant?: Variant;
|
|
style?: PressableProps['style'];
|
|
}
|
|
|
|
export function Button({
|
|
title,
|
|
loading,
|
|
variant = 'primary',
|
|
disabled,
|
|
style: externalStyle,
|
|
...rest
|
|
}: ButtonProps) {
|
|
const { colors } = useAppearance();
|
|
const isDisabled = disabled || loading;
|
|
|
|
const backgroundColor =
|
|
variant === 'primary'
|
|
? colors.brand
|
|
: variant === 'danger'
|
|
? colors.danger
|
|
: variant === 'secondary'
|
|
? colors.brandLight
|
|
: 'transparent';
|
|
|
|
const textColor =
|
|
variant === 'primary' || variant === 'danger'
|
|
? '#ffffff'
|
|
: variant === 'secondary'
|
|
? colors.brand
|
|
: colors.brand;
|
|
|
|
return (
|
|
<Pressable
|
|
accessibilityRole="button"
|
|
disabled={isDisabled}
|
|
style={(state) => {
|
|
const resolvedExternal =
|
|
typeof externalStyle === 'function' ? externalStyle(state) : externalStyle;
|
|
return [
|
|
styles.base,
|
|
{
|
|
backgroundColor,
|
|
borderColor: variant === 'ghost' ? colors.border : backgroundColor,
|
|
opacity: isDisabled ? 0.6 : state.pressed ? 0.85 : 1,
|
|
},
|
|
variant === 'ghost' && styles.ghost,
|
|
resolvedExternal,
|
|
];
|
|
}}
|
|
{...rest}
|
|
>
|
|
{loading ? (
|
|
<ActivityIndicator color={textColor} />
|
|
) : (
|
|
<Text style={[styles.label, { color: textColor }]}>{title}</Text>
|
|
)}
|
|
</Pressable>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
base: {
|
|
minHeight: 48,
|
|
borderRadius: 12,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingHorizontal: 16,
|
|
},
|
|
ghost: {
|
|
borderWidth: 1,
|
|
},
|
|
label: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
},
|
|
});
|