@react-navigation/stack
Version:
Stack navigator component for iOS and Android with animated transitions and gestures
275 lines (274 loc) • 7.36 kB
JavaScript
import { getHeaderTitle, HeaderBackContext, HeaderHeightContext, HeaderShownContext } from '@react-navigation/elements';
import { useLinkBuilder, useLocale, useTheme } from '@react-navigation/native';
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { ModalPresentationContext } from "../../utils/ModalPresentationContext.js";
import { useKeyboardManager } from "../../utils/useKeyboardManager.js";
import { Card } from "./Card.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const EPSILON = 0.1;
function CardContainerInner({
interpolationIndex,
index,
active,
opening,
closing,
gesture,
focused,
modal,
getPreviousScene,
getFocusedRoute,
hasAbsoluteFloatHeader,
headerHeight,
onHeaderHeightChange,
isParentHeaderShown,
isNextScreenTransparent,
detachCurrentScreen,
layout,
onCloseRoute,
onOpenRoute,
onGestureCancel,
onGestureEnd,
onGestureStart,
onTransitionEnd,
onTransitionStart,
preloaded,
renderHeader,
safeAreaInsetBottom,
safeAreaInsetLeft,
safeAreaInsetRight,
safeAreaInsetTop,
scene
}) {
const {
direction
} = useLocale();
const parentHeaderHeight = React.useContext(HeaderHeightContext);
const {
onPageChangeStart,
onPageChangeCancel,
onPageChangeConfirm
} = useKeyboardManager(React.useCallback(() => {
const {
options,
navigation
} = scene.descriptor;
return navigation.isFocused() && options.keyboardHandlingEnabled !== false;
}, [scene.descriptor]));
const handleOpen = () => {
const {
route
} = scene.descriptor;
onTransitionEnd({
route
}, false);
onOpenRoute({
route
});
};
const handleClose = () => {
const {
route
} = scene.descriptor;
onTransitionEnd({
route
}, true);
onCloseRoute({
route
});
};
const handleGestureBegin = () => {
const {
route
} = scene.descriptor;
onPageChangeStart();
onGestureStart({
route
});
};
const handleGestureCanceled = () => {
const {
route
} = scene.descriptor;
onPageChangeCancel();
onGestureCancel({
route
});
};
const handleGestureEnd = () => {
const {
route
} = scene.descriptor;
onGestureEnd({
route
});
};
const handleTransition = ({
closing,
gesture
}) => {
const {
route
} = scene.descriptor;
if (!gesture) {
onPageChangeConfirm?.(true);
} else if (active && closing) {
onPageChangeConfirm?.(false);
} else {
onPageChangeCancel?.();
}
onTransitionStart?.({
route
}, closing);
};
const insets = {
top: safeAreaInsetTop,
right: safeAreaInsetRight,
bottom: safeAreaInsetBottom,
left: safeAreaInsetLeft
};
const {
colors
} = useTheme();
const [pointerEvents, setPointerEvents] = React.useState('box-none');
React.useEffect(() => {
const listener = scene.progress.next?.addListener?.(({
value
}) => {
setPointerEvents(value <= EPSILON ? 'box-none' : 'none');
});
return () => {
if (listener) {
scene.progress.next?.removeListener?.(listener);
}
};
}, [pointerEvents, scene.progress.next]);
const {
presentation,
animation,
cardOverlay,
cardOverlayEnabled,
cardShadowEnabled,
cardStyle,
cardStyleInterpolator,
gestureDirection,
gestureEnabled,
gestureResponseDistance,
gestureVelocityImpact,
headerMode,
headerShown,
transitionSpec
} = scene.descriptor.options;
const {
buildHref
} = useLinkBuilder();
const previousScene = getPreviousScene({
route: scene.descriptor.route
});
let backTitle;
let href;
if (previousScene) {
const {
options,
route
} = previousScene.descriptor;
backTitle = getHeaderTitle(options, route.name);
href = buildHref(route.name, route.params);
}
const canGoBack = previousScene != null;
const headerBack = React.useMemo(() => {
if (canGoBack) {
return {
href,
title: backTitle
};
}
return undefined;
}, [canGoBack, backTitle, href]);
return /*#__PURE__*/_jsx(Card, {
interpolationIndex: interpolationIndex,
gestureDirection: gestureDirection,
layout: layout,
insets: insets,
direction: direction,
gesture: gesture,
current: scene.progress.current,
next: scene.progress.next,
opening: opening,
closing: closing,
onOpen: handleOpen,
onClose: handleClose,
overlay: cardOverlay,
overlayEnabled: cardOverlayEnabled,
shadowEnabled: cardShadowEnabled,
onTransition: handleTransition,
onGestureBegin: handleGestureBegin,
onGestureCanceled: handleGestureCanceled,
onGestureEnd: handleGestureEnd,
gestureEnabled: index === 0 ? false : gestureEnabled,
gestureResponseDistance: gestureResponseDistance,
gestureVelocityImpact: gestureVelocityImpact,
transitionSpec: transitionSpec,
styleInterpolator: cardStyleInterpolator,
"aria-hidden": !focused,
pointerEvents: active ? 'box-none' : pointerEvents,
pageOverflowEnabled: headerMode !== 'float' && presentation !== 'modal',
preloaded: preloaded,
containerStyle: hasAbsoluteFloatHeader && headerMode !== 'screen' ? {
marginTop: headerHeight
} : null,
contentStyle: [{
backgroundColor: presentation === 'transparentModal' ? 'transparent' : colors.background
}, cardStyle],
style: [{
// This is necessary to avoid unfocused larger pages increasing scroll area
// The issue can be seen on the web when a smaller screen is pushed over a larger one
overflow: active ? undefined : 'hidden',
display:
// Hide unfocused screens when animation isn't enabled
// This is also necessary for a11y on web
animation === 'none' && isNextScreenTransparent === false && detachCurrentScreen !== false && !focused ? 'none' : 'flex'
}, StyleSheet.absoluteFill],
children: /*#__PURE__*/_jsx(View, {
style: styles.container,
children: /*#__PURE__*/_jsxs(ModalPresentationContext.Provider, {
value: modal,
children: [headerMode !== 'float' ? renderHeader({
mode: 'screen',
layout,
scenes: [previousScene, scene],
getPreviousScene,
getFocusedRoute,
onContentHeightChange: onHeaderHeightChange,
style: styles.header
}) : null, /*#__PURE__*/_jsx(View, {
style: styles.scene,
children: /*#__PURE__*/_jsx(HeaderBackContext.Provider, {
value: headerBack,
children: /*#__PURE__*/_jsx(HeaderShownContext.Provider, {
value: isParentHeaderShown || headerShown !== false,
children: /*#__PURE__*/_jsx(HeaderHeightContext.Provider, {
value: headerShown !== false ? headerHeight : parentHeaderHeight ?? 0,
children: scene.descriptor.render()
})
})
})
})]
})
})
});
}
export const CardContainer = /*#__PURE__*/React.memo(CardContainerInner);
const styles = StyleSheet.create({
container: {
flex: 1
},
header: {
zIndex: 1
},
scene: {
flex: 1
}
});
//# sourceMappingURL=CardContainer.js.map
;