UNPKG

@tra-tech/react-native-kitra

Version:
164 lines 4.94 kB
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 { applyDefaults } from '../../core/KitraProvider'; const AnimatedTextInput = Animated.createAnimatedComponent(TextInput); const Slider = _ref => { let { theme, showPercentage, onChangeEnd = () => null, value, buttonStyle, barStyle, progressStyle } = _ref; 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()}` })); 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 /*#__PURE__*/React.createElement(View, { style: { flex: 1 } }, /*#__PURE__*/React.createElement(GestureDetector, { gesture: tap }, /*#__PURE__*/React.createElement(View, { ref: containerRef, onLayout: () => { var _containerRef$current; return (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.measure((x, y, width, height, pageX, pageY) => { setMeasure({ x, y, pageX, pageY, width, height }); }); }, style: [{ backgroundColor: theme === null || theme === void 0 ? void 0 : theme.primary15 }, Style.barStyle, barStyle] }, /*#__PURE__*/React.createElement(Animated.View, { style: [{ position: 'absolute', borderRadius: 14, backgroundColor: theme === null || theme === void 0 ? void 0 : theme.primary, width: progress, height: 6 }, progressStyle, percentageStyle] }), /*#__PURE__*/React.createElement(PanGestureHandler, { onGestureEvent: handler }, /*#__PURE__*/React.createElement(Animated.View, { hitSlop: { top: 25, bottom: 25, left: 25, right: 25 }, style: [{ backgroundColor: theme === null || theme === void 0 ? void 0 : theme.white }, Style.button, buttonStyle, progressBarStyle] }, showPercentage && /*#__PURE__*/React.createElement(View, { style: [Style.percentageIndicator, { backgroundColor: theme === null || theme === void 0 ? void 0 : theme.primary }] }, /*#__PURE__*/React.createElement(AnimatedTextInput, { underlineColorAndroid: "transparent", editable: false, style: { textAlign: 'center', color: theme === null || theme === void 0 ? void 0 : theme.white, fontSize: 12 }, value: progress.value.toString(), animatedProps }))))))); }; 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); //# sourceMappingURL=index.js.map