UNPKG

react-native-preview-story

Version:

React Native Story Component Which takes Stories array and show exact story view like infamous instagram

241 lines (240 loc) 8.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _Styled = _interopRequireDefault(require("../Styled.js")); var _Header = _interopRequireDefault(require("./Header.js")); var _ContentView = _interopRequireDefault(require("./ContentView.js")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } 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; } const { width } = _reactNative.Dimensions.get('window'); const StoryView = ({ onComplete, stories, visible, imageStyle, maxDuration = 3, renderHeaderComponent = null, storyName = '', onChangePosition, index, close = true, playPause = true, storyNameText = {}, headerStyle = { cornerRadius: 10, progressColor: 'orange', progressBarHeight: 7, progressBarBackground: 'white' }, noPause = false, noControls = false, nativeDriver = false, onPressBack = () => null, noLoop = false }, ref) => { const [currentStoryIndex, setCurrentStoryIndex] = (0, _react.useState)(index || 0); const progressAnim = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current; const pausedProgress = (0, _react.useRef)(0); const [isPaused, setIsPaused] = (0, _react.useState)(false); const isCompletedRef = (0, _react.useRef)(false); const currentStory = _react.default.useMemo(() => stories[currentStoryIndex], [currentStoryIndex, stories]); const maxDurationPerStory = _react.default.useMemo(() => currentStory?.duration || maxDuration, [currentStory, maxDuration]); const [wentBack, setWentBack] = (0, _react.useState)(0); let onClose = (0, _react.useCallback)(() => { if (!isCompletedRef.current) { isCompletedRef.current = true; onComplete(); return; } }, [onComplete]); const backAction = (0, _react.useCallback)(() => { if (visible) { onPressBack(); return true; } return false; }, [visible, onPressBack]); (0, _react.useEffect)(() => { const backHandler = _reactNative.BackHandler.addEventListener('hardwareBackPress', backAction); return () => backHandler.remove(); }, [backAction]); const goToNextStory = (0, _react.useCallback)(() => { if (currentStoryIndex < stories.length - 1) { _reactNative.Animated.timing(progressAnim, { toValue: 1, duration: 3, useNativeDriver: nativeDriver }).start(() => { pausedProgress.current = 0; setCurrentStoryIndex(currentStoryIndex + 1); progressAnim.setValue(0); onChangePosition && onChangePosition(currentStoryIndex + 1); }); } else { setWentBack(0); onClose(); if (!noLoop) { setCurrentStoryIndex(0); onChangePosition && onChangePosition(0); } onChangePosition && onChangePosition(currentStoryIndex); } }, [currentStoryIndex, stories, progressAnim, onChangePosition, onClose, nativeDriver, noLoop]); (0, _react.useImperativeHandle)(ref, () => ({ setPause: pause => { setIsPaused(pause); }, setCurrentStoryIndex: indexFromRef => { setCurrentStoryIndex(indexFromRef); }, progressAnim })); const runProgressAnimation = (0, _react.useCallback)(() => { // this will run the animations at the top for the story progressAnim.setValue(pausedProgress.current); //set the value of the progress of the story _reactNative.Animated.timing(progressAnim, { toValue: 1, duration: (1 - pausedProgress.current) * maxDurationPerStory * 1000, //for how long each story currently 6 seconds useNativeDriver: nativeDriver }).start(({ finished }) => { if (finished) { goToNextStory(); //once finished goes to nextStory() } }); }, [maxDurationPerStory, progressAnim, goToNextStory, nativeDriver]); const getProgressBarWidth = (storyIndex, currentIndex) => { if (currentIndex > storyIndex) { return '100%'; } // this is when the Story has been viewed if (currentIndex === storyIndex) { return progressAnim.interpolate({ inputRange: [0, 1], outputRange: ['0%', '100%'] // this is when the story is being viewed }); } return '0%'; // this is when the Story has not been viewed yet }; const goToPreviousStory = () => { if (isPaused) { setIsPaused(false); } pausedProgress.current = 0; progressAnim.setValue(0); if (currentStoryIndex === 0) { setWentBack(wentBack + 1); runProgressAnimation(); } else { setCurrentStoryIndex(currentStoryIndex - 1); onChangePosition && onChangePosition(currentStoryIndex - 1); } }; (0, _react.useEffect)(() => { if (index) { setCurrentStoryIndex(index); } }, [index]); const handlePressIn = () => { //for pause if user holds the screen setIsPaused(true); }; const handlePressOut = () => { //for pause if user releases the holded screen setIsPaused(false); }; const handleScreenTouch = evt => { //this function takes the width and decided where the click was pressed if left or right if (noControls) return; const touchX = evt?.nativeEvent?.locationX; if (touchX < width / 2) { goToPreviousStory(); } else { goToNextStory(); } }; const pausePlay = () => { if (isPaused) { setIsPaused(false); } else { setIsPaused(true); } }; (0, _react.useEffect)(() => { if (!isPaused) { runProgressAnimation(); } else { progressAnim.stopAnimation(value => { pausedProgress.current = value; }); } return () => { progressAnim.stopAnimation(); }; }, [currentStoryIndex, isPaused, progressAnim, runProgressAnimation]); return visible ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.SafeAreaView, { style: _Styled.default.safeArea, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, { onPress: handleScreenTouch, ...(noPause || noControls ? {} : { onLongPress: handlePressIn, onPressOut: handlePressOut }), style: ({ pressed }) => [{ opacity: pressed && !noControls ? 0.9 : 1 //when clicked shows the user screen a little dimmed for feedback }, _Styled.default.container], children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, { style: _Styled.default.container, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.SafeAreaView, { style: _Styled.default.topBarContainer, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { children: renderHeaderComponent ? renderHeaderComponent({ getProgressBarWidth, storyName, stories, currentStoryIndex, pausePlay, isPaused, onComplete: onClose, close, playPause, storyNameText, headerStyle }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Header.default, { getProgressBarWidth: getProgressBarWidth, storyName: storyName, stories: stories, currentStoryIndex: currentStoryIndex, pausePlay: pausePlay, isPaused: isPaused, onComplete: onClose, close: !noControls ? close : false, playPause: !noControls ? playPause : false, storyNameText: storyNameText, headerStyle: headerStyle }) }) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: _Styled.default.imageContainer, children: currentStory?.type && /*#__PURE__*/(0, _jsxRuntime.jsx)(_ContentView.default, { story: currentStory, imageStyle: imageStyle }) })] }) }) }) : null; }; var _default = exports.default = /*#__PURE__*/(0, _react.forwardRef)(StoryView); //# sourceMappingURL=StoryView.js.map