UNPKG

react-native-actions-sheet

Version:

A Cross Platform(Android & iOS) ActionSheet with a robust and flexible api, native performance and zero dependency code for react native. Create anything you want inside ActionSheet.

1,054 lines (1,053 loc) 56.6 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import React, { forwardRef, Fragment, useCallback, useEffect, useImperativeHandle, useRef, useState, } from 'react'; import { BackHandler, Dimensions, Keyboard, Modal, PanResponder, Platform, Pressable, StyleSheet, } from 'react-native'; import { Gesture, GestureDetector, GestureHandlerRootView, } from 'react-native-gesture-handler'; import Animated, { Easing, runOnJS, runOnUI, useAnimatedStyle, useSharedValue, withSpring, withTiming, } from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { DraggableNodesContext, PanGestureRefContext, } from './context'; import EventManager, { actionSheetEventManager } from './eventmanager'; import { useAccessibility } from './hooks/use-accessibility'; import { RouterContext, RouterParamsContext, useRouter, } from './hooks/use-router'; import { resolveScrollRef } from './hooks/use-scroll-handlers'; import useSheetManager from './hooks/use-sheet-manager'; import { useKeyboard } from './hooks/useKeyboard'; import { providerRegistryStack, SheetProvider, useProviderContext, useSheetIDContext, useSheetPayload, useSheetRef, } from './provider'; import { getZIndexFromStack, SheetManager } from './sheetmanager'; import { styles } from './styles'; import { CloseRequestType } from './types'; import { getElevation, SUPPORTED_ORIENTATIONS } from './utils'; var AnimatedPressable = Animated.createAnimatedComponent(Pressable); export default forwardRef(function ActionSheet(_a, ref) { var _this = this; var _b, _c; var _d = _a.animated, animated = _d === void 0 ? true : _d, _e = _a.closeOnPressBack, closeOnPressBack = _e === void 0 ? true : _e, _f = _a.springOffset, springOffset = _f === void 0 ? 50 : _f, _g = _a.elevation, elevation = _g === void 0 ? 5 : _g, _h = _a.disableElevation, disableElevation = _h === void 0 ? false : _h, _j = _a.defaultOverlayOpacity, defaultOverlayOpacity = _j === void 0 ? 0.3 : _j, _k = _a.overlayColor, overlayColor = _k === void 0 ? 'black' : _k, _l = _a.closable, closable = _l === void 0 ? true : _l, _m = _a.closeOnTouchBackdrop, closeOnTouchBackdrop = _m === void 0 ? true : _m, onTouchBackdrop = _a.onTouchBackdrop, _o = _a.drawUnderStatusBar, drawUnderStatusBar = _o === void 0 ? false : _o, _p = _a.gestureEnabled, gestureEnabled = _p === void 0 ? false : _p, _q = _a.isModal, isModal = _q === void 0 ? true : _q, _r = _a.snapPoints, snapPoints = _r === void 0 ? [100] : _r, _s = _a.initialSnapIndex, initialSnapIndex = _s === void 0 ? 0 : _s, _t = _a.overdrawEnabled, overdrawEnabled = _t === void 0 ? true : _t, _u = _a.overdrawFactor, overdrawFactor = _u === void 0 ? 15 : _u, _v = _a.overdrawSize, overdrawSize = _v === void 0 ? 100 : _v, _w = _a.zIndex, zIndex = _w === void 0 ? 999 : _w, _x = _a.keyboardHandlerEnabled, keyboardHandlerEnabled = _x === void 0 ? true : _x, ExtraOverlayComponent = _a.ExtraOverlayComponent, returnValue = _a.returnValue, routes = _a.routes, initialRoute = _a.initialRoute, onBeforeShow = _a.onBeforeShow, enableRouterBackNavigation = _a.enableRouterBackNavigation, onBeforeClose = _a.onBeforeClose, _y = _a.enableGesturesInScrollView, enableGesturesInScrollView = _y === void 0 ? true : _y, disableDragBeyondMinimumSnapPoint = _a.disableDragBeyondMinimumSnapPoint, _z = _a.useBottomSafeAreaPadding, useBottomSafeAreaPadding = _z === void 0 ? true : _z, _0 = _a.initialTranslateFactor, initialTranslateFactor = _0 === void 0 ? 1.1 : _0, _1 = _a.openAnimationConfig, openAnimationConfig = _1 === void 0 ? { damping: 110, mass: 4, stiffness: 900, overshootClamping: true, } : _1, onRequestClose = _a.onRequestClose, props = __rest(_a, ["animated", "closeOnPressBack", "springOffset", "elevation", "disableElevation", "defaultOverlayOpacity", "overlayColor", "closable", "closeOnTouchBackdrop", "onTouchBackdrop", "drawUnderStatusBar", "gestureEnabled", "isModal", "snapPoints", "initialSnapIndex", "overdrawEnabled", "overdrawFactor", "overdrawSize", "zIndex", "keyboardHandlerEnabled", "ExtraOverlayComponent", "returnValue", "routes", "initialRoute", "onBeforeShow", "enableRouterBackNavigation", "onBeforeClose", "enableGesturesInScrollView", "disableDragBeyondMinimumSnapPoint", "useBottomSafeAreaPadding", "initialTranslateFactor", "openAnimationConfig", "onRequestClose"]); snapPoints = snapPoints[snapPoints.length - 1] !== 100 ? __spreadArray(__spreadArray([], snapPoints, true), [100], false) : snapPoints; var initialValue = useRef(-1); var actionSheetHeight = useRef(0); var insets = useSafeAreaInsets(); var internalEventManager = React.useMemo(function () { return new EventManager(); }, []); var currentContext = useProviderContext(); var currentSnapIndex = useRef(initialSnapIndex); var accessibilityInfo = useAccessibility(); var sheetRef = useSheetRef(); var sheetHeightRef = useRef(0); var minTranslateValue = useRef(0); var keyboardWasVisible = useRef(false); var animationListenerId = 266786; var id = useSheetIDContext(); var sheetId = props.id || id; var panViewRef = useRef(null); var rootViewContainerRef = useRef(null); var payload = useSheetPayload(); var payloadRef = useRef(undefined); payloadRef.current = payload; var gestureBoundaries = useRef({}); var hiding = useRef(false); var returnValueRef = useRef(returnValue); var sheetPayload = useSheetPayload(); var panGestureRef = useRef(undefined); var closing = useRef(false); var draggableNodes = useRef([]); var layoutTimeoutRef = useRef(null); var _2 = useState({ width: -1, height: -1, }), dimensions = _2[0], setDimensions = _2[1]; var dimensionsRef = useRef(dimensions); dimensionsRef.current = dimensions; var containerStyle = StyleSheet.flatten(props.containerStyle); var providerId = useRef("$$-auto-".concat(sheetId, "-").concat(currentContext, "-provider")); providerId.current = "$$-auto-".concat(sheetId, "-").concat(currentContext, "-provider"); var _3 = useSheetManager({ id: sheetId, onHide: function (data) { hideSheet(undefined, data, true); }, onBeforeShow: function (data, snapIndex) { var _a; (_a = routerRef.current) === null || _a === void 0 ? void 0 : _a.initialNavigation(); if (snapIndex !== undefined) { currentSnapIndex.current = snapIndex; } onBeforeShow === null || onBeforeShow === void 0 ? void 0 : onBeforeShow(data); }, onContextUpdate: function () { if (sheetId) { SheetManager.add(sheetId, currentContext); SheetManager.registerRef(sheetId, currentContext, { current: getRef(), }); } }, }), visible = _3.visible, setVisible = _3.setVisible, visibleRef = _3.visibleRef; var opacity = useSharedValue(0); var actionSheetOpacity = useSharedValue(0); var translateY = useSharedValue(Dimensions.get('window').height * 2); var underlayTranslateY = useSharedValue(130); var routeOpacity = useSharedValue(0); var router = useRouter({ routes: routes, getRef: function () { return getRef(); }, initialRoute: initialRoute, onNavigate: props.onNavigate, onNavigateBack: props.onNavigateBack, routeOpacity: routeOpacity, }); var routerRef = useRef(router); returnValueRef.current = returnValue; routerRef.current = router; var keyboard = useKeyboard(keyboardHandlerEnabled); var prevSnapIndex = useRef(initialSnapIndex); var draggableNodesContext = React.useMemo(function () { return ({ nodes: draggableNodes, }); }, []); var notifyOffsetChange = function (value) { internalEventManager.publish('onoffsetchange', value); }; var notifySnapIndexChanged = React.useCallback(function () { var _a; if (prevSnapIndex.current !== currentSnapIndex.current) { prevSnapIndex.current = currentSnapIndex.current; (_a = props.onSnapIndexChange) === null || _a === void 0 ? void 0 : _a.call(props, currentSnapIndex.current); } }, [props.onSnapIndexChange]); var moveSheetWithAnimation = React.useCallback(function (velocity, value, min, gestureEnd) { var initial = value || initialValue.current; var minTranslate = min || minTranslateValue.current; if (!animated) { actionSheetOpacity.value = 1; translateY.value = initial; return; } var config = openAnimationConfig; var correctedValue = initial > minTranslate ? initial : 0; notifyOffsetChange(correctedValue); if (accessibilityInfo.current.prefersCrossFadeTransitions && !gestureEnd) { actionSheetOpacity.value = 0; translateY.value = initial; actionSheetOpacity.value = withTiming(1, { duration: 150, easing: Easing.in(Easing.ease), }); } else { actionSheetOpacity.value = 1; translateY.value = withSpring(initial, __assign(__assign({}, config), { velocity: typeof velocity !== 'number' ? undefined : velocity })); } notifySnapIndexChanged(); }, [animated, openAnimationConfig]); var animationSheetOpacity = React.useCallback(function (value) { opacity.value = withTiming(value, { duration: 300, easing: Easing.in(Easing.ease), }); }, []); var hideSheetWithAnimation = React.useCallback(function (vy, callback, gestureEnd) { if (!animated) { callback === null || callback === void 0 ? void 0 : callback(); return; } var config = props.closeAnimationConfig; animationSheetOpacity(0); var endTranslateValue = dimensionsRef.current.height * 1.3; if (accessibilityInfo.current.prefersCrossFadeTransitions && !gestureEnd) { actionSheetOpacity.value = withTiming(0, { duration: 200, easing: Easing.in(Easing.ease), }, function (finished) { if (finished) { translateY.value = endTranslateValue; } }); } else { translateY.value = withTiming(endTranslateValue, config || { velocity: typeof vy !== 'number' ? 3.0 : vy + 1, duration: 200, }); } /** * Using setTimeout to ensure onClose is triggered when sheet is off screen * or is close to reaching off screen. */ setTimeout(function () { return callback(); }, (config === null || config === void 0 ? void 0 : config.duration) || 200); }, [animated, animationSheetOpacity, props.closeAnimationConfig, setVisible]); var getCurrentPosition = React.useCallback(function () { return translateY.value <= minTranslateValue.current + 5 ? 0 : translateY.value; }, []); var getNextPosition = React.useCallback(function (snapIndex) { return (actionSheetHeight.current + minTranslateValue.current - (actionSheetHeight.current * snapPoints[snapIndex]) / 100); }, [snapPoints]); var hardwareBackPressEvent = useRef(null); var Root = isModal && !(props === null || props === void 0 ? void 0 : props.backgroundInteractionEnabled) ? Modal : Animated.View; useEffect(function () { if (drawUnderStatusBar || props.onChange) { var prevPercentage_1 = 0; var onValueChange_1 = function (value) { var _a; var correctedValue = value > minTranslateValue.current ? value - minTranslateValue.current : 0; var percentage = ((actionSheetHeight.current - correctedValue) / actionSheetHeight.current) * 100; var rounded = Math.round(percentage); if (rounded !== prevPercentage_1 && rounded > -1) { prevPercentage_1 = rounded; (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, Math.round(percentage)); } var percentScreenCovered = (actionSheetHeight.current / (dimensionsRef.current.height - insets.top)) * 100; if (drawUnderStatusBar) { if (percentage > 85 && percentScreenCovered > 99) { var distanceFromTop = 100 - percentage; underlayTranslateY.value = Math.max((actionSheetHeight.current / 100) * distanceFromTop); } else { underlayTranslateY.value = 130; } } else { underlayTranslateY.value = 130; } }; runOnUI(function () { translateY.addListener(animationListenerId, function (value) { runOnJS(onValueChange_1)(value); }); })(); } return function () { runOnUI(function (animationListener) { translateY.removeListener(animationListener); })(animationListenerId); }; }, [ props === null || props === void 0 ? void 0 : props.id, keyboard.keyboardShown, keyboard.keyboardHeight, dimensions, ]); var onSheetLayout = React.useCallback(function (height) { return __awaiter(_this, void 0, void 0, function () { var processLayout; return __generator(this, function (_a) { processLayout = function () { var _a, _b; var sheetHeight = height; sheetHeightRef.current = sheetHeight; if (dimensionsRef.current.height === -1) { return; } if (closing.current) return; var rootViewHeight = (_a = dimensionsRef.current) === null || _a === void 0 ? void 0 : _a.height; actionSheetHeight.current = sheetHeight > dimensionsRef.current.height ? dimensionsRef.current.height : sheetHeight; var minTranslate = 0; var initial = initialValue.current; minTranslate = rootViewHeight - actionSheetHeight.current; if (initial === -1) { translateY.value = rootViewHeight * initialTranslateFactor; } var nextInitialValue = actionSheetHeight.current + minTranslate - (actionSheetHeight.current * snapPoints[currentSnapIndex.current]) / 100; initial = (keyboard.keyboardShown || keyboardWasVisible.current) && initial <= nextInitialValue && initial >= minTranslate ? initial : nextInitialValue; var sheetBottomEdgePosition = initial + (actionSheetHeight.current * snapPoints[currentSnapIndex.current]) / 100; var sheetPositionWithKeyboard = sheetBottomEdgePosition - (((_b = dimensionsRef.current) === null || _b === void 0 ? void 0 : _b.height) - keyboard.keyboardHeight); initial = keyboard.keyboardShown ? initial - sheetPositionWithKeyboard : initial; if (keyboard.keyboardShown) { minTranslate = minTranslate - keyboard.keyboardHeight; } minTranslateValue.current = minTranslate; initialValue.current = initial; animationSheetOpacity(defaultOverlayOpacity); moveSheetWithAnimation(undefined, initial, minTranslate); if (initial > 130) { underlayTranslateY.value = 130; } if (Platform.OS === 'web') { document.body.style.overflowY = 'hidden'; document.documentElement.style.overflowY = 'hidden'; } }; // Debounce layout updates to prevent jumps if (Platform.OS === 'android' && !animated) { if (layoutTimeoutRef.current) { clearTimeout(layoutTimeoutRef.current); } layoutTimeoutRef.current = setTimeout(function () { processLayout(); layoutTimeoutRef.current = null; }, 32); return [2 /*return*/]; } processLayout(); return [2 /*return*/]; }); }); }, [ animated, snapPoints, keyboard.keyboardShown, keyboard.keyboardHeight, animationSheetOpacity, translateY, underlayTranslateY, moveSheetWithAnimation, ]); var hideSheet = React.useCallback(function (vy, data, isSheetManagerOrRef, gestureEnd) { if (hiding.current) return; var closeRequestResult = true; if (gestureEnd) { if (onRequestClose) { closeRequestResult = onRequestClose === null || onRequestClose === void 0 ? void 0 : onRequestClose(CloseRequestType.SWIPE); } } if ((!closable || !closeRequestResult) && !isSheetManagerOrRef) { var next = getNextPosition(currentSnapIndex.current); moveSheetWithAnimation(vy, next, undefined, gestureEnd); initialValue.current = next; return; } hiding.current = true; onBeforeClose === null || onBeforeClose === void 0 ? void 0 : onBeforeClose((data || returnValueRef.current || data)); if (closable) { closing.current = true; Keyboard.dismiss(); runOnUI(function (animationListener) { translateY.removeListener(animationListener); })(animationListenerId); } var onCompleteAnimation = function () { var _a, _b; if (closable || isSheetManagerOrRef) { var providerIndex = providerRegistryStack.indexOf(providerId.current); if (providerIndex > -1) { providerRegistryStack.splice(providerIndex, 1); } setVisible(false); visibleRef.current.value = false; if (props.onClose) { (_a = props.onClose) === null || _a === void 0 ? void 0 : _a.call(props, (data || returnValueRef.current || data)); hiding.current = false; } (_b = hardwareBackPressEvent.current) === null || _b === void 0 ? void 0 : _b.remove(); if (sheetId) { SheetManager.remove(sheetId, currentContext); hiding.current = false; actionSheetEventManager.publish("onclose_".concat(sheetId), data || returnValueRef.current || data, currentContext || 'global'); } else { hiding.current = false; } currentSnapIndex.current = initialSnapIndex; closing.current = false; initialValue.current = -1; actionSheetOpacity.value = 0; translateY.value = Dimensions.get('window').height * 2; keyboard.reset(); } else { opacity.value = 1; moveSheetWithAnimation(1, undefined, undefined, gestureEnd); } }; hideSheetWithAnimation(vy, onCompleteAnimation, gestureEnd); if (Platform.OS === 'web') { document.body.style.overflowY = 'auto'; document.documentElement.style.overflowY = 'auto'; } }, [ closable, hideSheetWithAnimation, props.onClose, moveSheetWithAnimation, keyboard, setVisible, ]); var onHardwareBackPress = React.useCallback(function () { var _a, _b; if (visible && enableRouterBackNavigation && ((_a = routerRef.current) === null || _a === void 0 ? void 0 : _a.canGoBack())) { (_b = routerRef.current) === null || _b === void 0 ? void 0 : _b.goBack(); return true; } var closeRequestResult = true; if (onRequestClose) { closeRequestResult = onRequestClose === null || onRequestClose === void 0 ? void 0 : onRequestClose(CloseRequestType.BACK_PRESS); } if (visible && closable && closeOnPressBack && closeRequestResult) { hideSheet(); return true; } return false; }, [ closable, closeOnPressBack, hideSheet, enableRouterBackNavigation, visible, ]); /** * Snap towards the top */ var snapForward = React.useCallback(function (vy, gestureEnd) { if (currentSnapIndex.current === snapPoints.length - 1) { var next_1 = getNextPosition(currentSnapIndex.current); moveSheetWithAnimation(vy, next_1, undefined, gestureEnd); initialValue.current = next_1; return; } var nextSnapPoint = 0; var nextSnapIndex = 0; if (getCurrentPosition() === 0) { nextSnapPoint = snapPoints[(nextSnapIndex = snapPoints.length - 1)]; } else { for (var i = currentSnapIndex.current; i < snapPoints.length; i++) { if (getNextPosition(i) < getCurrentPosition()) { nextSnapPoint = snapPoints[(nextSnapIndex = i)]; break; } } } if (nextSnapPoint > 100) { console.warn('Snap points should range between 0 to 100.'); moveSheetWithAnimation(vy, undefined, undefined, gestureEnd); return; } currentSnapIndex.current = nextSnapIndex; var next = getNextPosition(currentSnapIndex.current); initialValue.current = next; moveSheetWithAnimation(vy, next, undefined, gestureEnd); }, [getCurrentPosition, getNextPosition, moveSheetWithAnimation, snapPoints]); /** * Snap towards the bottom */ var snapBackward = React.useCallback(function (vy, gestureEnd) { if (currentSnapIndex.current === 0) { if (closable) { initialValue.current = dimensionsRef.current.height * 1.3; hideSheet(vy, undefined, false, gestureEnd); } else { var next_2 = getNextPosition(currentSnapIndex.current); moveSheetWithAnimation(vy, next_2, undefined, gestureEnd); initialValue.current = next_2; } return; } var nextSnapPoint = 0; var nextSnapIndex = 0; for (var i = currentSnapIndex.current; i > -1; i--) { if (getNextPosition(i) > getCurrentPosition()) { nextSnapPoint = snapPoints[(nextSnapIndex = i)]; break; } if (i === 0 && getCurrentPosition() > getNextPosition(i)) { if (closable) { initialValue.current = dimensionsRef.current.height * 1.3; hideSheet(vy, undefined, undefined, gestureEnd); return; } } } if (nextSnapPoint < 0) { console.warn('Snap points should range between 0 to 100.'); moveSheetWithAnimation(vy, undefined, undefined, gestureEnd); return; } currentSnapIndex.current = nextSnapIndex; var next = getNextPosition(currentSnapIndex.current); initialValue.current = next; moveSheetWithAnimation(vy, next, undefined, gestureEnd); }, [ closable, getCurrentPosition, getNextPosition, hideSheet, moveSheetWithAnimation, snapPoints, ]); function getRectBoundary(rect) { if (rect) { var w = rect.w, h = rect.h, px = rect.px, py = rect.py; return __assign(__assign({}, rect), { boundryX: px + w, boundryY: py + h }); } return { w: 0, h: 0, px: 0, py: 0, x: 0, y: 0, boundryX: 0, boundryY: 0 }; } var getActiveDraggableNodes = React.useCallback(function (absoluteX, absoluteY, returnAllNodes) { var _a; if (((_a = draggableNodes.current) === null || _a === void 0 ? void 0 : _a.length) === 0) return []; var activeNodes = []; for (var _i = 0, _b = draggableNodes.current; _i < _b.length; _i++) { var node = _b[_i]; var rect = getRectBoundary(node.rect.current); if (rect.boundryX === 0 && rect.boundryY === 0) continue; if (returnAllNodes) { activeNodes.push({ rectWithBoundary: rect, node: node, }); } else if (absoluteX > rect.px && absoluteY > rect.py && absoluteX < rect.boundryX && absoluteY < rect.boundryY) { activeNodes.push({ rectWithBoundary: rect, node: node, }); } } return activeNodes; }, []); var panGesture = React.useMemo(function () { var prevDeltaY = 0; var deltaYOnGestureStart = 0; var velocity = 0; var start; var oldValue = 0; var isRefreshing = false; var offsets = []; function scrollable(value) { var _a, _b, _c; for (var i = 0; i < draggableNodes.current.length; i++) { var node = draggableNodes.current[i]; var scrollRef = resolveScrollRef(node.ref); if (Platform.OS === 'ios' || Platform.OS === 'web') { if (!value) { if (!offsets[i] || ((_a = node.offset.current) === null || _a === void 0 ? void 0 : _a.y) === 0) { offsets[i] = ((_b = node.offset.current) === null || _b === void 0 ? void 0 : _b.y) || 0; } if (Platform.OS === 'web') { scrollRef.scrollTop = offsets[i]; } else { scrollRef.scrollTo({ x: 0, y: offsets[i], animated: false, }); } } else { offsets[i] = ((_c = node.offset.current) === null || _c === void 0 ? void 0 : _c.y) || 0; } } else if (Platform.OS === 'android') { scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.setNativeProps({ scrollEnabled: value, }); } } } var blockPan = false; var onChange = function (absoluteX, absoluteY, translationY) { if (!gestureEnabled) return; var deltaY = translationY; var isSwipingDown = prevDeltaY < deltaY; prevDeltaY = deltaY; if (!start) { start = { x: absoluteX, y: absoluteY, }; } var isFullOpen = getCurrentPosition() === 0; var activeDraggableNodes = getActiveDraggableNodes(start.x, start.y, !isFullOpen || (isFullOpen && !isSwipingDown)); if (enableGesturesInScrollView && activeDraggableNodes.length > 0 && !isRefreshing) { var nodeIsScrolling = activeDraggableNodes.some(function (node) { return node.node.offset.current.y !== 0; }); /** * Draggable nodes handling cases: * * 1. Sheet not fully open, swiping up, scrolling: false panning: true (will transition to scrolling once sheet reaches top position) * 2. Sheet fully open, swiping up, scrolling: true, panning: false * 3. Sheet not fully open, swiping down, scrolling: false, panning: true * 4. Sheet fully open, scroll offset > 0, scrolling: true, panning: false will transition into scrolling: false, panning: true, once scroll reaches offset=0 * 5. Add support for pull to refresh */ // 1. Sheet not fully open, swiping up, scrolling: false panning: true (will transition to scrolling once sheet reaches top position) if (!isFullOpen && !isSwipingDown) { scrollable(false); blockPan = false; } // 2. Sheet fully open, swiping up, scrolling: true, panning: false if (isFullOpen && !isSwipingDown) { scrollable(true); blockPan = true; } // 3. Sheet not fully open, swiping down, scrolling: false, panning: true if (!isFullOpen && isSwipingDown) { if (nodeIsScrolling) { scrollable(true); blockPan = true; } else { scrollable(false); blockPan = false; } } // 4. Sheet fully open, scroll offset > 0, scrolling: true, panning: false will transition into scrolling: false, panning: true, once scroll reaches offset=0 if (isFullOpen && isSwipingDown) { if (nodeIsScrolling) { scrollable(true); blockPan = true; } else { if (!deltaYOnGestureStart && deltaY > 0) { deltaYOnGestureStart = deltaY; } var hasRefreshControl = activeDraggableNodes.some(function (node) { return node.node.handlerConfig.hasRefreshControl; }); if (hasRefreshControl) { for (var _i = 0, activeDraggableNodes_1 = activeDraggableNodes; _i < activeDraggableNodes_1.length; _i++) { var node = activeDraggableNodes_1[_i]; if (node.node.handlerConfig.hasRefreshControl) { // Refresh Control will work in to 15% area of the DraggableNode. var refreshControlBounds = node.rectWithBoundary.py + node.rectWithBoundary.h * node.node.handlerConfig.refreshControlBoundary; if (!refreshControlBounds) continue; if (absoluteY < refreshControlBounds) { scrollable(true); blockPan = true; isRefreshing = true; } } } } else { scrollable(false); blockPan = false; } } } } else if (!enableGesturesInScrollView && activeDraggableNodes.length > 0) { blockPan = true; } else { blockPan = false; } if (isRefreshing) { blockPan = true; scrollable(true); } var value = oldValue; deltaY = deltaY - deltaYOnGestureStart; if (!blockPan) { value = initialValue.current + deltaY; oldValue = value; } if (blockPan) return; velocity = 1; var correctedValue = value <= minTranslateValue.current ? minTranslateValue.current - value : value; if (correctedValue / overdrawFactor >= overdrawSize && deltaY <= 0) { return; } var minSnapPoint = getNextPosition(0); var translateYValue = value <= minTranslateValue.current ? overdrawEnabled ? minTranslateValue.current - correctedValue / overdrawFactor : minTranslateValue.current : value; if (!closable && disableDragBeyondMinimumSnapPoint) { translateY.value = translateYValue >= minSnapPoint ? minSnapPoint : translateYValue; } else { translateY.value = translateYValue; } }; var onEnd = function () { if (!gestureEnabled) return; deltaYOnGestureStart = 0; var isMovingUp = getCurrentPosition() < initialValue.current; scrollable(true); if ((!isMovingUp && getCurrentPosition() < initialValue.current + springOffset) || (isMovingUp && getCurrentPosition() > initialValue.current - springOffset)) { moveSheetWithAnimation(1, undefined, undefined, true); velocity = 0; return; } if (!isMovingUp) { snapBackward(velocity, true); } else { snapForward(velocity, true); } velocity = 0; }; return Platform.OS === 'web' ? PanResponder.create({ onMoveShouldSetPanResponder: function (_event, gesture) { var vy = gesture.vy < 0 ? gesture.vy * -1 : gesture.vy; var vx = gesture.vx < 0 ? gesture.vx * -1 : gesture.vx; if (vy < 0.05 || vx > 0.05) { return false; } var activeDraggableNodes = getActiveDraggableNodes(_event.nativeEvent.pageX, _event.nativeEvent.pageY); for (var _i = 0, activeDraggableNodes_2 = activeDraggableNodes; _i < activeDraggableNodes_2.length; _i++) { var node = activeDraggableNodes_2[_i]; var scrollRef = resolveScrollRef(node.node.ref); offsets.push(scrollRef.scrollTop); } return true; }, onStartShouldSetPanResponder: function (_event, _gesture) { var activeDraggableNodes = getActiveDraggableNodes(_event.nativeEvent.pageX, _event.nativeEvent.pageY); for (var _i = 0, activeDraggableNodes_3 = activeDraggableNodes; _i < activeDraggableNodes_3.length; _i++) { var node = activeDraggableNodes_3[_i]; var scrollRef = resolveScrollRef(node.node.ref); offsets.push(scrollRef.scrollTop); } return true; }, onPanResponderMove: function (_event, gesture) { onChange(_event.nativeEvent.pageX, _event.nativeEvent.pageY, gesture.dy); }, onPanResponderEnd: onEnd, }) : Gesture.Pan() .withRef(panGestureRef) .onChange(function (event) { return onChange(event.absoluteX, event.absoluteY, event.translationY); }) .runOnJS(true) .activeOffsetY([-5, 5]) .failOffsetX([-5, 5]) .onEnd(onEnd); }, [gestureEnabled]); var onTouch = function (event) { onTouchBackdrop === null || onTouchBackdrop === void 0 ? void 0 : onTouchBackdrop(event); if (enableRouterBackNavigation && router.canGoBack()) { router.goBack(); return; } var closeRequestResult = true; if (onRequestClose) { closeRequestResult = onRequestClose === null || onRequestClose === void 0 ? void 0 : onRequestClose(CloseRequestType.TOUCH_BACKDROP); } if (closeOnTouchBackdrop && closable && closeRequestResult) { hideSheet(); } }; var getRef = useCallback(function () { return ({ show: function (snapIndex) { var _a; if (typeof snapIndex === 'number') { currentSnapIndex.current = snapIndex; } onBeforeShow === null || onBeforeShow === void 0 ? void 0 : onBeforeShow(); (_a = routerRef.current) === null || _a === void 0 ? void 0 : _a.initialNavigation(); setVisible(true); }, hide: function (data) { hideSheet(undefined, data, true); }, setModalVisible: function (_visible) { if (_visible) { setVisible(true); } else { hideSheet(); } }, snapToOffset: function (offset) { initialValue.current = actionSheetHeight.current + minTranslateValue.current - (actionSheetHeight.current * offset) / 100; translateY.value = withSpring(initialValue.current, openAnimationConfig); }, snapToRelativeOffset: function (offset) { if (offset === 0) { getRef().snapToIndex(currentSnapIndex.current); return; } var availableHeight = actionSheetHeight.current + minTranslateValue.current; initialValue.current = initialValue.current + initialValue.current * (offset / 100); if (initialValue.current > availableHeight) { getRef().snapToOffset(100); return; } translateY.value = withSpring(initialValue.current, openAnimationConfig); }, snapToIndex: function (index) { if (index > snapPoints.length || index < 0) return; if (!visibleRef.current.value) { getRef().show(index); return; } currentSnapIndex.current = index; initialValue.current = getNextPosition(index); translateY.value = withSpring(initialValue.current, openAnimationConfig); notifySnapIndexChanged(); }, handleChildScrollEnd: function () { console.warn('handleChildScrollEnd has been removed. Please use `useScrollHandlers` hook to enable scrolling in ActionSheet'); }, modifyGesturesForLayout: function (_id, layout, scrollOffset) { gestureBoundaries.current[_id] = __assign(__assign({}, layout), { scrollOffset: scrollOffset }); }, currentSnapIndex: function () { return currentSnapIndex.current; }, isGestureEnabled: function () { return gestureEnabled; }, isOpen: function () { return visibleRef.current.value; }, keyboardHandler: function (enabled) { keyboard.pauseKeyboardHandler.current = enabled; }, ev: internalEventManager, currentPayload: function () { return payloadRef.current; }, }); }, [ internalEventManager, onBeforeShow, setVisible, hideSheet, translateY, openAnimationConfig, snapPoints.length, getNextPosition, notifySnapIndexChanged, gestureEnabled, visible, keyboard.pauseKeyboardHandler, ]); useImperativeHandle(ref, getRef, [getRef]); useEffect(function () { if (sheetId) { SheetManager.registerRef(sheetId, currentContext, { current: getRef(), }); } sheetRef.current = getRef(); }, [currentContext, getRef, sheetId, sheetRef]); var onModalRequestClose = React.useCallback(function () { var _a, _b; if (enableRouterBackNavigation && ((_a = routerRef.current) === null || _a === void 0 ? void 0 : _a.canGoBack())) { (_b = routerRef.current) === null || _b === void 0 ? void 0 : _b.goBack(); return; } var closeRequestResult = true; if (onRequestClose) { closeRequestResult = onRequestClose === null || onRequestClose === void 0 ? void 0 : onRequestClose(CloseRequestType.BACK_PRESS); } if (visible && closable && closeOnPressBack && closeRequestResult) { hideSheet(); } }, [hideSheet, enableRouterBackNavigation, closeOnPressBack, visible]); var rootProps = React.useMemo(function () { var _a, _b; return isModal && !props.backgroundInteractionEnabled ? { visible: true, animationType: 'none', testID: ((_a = props.testIDs) === null || _a === void 0 ? void 0 : _a.modal) || props.testID, supportedOrientations: SUPPORTED_ORIENTATIONS, onShow: props.onOpen, onRequestClose: onModalRequestClose, transparent: true, /** * Always true, it causes issue with keyboard handling. */ statusBarTranslucent: true, } : { testID: ((_b = props.testIDs) === null || _b === void 0 ? void 0 : _b.root) || props.testID, onLayout: function () { var _a; hardwareBackPressEvent.current = BackHandler.addEventListener('hardwareBackPress', onHardwareBackPress); (_a = props === null || props === void 0 ? void 0 : props.onOpen) === null || _a === void 0 ? void 0 : _a.call(props); }, style: { position: 'absolute', zIndex: zIndex ? zIndex : sheetId ? getZIndexFromStack(sheetId, currentContext) : 999, width: '100%', height: '100%', }, pointerEvents: (props === null || props === void 0 ? void 0 : props.backgroundInteractionEnabled) ? 'box-none' : 'auto', }; }, [ currentContext, isModal, onHardwareBackPress, onModalRequestClose, props, zIndex, sheetId, ]); var renderRoute = useCallback(function (route) { var _a; var RouteComponent = route.component; return (<Animated.View key={route.name} style={{ display: route.name !== ((_a = router.currentRoute) === null || _a === void 0 ? void 0 : _a.name) ? 'none' : 'flex', opacity: routeOpacity, }}> <RouterParamsContext.Provider value={route === null || route === void 0 ? void 0 : route.params}> <RouteComponent router={router} params={route === null || route === void 0 ? void 0 : route.params} payload={sheetPayload}/> </RouterParamsContext.Provider> </Animated.View>); }, [routeOpacity, router, sheetPayload]); var context = { ref: panGestureRef, eventManager: internalEventManager, }; var animatedOpacityStyle = useAnimatedStyle(function () { return { opacity: opacity.value, }; }, [opacity]); var animatedActionSheetStyle = useAnimatedStyle(function () { return { transform: [ { translateY: translateY.value, }, ], opacity: actionSheetOpacity.value, }; }, [translateY]); var animatedUnderlayTranslateStyle = useAnimatedStyle(function () { return { transform: [ { translateY: underlayTranslateY.value, }, ], }; }, [underlayTranslateY]); var GestureMobileOnly = Platform.OS === 'web' ? Fragment : GestureDetector; return (<> {visible ? (<Root {...rootProps}> <GestureHandlerRoot isModal={isModal} style={styles.parentContainer} pointerEvents={(props === null || props === void 0 ? void 0 : props.backgroundInteractionEnabled) ? 'box-none' : 'auto'}> <PanGestureRefContext.Provider value={context}> <DraggableNodesContext.Provider value={draggableNodesContext}> <Animated.View onLayout={function (event) { if (event.nativeEvent.layout.height < 10) return; setDimensions({ width: event.nativeEvent.layout.width, height: event.nativeEvent.layout.height, }); }} ref={rootViewContainerRef} pointerEvents={(props === null || props === void 0 ? void 0 : props.backgroundInteractionEnabled) ? 'box-none' : 'auto'} style={[ styles.parentContainer, { width: '100%', justifyContent: 'flex-end', }, ]}>