UNPKG

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
"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