import React from "react" import { ViewStyle, Animated, Easing, TouchableWithoutFeedback } from "react-native" import { color } from "../../theme" import { SwitchProps } from "./switch.props" // dimensions const THUMB_SIZE = 30 const WIDTH = 56 const MARGIN = 2 const OFF_POSITION = -0.5 const ON_POSITION = WIDTH - THUMB_SIZE - MARGIN const BORDER_RADIUS = (THUMB_SIZE * 3) / 4 // colors const ON_COLOR = color.primary const OFF_COLOR = color.palette.offWhite const BORDER_ON_COLOR = ON_COLOR const BORDER_OFF_COLOR = "rgba(0, 0, 0, 0.1)" // animation const DURATION = 250 // the track always has these props const TRACK = { height: THUMB_SIZE + MARGIN, width: WIDTH, borderRadius: BORDER_RADIUS, borderWidth: MARGIN / 2, backgroundColor: color.background, } // the thumb always has these props const THUMB: ViewStyle = { position: "absolute", width: THUMB_SIZE, height: THUMB_SIZE, borderColor: BORDER_OFF_COLOR, borderRadius: THUMB_SIZE / 2, borderWidth: MARGIN / 2, backgroundColor: color.background, shadowColor: BORDER_OFF_COLOR, shadowOffset: { width: 1, height: 2 }, shadowOpacity: 1, shadowRadius: 2, elevation: 2, } const makeAnimatedValue = (switchOn) => new Animated.Value(switchOn ? 1 : 0) export function Switch(props: SwitchProps) { const [timer] = React.useState(makeAnimatedValue(props.value)) const startAnimation = React.useMemo( () => (newValue: boolean) => { const toValue = newValue ? 1 : 0 const easing = Easing.out(Easing.circle) Animated.timing(timer, { toValue, duration: DURATION, easing, useNativeDriver: true, }).start() }, [timer], ) const [previousValue, setPreviousValue] = React.useState(props.value) React.useEffect(() => { if (props.value !== previousValue) { startAnimation(props.value) setPreviousValue(props.value) } }, [props.value]) const handlePress = React.useMemo(() => () => props.onToggle && props.onToggle(!props.value), [ props.onToggle, props.value, ]) if (!timer) { return null } const translateX = timer.interpolate({ inputRange: [0, 1], outputRange: [OFF_POSITION, ON_POSITION], }) const style = props.style const trackStyle = [ TRACK, { backgroundColor: props.value ? ON_COLOR : OFF_COLOR, borderColor: props.value ? BORDER_ON_COLOR : BORDER_OFF_COLOR, }, props.value ? props.trackOnStyle : props.trackOffStyle, ] const thumbStyle = [ THUMB, { transform: [{ translateX }], }, props.value ? props.thumbOnStyle : props.thumbOffStyle, ] return ( ) }