/* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable no-return-assign */ import React, { Component } from 'react'; import { Animated, StyleSheet, PanResponder, View, Dimensions } from 'react-native'; const { height: sHeight } = Dimensions.get('screen'); interface AnimateContainerProps { style?: any; name?: string; children?: any; onRequestClose?: () => void; addAnimateListener?: (a: any) => void; onSlideAnimateEnd?: any; onSlideAnimateStart: any; onClose?: () => void; touchEnableArea?: number; duration?: number; } interface AnimateContainerState { fadeAnim: any; isShow: boolean; childHeight: number; } export default class AnimateContainerView extends Component< AnimateContainerProps, AnimateContainerState > { static defaultProps = { style: null, name: '', children: null, onRequestClose: null, addAnimateListener: () => {}, onSlideAnimateEnd: () => {}, onClose: () => {}, touchEnableArea: 100, duration: 380, }; constructor(props) { super(props); this.state = { fadeAnim: new Animated.Value(0), isShow: false, childHeight: 0, }; this._modal = null; this.grantPointY = null; this.offset = 0; this._panResponder = PanResponder.create({ onStartShouldSetPanResponder: () => true, onStartShouldSetPanResponderCapture: () => false, // @ts-ignore onMoveShouldSetResponderCapture: () => false, onMoveShouldSetPanResponder: () => false, onPanResponderRelease: () => this.onSlide(false), onResponderTerminationRequest: () => true, }); this._childPanResponder = PanResponder.create({ onStartShouldSetPanResponder: () => true, onStartShouldSetPanResponderCapture: () => false, // @ts-ignore onMoveShouldSetResponderCapture: () => false, onMoveShouldSetPanResponder: () => false, onResponderTerminationRequest: () => true, onPanResponderGrant: (e, gestureState) => this.onResponderGrant(e, gestureState), onPanResponderMove: (e, gestureState) => this.onResponderMove(e, gestureState), onPanResponderRelease: () => this.onPanResponderRelease(), }); } componentDidMount() { const { addAnimateListener } = this.props; addAnimateListener && addAnimateListener(this.state.fadeAnim); } onResponderGrant = (e, gestureState) => { const { y0 } = gestureState; this.grantPointY = y0 >= this.state.childHeight ? this.state.childHeight : y0; }; onResponderMove = (__, gestureState) => { const { moveY } = gestureState; const { touchEnableArea } = this.props; const { childHeight } = this.state; if (typeof this.grantPointY === 'undefined') { this.grantPointY = moveY; } if ( this.grantPointY > sHeight - childHeight + touchEnableArea || childHeight === 0 || typeof childHeight === 'undefined' || moveY < this.grantPointY ) return; if (moveY >= sHeight - childHeight) { this.offset = this.grantPointY - moveY; this.state.fadeAnim.setValue(1 - Math.abs(this.offset) / childHeight); } else { this.offset = 0; this.state.fadeAnim.setValue(1); } }; onPanResponderRelease = () => { const { touchEnableArea } = this.props; if (Math.abs(this.offset) < touchEnableArea && this.offset !== 0 && this.offset < 0) { this.onSlide(true); } else this.offset && this.onSlide(false); }; onLayout = ({ nativeEvent: { layout: { height }, }, }) => { this.setState({ childHeight: height }); }; onSlideAnimateStart = () => { const { onSlideAnimateEnd } = this.props; onSlideAnimateEnd && onSlideAnimateEnd(); }; onSlideAnimateEnd = () => { const { onSlideAnimateEnd } = this.props; onSlideAnimateEnd && onSlideAnimateEnd(); }; onSlide = (show = false) => { const { onClose, duration } = this.props; show && this.setState({ isShow: true }); this.onSlideAnimateStart(); Animated.timing(this.state.fadeAnim, { toValue: show ? 1 : 0, duration, }).start(({ finished }) => { if (finished) { this.onSlideAnimateEnd(); !show && onClose && finished && onClose(); !show && this.setState({ isShow: false }); } finished && this.onSlideAnimateEnd(); }); }; setNativeProps = (...args) => { this._modal && this._modal.setNativeProps(...args); }; _modal: any; grantPointY: any; offset: number; _panResponder: any; _childPanResponder: any; render() { const { fadeAnim, childHeight } = this.state; if (!this.state.isShow) return ; return ( (this._modal = ref)} style={[ styles.mask, this.props.style, { zIndex: this.state.isShow ? 1 : -1, backgroundColor: 'rgba(0, 0, 0, 0.4)', opacity: fadeAnim, }, ]} /> {this.props.children} ); } } const styles = StyleSheet.create({ content: { alignItems: 'center', alignSelf: 'center', bottom: 0, justifyContent: 'center', position: 'absolute', zIndex: 10, }, mask: { backgroundColor: `rgba(0, 0, 0, 0.6)`, overflow: 'hidden', ...StyleSheet.absoluteFillObject, }, });