import { useEffect } from 'react';
import {
Pressable,
StyleSheet,
View
} from 'react-native';
import Animated, {
interpolateColor,
useAnimatedStyle,
useSharedValue,
withTiming
} from 'react-native-reanimated';
import {
fonts,
radius,
} from '@/theme';
import { createThemedStyles, useColors } from '@/theme/themed';
import { useRipple } from '@/theme/ripple';
import { motion } from '@/theme/motion';
import { playHaptic } from '@/lib/haptics';
const THUMB_INSET = 3;
export interface Segment {
key: string;
label: string;
}
interface SegmentedControlProps {
segments: Segment[];
value: string;
onChange: (key: string) => void;
}
/**
* Equal-width segmented control with a selection pill anchored inside the
* active segment. The structural tie to `focused` keeps the pill and content
* selection synchronized; labels still cross-fade via Animated.Text.
*/
export function SegmentedControl({ segments, value, onChange }: SegmentedControlProps) {
const styles = useStyles();
return (
{segments.map((segment) => (
onChange(segment.key)}
/>
))}
);
}
function SegmentButton({
label,
focused,
onPress,
}: {
label: string;
focused: boolean;
onPress: () => void;
}) {
const styles = useStyles();
const colors = useColors();
const ripple = useRipple();
// 0 = inactive, 1 = active; drives the label colour cross-fade.
const progress = useSharedValue(focused ? 1 : 0);
useEffect(() => {
progress.value = withTiming(focused ? 1 : 0, motion.quick);
}, [focused, progress]);
// Locals so the worklet captures plain strings: a theme switch re-renders,
// the captured values change, and Reanimated rebuilds the worklet.
const inactiveColor = colors.textSecondary;
const activeColor = colors.accentTextStrong;
const labelStyle = useAnimatedStyle(() => ({
color: interpolateColor(progress.value, [0, 1], [inactiveColor, activeColor]),
}));
const handlePress = () => {
if (focused) return;
playHaptic('selection');
onPress();
};
return (
{focused ? : null}
{label}
);
}
const useStyles = createThemedStyles((colors) => ({
track: {
flexDirection: 'row',
backgroundColor: colors.glassBg,
borderColor: colors.glassBorder,
borderWidth: StyleSheet.hairlineWidth,
borderRadius: radius.pill,
padding: THUMB_INSET,
},
thumb: {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
backgroundColor: colors.glassHighlight,
borderColor: colors.accent,
borderWidth: StyleSheet.hairlineWidth,
borderRadius: radius.pill,
},
segment: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 7,
},
label: {
fontSize: 12,
fontFamily: fonts.sans.medium,
},
}));
export default SegmentedControl;