@tra-tech/react-native-kitra
Version:
UI kit for React Native
164 lines • 4.94 kB
JavaScript
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