import React, { ReactNode, useMemo, useState } from "react"; import { Text, TextStyle, TouchableOpacity } from "react-native"; import Animated, { useSharedValue, useAnimatedStyle, withSpring, } from "react-native-reanimated"; import { themeColors, ThemeName } from "../constants/Colors"; import useTheme from "../hooks/useTheme"; interface CheckboxProps { label?: string; isSelected?: boolean; onToggle?: (isSelected: boolean) => void; size?: number; bounceIntensity?: number; themeScheme?: "light" | "dark"; variant?: "default" | "secondary" | ThemeName; innerComponent?: ReactNode disabled?: boolean radius?: number labelTextStyle?: TextStyle } const Checkbox: React.FC = ({ label, isSelected = false, onToggle, size = 24, variant = "default", bounceIntensity = 8, themeScheme, innerComponent, disabled, radius, labelTextStyle }) => { const { currentTheme, themeScheme: defaultThemeScheme } = useTheme(); // Shared values for animated styles const scale = useSharedValue(isSelected ? 1 : 0.9); const borderWidth = useSharedValue(isSelected ? 2 : 1.6); const [isChecked, setIsChecked] = useState(isSelected); const colorStyle = useMemo(() => { if (variant === 'default') { return { backgroundColor: currentTheme.primary, color: currentTheme.primary_foreground, borderColor: currentTheme.border, }; } if (variant === 'secondary') { return { backgroundColor: currentTheme.secondary, color: currentTheme.secondary_foreground, borderColor: currentTheme.border, }; } const theme = themeColors.find((t) => t.name === variant)?.[themeScheme ?? defaultThemeScheme]; return { backgroundColor: theme?.primary || currentTheme.primary, color: theme?.primary_foreground || currentTheme.primary_foreground, borderColor: theme?.border || currentTheme.border, }; }, [currentTheme, themeScheme, defaultThemeScheme, variant]); // Animated styles for checkbox animation const animatedCheckboxStyle = useAnimatedStyle(() => { return { transform: [{ scale: scale.value }], borderWidth: borderWidth.value, borderColor: colorStyle.backgroundColor, }; }); const handlePress = () => { if (disabled) return; const newSelection = !isChecked; // Apply the bouncy spring animation for scale and border width const springConfig = { damping: bounceIntensity, stiffness: 150, overshootClamping: true, }; scale.value = withSpring(newSelection ? 1 : 0.9, springConfig); borderWidth.value = withSpring(newSelection ? 2 : 1.6, { ...springConfig, stiffness: 100 }); setIsChecked(newSelection); onToggle?.(newSelection); }; return ( <> {isChecked && ( {innerComponent ? innerComponent : } )} {label ? {label} : <>} ); }; export default Checkbox;