rn-vertical-slider
Version:
A vertical Slider for React Native written entirely in javascript.
111 lines (110 loc) • 3.71 kB
JavaScript
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