react-native-pages-flipper
Version:
291 lines (283 loc) • 8.87 kB
JavaScript
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Pressable, StyleSheet, View } from 'react-native';
import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, { Easing, Extrapolation, interpolate, runOnJS, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated';
import BackShadow from '../BookPage/BackShadow';
import FrontShadow from '../BookPage/FrontShadow';
import PageShadow from '../BookPage/PageShadow';
const timingConfig = {
duration: 800,
easing: Easing.inOut(Easing.cubic)
};
const BookPagePortrait = /*#__PURE__*/React.forwardRef(({
current,
prev,
onPageFlip,
containerSize,
enabled,
isPressable,
setIsAnimating,
getPageStyle,
isAnimating,
isAnimatingRef,
next,
onFlipStart,
renderPage
}, ref) => {
const containerWidth = containerSize.width;
const isMounted = useRef(false);
const rotateYAsDeg = useSharedValue(0);
// might not need this
// useEffect(() => {
// if (!enabled) {
// setIsDragging(false);
// }
// }, [enabled]);
const turnPage = useCallback(id => {
setIsAnimating(true);
if (onFlipStart && typeof onFlipStart === 'function') {
onFlipStart(id);
}
rotateYAsDeg.value = withTiming(id < 0 ? -180 : 180, timingConfig, () => {
runOnJS(onPageFlip)(id, false);
});
}, [onFlipStart, onPageFlip, rotateYAsDeg, setIsAnimating]);
React.useImperativeHandle(ref, () => ({
turnPage
}), [turnPage]);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
const containerStyle = useAnimatedStyle(() => {
return {
flex: 1
};
});
// const onPanGestureHandler = useAnimatedGestureHandler<
// PanGestureHandlerGestureEvent,
// { x: number }
// >({
// // @ts-ignore
// onStart: (event, ctx) => {
// ctx.x = x.value;
// if (onPageDragStart && typeof onPageDragStart === 'function') {
// runOnJS(onPageDragStart)();
// }
// },
// onActive: (event, ctx) => {
// const newX = ctx.x + event.translationX;
// const degrees = getDegreesForX(newX);
// x.value = newX;
// rotateYAsDeg.value = degrees;
// if (onPageDrag && typeof onPageDrag === 'function') {
// runOnJS(onPageDrag)();
// }
// },
// onEnd: (event) => {
// if (onPageDragEnd && typeof onPageDragEnd === 'function') {
// runOnJS(onPageDragEnd)();
// }
// const snapTo = snapPoint(x.value, event.velocityX, pSnapPoints);
// const id = snapTo > 0 ? -1 : snapTo < 0 ? 1 : 0;
// if (!next && id > 0) {
// // reset
// x.value = withTiming(0);
// rotateYAsDeg.value = withTiming(0);
// // runOnJS(onDrag)(false);
// return;
// }
// const degrees = getDegreesForX(snapTo);
// x.value = snapTo;
// if (rotateYAsDeg.value === degrees) {
// // already same value
// // debugValue('already there');
// runOnJS(onPageFlip)(id, false);
// } else {
// runOnJS(setIsAnimating)(true);
// const progress =
// Math.abs(rotateYAsDeg.value - degrees) / 100;
// const duration = clamp(
// 800 * progress - Math.abs(0.1 * event.velocityX),
// 350,
// 1000
// );
// rotateYAsDeg.value = withTiming(
// degrees,
// {
// ...timingConfig,
// duration: duration,
// },
// () => {
// if (snapTo === 0) {
// //
// }
// runOnJS(onPageFlip)(id, false);
// }
// );
// }
// },
// });
const gesturesEnabled = enabled && !isAnimating;
const iPageProps = {
containerSize,
containerWidth,
getPageStyle,
rotateYAsDeg,
renderPage
};
return /*#__PURE__*/React.createElement(Animated.View, {
style: containerStyle
}, /*#__PURE__*/React.createElement(PanGestureHandler, {
enabled: gesturesEnabled
}, /*#__PURE__*/React.createElement(Animated.View, {
style: containerStyle
}, isPressable && prev && /*#__PURE__*/React.createElement(Pressable, {
disabled: isAnimating,
onPress: () => {
if (!isAnimatingRef.current) turnPage(-1);
},
style: {
position: 'absolute',
height: '100%',
width: '25%',
zIndex: 10000,
left: 0
// backgroundColor: 'red',
// opacity: 0.2,
}
}), isPressable && next && /*#__PURE__*/React.createElement(Pressable, {
disabled: isAnimating,
onPress: () => {
if (!isAnimatingRef.current) turnPage(1);
},
style: {
position: 'absolute',
height: '100%',
width: '30%',
zIndex: 10000,
right: 0
// backgroundColor: 'blue',
// opacity: 0.2,
}
}), current && next ? /*#__PURE__*/React.createElement(IPage, _extends({
page: current,
right: true
}, iPageProps)) : /*#__PURE__*/React.createElement(View, {
style: {
height: '100%',
width: '100%'
}
}, renderPage && /*#__PURE__*/React.createElement(View, {
style: getPageStyle(true, true)
}, renderPage(current.right))), prev && /*#__PURE__*/React.createElement(IPage, _extends({
page: prev,
right: false
}, iPageProps)))));
});
const IPage = ({
right,
page,
rotateYAsDeg,
containerWidth,
containerSize,
getPageStyle,
renderPage
}) => {
const [loaded, setLoaded] = useState(right);
useEffect(() => {
// hack fix
setTimeout(() => {
setLoaded(true);
}, 50);
}, []);
const rotationVal = useDerivedValue(() => {
const val = right ? rotateYAsDeg.value : interpolate(rotateYAsDeg.value, [-180, 0], [0, 180]);
return val;
});
const portraitBackStyle = useAnimatedStyle(() => {
const x = interpolate(rotationVal.value, [0, 180], [containerWidth, -containerWidth / 2]);
const w = interpolate(rotationVal.value, [0, 180], [0, containerWidth / 2]);
return {
width: Math.ceil(w),
zIndex: 2,
opacity: 1,
transform: [{
translateX: x
}]
};
});
const portraitFrontStyle = useAnimatedStyle(() => {
const w = interpolate(rotationVal.value, [0, 160], [containerWidth, -20], Extrapolation.CLAMP);
const style = {
zIndex: 1,
width: Math.floor(w)
};
if (!right) {
style['left'] = 0;
} else {
// style['right'] = 0;
}
return style;
});
const frontPageStyle = getPageStyle(right, true);
const backPageStyle = getPageStyle(right, false);
if (!loaded) {
// hack fix
return null;
}
const shadowProps = {
right: true,
degrees: rotationVal,
width: containerSize.width,
viewHeight: containerSize.height
};
return /*#__PURE__*/React.createElement(View, {
style: {
...StyleSheet.absoluteFillObject,
zIndex: !right ? 5 : 0
}
}, /*#__PURE__*/React.createElement(Animated.View, {
style: [styles.pageContainer, portraitBackStyle, {
overflow: 'visible'
}]
}, /*#__PURE__*/React.createElement(View, {
style: styles.pageContainer
}, renderPage && /*#__PURE__*/React.createElement(Animated.View, {
style: [backPageStyle, {
opacity: 0.2,
transform: [{
rotateX: '180deg'
}, {
rotateZ: '180deg'
}]
}]
}, renderPage(page.left))), /*#__PURE__*/React.createElement(BackShadow, {
degrees: rotationVal,
right: true
}), /*#__PURE__*/React.createElement(FrontShadow, shadowProps), /*#__PURE__*/React.createElement(PageShadow, _extends({}, shadowProps, {
containerSize: containerSize
}))), /*#__PURE__*/React.createElement(Animated.View, {
style: [styles.pageContainer, portraitFrontStyle]
}, renderPage && /*#__PURE__*/React.createElement(Animated.View, {
style: [frontPageStyle]
}, renderPage(page.left))));
};
export { BookPagePortrait };
const styles = StyleSheet.create({
container: {
flex: 1
},
pageContainer: {
height: '100%',
width: '100%',
position: 'absolute',
backfaceVisibility: 'hidden',
overflow: 'hidden',
backgroundColor: 'white'
}
});
//# sourceMappingURL=BookPagePortrait.js.map