react-native-unit-components
Version:
Unit React Native components
180 lines • 6.79 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, { useEffect, useRef, useState } from 'react';
import { Animated, BackHandler, Easing, Image, PanResponder, Platform, TouchableOpacity, View } from 'react-native';
import { CloseIcon } from '../../assets/images';
import { androidStatusBarHeight, fullScreenHeight, isAndroid10AndAbove, statusBarHeight } from '../../components/UNBottomSheetComponent/UNBottomSheetComponent.constants';
import { getStylesObject } from './BottomSheet.styles';
import { useIsBackFromLongBackground } from '../../hooks/useAppStateListener';
import { BottomSheetNativePlaceType } from '../../types/internal/bottomSheet.types';
import { UNBaseView } from '../../nativeComponents/UNBaseView';
const BottomSheet = props => {
const isStatic = props.nativePlace === BottomSheetNativePlaceType.modal;
const panelHeightValue = useRef(new Animated.Value(props.sliderMaxHeight)).current;
const fadeAnim = useRef(new Animated.Value(0)).current;
const styles = getStylesObject(fadeAnim);
const [isPanelOpened, setIsPanelOpened] = useState(props.isOpen);
const [contentHeight, setContentHeight] = useState(undefined);
const [currentHeight, setCurrentHeight] = useState(props.sliderMaxHeight);
const [dy, setDy] = useState(0);
const isAppInactive = useIsBackFromLongBackground();
const _parentPanResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: (_, gestureState) => {
if (isStatic) return false;
return props.shouldEnableBottomSheetScroll && Math.abs(gestureState.dy) > 10;
},
onPanResponderMove(_, gestureState) {
if (props.shouldEnableBottomSheetScroll && gestureState.dy < 5) {
props.handleWebViewScroll();
}
if (currentHeight + gestureState.dy < 0) return;
if (!props.expandToMaxHeightEnabled && contentHeight && currentHeight + gestureState.dy < props.sliderMaxHeight - contentHeight) return;
panelHeightValue.setValue(currentHeight + gestureState.dy);
setDy(gestureState.dy);
},
onPanResponderRelease: () => {
if (dy > 0) {
collapse();
} else if (!props.expandToMaxHeightEnabled) {
contentHeight && setToContentHeight(contentHeight);
} else {
expand();
}
}
});
useEffect(() => {
// on App Active State change reset the bottom-sheet
if (isAppInactive) {
setContentHeight(0);
_dismiss(false);
}
}, [isAppInactive]);
useEffect(() => {
if (props.isOpen && !isPanelOpened) {
fadeIn();
} else if (isPanelOpened) {
setContentHeight(0);
_dismiss();
}
}, [props.isOpen]);
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', _onBackPress);
const id = panelHeightValue.addListener(e => setCurrentHeight(e.value));
return () => {
BackHandler.removeEventListener('hardwareBackPress', _onBackPress);
panelHeightValue.removeListener(id);
};
}, []);
const fadeIn = () => {
setIsPanelOpened(true);
Animated.timing(fadeAnim, {
toValue: 0.3,
duration: 500,
useNativeDriver: false
}).start();
};
const fadeOut = () => {
/*
withTimeout - most of the time we declare 'Close' after the animation is end.
In a case that the app is not active we do it without timeout. (Otherwise a race condition may occur.)
*/
setIsPanelOpened(false);
Animated.timing(fadeAnim, {
toValue: 0,
duration: 500,
useNativeDriver: false
}).start();
};
const setToContentHeight = contentHeight => {
Animated.timing(panelHeightValue, {
duration: props.animationDuration,
easing: Easing.quad,
toValue: props.sliderMaxHeight - contentHeight,
useNativeDriver: false
}).start();
};
const expand = () => {
const {
animationDuration
} = props;
props.onOpen();
if (contentHeight && currentHeight > props.sliderMaxHeight - contentHeight) {
setToContentHeight(contentHeight);
return;
}
Animated.timing(panelHeightValue, {
duration: animationDuration,
easing: Easing.quad,
toValue: 0,
useNativeDriver: false
}).start();
};
const collapse = () => {
if (contentHeight && currentHeight > props.sliderMaxHeight - contentHeight) {
_dismiss();
return;
}
contentHeight && setToContentHeight(contentHeight);
};
const _onBackPress = () => {
isPanelOpened && collapse();
return isPanelOpened;
};
const _setSize = e => {
const newContentHeight = e.nativeEvent.layout.height;
setContentHeight(newContentHeight);
setToContentHeight(newContentHeight);
};
const _dismiss = (withAnimation = true) => {
const {
animationDuration
} = props;
Animated.timing(panelHeightValue, {
duration: withAnimation ? animationDuration : 0,
easing: Easing.quad,
toValue: props.sliderMaxHeight,
useNativeDriver: false
}).start(() => {
props.onClose();
});
fadeOut();
};
const {
children
} = props;
const isModal = props.nativePlace === BottomSheetNativePlaceType.modal;
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TouchableOpacity, {
style: styles.outsideContainer,
activeOpacity: 1,
onPress: () => _dismiss()
}, /*#__PURE__*/React.createElement(Animated.View, {
style: styles.animation
})), /*#__PURE__*/React.createElement(Animated.View, _extends({}, _parentPanResponder.panHandlers, {
style: {
...styles.container,
borderTopLeftRadius: isModal ? 0 : styles.container.borderTopLeftRadius,
borderTopRightRadius: isModal ? 0 : styles.container.borderTopRightRadius,
height: props.sliderMaxHeight,
marginTop: fullScreenHeight - props.sliderMaxHeight - (!isModal && isAndroid10AndAbove ? androidStatusBarHeight : 0),
transform: [{
translateY: panelHeightValue
}],
paddingTop: Platform.OS === 'ios' && isModal ? statusBarHeight : 0
}
}), /*#__PURE__*/React.createElement(View, {
style: styles.outerContent
}, /*#__PURE__*/React.createElement(TouchableOpacity, {
activeOpacity: 1,
style: styles.closeButton,
onPress: () => _dismiss()
}, /*#__PURE__*/React.createElement(Image, {
source: CloseIcon
})), /*#__PURE__*/React.createElement(View, {
onLayout: _setSize
}, /*#__PURE__*/React.createElement(UNBaseView, {
style: {
height: props.height
}
}, children)))));
};
export default BottomSheet;
//# sourceMappingURL=BottomSheet.js.map