react-native-modern-elements
Version:
A modern, customizable UI component library for React Native
313 lines (312 loc) • 15.2 kB
JavaScript
import React, { memo, useRef, useState } from "react";
import { PanResponder, StyleSheet, Text, View } from "react-native";
import TrackThumlable from "../helper/TrackThumlable";
import Wheel from "../helper/Wheel";
import formatPrice from "../helper/formatPrice";
const RangeSlider = ({ sliderWidth, min, max, step = 10, mode = "range", // default = 2 thumbs
onValueChange, thumbStyle = "one", // default = one thumb
thumbValue = "parcentage", // default = percentage
// ==== New STYLE PROPS ====
TrackthumbLabelBackgroundColor = "#3F4CF6", TrackHeight = 8, defaultTrackColor = "#DFEAFB", trickBorderRadious = 50, // default = 50
textColor = "white", fontSize = 10, // default = 12
priceSymbols = "$", defaultLeftPercent, // default = 15%
defaultRightPercent, // default = 80%
formatPrices = false, }) => {
const [minVal, setMinVal] = useState(Math.round(min + (max - min) * (defaultLeftPercent !== null && defaultLeftPercent !== void 0 ? defaultLeftPercent : 0)) // default 0%
);
const [maxVal, setMaxVal] = useState(Math.round(min + (max - min) * (defaultRightPercent !== null && defaultRightPercent !== void 0 ? defaultRightPercent : 1)) // default 100%
);
// const minPos = useRef(0);
// const maxPos = useRef(sliderWidth);
// Initialize thumb positions in pixels
const minPos = useRef((defaultLeftPercent !== null && defaultLeftPercent !== void 0 ? defaultLeftPercent : 0) * sliderWidth);
const maxPos = useRef((defaultRightPercent !== null && defaultRightPercent !== void 0 ? defaultRightPercent : 1) * sliderWidth);
const gapPixels = ((step * 1) / (max - min)) * sliderWidth;
// === Range Mode - Left Thumb ===
const minPan = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (_, gesture) => {
let newPos = minPos.current + gesture.dx;
newPos = Math.max(0, Math.min(newPos, maxPos.current - gapPixels));
minPos.current = newPos;
const val = Math.round((newPos / sliderWidth) * (max - min) + min);
setMinVal(val);
onValueChange({ min: val, max: maxVal });
},
});
// === Range Mode - Right Thumb ===
const maxPan = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (_, gesture) => {
let newPos = maxPos.current + gesture.dx;
newPos = Math.min(sliderWidth, Math.max(newPos, minPos.current + gapPixels));
maxPos.current = newPos;
const val = Math.round((newPos / sliderWidth) * (max - min) + min);
setMaxVal(val);
onValueChange({ min: minVal, max: val });
},
});
// === Single Thumb Mode ===
const singlePos = useRef((defaultLeftPercent !== null && defaultLeftPercent !== void 0 ? defaultLeftPercent : 0) * sliderWidth);
const [singleVal, setSingleVal] = useState(Math.round(min + (max - min) * (defaultLeftPercent !== null && defaultLeftPercent !== void 0 ? defaultLeftPercent : 0)));
const singlePan = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (_, gesture) => {
let newPos = singlePos.current + gesture.dx;
newPos = Math.max(0, Math.min(newPos, sliderWidth));
singlePos.current = newPos;
const val = Math.round((newPos / sliderWidth) * (max - min) + min);
setSingleVal(val);
// ✅ always return object, no TypeScript error
onValueChange({ min, max: val });
},
});
return (React.createElement(View, { style: [styles.sliderContainer, { width: sliderWidth }] },
React.createElement(View, { style: [
{
height: TrackHeight,
backgroundColor: defaultTrackColor,
borderRadius: trickBorderRadious,
},
styles.track,
] }),
mode === "range" && (React.createElement(View, { style: [
{
backgroundColor: TrackthumbLabelBackgroundColor,
height: TrackHeight,
borderRadius: trickBorderRadious,
},
styles.selectedTrack,
{
left: ((minVal - min) / (max - min)) * sliderWidth,
width: ((maxVal - minVal) / (max - min)) * sliderWidth,
},
] })),
mode === "single" && (React.createElement(View, { style: [
{
backgroundColor: TrackthumbLabelBackgroundColor,
height: TrackHeight,
borderRadius: trickBorderRadious,
},
styles.selectedTrack,
{
width: ((singleVal - min) / (max - min)) * sliderWidth,
},
] })),
mode === "range" && (React.createElement(View, Object.assign({ style: [
{ borderColor: TrackthumbLabelBackgroundColor },
thumbStyle === "one"
? styles.thumb
: thumbStyle === "two"
? styles.thumbs
: thumbStyle === "three"
? styles.thumb
: thumbStyle === "four"
? styles.thumb
: thumbStyle === "five" && styles.thumb,
{ left: ((minVal - min) / (max - min)) * sliderWidth - 10 },
] }, minPan.panHandlers),
React.createElement(TrackThumlable, null),
thumbStyle === "one" ? (React.createElement(React.Fragment, null,
React.createElement(Text, { style: [
{
backgroundColor: TrackthumbLabelBackgroundColor,
color: textColor,
fontSize: fontSize,
},
styles.thumbLabel,
] }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(minVal) : minVal}`
: `${Math.round(((minVal - min) / (max - min)) * 100)}%`),
React.createElement(Wheel, null))) : thumbStyle === "two" ? (React.createElement(Text, { style: { color: textColor, fontSize: fontSize } }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(minVal) : minVal}`
: `${Math.round(((minVal - min) / (max - min)) * 100)}%`)) : thumbStyle === "three" ? null : thumbStyle === "four" ? (React.createElement(Text, { style: [
styles === null || styles === void 0 ? void 0 : styles.thumbLabelss,
{ color: textColor, fontSize: fontSize },
] }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(minVal) : minVal}`
: `${Math.round(((minVal - min) / (max - min)) * 100)}%`)) : (thumbStyle === "five" && (React.createElement(Text, { style: [
styles === null || styles === void 0 ? void 0 : styles.thumbLabelss5,
{ color: textColor, fontSize: fontSize },
] }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(minVal) : minVal}`
: `${Math.round(((minVal - min) / (max - min)) * 100)}%`))))),
mode === "range" && (React.createElement(View, Object.assign({ style: [
{ borderColor: TrackthumbLabelBackgroundColor },
thumbStyle === "one"
? styles.thumb
: thumbStyle === "two"
? styles.thumbs
: thumbStyle === "three"
? styles.thumb
: thumbStyle === "four"
? styles.thumb
: thumbStyle === "five" && styles.thumb,
,
{ left: ((maxVal - min) / (max - min)) * sliderWidth - 10 },
] }, maxPan.panHandlers),
React.createElement(TrackThumlable, null),
thumbStyle === "one" ? (React.createElement(React.Fragment, null,
React.createElement(Text, { style: [
{
backgroundColor: TrackthumbLabelBackgroundColor,
color: textColor,
fontSize: fontSize,
},
,
styles.thumbLabelRight,
] }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(maxVal) : maxVal}`
: `${Math.round(((maxVal - min) / (max - min)) * 100)}%`),
React.createElement(Wheel, null))) : thumbStyle === "two" ? (React.createElement(Text, { style: { color: textColor, fontSize: fontSize } }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(maxVal) : maxVal}`
: `${Math.round(((maxVal - min) / (max - min)) * 100)}%`)) : thumbStyle === "three" ? null : thumbStyle === "four" ? (React.createElement(Text, { style: [
styles === null || styles === void 0 ? void 0 : styles.thumbLabelss,
{ color: textColor, fontSize: fontSize },
] }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(maxVal) : maxVal}`
: `${Math.round(((maxVal - min) / (max - min)) * 100)}%`)) : (thumbStyle === "five" && (React.createElement(Text, { style: [
styles === null || styles === void 0 ? void 0 : styles.thumbLabelss5,
{ color: textColor, fontSize: fontSize },
] }, thumbValue === "Value"
? `${priceSymbols}${formatPrices === true ? formatPrice(maxVal) : maxVal}`
: `${Math.round(((maxVal - min) / (max - min)) * 100)}%`))))),
mode === "single" && (React.createElement(View, Object.assign({ style: [
{ borderColor: TrackthumbLabelBackgroundColor },
thumbStyle === "one"
? styles.thumb
: thumbStyle === "two"
? styles.thumbs
: thumbStyle === "three"
? styles.thumb
: thumbStyle === "four"
? styles.thumb
: thumbStyle === "five" && styles.thumb,
{ left: ((singleVal - min) / (max - min)) * sliderWidth - 10 },
] }, singlePan.panHandlers),
React.createElement(TrackThumlable, null),
thumbStyle === "one" ? (React.createElement(React.Fragment, null,
React.createElement(Text, { style: [
{
backgroundColor: TrackthumbLabelBackgroundColor,
color: textColor,
fontSize: fontSize,
},
styles.thumbLabel,
] }, thumbValue === "Value"
? ` ${priceSymbols}${formatPrices === true ? formatPrice(singleVal) : singleVal}`
: `${Math.round(((singleVal - min) / (max - min)) * 100)}%`),
React.createElement(Wheel, null))) : thumbStyle === "two" ? (React.createElement(Text, { style: { color: textColor, fontSize } }, thumbValue === "Value"
? ` ${priceSymbols}${formatPrices === true ? formatPrice(singleVal) : singleVal}`
: `${Math.round(((singleVal - min) / (max - min)) * 100)}%`)) : thumbStyle === "three" ? null : thumbStyle === "four" ? (React.createElement(Text, { style: [
styles === null || styles === void 0 ? void 0 : styles.thumbLabelss,
{ color: textColor, fontSize: fontSize },
] }, thumbValue === "Value"
? ` ${priceSymbols}${formatPrices === true ? formatPrice(singleVal) : singleVal}`
: `${Math.round(((singleVal - min) / (max - min)) * 100)}%`)) : (thumbStyle === "five" && (React.createElement(Text, { style: [
styles === null || styles === void 0 ? void 0 : styles.thumbLabelss5,
{ color: textColor, fontSize: fontSize },
] }, thumbValue === "Value"
? ` ${priceSymbols}${formatPrices === true ? formatPrice(singleVal) : singleVal}`
: `${Math.round(((singleVal - min) / (max - min)) * 100)}%`)))))));
};
export default memo(RangeSlider);
const styles = StyleSheet.create({
sliderContainer: { height: 50, justifyContent: "center" },
track: {},
selectedTrack: {
position: "absolute",
// top: 20,
left: 0,
},
thumb: {
position: "absolute",
width: 20,
height: 20,
backgroundColor: "white",
borderWidth: 3,
// borderColor: "#3F4CF6",
borderRadius: 10,
justifyContent: "center",
alignItems: "center",
top: 10,
},
thumbLabel: {
position: "absolute",
top: -30,
width: 40,
height: 22,
textAlign: "center",
fontWeight: "bold",
borderTopRightRadius: 50,
borderTopLeftRadius: 10,
borderBottomRightRadius: 10,
overflow: "hidden",
},
thumbLabel2: {
position: "absolute",
top: -40,
width: 50,
height: 120,
borderWidth: 1,
textAlign: "center",
fontWeight: "bold",
borderTopRightRadius: 50,
borderTopLeftRadius: 10,
borderBottomRightRadius: 10,
overflow: "hidden",
},
thumbLabelRight: {
position: "absolute",
top: -30,
width: 41,
height: 24,
flexDirection: "column",
textAlign: "center",
fontWeight: "500",
borderTopRightRadius: 10,
borderTopLeftRadius: 50,
borderBottomLeftRadius: 10,
overflow: "hidden",
},
thumbs: {
position: "absolute",
width: 36,
height: 36,
backgroundColor: "white",
borderWidth: 3,
// borderColor: "#3F4CF6",
borderRadius: 50,
justifyContent: "center",
alignItems: "center",
top: 2.5,
},
thumbLabelss: {
position: "absolute",
top: -30,
fontSize: 12,
color: "black",
width: 100,
height: 25,
textAlign: "center",
fontWeight: "bold",
borderTopRightRadius: 50,
borderTopLeftRadius: 10,
borderBottomRightRadius: 10,
overflow: "hidden",
},
thumbLabelss5: {
position: "absolute",
top: 30,
fontSize: 12,
color: "black",
width: 100,
height: 25,
textAlign: "center",
fontWeight: "bold",
borderTopRightRadius: 50,
borderTopLeftRadius: 10,
borderBottomRightRadius: 10,
overflow: "hidden",
},
});