import MaskedView from '@react-native-masked-view/masked-view' import React from 'react' import { LayoutChangeEvent, StyleSheet, Text, View } from 'react-native' import Animated, { Extrapolation, interpolate, interpolateColor } from 'react-native-reanimated' import Touchable from 'src/components/Touchable' import colors from 'src/styles/colors' import { typeScale } from 'src/styles/fonts' const HEIGHT = 24 interface Props { values: string[] selectedIndex?: number onChange?: (value: string, selectedIndex: number) => void } export default function SegmentedControl({ values, selectedIndex = 0, onChange }: Props) { const [segmentWidth, setSegmentWidth] = React.useState(0) const handleChange = (index: number) => { onChange?.(values[index], index) } const inputRange = values.map((_, i) => i) const translateX = interpolate( selectedIndex, inputRange, inputRange.map((i) => i * segmentWidth), Extrapolation.CLAMP ) const color = interpolateColor( selectedIndex, [0.5, 1], [colors.qrTabBarPrimary, colors.qrTabBarSecondary] ) const colorInverted = interpolateColor( selectedIndex, [0.5, 1], [colors.qrTabBarSecondary, colors.qrTabBarPrimary] ) const onLayout = ({ nativeEvent: { layout: { width }, }, }: LayoutChangeEvent) => { const newSegmentWidth = values.length ? width / values.length : 0 if (newSegmentWidth !== segmentWidth) { setSegmentWidth(newSegmentWidth) } } return ( {selectedIndex != null && !!segmentWidth && ( )} {values.map((value, index) => { return ( {value} ) })} } > {/* Shows behind the mask, i.e. inside the text */} {selectedIndex != null && !!segmentWidth && ( )} {values.map((value, index) => { const isFocused = index === selectedIndex const state = { selected: isFocused } const onPress = () => handleChange(index) return ( ) })} ) } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'row', height: HEIGHT, borderRadius: HEIGHT / 2, borderWidth: 1, overflow: 'hidden', marginHorizontal: 30, }, slider: { position: 'absolute', top: 0, bottom: 0, right: 0, left: 0, }, maskedContainer: { // Transparent background because mask is based off alpha channel. backgroundColor: 'transparent', flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, value: { flex: 1, justifyContent: 'center', alignItems: 'center', }, text: { ...typeScale.labelSemiBoldXSmall, color: colors.accent, }, })