@crossed/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,244 lines (1,243 loc) • 56 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ActionSheet_exports = {};
__export(ActionSheet_exports, {
default: () => ActionSheet_default
});
module.exports = __toCommonJS(ActionSheet_exports);
var import_jsx_runtime = require("react/jsx-runtime");
var import_react = __toESM(require("react"));
var import_react_native = require("react-native");
var import_react_native_gesture_handler = require("react-native-gesture-handler");
var import_context = require("./context");
var import_eventmanager = __toESM(require("./eventmanager"));
var import_use_router = require("./hooks/use-router");
var import_use_scroll_handlers = require("./hooks/use-scroll-handlers");
var import_use_sheet_manager = __toESM(require("./hooks/use-sheet-manager"));
var import_useKeyboard = require("./hooks/useKeyboard");
var import_provider = require("./provider");
var import_sheetmanager = require("./sheetmanager");
var import_styles = require("./styles");
var import_utils = require("./utils");
const EVENTS_INTERNAL = {
safeAreaLayout: "safeAreaLayout"
};
var ActionSheet_default = (0, import_react.forwardRef)(
function ActionSheet({
animated = true,
closeOnPressBack = true,
springOffset = 50,
elevation = 5,
defaultOverlayOpacity = 0.3,
overlayColor = "black",
closable = true,
closeOnTouchBackdrop = true,
onTouchBackdrop,
drawUnderStatusBar = false,
gestureEnabled = false,
isModal = true,
snapPoints = [100],
initialSnapIndex = 0,
overdrawEnabled = true,
overdrawFactor = 15,
overdrawSize = 100,
zIndex = 999,
keyboardHandlerEnabled = true,
ExtraOverlayComponent,
payload,
safeAreaInsets,
routes,
initialRoute,
onBeforeShow,
enableRouterBackNavigation,
onBeforeClose,
enableGesturesInScrollView = true,
disableDragBeyondMinimumSnapPoint,
...props
}, ref) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
snapPoints = snapPoints[snapPoints.length - 1] !== 100 ? [...snapPoints, 100] : snapPoints;
const initialValue = (0, import_react.useRef)(-1);
const actionSheetHeight = (0, import_react.useRef)(0);
const safeAreaPaddings = (0, import_react.useRef)(
safeAreaInsets || {
top: 0,
left: 0,
bottom: 0,
right: 0
}
);
const internalEventManager = import_react.default.useMemo(() => new import_eventmanager.default(), []);
const currentContext = (0, import_provider.useProviderContext)();
const currentSnapIndex = (0, import_react.useRef)(initialSnapIndex);
const sheetRef = (0, import_provider.useSheetRef)();
const dimensionsRef = (0, import_react.useRef)({
width: 0,
height: 0,
portrait: true
});
const minTranslateValue = (0, import_react.useRef)(0);
const keyboardWasVisible = (0, import_react.useRef)(false);
const prevKeyboardHeight = (0, import_react.useRef)(0);
const id = (0, import_provider.useSheetIDContext)();
const sheetId = props.id || id;
const lock = (0, import_react.useRef)(false);
const panViewRef = (0, import_react.useRef)(null);
const rootViewContainerRef = (0, import_react.useRef)(null);
const gestureBoundaries = (0, import_react.useRef)({});
const hiding = (0, import_react.useRef)(false);
const payloadRef = (0, import_react.useRef)(payload);
const sheetPayload = (0, import_provider.useSheetPayload)();
const panHandlerRef = (0, import_react.useRef)();
const closing = (0, import_react.useRef)(false);
const draggableNodes = (0, import_react.useRef)([]);
const sheetLayoutRef = (0, import_react.useRef)();
const [dimensions, setDimensions] = (0, import_react.useState)({
width: import_react_native.Dimensions.get("window").width,
height: 0,
portrait: true,
paddingBottom: (props == null ? void 0 : props.useBottomSafeAreaPadding) ? 25 : 0
});
const rootViewLayoutEventValues = (0, import_react.useRef)({});
if (safeAreaInsets) {
safeAreaPaddings.current = safeAreaInsets;
}
const { visible, setVisible } = (0, import_use_sheet_manager.default)({
id: sheetId,
onHide: (data) => {
hideSheet(void 0, data, true);
},
onBeforeShow: (data) => {
var _a2;
(_a2 = routerRef.current) == null ? void 0 : _a2.initialNavigation();
onBeforeShow == null ? void 0 : onBeforeShow(data);
},
onContextUpdate: () => {
if (sheetId) {
import_sheetmanager.SheetManager.add(sheetId, currentContext);
import_sheetmanager.SheetManager.registerRef(sheetId, currentContext, {
current: getRef()
});
}
}
});
const animations = (0, import_react.useMemo)(
() => ({
opacity: new import_react_native.Animated.Value(0),
translateY: new import_react_native.Animated.Value(0),
underlayTranslateY: new import_react_native.Animated.Value(100),
keyboardTranslate: new import_react_native.Animated.Value(0),
routeOpacity: new import_react_native.Animated.Value(0)
}),
[]
);
const animationListeners = (0, import_react.useRef)({});
const router = (0, import_use_router.useRouter)({
routes,
getRef: () => getRef(),
initialRoute,
onNavigate: props.onNavigate,
onNavigateBack: props.onNavigateBack,
routeOpacity: animations.routeOpacity
});
const routerRef = (0, import_react.useRef)(router);
payloadRef.current = payload;
routerRef.current = router;
const keyboard = (0, import_useKeyboard.useKeyboard)(keyboardHandlerEnabled);
const prevSnapIndex = (0, import_react.useRef)(initialSnapIndex);
const draggableNodesContext = import_react.default.useMemo(
() => ({
nodes: draggableNodes
}),
[]
);
const notifyOffsetChange = (value) => {
internalEventManager.publish("onoffsetchange", value);
};
const notifySnapIndexChanged = import_react.default.useCallback(() => {
var _a2;
if (prevSnapIndex.current !== currentSnapIndex.current) {
prevSnapIndex.current = currentSnapIndex.current;
(_a2 = props.onSnapIndexChange) == null ? void 0 : _a2.call(props, currentSnapIndex.current);
}
}, [props.onSnapIndexChange]);
const returnAnimation = import_react.default.useCallback(
(velocity) => {
if (!animated) {
animations.translateY.setValue(initialValue.current);
return;
}
const config = props.openAnimationConfig;
const correctedValue = initialValue.current > minTranslateValue.current ? initialValue.current : 0;
notifyOffsetChange(correctedValue);
if (!config) {
import_react_native.Animated.spring(animations.translateY, {
toValue: initialValue.current,
useNativeDriver: true,
friction: 8,
...config,
velocity: typeof velocity !== "number" ? void 0 : velocity
}).start();
} else {
import_react_native.Animated.spring(animations.translateY, {
toValue: initialValue.current,
useNativeDriver: true,
...config,
velocity: typeof velocity !== "number" ? void 0 : velocity
}).start();
}
notifySnapIndexChanged();
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[animated, props.openAnimationConfig]
);
const opacityAnimation = import_react.default.useCallback(
(opacity) => {
import_react_native.Animated.timing(animations.opacity, {
duration: 150,
easing: import_react_native.Easing.in(import_react_native.Easing.ease),
toValue: opacity,
useNativeDriver: true
}).start();
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
const hideAnimation = import_react.default.useCallback(
(vy, callback) => {
if (!animated) {
callback == null ? void 0 : callback({ finished: true });
return;
}
const config = props.closeAnimationConfig;
opacityAnimation(0);
const animation = import_react_native.Animated.spring(animations.translateY, {
velocity: typeof vy !== "number" ? 3 : vy + 1,
toValue: dimensionsRef.current.height * 1.3,
useNativeDriver: true,
...config
});
animation.start();
setTimeout(() => {
animation.stop();
callback == null ? void 0 : callback({ finished: true });
}, 150);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[animated, opacityAnimation, props.closeAnimationConfig]
);
const getCurrentPosition = import_react.default.useCallback(() => {
return animations.translateY._value <= minTranslateValue.current + 5 ? 0 : animations.translateY._value;
}, []);
const getNextPosition = import_react.default.useCallback(
(snapIndex) => {
return actionSheetHeight.current + minTranslateValue.current - actionSheetHeight.current * snapPoints[snapIndex] / 100;
},
[snapPoints]
);
const hardwareBackPressEvent = (0, import_react.useRef)();
const Root = isModal && !(props == null ? void 0 : props.backgroundInteractionEnabled) ? import_react_native.Modal : import_react_native.Animated.View;
(0, import_react.useEffect)(() => {
let animationListener;
if (drawUnderStatusBar || props.onChange) {
animationListener = animations.translateY.addListener((value) => {
var _a2;
const correctedValue = value.value > minTranslateValue.current ? value.value - minTranslateValue.current : 0;
(_a2 = props == null ? void 0 : props.onChange) == null ? void 0 : _a2.call(props, correctedValue, actionSheetHeight.current);
if (drawUnderStatusBar) {
if (lock.current)
return;
const correctedHeight = keyboard.keyboardShown ? dimensionsRef.current.height - (keyboard.keyboardHeight + safeAreaPaddings.current.bottom) : dimensionsRef.current.height - safeAreaPaddings.current.bottom;
if (actionSheetHeight.current >= correctedHeight - 1) {
if (value.value < 100) {
animations.underlayTranslateY.setValue(
Math.max(value.value - 20, -20)
);
} else {
if (animations.underlayTranslateY._value !== 100) {
animations.underlayTranslateY.setValue(100);
}
}
} else {
if (animations.underlayTranslateY._value !== 100) {
animations.underlayTranslateY.setValue(100);
}
}
}
});
}
animationListeners.current.translateY = animationListener;
return () => {
animationListener && animations.translateY.removeListener(animationListener);
};
}, [props == null ? void 0 : props.id, keyboard.keyboardShown, keyboard.keyboardHeight]);
const onSheetLayout = import_react.default.useCallback(
(event) => {
var _a2, _b2;
sheetLayoutRef.current = { ...event.nativeEvent.layout };
if (rootViewLayoutEventValues.current.resizing)
return;
if (closing.current)
return;
const rootViewHeight = (_a2 = dimensionsRef.current) == null ? void 0 : _a2.height;
actionSheetHeight.current = event.nativeEvent.layout.height > dimensionsRef.current.height ? dimensionsRef.current.height : event.nativeEvent.layout.height;
minTranslateValue.current = rootViewHeight - (actionSheetHeight.current + safeAreaPaddings.current.bottom);
if (initialValue.current < 0) {
animations.translateY.setValue(rootViewHeight * 1.1);
}
const nextInitialValue = actionSheetHeight.current + minTranslateValue.current - actionSheetHeight.current * snapPoints[currentSnapIndex.current] / 100;
initialValue.current = (keyboard.keyboardShown || keyboardWasVisible.current) && initialValue.current <= nextInitialValue && initialValue.current >= minTranslateValue.current ? initialValue.current : nextInitialValue;
const sheetBottomEdgePosition = initialValue.current + actionSheetHeight.current * snapPoints[currentSnapIndex.current] / 100;
const sheetPositionWithKeyboard = sheetBottomEdgePosition - (((_b2 = dimensionsRef.current) == null ? void 0 : _b2.height) - keyboard.keyboardHeight);
initialValue.current = sheetPositionWithKeyboard > 0 ? initialValue.current - sheetPositionWithKeyboard : initialValue.current;
if (keyboard.keyboardShown) {
minTranslateValue.current = minTranslateValue.current - (keyboard.keyboardHeight + safeAreaPaddings.current.bottom);
keyboardWasVisible.current = true;
prevKeyboardHeight.current = keyboard.keyboardHeight;
} else {
keyboardWasVisible.current = false;
}
opacityAnimation(1);
setTimeout(() => {
returnAnimation();
}, 1);
if (initialValue.current > 100) {
if (lock.current)
return;
animations.underlayTranslateY.setValue(100);
}
if (import_react_native.Platform.OS === "web") {
document.body.style.overflowY = "hidden";
document.documentElement.style.overflowY = "hidden";
}
},
[
snapPoints,
keyboard.keyboardShown,
keyboard.keyboardHeight,
opacityAnimation,
animations.translateY,
animations.underlayTranslateY,
returnAnimation
]
);
const onRootViewLayout = import_react.default.useCallback(
(event) => {
var _a2, _b2;
if (keyboard.keyboardShown && !isModal) {
return;
}
rootViewLayoutEventValues.current.resizing = true;
const rootViewHeight = event.nativeEvent.layout.height;
const rootViewWidth = event.nativeEvent.layout.width;
(_a2 = rootViewLayoutEventValues.current.sub) == null ? void 0 : _a2.unsubscribe();
rootViewLayoutEventValues.current.sub = internalEventManager.subscribe(
EVENTS_INTERNAL.safeAreaLayout,
() => {
var _a3;
(_a3 = rootViewLayoutEventValues.current.sub) == null ? void 0 : _a3.unsubscribe();
const safeMarginFromTop = import_react_native.Platform.OS === "ios" ? safeAreaPaddings.current.top < 20 ? 20 : safeAreaPaddings.current.top : import_react_native.StatusBar.currentHeight || 0;
const height = rootViewHeight - safeMarginFromTop;
const width = rootViewWidth;
dimensionsRef.current = {
width,
height,
portrait: width < height
};
setDimensions({ ...dimensionsRef.current });
rootViewLayoutEventValues.current.resizing = false;
if (sheetLayoutRef.current) {
onSheetLayout({
nativeEvent: {
layout: sheetLayoutRef.current
}
});
}
}
);
clearTimeout(rootViewLayoutEventValues.current.timer);
clearTimeout(rootViewLayoutEventValues.current.layouTimer);
if (safeAreaPaddings.current.top !== void 0 || import_react_native.Platform.OS !== "ios") {
rootViewLayoutEventValues.current.layouTimer = setTimeout(
() => {
internalEventManager.publish(EVENTS_INTERNAL.safeAreaLayout);
},
import_react_native.Platform.OS === "ios" || rootViewLayoutEventValues.current.firstEventFired ? 0 : 300
);
}
if (!((_b2 = rootViewLayoutEventValues.current) == null ? void 0 : _b2.firstEventFired)) {
rootViewLayoutEventValues.current.firstEventFired = true;
}
},
[keyboard.keyboardShown, isModal, internalEventManager, onSheetLayout]
);
const hideSheet = import_react.default.useCallback(
(vy, data, isSheetManagerOrRef) => {
if (hiding.current)
return;
if (!closable && !isSheetManagerOrRef) {
returnAnimation(vy);
return;
}
hiding.current = true;
onBeforeClose == null ? void 0 : onBeforeClose(data || payloadRef.current || data);
setTimeout(() => {
if (closable) {
closing.current = true;
import_react_native.Keyboard.dismiss();
animationListeners.current.translateY && animations.translateY.removeListener(
animationListeners.current.translateY
);
animationListeners.current.translateY = void 0;
}
hideAnimation(vy, ({ finished }) => {
var _a2, _b2;
if (finished) {
if (closable || isSheetManagerOrRef) {
setVisible(false);
if (props.onClose) {
(_a2 = props.onClose) == null ? void 0 : _a2.call(
props,
data || payloadRef.current || data
);
hiding.current = false;
}
(_b2 = hardwareBackPressEvent.current) == null ? void 0 : _b2.remove();
if (sheetId) {
import_sheetmanager.SheetManager.remove(sheetId, currentContext);
hiding.current = false;
import_eventmanager.actionSheetEventManager.publish(
`onclose_${sheetId}`,
data || payloadRef.current || data,
currentContext
);
} else {
hiding.current = false;
}
currentSnapIndex.current = initialSnapIndex;
closing.current = false;
setTimeout(() => {
keyboard.reset();
});
} else {
animations.opacity.setValue(1);
returnAnimation();
}
}
});
}, 1);
if (import_react_native.Platform.OS === "web") {
document.body.style.overflowY = "auto";
document.documentElement.style.overflowY = "auto";
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
closable,
hideAnimation,
props.onClose,
returnAnimation,
setVisible,
keyboard
]
);
const onHardwareBackPress = import_react.default.useCallback(() => {
var _a2, _b2;
if (visible && enableRouterBackNavigation && ((_a2 = routerRef.current) == null ? void 0 : _a2.canGoBack())) {
(_b2 = routerRef.current) == null ? void 0 : _b2.goBack();
return true;
}
if (visible && closable && closeOnPressBack) {
hideSheet();
return true;
}
return false;
}, [
closable,
closeOnPressBack,
hideSheet,
enableRouterBackNavigation,
visible
]);
const snapForward = import_react.default.useCallback(
(vy) => {
if (currentSnapIndex.current === snapPoints.length - 1) {
initialValue.current = getNextPosition(currentSnapIndex.current);
returnAnimation(vy);
return;
}
let nextSnapPoint = 0;
let nextSnapIndex = 0;
if (getCurrentPosition() === 0) {
nextSnapPoint = snapPoints[nextSnapIndex = snapPoints.length - 1];
} else {
for (let 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.");
returnAnimation(vy);
return;
}
currentSnapIndex.current = nextSnapIndex;
initialValue.current = getNextPosition(currentSnapIndex.current);
returnAnimation(vy);
},
[getCurrentPosition, getNextPosition, returnAnimation, snapPoints]
);
const snapBackward = import_react.default.useCallback(
(vy) => {
if (currentSnapIndex.current === 0) {
if (closable) {
initialValue.current = dimensionsRef.current.height * 1.3;
hideSheet(vy);
} else {
initialValue.current = getNextPosition(currentSnapIndex.current);
returnAnimation(vy);
}
return;
}
let nextSnapPoint = 0;
let nextSnapIndex = 0;
for (let i = currentSnapIndex.current; i > -1; i--) {
if (getNextPosition(i) > getCurrentPosition()) {
nextSnapPoint = snapPoints[nextSnapIndex = i];
break;
}
}
if (nextSnapPoint < 0) {
console.warn("Snap points should range between 0 to 100.");
returnAnimation(vy);
return;
}
currentSnapIndex.current = nextSnapIndex;
initialValue.current = getNextPosition(currentSnapIndex.current);
returnAnimation(vy);
},
[
closable,
getCurrentPosition,
getNextPosition,
hideSheet,
returnAnimation,
snapPoints
]
);
function getRectBoundary(rect) {
if (rect) {
const { w, h, px, py } = rect;
return { ...rect, boundryX: px + w, boundryY: py + h };
}
return { w: 0, h: 0, px: 0, py: 0, x: 0, y: 0, boundryX: 0, boundryY: 0 };
}
const getActiveDraggableNodes = import_react.default.useCallback(
(absoluteX, absoluteY) => {
var _a2;
if (((_a2 = draggableNodes.current) == null ? void 0 : _a2.length) === 0)
return [];
const activeNodes = [];
for (const node of draggableNodes.current) {
const rect = getRectBoundary(node.rect.current);
if (rect.boundryX === 0 && rect.boundryY === 0)
continue;
if (absoluteX > rect.px && absoluteY > rect.py && absoluteX < rect.boundryX && absoluteY < rect.boundryY) {
activeNodes.push({
rectWithBoundry: rect,
node
});
}
}
return activeNodes;
},
[]
);
const panHandlers = import_react.default.useMemo(() => {
let velocity = 0;
let prevDeltaY = 0;
let offsets = [];
let lockGesture = false;
let gestureEventCounter = 0;
let isScrollingGesture = false;
let deltaYOnGestureStart = 0;
let start;
function scrollable(value) {
if (import_react_native.Platform.OS === "ios")
return;
for (let i = 0; i < draggableNodes.current.length; i++) {
const node = draggableNodes.current[i];
const scrollRef = (0, import_use_scroll_handlers.resolveScrollRef)(node.ref);
scrollRef == null ? void 0 : scrollRef.setNativeProps({
scrollEnabled: value
});
}
}
return import_react_native.Platform.OS === "web" ? { enabled: false } : {
onBegan: () => {
if (import_react_native.Platform.OS === "android") {
scrollable(false);
}
},
onGestureEvent(event) {
var _a2, _b2;
if (sheetId && !(0, import_sheetmanager.isRenderedOnTop)(sheetId, currentContext))
return;
const gesture = event.nativeEvent;
let deltaY = gesture.translationY;
const swipingDown = prevDeltaY < deltaY;
prevDeltaY = deltaY;
if (!start) {
start = {
x: event.nativeEvent.absoluteX,
y: event.nativeEvent.absoluteY
};
}
const activeDraggableNodes = getActiveDraggableNodes(
start.x,
start.y
);
const isFullOpen = getCurrentPosition() === 0;
let blockSwipeGesture = false;
if (activeDraggableNodes.length > 0) {
if (isFullOpen) {
if (swipingDown) {
for (const node of activeDraggableNodes) {
if (!node.node.offset.current)
continue;
const { y } = node.node.offset.current;
if (y === import_use_scroll_handlers.ScrollState.END) {
blockSwipeGesture = true;
continue;
}
if (y < 1 && node.node.handlerConfig.hasRefreshControl) {
const refreshControlBounds = node.rectWithBoundry.py + node.rectWithBoundry.h * node.node.handlerConfig.refreshControlBoundary;
if (!refreshControlBounds)
continue;
if (event.nativeEvent.absoluteY < refreshControlBounds) {
lockGesture = true;
blockSwipeGesture = false;
continue;
} else {
blockSwipeGesture = false;
continue;
}
}
if (y > 1) {
blockSwipeGesture = true;
}
}
} else {
for (const node of activeDraggableNodes) {
if (!node.node.offset.current)
continue;
const { y } = node.node.offset.current;
if (
// Scroll has not reached end
y !== import_use_scroll_handlers.ScrollState.END
) {
blockSwipeGesture = true;
}
}
}
}
}
gestureEventCounter++;
if (isFullOpen && (blockSwipeGesture || lockGesture)) {
isScrollingGesture = true;
scrollable(true);
return;
}
const startY = event.nativeEvent.y - event.nativeEvent.translationY;
if (!enableGesturesInScrollView && startY > 100) {
return;
}
if (gestureEventCounter < 2) {
return;
}
if (swipingDown || !isFullOpen) {
if (import_react_native.Platform.OS === "ios") {
for (let i = 0; i < draggableNodes.current.length; i++) {
const node = draggableNodes.current[i];
const scrollRef = (0, import_use_scroll_handlers.resolveScrollRef)(node.ref);
if (!offsets[i] || ((_a2 = node.offset.current) == null ? void 0 : _a2.y) === 0) {
offsets[i] = ((_b2 = node.offset.current) == null ? void 0 : _b2.y) || 0;
}
if (scrollRef == null ? void 0 : scrollRef.current) {
scrollRef.current.scrollTo({
x: 0,
y: offsets[i],
animated: false
});
}
}
}
}
if (!isFullOpen) {
isScrollingGesture = false;
blockSwipeGesture = false;
}
if (isScrollingGesture && !swipingDown) {
return scrollable(true);
} else {
scrollable(false);
}
isScrollingGesture = false;
if (!deltaYOnGestureStart) {
deltaYOnGestureStart = deltaY;
}
deltaY = deltaY - deltaYOnGestureStart;
const value = initialValue.current + deltaY;
velocity = 1;
const correctedValue = value <= minTranslateValue.current ? minTranslateValue.current - value : value;
if (correctedValue / overdrawFactor >= overdrawSize && deltaY <= 0) {
return;
}
const minSnapPoint = getNextPosition(0);
const translateYValue = value <= minTranslateValue.current ? overdrawEnabled ? minTranslateValue.current - correctedValue / overdrawFactor : minTranslateValue.current : value;
if (!closable && disableDragBeyondMinimumSnapPoint) {
animations.translateY.setValue(
translateYValue >= minSnapPoint ? minSnapPoint : translateYValue
);
} else {
animations.translateY.setValue(translateYValue);
}
},
failOffsetX: [-20, 20],
activeOffsetY: [-5, 5],
onEnded() {
deltaYOnGestureStart = 0;
offsets = [];
start = void 0;
isScrollingGesture = false;
gestureEventCounter = 0;
lockGesture = false;
const isMovingUp = getCurrentPosition() < initialValue.current;
scrollable(true);
if (!isMovingUp && getCurrentPosition() < initialValue.current + springOffset || isMovingUp && getCurrentPosition() > initialValue.current - springOffset) {
returnAnimation(1);
velocity = 0;
return;
}
if (!isMovingUp) {
snapBackward(velocity);
} else {
snapForward(velocity);
}
velocity = 0;
},
enabled: gestureEnabled
};
}, [
animations.translateY,
closable,
currentContext,
disableDragBeyondMinimumSnapPoint,
enableGesturesInScrollView,
gestureEnabled,
getActiveDraggableNodes,
getCurrentPosition,
getNextPosition,
overdrawEnabled,
overdrawFactor,
overdrawSize,
returnAnimation,
sheetId,
snapBackward,
snapForward,
springOffset
]);
const handlers = import_react.default.useMemo(() => {
let prevDeltaY = 0;
let lockGesture = false;
let offsets = [];
let start;
let deltaYOnGestureStart = 0;
return !gestureEnabled || import_react_native.Platform.OS !== "web" ? { panHandlers: {} } : import_react_native.PanResponder.create({
onMoveShouldSetPanResponder: (_event, gesture) => {
if (sheetId && !(0, import_sheetmanager.isRenderedOnTop)(sheetId, currentContext))
return false;
const vy = gesture.vy < 0 ? gesture.vy * -1 : gesture.vy;
const vx = gesture.vx < 0 ? gesture.vx * -1 : gesture.vx;
if (vy < 0.05 || vx > 0.05) {
return false;
}
const activeDraggableNodes = getActiveDraggableNodes(
_event.nativeEvent.pageX,
_event.nativeEvent.pageY
);
for (const node of activeDraggableNodes) {
const scrollRef = (0, import_use_scroll_handlers.resolveScrollRef)(node.node.ref);
offsets.push(scrollRef.scrollTop);
}
return true;
},
onStartShouldSetPanResponder: (_event, _gesture) => {
if (sheetId && !(0, import_sheetmanager.isRenderedOnTop)(sheetId, currentContext))
return false;
const activeDraggableNodes = getActiveDraggableNodes(
_event.nativeEvent.pageX,
_event.nativeEvent.pageY
);
for (const node of activeDraggableNodes) {
const scrollRef = (0, import_use_scroll_handlers.resolveScrollRef)(node.node.ref);
offsets.push(scrollRef.scrollTop);
}
return true;
},
onPanResponderMove: (_event, gesture) => {
let deltaY = gesture.dy;
const swipingDown = prevDeltaY < deltaY;
prevDeltaY = deltaY;
const isFullOpen = getCurrentPosition() === 0;
let blockSwipeGesture = false;
if (!start) {
start = {
x: _event.nativeEvent.pageX,
y: _event.nativeEvent.pageY
};
}
const activeDraggableNodes = getActiveDraggableNodes(
start.x,
start.y
);
if (activeDraggableNodes.length > 0) {
if (isFullOpen) {
if (swipingDown) {
for (let i = 0; i < activeDraggableNodes.length; i++) {
const node = activeDraggableNodes[i];
if (!node.node.offset.current)
continue;
const { y } = node.node.offset.current;
if (y === import_use_scroll_handlers.ScrollState.END) {
blockSwipeGesture = true;
const scrollRef = (0, import_use_scroll_handlers.resolveScrollRef)(node.node.ref);
offsets[i] = scrollRef.scrollTop;
continue;
}
if (y === 0 && node.node.handlerConfig.hasRefreshControl) {
const refreshControlBounds = node.rectWithBoundry.py + node.rectWithBoundry.h * node.node.handlerConfig.refreshControlBoundary;
if (!refreshControlBounds)
continue;
if (_event.nativeEvent.pageY < refreshControlBounds) {
lockGesture = true;
blockSwipeGesture = false;
continue;
} else {
blockSwipeGesture = false;
continue;
}
}
if (y > 5) {
blockSwipeGesture = true;
const scrollRef = (0, import_use_scroll_handlers.resolveScrollRef)(node.node.ref);
offsets[i] = scrollRef.scrollTop;
}
}
} else {
for (let i = 0; i < activeDraggableNodes.length; i++) {
const node = activeDraggableNodes[i];
if (!node.node.offset.current)
continue;
const { y } = node.node.offset.current;
if (y > -1) {
blockSwipeGesture = true;
}
}
}
} else {
for (let i = 0; i < activeDraggableNodes.length; i++) {
const node = activeDraggableNodes[i];
const scrollRef = (0, import_use_scroll_handlers.resolveScrollRef)(node.node.ref);
scrollRef.scrollTop = offsets[i];
}
}
}
if (blockSwipeGesture || lockGesture) {
return;
}
const startY = gesture.moveY - gesture.dy;
if (!enableGesturesInScrollView && startY > 100) {
return;
}
if (!deltaYOnGestureStart) {
deltaYOnGestureStart = deltaY;
}
deltaY = deltaY - deltaYOnGestureStart;
const value = initialValue.current + deltaY;
const correctedValue = value <= minTranslateValue.current ? minTranslateValue.current - value : value;
if (correctedValue / overdrawFactor >= overdrawSize && gesture.dy <= 0) {
return;
}
const minSnapPoint = getNextPosition(0);
const translateYValue = value <= minTranslateValue.current ? overdrawEnabled ? minTranslateValue.current - correctedValue / overdrawFactor : minTranslateValue.current : value;
if (!closable && disableDragBeyondMinimumSnapPoint) {
animations.translateY.setValue(
translateYValue >= minSnapPoint ? minSnapPoint : translateYValue
);
} else {
animations.translateY.setValue(translateYValue);
}
},
onPanResponderEnd: (_event, gesture) => {
start = void 0;
offsets = [];
prevDeltaY = 0;
deltaYOnGestureStart = 0;
const isMovingUp = getCurrentPosition() < initialValue.current;
if (!isMovingUp && getCurrentPosition() < initialValue.current + springOffset || isMovingUp && getCurrentPosition() > initialValue.current - springOffset) {
returnAnimation(gesture.vy);
return;
}
if (!isMovingUp) {
snapBackward(gesture.vy);
} else {
snapForward(gesture.vy);
}
}
});
}, [
gestureEnabled,
sheetId,
currentContext,
getActiveDraggableNodes,
getCurrentPosition,
enableGesturesInScrollView,
overdrawFactor,
overdrawSize,
getNextPosition,
overdrawEnabled,
closable,
disableDragBeyondMinimumSnapPoint,
animations.translateY,
springOffset,
returnAnimation,
snapBackward,
snapForward
]);
const onTouch = (event) => {
onTouchBackdrop == null ? void 0 : onTouchBackdrop(event);
if (enableRouterBackNavigation && router.canGoBack()) {
router.goBack();
return;
}
if (closeOnTouchBackdrop && closable) {
hideSheet();
}
};
const getRef = (0, import_react.useCallback)(
() => ({
show: (snapIndex) => {
var _a2;
if (typeof snapIndex === "number") {
currentSnapIndex.current = snapIndex;
}
onBeforeShow == null ? void 0 : onBeforeShow();
(_a2 = routerRef.current) == null ? void 0 : _a2.initialNavigation();
setVisible(true);
},
hide: (data) => {
hideSheet(void 0, data, true);
},
setModalVisible: (_visible) => {
if (_visible) {
setVisible(true);
} else {
hideSheet();
}
},
snapToOffset: (offset) => {
initialValue.current = actionSheetHeight.current + minTranslateValue.current - actionSheetHeight.current * offset / 100;
import_react_native.Animated.spring(animations.translateY, {
toValue: initialValue.current,
useNativeDriver: true,
...props.openAnimationConfig
}).start();
},
snapToRelativeOffset: (offset) => {
if (offset === 0) {
getRef().snapToIndex(currentSnapIndex.current);
return;
}
const availableHeight = actionSheetHeight.current + minTranslateValue.current;
initialValue.current = initialValue.current + initialValue.current * (offset / 100);
if (initialValue.current > availableHeight) {
getRef().snapToOffset(100);
return;
}
import_react_native.Animated.spring(animations.translateY, {
toValue: initialValue.current,
useNativeDriver: true,
...props.openAnimationConfig
}).start();
},
snapToIndex: (index) => {
if (index > snapPoints.length || index < 0)
return;
currentSnapIndex.current = index;
initialValue.current = getNextPosition(index);
import_react_native.Animated.spring(animations.translateY, {
toValue: initialValue.current,
useNativeDriver: true,
...props.openAnimationConfig
}).start();
notifySnapIndexChanged();
},
handleChildScrollEnd: () => {
console.warn(
"handleChildScrollEnd has been removed. Please use `useScrollHandlers` hook to enable scrolling in ActionSheet"
);
},
modifyGesturesForLayout: (_id, layout, scrollOffset) => {
gestureBoundaries.current[_id] = {
...layout,
scrollOffset
};
},
currentSnapIndex: () => currentSnapIndex.current,
isGestureEnabled: () => gestureEnabled,
isOpen: () => visible,
keyboardHandler: (enabled) => {
keyboard.pauseKeyboardHandler.current = enabled;
},
ev: internalEventManager
}),
[
internalEventManager,
onBeforeShow,
setVisible,
hideSheet,
animations.translateY,
props.openAnimationConfig,
snapPoints.length,
getNextPosition,
notifySnapIndexChanged,
gestureEnabled,
visible,
keyboard.pauseKeyboardHandler
]
);
(0, import_react.useImperativeHandle)(ref, getRef, [getRef]);
(0, import_react.useEffect)(() => {
if (sheetId) {
import_sheetmanager.SheetManager.registerRef(sheetId, currentContext, {
current: getRef()
});
}
sheetRef.current = getRef();
}, [currentContext, getRef, sheetId, sheetRef]);
const onRequestClose = import_react.default.useCallback(() => {
var _a2, _b2;
if (enableRouterBackNavigation && ((_a2 = routerRef.current) == null ? void 0 : _a2.canGoBack())) {
(_b2 = routerRef.current) == null ? void 0 : _b2.goBack();
return;
}
if (visible && closeOnPressBack) {
hideSheet();
}
}, [hideSheet, enableRouterBackNavigation, closeOnPressBack, visible]);
const rootProps = import_react.default.useMemo(
() => {
var _a2, _b2;
return isModal && !props.backgroundInteractionEnabled ? {
visible: true,
animationType: "none",
testID: ((_a2 = props.testIDs) == null ? void 0 : _a2.modal) || props.testID,
supportedOrientations: import_utils.SUPPORTED_ORIENTATIONS,
onShow: props.onOpen,
onRequestClose,
transparent: true,
/**
* Always true, it causes issue with keyboard handling.
*/
statusBarTranslucent: true
} : {
testID: ((_b2 = props.testIDs) == null ? void 0 : _b2.root) || props.testID,
onLayout: () => {
var _a3;
hardwareBackPressEvent.current = import_react_native.BackHandler.addEventListener(
"hardwareBackPress",
onHardwareBackPress
);
(_a3 = props == null ? void 0 : props.onOpen) == null ? void 0 : _a3.call(props);
},
style: {
position: "absolute",
zIndex: zIndex ? zIndex : sheetId ? (0, import_sheetmanager.getZIndexFromStack)(sheetId, currentContext) : 999,
width: "100%",
height: "100%"
},
pointerEvents: (props == null ? void 0 : props.backgroundInteractionEnabled) ? "box-none" : "auto"
};
},
[
currentContext,
isModal,
onHardwareBackPress,
onRequestClose,
props,
zIndex,
sheetId
]
);
const renderRoute = (0, import_react.useCallback)(
(route) => {
var _a2;
const RouteComponent = route.component;
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_native.Animated.View,
{
style: {
display: route.name !== ((_a2 = router.currentRoute) == null ? void 0 : _a2.name) ? "none" : "flex",
opacity: animations.routeOpacity
},
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_use_router.RouterParamsContext.Provider, { value: route == null ? void 0 : route.params, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
RouteComponent,
{
router,
params: route == null ? void 0 : route.params,
payload: sheetPayload
}
) })
},
route.name
);
},
[animations.routeOpacity, router, sheetPayload]
);
const context = {
ref: panHandlerRef,
eventManager: internalEventManager
};
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { children: [
import_react_native.Platform.OS === "ios" && !safeAreaInsets ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_native.SafeAreaView,
{
pointerEvents: "none",
collapsable: false,
onLayout: (event) => {
const height = event.nativeEvent.layout.height;
if (height !== void 0) {
safeAreaPaddings.current.top = height;
clearTimeout(rootViewLayoutEventValues.current.timer);
rootViewLayoutEventValues.current.timer = setTimeout(() => {
internalEventManager.publish(EVENTS_INTERNAL.safeAreaLayout);
}, 0);
}
},
style: {
position: "absolute",
width: 1,
height: 0,
top: 0,
left: 0,
backgroundColor: "transparent"
},
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, {})
}
) : null,
import_react_native.Platform.OS === "ios" && !safeAreaInsets ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_native.SafeAreaView,
{
pointerEvents: "none",
collapsable: false,
onLayout: (event) => {
const height = event.nativeEvent.layout.height;
if (height !== void 0) {
safeAreaPaddings.current.bottom = height;
clearTimeout(rootViewLayoutEventValues.current.timer);
rootViewLayoutEventValues.current.timer = setTimeout(() => {
internalEventManager.publish(EVENTS_INTERNAL.safeAreaLayout);
}, 0);
}
},
style: {
position: "absolute",
width: 1,
height: 1,
bottom: 0,
left: 0,
backgroundColor: "transparent"
},
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, {})
}
) : null,
visible ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Root, { ...rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
GestureHandlerRoot,
{
isModal,
style: import_styles.styles.parentContainer,
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_context.PanGestureRefContext.Provider, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_context.DraggableNodesContext.Provider, { value: draggableNodesContext, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
import_react_native.Animated.View,
{
onLayout: onRootViewLayout,
ref: rootViewContainerRef,
pointerEvents: (props == null ? void 0 : props.backgroundInteractionEnabled) ? "box-none" : "auto",
style: [
import_styles.styles.parentContainer,
{
opacity: animations.opacity,
width: "100%",
justifyContent: "flex-end",
transform: [
{
translateY: animations.keyboardTranslate
}
]
}
],
children: [
!(props == null ? void 0 : props.backgroundInteractionEnabled) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_react_native.TouchableOpacity,
{
onPress: onTouch,
activeOpacity: defaultOverlayOpacity,
testID: (_a = props.testIDs) == null ? void 0 : _a.backdrop,
style: {
height: dimensions.height + (safeAreaPaddings.current.top || 0) + 100,
width: "100%",
position: "absolute",
backgroundColor: overlayColor,
opacity: defaultOverlayOpacity
},
...props.backdropProps ? props.backdropProps : {}
}
) : null,
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
import_react_native.Animated.View,
{
pointerEvents: "box-none",
style: {
borderTopRightRadius: ((_b = props.containerStyle) == null ? void 0 : _b.borderTopRightRadius) || 10,
borderTopLeftRadius: ((_c = props.containerStyle) == null ? void 0 : _c.borderTopLeftRadius) || 10,
backgroundColor: ((_d = props.containerStyle) == null ? void 0 : _d.backgroundColor) || "white",
borderBottomLeftRadius: ((_e = props.containerStyle) == null ? void 0 : _e.borderBottomLeftRadius) || void 0,
borderBottomRightRadius: ((_f = props.containerStyle) == null ? void 0 : _f.borderBottomRightRadius) || void 0,
borderRadius: ((_g = props.containerStyle) == null ? void 0 : _g.borderRadius) || void 0,