react-native-modalize-custom-handle
Version:
A highly customizable modal/bottom sheet that loves scrolling content.
658 lines (657 loc) • 34.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Modalize = void 0;
/**
* esModuleInterop: true looks to work everywhere except
* on snack.expo for some reason. Will revisit this later.
*/
const React = __importStar(require("react"));
const react_native_1 = require("react-native");
const react_native_gesture_handler_1 = require("react-native-gesture-handler");
const use_dimensions_1 = require("./utils/use-dimensions");
const get_spring_config_1 = require("./utils/get-spring-config");
const devices_1 = require("./utils/devices");
const invariant_1 = require("./utils/invariant");
const compose_refs_1 = require("./utils/compose-refs");
const styles_1 = __importDefault(require("./styles"));
const AnimatedKeyboardAvoidingView = react_native_1.Animated.createAnimatedComponent(react_native_1.KeyboardAvoidingView);
/**
* When scrolling, it happens than beginScrollYValue is not always equal to 0 (top of the ScrollView).
* Since we use this to trigger the swipe down gesture animation, we allow a small threshold to
* not dismiss Modalize when we are using the ScrollView and we don't want to dismiss.
*/
const SCROLL_THRESHOLD = -4;
const USE_NATIVE_DRIVER = true;
const ACTIVATED = 20;
const PAN_DURATION = 150;
const ModalizeBase = ({
// Refs
contentRef,
// Renderers
children, scrollViewProps, flatListProps, sectionListProps, customRenderer,
// Styles
rootStyle, modalStyle, handleStyle, overlayStyle, childrenStyle,
// Layout
snapPoint, modalHeight, modalTopOffset = react_native_1.Platform.select({
ios: 0,
android: react_native_1.StatusBar.currentHeight || 0,
default: 0,
}), alwaysOpen, adjustToContentHeight = false,
// Options
handlePosition = 'outside', disableScrollIfPossible = true, avoidKeyboardLikeIOS = react_native_1.Platform.select({
ios: true,
android: false,
default: true,
}), keyboardAvoidingBehavior = 'padding', keyboardAvoidingOffset, panGestureEnabled = true, panGestureComponentEnabled = false, tapGestureEnabled = true, closeOnOverlayTap = true, closeSnapPointStraightEnabled = true,
// Animations
openAnimationConfig = {
timing: { duration: 240, easing: react_native_1.Easing.ease },
spring: { speed: 14, bounciness: 4 },
}, closeAnimationConfig = {
timing: { duration: 240, easing: react_native_1.Easing.ease },
}, dragToss = 0.18, threshold = 120, velocity = 2800, panGestureAnimatedValue, useNativeDriver = true,
// Elements visibilities
withReactModal = false, withHandle = true, withOverlay = true,
// Additional components
HeaderComponent, FooterComponent, FloatingComponent, CustomHandleComponent,
// Callbacks
onOpen, onOpened, onClose, onClosed, onBackButtonPress, onPositionChange, onOverlayPress, onLayout, }, ref) => {
const { height: screenHeight } = use_dimensions_1.useDimensions();
const isHandleOutside = handlePosition === 'outside';
const handleHeight = withHandle ? 20 : isHandleOutside ? 35 : 20;
const fullHeight = screenHeight - modalTopOffset;
const computedHeight = fullHeight - handleHeight - (devices_1.isIphoneX ? 34 : 0);
const endHeight = modalHeight || computedHeight;
const adjustValue = adjustToContentHeight ? undefined : endHeight;
const snaps = snapPoint ? [0, endHeight - snapPoint, endHeight] : [0, endHeight];
const [modalHeightValue, setModalHeightValue] = React.useState(adjustValue);
const [lastSnap, setLastSnap] = React.useState(snapPoint ? endHeight - snapPoint : 0);
const [isVisible, setIsVisible] = React.useState(false);
const [showContent, setShowContent] = React.useState(true);
const [enableBounces, setEnableBounces] = React.useState(true);
const [keyboardToggle, setKeyboardToggle] = React.useState(false);
const [keyboardHeight, setKeyboardHeight] = React.useState(0);
const [disableScroll, setDisableScroll] = React.useState(alwaysOpen || snapPoint ? true : undefined);
const [beginScrollYValue, setBeginScrollYValue] = React.useState(0);
const [modalPosition, setModalPosition] = React.useState('initial');
const [cancelClose, setCancelClose] = React.useState(false);
const [layouts, setLayouts] = React.useState(new Map());
const cancelTranslateY = React.useRef(new react_native_1.Animated.Value(1)).current; // 1 by default to have the translateY animation running
const componentTranslateY = React.useRef(new react_native_1.Animated.Value(0)).current;
const overlay = React.useRef(new react_native_1.Animated.Value(0)).current;
const beginScrollY = React.useRef(new react_native_1.Animated.Value(0)).current;
const dragY = React.useRef(new react_native_1.Animated.Value(0)).current;
const translateY = React.useRef(new react_native_1.Animated.Value(screenHeight)).current;
const reverseBeginScrollY = React.useRef(react_native_1.Animated.multiply(new react_native_1.Animated.Value(-1), beginScrollY))
.current;
const tapGestureModalizeRef = React.useRef(null);
const panGestureChildrenRef = React.useRef(null);
const nativeViewChildrenRef = React.useRef(null);
const contentViewRef = React.useRef(null);
const tapGestureOverlayRef = React.useRef(null);
const backButtonListenerRef = React.useRef(null);
// We diff and get the negative value only. It sometimes go above 0
// (e.g. 1.5) and creates the flickering on Modalize for a ms
const diffClamp = react_native_1.Animated.diffClamp(reverseBeginScrollY, -screenHeight, 0);
const componentDragEnabled = componentTranslateY._value === 1;
// When we have a scrolling happening in the ScrollView, we don't want to translate
// the modal down. We either multiply by 0 to cancel the animation, or 1 to proceed.
const dragValue = react_native_1.Animated.add(react_native_1.Animated.multiply(dragY, componentDragEnabled ? 1 : cancelTranslateY), diffClamp);
const value = react_native_1.Animated.add(react_native_1.Animated.multiply(translateY, componentDragEnabled ? 1 : cancelTranslateY), dragValue);
let willCloseModalize = false;
beginScrollY.addListener(({ value }) => setBeginScrollYValue(value));
const handleBackPress = () => {
if (alwaysOpen) {
return false;
}
if (onBackButtonPress) {
return onBackButtonPress();
}
else {
handleClose();
}
return true;
};
const handleKeyboardShow = (event) => {
const { height } = event.endCoordinates;
setKeyboardToggle(true);
setKeyboardHeight(height);
};
const handleKeyboardHide = () => {
setKeyboardToggle(false);
setKeyboardHeight(0);
};
const handleAnimateOpen = (alwaysOpenValue, dest = 'default') => {
const { timing, spring } = openAnimationConfig;
backButtonListenerRef.current = react_native_1.BackHandler.addEventListener('hardwareBackPress', handleBackPress);
let toValue = 0;
let toPanValue = 0;
let newPosition;
if (dest === 'top') {
toValue = 0;
}
else if (alwaysOpenValue) {
toValue = (modalHeightValue || 0) - alwaysOpenValue;
}
else if (snapPoint) {
toValue = (modalHeightValue || 0) - snapPoint;
}
if (panGestureAnimatedValue && (alwaysOpenValue || snapPoint)) {
toPanValue = 0;
}
else if (panGestureAnimatedValue &&
!alwaysOpenValue &&
(dest === 'top' || dest === 'default')) {
toPanValue = 1;
}
setIsVisible(true);
setShowContent(true);
if ((alwaysOpenValue && dest !== 'top') || (snapPoint && dest === 'default')) {
newPosition = 'initial';
}
else {
newPosition = 'top';
}
react_native_1.Animated.parallel([
react_native_1.Animated.timing(overlay, {
toValue: alwaysOpenValue && dest === 'default' ? 0 : 1,
duration: timing.duration,
easing: react_native_1.Easing.ease,
useNativeDriver: USE_NATIVE_DRIVER,
}),
panGestureAnimatedValue
? react_native_1.Animated.timing(panGestureAnimatedValue, {
toValue: toPanValue,
duration: PAN_DURATION,
easing: react_native_1.Easing.ease,
useNativeDriver,
})
: react_native_1.Animated.delay(0),
spring
? react_native_1.Animated.spring(translateY, Object.assign(Object.assign({}, get_spring_config_1.getSpringConfig(spring)), { toValue, useNativeDriver: USE_NATIVE_DRIVER }))
: react_native_1.Animated.timing(translateY, {
toValue,
duration: timing.duration,
easing: timing.easing,
useNativeDriver: USE_NATIVE_DRIVER,
}),
]).start(() => {
if (onOpened) {
onOpened();
}
setModalPosition(newPosition);
if (onPositionChange) {
onPositionChange(newPosition);
}
});
};
const handleAnimateClose = (dest = 'default') => {
var _a;
const { timing, spring } = closeAnimationConfig;
const lastSnapValue = snapPoint ? snaps[1] : 80;
const toInitialAlwaysOpen = dest === 'alwaysOpen' && Boolean(alwaysOpen);
const toValue = toInitialAlwaysOpen && alwaysOpen ? (modalHeightValue || 0) - alwaysOpen : screenHeight;
(_a = backButtonListenerRef.current) === null || _a === void 0 ? void 0 : _a.remove();
cancelTranslateY.setValue(1);
setBeginScrollYValue(0);
beginScrollY.setValue(0);
react_native_1.Animated.parallel([
react_native_1.Animated.timing(overlay, {
toValue: 0,
duration: timing.duration,
easing: react_native_1.Easing.ease,
useNativeDriver: USE_NATIVE_DRIVER,
}),
panGestureAnimatedValue
? react_native_1.Animated.timing(panGestureAnimatedValue, {
toValue: 0,
duration: PAN_DURATION,
easing: react_native_1.Easing.ease,
useNativeDriver,
})
: react_native_1.Animated.delay(0),
spring
? react_native_1.Animated.spring(translateY, Object.assign(Object.assign({}, get_spring_config_1.getSpringConfig(spring)), { toValue, useNativeDriver: USE_NATIVE_DRIVER }))
: react_native_1.Animated.timing(translateY, {
duration: timing.duration,
easing: react_native_1.Easing.out(react_native_1.Easing.ease),
toValue,
useNativeDriver: USE_NATIVE_DRIVER,
}),
]).start(() => {
if (onClosed) {
onClosed();
}
if (alwaysOpen && dest === 'alwaysOpen' && onPositionChange) {
onPositionChange('initial');
}
if (alwaysOpen && dest === 'alwaysOpen') {
setModalPosition('initial');
}
setShowContent(toInitialAlwaysOpen);
translateY.setValue(toValue);
dragY.setValue(0);
willCloseModalize = false;
setLastSnap(lastSnapValue);
setIsVisible(toInitialAlwaysOpen);
});
};
const handleModalizeContentLayout = ({ nativeEvent: { layout } }) => {
const value = Math.min(layout.height + (!adjustToContentHeight || keyboardHeight ? layout.y : 0), endHeight -
react_native_1.Platform.select({
ios: 0,
android: keyboardHeight,
default: 0,
}));
setModalHeightValue(value);
};
const handleBaseLayout = (component, height) => {
setLayouts(new Map(layouts.set(component, height)));
const max = Array.from(layouts).reduce((acc, cur) => acc + (cur === null || cur === void 0 ? void 0 : cur[1]), 0);
const maxFixed = +max.toFixed(3);
const endHeightFixed = +endHeight.toFixed(3);
const shorterHeight = maxFixed < endHeightFixed;
setDisableScroll(shorterHeight && disableScrollIfPossible);
};
const handleContentLayout = ({ nativeEvent }) => {
if (onLayout) {
onLayout(nativeEvent);
}
if (alwaysOpen && adjustToContentHeight) {
const { height } = nativeEvent.layout;
return setModalHeightValue(height);
}
// We don't want to disable the scroll if we are not using adjustToContentHeight props
if (!adjustToContentHeight) {
return;
}
handleBaseLayout('content', nativeEvent.layout.height);
};
const handleComponentLayout = ({ nativeEvent }, name, absolute) => {
/**
* We don't want to disable the scroll if we are not using adjustToContentHeight props.
* Also, if the component is in absolute positioning we don't want to take in
* account its dimensions, so we just skip.
*/
if (!adjustToContentHeight || absolute) {
return;
}
handleBaseLayout(name, nativeEvent.layout.height);
};
const handleClose = (dest) => {
if (onClose) {
onClose();
}
handleAnimateClose(dest);
};
const handleChildren = ({ nativeEvent }, type) => {
const { timing } = closeAnimationConfig;
const { velocityY, translationY } = nativeEvent;
const negativeReverseScroll = modalPosition === 'top' &&
beginScrollYValue >= (snapPoint ? 0 : SCROLL_THRESHOLD) &&
translationY < 0;
const thresholdProps = translationY > threshold && beginScrollYValue === 0;
const closeThreshold = velocity
? (beginScrollYValue <= 20 && velocityY >= velocity) || thresholdProps
: thresholdProps;
let enableBouncesValue = true;
// We make sure to reset the value if we are dragging from the children
if (type !== 'component' && cancelTranslateY._value === 0) {
componentTranslateY.setValue(0);
}
/*
* When the pan gesture began we check the position of the ScrollView "cursor".
* We cancel the translation animation if the ScrollView is not scrolled to the top
*/
if (nativeEvent.oldState === react_native_gesture_handler_1.State.BEGAN) {
setCancelClose(false);
if (!closeSnapPointStraightEnabled && snapPoint
? beginScrollYValue > 0
: beginScrollYValue > 0 || negativeReverseScroll) {
setCancelClose(true);
translateY.setValue(0);
dragY.setValue(0);
cancelTranslateY.setValue(0);
enableBouncesValue = true;
}
else {
cancelTranslateY.setValue(1);
enableBouncesValue = false;
if (!tapGestureEnabled) {
setDisableScroll((Boolean(snapPoint) || Boolean(alwaysOpen)) && modalPosition === 'initial');
}
}
}
setEnableBounces(devices_1.isAndroid
? false
: alwaysOpen
? beginScrollYValue > 0 || translationY < 0
: enableBouncesValue);
if (nativeEvent.oldState === react_native_gesture_handler_1.State.ACTIVE) {
const toValue = translationY - beginScrollYValue;
let destSnapPoint = 0;
if (snapPoint || alwaysOpen) {
const endOffsetY = lastSnap + toValue + dragToss * velocityY;
/**
* snapPoint and alwaysOpen use both an array of points to define the first open state and the final state.
*/
snaps.forEach((snap) => {
const distFromSnap = Math.abs(snap - endOffsetY);
const diffPoint = Math.abs(destSnapPoint - endOffsetY);
// For snapPoint
if (distFromSnap < diffPoint && !alwaysOpen) {
if (closeSnapPointStraightEnabled) {
if (modalPosition === 'initial' && negativeReverseScroll) {
destSnapPoint = snap;
willCloseModalize = false;
}
if (snap === endHeight) {
destSnapPoint = snap;
willCloseModalize = true;
handleClose();
}
}
else {
destSnapPoint = snap;
willCloseModalize = false;
if (snap === endHeight) {
willCloseModalize = true;
handleClose();
}
}
}
// For alwaysOpen props
if (distFromSnap < diffPoint && alwaysOpen && beginScrollYValue <= 0) {
destSnapPoint = (modalHeightValue || 0) - alwaysOpen;
willCloseModalize = false;
}
});
}
else if (closeThreshold && !alwaysOpen && !cancelClose) {
willCloseModalize = true;
handleClose();
}
if (willCloseModalize) {
return;
}
setLastSnap(destSnapPoint);
translateY.extractOffset();
translateY.setValue(toValue);
translateY.flattenOffset();
dragY.setValue(0);
if (alwaysOpen) {
react_native_1.Animated.timing(overlay, {
toValue: Number(destSnapPoint <= 0),
duration: timing.duration,
easing: react_native_1.Easing.ease,
useNativeDriver: USE_NATIVE_DRIVER,
}).start();
}
react_native_1.Animated.spring(translateY, {
tension: 50,
friction: 12,
velocity: velocityY,
toValue: destSnapPoint,
useNativeDriver: USE_NATIVE_DRIVER,
}).start();
if (beginScrollYValue <= 0) {
const modalPositionValue = destSnapPoint <= 0 ? 'top' : 'initial';
if (panGestureAnimatedValue) {
react_native_1.Animated.timing(panGestureAnimatedValue, {
toValue: Number(modalPositionValue === 'top'),
duration: PAN_DURATION,
easing: react_native_1.Easing.ease,
useNativeDriver,
}).start();
}
if (!adjustToContentHeight && modalPositionValue === 'top') {
setDisableScroll(false);
}
if (onPositionChange && modalPosition !== modalPositionValue) {
onPositionChange(modalPositionValue);
}
if (modalPosition !== modalPositionValue) {
setModalPosition(modalPositionValue);
}
}
}
};
const handleComponent = ({ nativeEvent }) => {
// If we drag from the HeaderComponent/FooterComponent/FloatingComponent we allow the translation animation
if (nativeEvent.oldState === react_native_gesture_handler_1.State.BEGAN) {
componentTranslateY.setValue(1);
beginScrollY.setValue(0);
}
handleChildren({ nativeEvent }, 'component');
};
const handleOverlay = ({ nativeEvent }) => {
if (nativeEvent.oldState === react_native_gesture_handler_1.State.ACTIVE && !willCloseModalize) {
if (onOverlayPress) {
onOverlayPress();
}
const dest = !!alwaysOpen ? 'alwaysOpen' : 'default';
handleClose(dest);
}
};
const handleGestureEvent = react_native_1.Animated.event([{ nativeEvent: { translationY: dragY } }], {
useNativeDriver: USE_NATIVE_DRIVER,
listener: ({ nativeEvent: { translationY } }) => {
var _a;
if (panGestureAnimatedValue) {
const offset = (_a = alwaysOpen !== null && alwaysOpen !== void 0 ? alwaysOpen : snapPoint) !== null && _a !== void 0 ? _a : 0;
const diff = Math.abs(translationY / (endHeight - offset));
const y = translationY <= 0 ? diff : 1 - diff;
let value;
if (modalPosition === 'initial' && translationY > 0) {
value = 0;
}
else if (modalPosition === 'top' && translationY <= 0) {
value = 1;
}
else {
value = y;
}
panGestureAnimatedValue.setValue(value);
}
},
});
const renderHandle = () => {
const handleStyles = [styles_1.default.handle];
const shapeStyles = [styles_1.default.handle__shape, handleStyle];
if (!withHandle) {
return null;
}
if (!isHandleOutside) {
handleStyles.push(styles_1.default.handleBottom);
shapeStyles.push(styles_1.default.handle__shapeBottom, handleStyle);
}
return (React.createElement(react_native_gesture_handler_1.PanGestureHandler, { enabled: panGestureEnabled, simultaneousHandlers: tapGestureModalizeRef, shouldCancelWhenOutside: false, onGestureEvent: handleGestureEvent, onHandlerStateChange: handleComponent },
React.createElement(react_native_1.Animated.View, { style: handleStyles },
React.createElement(react_native_1.View, { style: shapeStyles }))));
};
const renderElement = (Element) => typeof Element === 'function' ? Element() : Element;
const renderComponent = (component, name) => {
var _a;
if (!component) {
return null;
}
const tag = renderElement(component);
/**
* Nesting Touchable/ScrollView components with RNGH PanGestureHandler cancels the inner events.
* Until a better solution lands in RNGH, I will disable the PanGestureHandler for Android only,
* so inner touchable/gestures are working from the custom components you can pass in.
*/
if (devices_1.isAndroid && !panGestureComponentEnabled) {
return tag;
}
const obj = react_native_1.StyleSheet.flatten((_a = tag === null || tag === void 0 ? void 0 : tag.props) === null || _a === void 0 ? void 0 : _a.style);
const absolute = (obj === null || obj === void 0 ? void 0 : obj.position) === 'absolute';
const zIndex = obj === null || obj === void 0 ? void 0 : obj.zIndex;
return (React.createElement(react_native_gesture_handler_1.PanGestureHandler, { enabled: panGestureEnabled, shouldCancelWhenOutside: false, onGestureEvent: handleGestureEvent, onHandlerStateChange: handleComponent },
React.createElement(react_native_1.Animated.View, { style: { zIndex }, onLayout: (e) => handleComponentLayout(e, name, absolute) }, tag)));
};
const renderContent = () => {
var _a;
const keyboardDismissMode = devices_1.isIos ? 'interactive' : 'on-drag';
const passedOnProps = (_a = flatListProps !== null && flatListProps !== void 0 ? flatListProps : sectionListProps) !== null && _a !== void 0 ? _a : scrollViewProps;
// We allow overwrites when the props (bounces, scrollEnabled) are set to false, when true we use Modalize's core behavior
const bounces = (passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.bounces) !== undefined && !(passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.bounces)
? passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.bounces : enableBounces;
const scrollEnabled = (passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.scrollEnabled) !== undefined && !(passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.scrollEnabled)
? passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.scrollEnabled : keyboardToggle || !disableScroll;
const scrollEventThrottle = (passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.scrollEventThrottle) || 16;
const onScrollBeginDrag = passedOnProps === null || passedOnProps === void 0 ? void 0 : passedOnProps.onScrollBeginDrag;
const opts = {
ref: compose_refs_1.composeRefs(contentViewRef, contentRef),
bounces,
onScrollBeginDrag: react_native_1.Animated.event([{ nativeEvent: { contentOffset: { y: beginScrollY } } }], {
useNativeDriver: USE_NATIVE_DRIVER,
listener: onScrollBeginDrag,
}),
scrollEventThrottle,
onLayout: handleContentLayout,
scrollEnabled,
keyboardDismissMode,
};
if (flatListProps) {
return React.createElement(react_native_1.Animated.FlatList, Object.assign({}, flatListProps, opts));
}
if (sectionListProps) {
return React.createElement(react_native_1.Animated.SectionList, Object.assign({}, sectionListProps, opts));
}
if (customRenderer) {
const tag = renderElement(customRenderer);
return React.cloneElement(tag, Object.assign({}, opts));
}
return (React.createElement(react_native_1.Animated.ScrollView, Object.assign({}, scrollViewProps, opts), children));
};
const renderChildren = () => {
const style = adjustToContentHeight ? styles_1.default.content__adjustHeight : styles_1.default.content__container;
return (React.createElement(react_native_gesture_handler_1.PanGestureHandler, { ref: panGestureChildrenRef, enabled: panGestureEnabled, simultaneousHandlers: [nativeViewChildrenRef, tapGestureModalizeRef], shouldCancelWhenOutside: false, onGestureEvent: handleGestureEvent, minDist: ACTIVATED, activeOffsetY: ACTIVATED, activeOffsetX: ACTIVATED, onHandlerStateChange: handleChildren },
React.createElement(react_native_1.Animated.View, { style: [style, childrenStyle] },
React.createElement(react_native_gesture_handler_1.NativeViewGestureHandler, { ref: nativeViewChildrenRef, waitFor: tapGestureModalizeRef, simultaneousHandlers: panGestureChildrenRef }, renderContent()))));
};
const renderOverlay = () => {
const pointerEvents = alwaysOpen && (modalPosition === 'initial' || !modalPosition) ? 'box-none' : 'auto';
return (React.createElement(react_native_gesture_handler_1.PanGestureHandler, { enabled: panGestureEnabled, simultaneousHandlers: tapGestureModalizeRef, shouldCancelWhenOutside: false, onGestureEvent: handleGestureEvent, onHandlerStateChange: handleChildren },
React.createElement(react_native_1.Animated.View, { style: styles_1.default.overlay, pointerEvents: pointerEvents }, showContent && (React.createElement(react_native_gesture_handler_1.TapGestureHandler, { ref: tapGestureOverlayRef, enabled: closeOnOverlayTap !== undefined ? closeOnOverlayTap : panGestureEnabled, onHandlerStateChange: handleOverlay },
React.createElement(react_native_1.Animated.View, { style: [
styles_1.default.overlay__background,
overlayStyle,
{
opacity: overlay.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
}),
},
], pointerEvents: pointerEvents }))))));
};
React.useImperativeHandle(ref, () => ({
open(dest) {
if (onOpen) {
onOpen();
}
handleAnimateOpen(alwaysOpen, dest);
},
close(dest) {
handleClose(dest);
},
}));
React.useEffect(() => {
if (alwaysOpen && (modalHeightValue || adjustToContentHeight)) {
handleAnimateOpen(alwaysOpen);
}
}, [alwaysOpen, modalHeightValue]);
React.useEffect(() => {
invariant_1.invariant(modalHeight && adjustToContentHeight, `You can't use both 'modalHeight' and 'adjustToContentHeight' props at the same time. Only choose one of the two.`);
invariant_1.invariant((scrollViewProps || children) && flatListProps, `You have defined 'flatListProps' along with 'scrollViewProps' or 'children' props. Remove 'scrollViewProps' or 'children' or 'flatListProps' to fix the error.`);
invariant_1.invariant((scrollViewProps || children) && sectionListProps, `You have defined 'sectionListProps' along with 'scrollViewProps' or 'children' props. Remove 'scrollViewProps' or 'children' or 'sectionListProps' to fix the error.`);
}, [
modalHeight,
adjustToContentHeight,
scrollViewProps,
children,
flatListProps,
sectionListProps,
]);
React.useEffect(() => {
setModalHeightValue(adjustValue);
}, [adjustToContentHeight, modalHeight, screenHeight]);
React.useEffect(() => {
react_native_1.Keyboard.addListener('keyboardDidShow', handleKeyboardShow);
react_native_1.Keyboard.addListener('keyboardDidHide', handleKeyboardHide);
return () => {
var _a;
(_a = backButtonListenerRef.current) === null || _a === void 0 ? void 0 : _a.remove();
react_native_1.Keyboard.removeListener('keyboardDidShow', handleKeyboardShow);
react_native_1.Keyboard.removeListener('keyboardDidHide', handleKeyboardHide);
};
}, []);
const keyboardAvoidingViewProps = {
keyboardVerticalOffset: keyboardAvoidingOffset,
behavior: keyboardAvoidingBehavior,
enabled: avoidKeyboardLikeIOS,
style: [
styles_1.default.modalize__content,
modalStyle,
{
height: modalHeightValue,
maxHeight: endHeight,
transform: [
{
translateY: value.interpolate({
inputRange: [-40, 0, endHeight],
outputRange: [0, 0, endHeight],
extrapolate: 'clamp',
}),
},
],
},
],
};
if (!avoidKeyboardLikeIOS && !adjustToContentHeight) {
keyboardAvoidingViewProps.onLayout = handleModalizeContentLayout;
}
const renderModalize = (React.createElement(react_native_1.View, { style: [styles_1.default.modalize, rootStyle], pointerEvents: alwaysOpen || !withOverlay ? 'box-none' : 'auto' },
React.createElement(react_native_gesture_handler_1.TapGestureHandler, { ref: tapGestureModalizeRef, maxDurationMs: tapGestureEnabled ? 100000 : 50, maxDeltaY: lastSnap, enabled: panGestureEnabled },
React.createElement(react_native_1.View, { style: styles_1.default.modalize__wrapper, pointerEvents: "box-none" },
showContent && (React.createElement(AnimatedKeyboardAvoidingView, Object.assign({}, keyboardAvoidingViewProps),
renderComponent(CustomHandleComponent, 'customHandle'),
renderHandle(),
renderComponent(HeaderComponent, 'header'),
renderChildren(),
renderComponent(FooterComponent, 'footer'))),
withOverlay && renderOverlay())),
renderComponent(FloatingComponent, 'floating')));
const renderReactModal = (child) => (React.createElement(react_native_1.Modal, { supportedOrientations: ['landscape', 'portrait', 'portrait-upside-down'], onRequestClose: handleBackPress, hardwareAccelerated: USE_NATIVE_DRIVER, visible: isVisible, transparent: true }, child));
if (!isVisible) {
return null;
}
if (withReactModal) {
return renderReactModal(renderModalize);
}
return renderModalize;
};
exports.Modalize = React.forwardRef(ModalizeBase);