react-native-sticky-range-slider
Version:
[React Native | TypeScript] A pure TypeScript component offering a customizable range slider optimized for performance. It supports dragging functionalities for selecting a range of values, with values that smoothly follow the thumb. This component is ful
249 lines (248 loc) • 10.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _hooks = require("../hooks");
var _helpers = require("../utils/helpers");
var _Rail = _interopRequireDefault(require("./Rail"));
var _RailSelected = _interopRequireDefault(require("./RailSelected"));
var _TextValue = _interopRequireDefault(require("./TextValue"));
var _Thumb = _interopRequireDefault(require("./Thumb"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const trueFunc = () => true;
const falseFunc = () => false;
const Slider = ({
min,
max,
minRange: minRangeProp = 0,
step,
low: lowProp,
high: highProp,
onValueChanged,
renderThumb = () => /*#__PURE__*/_react.default.createElement(_Thumb.default, null),
renderRail = () => /*#__PURE__*/_react.default.createElement(_Rail.default, null),
renderRailSelected = () => /*#__PURE__*/_react.default.createElement(_RailSelected.default, null),
renderLowValue = low => /*#__PURE__*/_react.default.createElement(_TextValue.default, {
value: low
}),
renderHighValue = high => /*#__PURE__*/_react.default.createElement(_TextValue.default, {
value: high
}),
pannableAreaStyle,
disableRange = false,
disabled = false,
...restProps
}) => {
const minRange = disableRange ? 0 : minRangeProp;
const {
inPropsRef,
inPropsRefPrev,
setLow,
setHigh
} = (0, _hooks.useLowHigh)(lowProp, disableRange ? max : highProp, min, max, step);
const lowThumbXRef = (0, _react.useRef)(new _reactNative.Animated.Value(0));
const highThumbXRef = (0, _react.useRef)(new _reactNative.Animated.Value(0));
const pointerX = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current;
const {
current: lowThumbX
} = lowThumbXRef;
const {
current: highThumbX
} = highThumbXRef;
const gestureStateRef = (0, _react.useRef)({
isLow: true,
lastValue: 0,
lastPosition: 0
});
const containerWidthRef = (0, _react.useRef)(0);
const [thumbWidth, setThumbWidth] = (0, _react.useState)(0);
const {
selectedRailStyle,
updateSelectedRail
} = (0, _hooks.useSelectedRail)(inPropsRef, containerWidthRef, thumbWidth, disableRange);
const updateThumbs = (0, _react.useCallback)(() => {
const {
current: containerWidth
} = containerWidthRef;
if (!thumbWidth || !containerWidth) {
return;
}
const {
low,
high
} = inPropsRef.current;
if (!disableRange) {
const highPosition = (high - min) / (max - min) * (containerWidth - thumbWidth);
highThumbXRef.current.setValue(highPosition);
}
const lowPosition = (low - min) / (max - min) * (containerWidth - thumbWidth);
lowThumbXRef.current.setValue(lowPosition);
updateSelectedRail();
onValueChanged?.(low, high);
}, [disableRange, inPropsRef, max, min, onValueChanged, thumbWidth, updateSelectedRail]);
(0, _react.useEffect)(() => {
const {
lowPrev,
highPrev
} = inPropsRefPrev;
if (lowProp !== undefined && lowProp !== lowPrev || highProp !== undefined && highProp !== highPrev) {
updateThumbs();
}
}, [highProp, inPropsRefPrev, lowProp, updateThumbs]);
(0, _react.useEffect)(() => {
updateThumbs();
}, [updateThumbs]);
const handleContainerLayout = (0, _hooks.useWidthLayout)(containerWidthRef, updateThumbs);
const handleThumbLayout = (0, _react.useCallback)(({
nativeEvent
}) => {
const {
layout: {
width
}
} = nativeEvent;
if (thumbWidth !== width) {
setThumbWidth(width);
}
}, [thumbWidth]);
const lowStyles = (0, _react.useMemo)(() => {
return {
transform: [{
translateX: lowThumbX
}]
};
}, [lowThumbX]);
const highStyles = (0, _react.useMemo)(() => {
return disableRange ? null : [styles.highThumbContainer, {
transform: [{
translateX: highThumbX
}]
}];
}, [disableRange, highThumbX]);
const railContainerStyles = (0, _react.useMemo)(() => {
return [styles.railsContainer, {
marginHorizontal: thumbWidth / 2
}];
}, [thumbWidth]);
const lowThumb = renderThumb('low');
const highThumb = renderThumb('high');
const {
panHandlers
} = (0, _react.useMemo)(() => _reactNative.PanResponder.create({
onStartShouldSetPanResponderCapture: falseFunc,
onMoveShouldSetPanResponderCapture: falseFunc,
onPanResponderTerminationRequest: falseFunc,
onPanResponderTerminate: trueFunc,
onShouldBlockNativeResponder: trueFunc,
onMoveShouldSetPanResponder: (_evt, gestureState) => Math.abs(gestureState.dx) > 2 * Math.abs(gestureState.dy),
onPanResponderGrant: ({
nativeEvent
}, gestureState) => {
if (disabled) {
return;
}
const {
numberActiveTouches
} = gestureState;
if (numberActiveTouches > 1) {
return;
}
const {
locationX: downX,
pageX
} = nativeEvent;
const containerX = pageX - downX;
const containerWidth = containerWidthRef.current;
const lowPosition = thumbWidth / 2 + (inPropsRef.current.low - inPropsRef.current.min) / (inPropsRef.current.max - inPropsRef.current.min) * (containerWidth - thumbWidth);
const highPosition = thumbWidth / 2 + (inPropsRef.current.high - inPropsRef.current.min) / (inPropsRef.current.max - inPropsRef.current.min) * (containerWidth - thumbWidth);
const isLow = disableRange || (0, _helpers.isLowCloser)(downX, lowPosition, highPosition);
gestureStateRef.current.isLow = isLow;
const handlePositionChange = positionInView => {
const minValue = isLow ? inPropsRef.current.min : inPropsRef.current.low + minRange;
const maxValue = isLow ? inPropsRef.current.high - minRange : inPropsRef.current.max;
const value = (0, _helpers.clamp)((0, _helpers.getValueForPosition)(positionInView, containerWidth, thumbWidth, inPropsRef.current.min, inPropsRef.current.max, inPropsRef.current.step), minValue, maxValue);
if (gestureStateRef.current.lastValue === value) {
return;
}
const availableSpace = containerWidth - thumbWidth;
const absolutePosition = (value - inPropsRef.current.min) / (inPropsRef.current.max - inPropsRef.current.min) * availableSpace;
gestureStateRef.current.lastValue = value;
gestureStateRef.current.lastPosition = absolutePosition + thumbWidth / 2;
(isLow ? lowThumbXRef.current : highThumbXRef.current).setValue(absolutePosition);
onValueChanged?.(isLow ? value : inPropsRef.current.low, isLow ? inPropsRef.current.high : value);
(isLow ? setLow : setHigh)(value);
updateSelectedRail();
};
handlePositionChange(downX);
pointerX.removeAllListeners();
pointerX.addListener(({
value: pointerPosition
}) => {
const positionInView = pointerPosition - containerX;
handlePositionChange(positionInView);
});
},
onPanResponderMove: disabled ? undefined : _reactNative.Animated.event([null, {
moveX: pointerX
}], {
useNativeDriver: false
})
}), [disableRange, disabled, inPropsRef, minRange, onValueChanged, pointerX, setHigh, setLow, thumbWidth, updateSelectedRail]);
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactNative.View, restProps, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
onLayout: handleContainerLayout,
style: styles.controlsContainer
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: railContainerStyles
}, renderRail(), /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {
style: selectedRailStyle
}, renderRailSelected())), /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {
style: lowStyles,
onLayout: handleThumbLayout
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: styles.value
}, renderLowValue(inPropsRef.current.low)), lowThumb), !disableRange && /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {
style: highStyles
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: styles.value
}, renderHighValue(inPropsRef.current.high)), highThumb), /*#__PURE__*/_react.default.createElement(_reactNative.View, _extends({}, panHandlers, {
style: [styles.touchableArea, pannableAreaStyle],
collapsable: false
})))));
};
const styles = _reactNative.StyleSheet.create({
controlsContainer: {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center'
},
highThumbContainer: {
position: 'absolute'
},
railsContainer: {
..._reactNative.StyleSheet.absoluteFillObject,
flexDirection: 'row',
alignItems: 'center'
},
touchableArea: {
position: "absolute",
top: -20,
bottom: -20,
left: -20,
right: -20,
opacity: 0.5,
zIndex: 1000
},
value: {
position: 'absolute',
top: -20,
width: 40
}
});
var _default = exports.default = /*#__PURE__*/(0, _react.memo)(Slider);
//# sourceMappingURL=RangeSlider.js.map