UNPKG

rn-vertical-slider

Version:

A vertical Slider for React Native written entirely in javascript.

111 lines (110 loc) 3.71 kB
import React from 'react'; import { StyleSheet, View } from 'react-native'; import { Gesture, GestureDetector } from 'react-native-gesture-handler'; import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated'; const calculateValue = (position, min, max, step, height) => { 'worklet'; let sliderPosition = height - position; sliderPosition = Math.min(Math.max(sliderPosition, 0), height); let value = sliderPosition / height * (max - min) + min; value = Math.round(value / step) * step; value = Math.min(Math.max(value, min), max); return value; }; const RNVerticalSlider = /*#__PURE__*/React.forwardRef(({ min = 0, max = 100, step = 1, width = 350, height = 30, borderRadius = 5, maximumTrackTintColor = '#3F2DA5', minimumTrackTintColor = '#77ADE6', disabled = false, onChange = () => {}, onComplete = () => {}, value: currentValue = 0, showIndicator = false, renderIndicatorHeight = 40, renderIndicator = () => null, containerStyle = {}, sliderStyle = {}, animationConfig = { damping: 15 } }, ref) => { let point = useSharedValue(currentValue); let disabledProp = useSharedValue(disabled); // Memoized BaseView styles const calculateBaseView = () => ({ height, width, borderRadius, backgroundColor: maximumTrackTintColor }); const baseViewStyle = React.useMemo(calculateBaseView, [borderRadius, height, maximumTrackTintColor, width]); // Gesture handler const handleGesture = type => eventY => { if (disabledProp.value) return; let value = calculateValue(eventY, min, max, step, height); point.value = withSpring(value, animationConfig); runOnJS(type === 'BEGIN' || type === 'CHANGE' ? onChange : onComplete)(value); }; const onGestureStart = event => handleGesture('BEGIN')(event.y); const onGestureChange = event => handleGesture('CHANGE')(event.y); const onGestureEnd = event => handleGesture('END')(event.y); const panGesture = Gesture.Pan().onBegin(onGestureStart).onChange(onGestureChange).onEnd(onGestureEnd).onFinalize(onGestureEnd).runOnJS(true); // Ref methods React.useImperativeHandle(ref, () => ({ setValue: value => { point.value = withSpring(value, animationConfig); onChange(value); }, setState: state => { disabledProp.value = state; } })); // slider styles const slider = useAnimatedStyle(() => { let heightPercentage = (point.value - min) / (max - min) * 100; const style = { backgroundColor: minimumTrackTintColor, height: `${heightPercentage}%` }; return style; }, [point.value]); // indicator styles const indicator = useAnimatedStyle(() => { const style = {}; if (showIndicator) { let bottom = (point.value - min) / (max - min) * height; bottom = Math.min(Math.max(bottom, 0), height - renderIndicatorHeight); style.bottom = bottom; } return style; }, [point.value]); return /*#__PURE__*/React.createElement(GestureDetector, { gesture: panGesture }, /*#__PURE__*/React.createElement(View, { style: [baseViewStyle, containerStyle] }, /*#__PURE__*/React.createElement(View, { style: [baseViewStyle, styles.box, sliderStyle] }, /*#__PURE__*/React.createElement(Animated.View, { style: [styles.box, slider] })), /*#__PURE__*/React.createElement(Animated.View, { style: [styles.indicator, indicator] }, renderIndicator(point.value)))); }); const styles = StyleSheet.create({ box: { overflow: 'hidden', position: 'absolute', bottom: 0, width: '100%' }, indicator: { position: 'absolute' } }); export default RNVerticalSlider; //# sourceMappingURL=Slider.js.map