import React, { useEffect, useRef, useState } from 'react'; import { StyleSheet, TextInput, View } from 'react-native'; import { Gesture, GestureDetector, PanGestureHandler } from 'react-native-gesture-handler'; import Animated, { runOnJS, useAnimatedGestureHandler, useAnimatedProps, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'; import type { FCCWD, SliderProps } from '../../types'; import { applyDefaults } from '../../core/KitraProvider'; const AnimatedTextInput = Animated.createAnimatedComponent(TextInput); const Slider: FCCWD = ( { theme, showPercentage, onChangeEnd = () => null, value, buttonStyle, barStyle, progressStyle, }, ) => { const progress = useSharedValue(0); const containerRef = useRef(null); const [measure, setMeasure] = useState({ x: 0, y: 0, pageX: 0, pageY: 0, width: 0, height: 0 }); const onEndHandler = () => { onChangeEnd(Number(((progress.value / (measure.width - 20)) * 100).toFixed())); }; const animatedProps = useAnimatedProps(() => ({ text: `%${((progress.value / (measure.width - 20)) * 100).toFixed().toString()}`, } as any)); const handler = useAnimatedGestureHandler({ onStart: (_, ctx) => { // @ts-ignore ctx.offsetX = progress.value; }, onActive: (event, ctx) => { // @ts-ignore let newTranslateX = event.translationX + ctx.offsetX; if (newTranslateX < 0) { newTranslateX = 0; } if (newTranslateX > measure.width - 20) { newTranslateX = measure.width - 20; } if (newTranslateX >= 0 && newTranslateX <= measure.width - 20) { progress.value = newTranslateX; } }, onEnd: () => runOnJS(onEndHandler)(), }, [measure]); useEffect(() => { if (value) { if (value >= 100) progress.value = withTiming(100); if (value <= 0) { progress.value = withTiming(0); } else progress.value = withTiming((value / 100) * (measure.width - 20)); } }, [value, measure]); const progressBarStyle = useAnimatedStyle(() => ({ transform: [{ translateX: progress.value }], }), [progress.value]); const percentageStyle = useAnimatedStyle(() => ({ width: progress.value + 5, }), [progress.value]); const tap = Gesture.Tap().onStart(e => { const translateX = e.x > measure.width - 20 ? measure.width - 20 : e.x; progress.value = withTiming(translateX); }); return ( containerRef.current?.measure((x, y, width, height, pageX, pageY) => { setMeasure({ x, y, pageX, pageY, width, height }); })} style={[{ backgroundColor: theme?.primary15 }, Style.barStyle, barStyle]} > {showPercentage && ( )} ); }; const Style = StyleSheet.create({ percentageIndicator: { position: 'absolute', justifyContent: 'center', top: -30, width: 35, height: 25, borderRadius: 5, alignSelf: 'center' }, button: { position: 'absolute', height: 20, width: 20, borderRadius: 10, shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.46, shadowRadius: 11.14, elevation: 17 }, barStyle: { borderRadius: 14, height: 6, justifyContent: 'center' }, }); export default applyDefaults(Slider);