mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-03-06 22:39:41 +08:00
chore: sync latest stack
This commit is contained in:
@@ -99,6 +99,7 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
||||
>
|
||||
<Text
|
||||
accessibilityRole="header"
|
||||
aria-level="1"
|
||||
numberOfLines={1}
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
@@ -152,6 +153,7 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
||||
onClose={[Function]}
|
||||
onGestureBegin={[Function]}
|
||||
onGestureCanceled={[Function]}
|
||||
onGestureEnd={[Function]}
|
||||
onOpen={[Function]}
|
||||
onTransitionStart={[Function]}
|
||||
pointerEvents="box-none"
|
||||
@@ -319,6 +321,7 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
||||
onClose={[Function]}
|
||||
onGestureBegin={[Function]}
|
||||
onGestureCanceled={[Function]}
|
||||
onGestureEnd={[Function]}
|
||||
onOpen={[Function]}
|
||||
onTransitionStart={[Function]}
|
||||
pointerEvents="box-none"
|
||||
|
||||
@@ -100,6 +100,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
|
||||
>
|
||||
<Text
|
||||
accessibilityRole="header"
|
||||
aria-level="1"
|
||||
numberOfLines={1}
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
@@ -169,6 +170,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
|
||||
onClose={[Function]}
|
||||
onGestureBegin={[Function]}
|
||||
onGestureCanceled={[Function]}
|
||||
onGestureEnd={[Function]}
|
||||
onOpen={[Function]}
|
||||
onTransitionStart={[Function]}
|
||||
pointerEvents="box-none"
|
||||
@@ -404,6 +406,7 @@ exports[`StackNavigator renders successfully 1`] = `
|
||||
>
|
||||
<Text
|
||||
accessibilityRole="header"
|
||||
aria-level="1"
|
||||
numberOfLines={1}
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
@@ -457,6 +460,7 @@ exports[`StackNavigator renders successfully 1`] = `
|
||||
onClose={[Function]}
|
||||
onGestureBegin={[Function]}
|
||||
onGestureCanceled={[Function]}
|
||||
onGestureEnd={[Function]}
|
||||
onOpen={[Function]}
|
||||
onTransitionStart={[Function]}
|
||||
pointerEvents="box-none"
|
||||
|
||||
20
packages/stack/src/vendor/types.tsx
vendored
20
packages/stack/src/vendor/types.tsx
vendored
@@ -41,6 +41,18 @@ export type StackNavigationEventMap = {
|
||||
* Event which fires when a transition animation ends.
|
||||
*/
|
||||
transitionEnd: { data: { closing: boolean } };
|
||||
/**
|
||||
* Event which fires when navigation gesture starts.
|
||||
*/
|
||||
gestureStart: { data: undefined };
|
||||
/**
|
||||
* Event which fires when navigation gesture is completed.
|
||||
*/
|
||||
gestureEnd: { data: undefined };
|
||||
/**
|
||||
* Event which fires when navigation gesture is canceled.
|
||||
*/
|
||||
gestureCancel: { data: undefined };
|
||||
};
|
||||
|
||||
export type StackNavigationHelpers = NavigationProp<NavigationStackState>;
|
||||
@@ -125,7 +137,7 @@ export type StackHeaderOptions = {
|
||||
/**
|
||||
* Style object for the title component.
|
||||
*/
|
||||
headerTitleStyle?: React.ComponentProps<typeof Animated.Text>['style'];
|
||||
headerTitleStyle?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
|
||||
/**
|
||||
* Style object for the container of the `headerTitle` component, for example to add padding.
|
||||
* By default, `headerTitleContainerStyle` is with an absolute position style and offsets both `left` and `right`.
|
||||
@@ -426,6 +438,10 @@ export type StackHeaderLeftButtonProps = {
|
||||
* Accessibility label for the button for screen readers.
|
||||
*/
|
||||
accessibilityLabel?: string;
|
||||
/**
|
||||
* Style object for the button.
|
||||
*/
|
||||
style?: StyleProp<ViewStyle>;
|
||||
};
|
||||
|
||||
export type StackHeaderTitleProps = {
|
||||
@@ -448,7 +464,7 @@ export type StackHeaderTitleProps = {
|
||||
/**
|
||||
* Style object for the title element.
|
||||
*/
|
||||
style?: React.ComponentProps<typeof Animated.Text>['style'];
|
||||
style?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
|
||||
};
|
||||
|
||||
export type TransitionSpec =
|
||||
|
||||
1
packages/stack/src/vendor/views/GestureHandler.android.tsx
vendored
Normal file
1
packages/stack/src/vendor/views/GestureHandler.android.tsx
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './GestureHandlerNative';
|
||||
1
packages/stack/src/vendor/views/GestureHandler.ios.tsx
vendored
Normal file
1
packages/stack/src/vendor/views/GestureHandler.ios.tsx
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './GestureHandlerNative';
|
||||
@@ -8,9 +8,9 @@ import {
|
||||
StyleSheet,
|
||||
LayoutChangeEvent,
|
||||
} from 'react-native';
|
||||
import MaskedView from '../MaskedView';
|
||||
import { TouchableItem } from '../TouchableItem';
|
||||
import useTheme from '../../../utils/useTheme';
|
||||
import MaskedView from '../MaskedView';
|
||||
import TouchableItem from '../TouchableItem';
|
||||
import type { StackHeaderLeftButtonProps } from '../../types';
|
||||
|
||||
type Props = StackHeaderLeftButtonProps;
|
||||
@@ -30,6 +30,7 @@ export default function HeaderBackButton({
|
||||
titleLayout,
|
||||
truncatedLabel = 'Back',
|
||||
accessibilityLabel = label && label !== 'Back' ? `${label}, back` : 'Go back',
|
||||
style,
|
||||
}: Props) {
|
||||
const { dark, colors } = useTheme();
|
||||
|
||||
@@ -160,7 +161,7 @@ export default function HeaderBackButton({
|
||||
delayPressIn={0}
|
||||
onPress={disabled ? undefined : handlePress}
|
||||
pressColor={pressColorAndroid}
|
||||
style={[styles.container, disabled && styles.disabled]}
|
||||
style={[styles.container, disabled && styles.disabled, style]}
|
||||
hitSlop={Platform.select({
|
||||
ios: undefined,
|
||||
default: { top: 16, right: 16, bottom: 16, left: 16 },
|
||||
|
||||
@@ -223,7 +223,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
warnIfHeaderStylesDefined(unsafeStyles);
|
||||
}
|
||||
|
||||
const safeStyles = {
|
||||
const safeStyles: ViewStyle = {
|
||||
backgroundColor,
|
||||
borderBottomColor,
|
||||
borderBottomEndRadius,
|
||||
@@ -249,6 +249,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
borderTopStartRadius,
|
||||
borderTopWidth,
|
||||
borderWidth,
|
||||
// @ts-expect-error: boxShadow is only for Web
|
||||
boxShadow,
|
||||
elevation,
|
||||
shadowColor,
|
||||
@@ -314,10 +315,8 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
style={[StyleSheet.absoluteFill, { zIndex: 0 }, backgroundStyle]}
|
||||
>
|
||||
{headerBackground ? (
|
||||
// @ts-ignore
|
||||
headerBackground({ style: safeStyles })
|
||||
) : headerTransparent ? null : (
|
||||
// @ts-ignore
|
||||
<HeaderBackground style={safeStyles} />
|
||||
)}
|
||||
</Animated.View>
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import * as React from 'react';
|
||||
import { Animated, StyleSheet, Platform } from 'react-native';
|
||||
import {
|
||||
Animated,
|
||||
StyleSheet,
|
||||
Platform,
|
||||
TextProps,
|
||||
StyleProp,
|
||||
TextStyle,
|
||||
} from 'react-native';
|
||||
import useTheme from '../../../utils/useTheme';
|
||||
|
||||
type Props = Omit<React.ComponentProps<typeof Animated.Text>, 'key'> & {
|
||||
type Props = Omit<TextProps, 'style'> & {
|
||||
tintColor?: string;
|
||||
children?: string;
|
||||
style?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
|
||||
};
|
||||
|
||||
export default function HeaderTitle({ tintColor, style, ...rest }: Props) {
|
||||
@@ -13,6 +21,7 @@ export default function HeaderTitle({ tintColor, style, ...rest }: Props) {
|
||||
return (
|
||||
<Animated.Text
|
||||
accessibilityRole="header"
|
||||
aria-level="1"
|
||||
numberOfLines={1}
|
||||
{...rest}
|
||||
style={[
|
||||
|
||||
@@ -17,7 +17,7 @@ export default class KeyboardManager extends React.Component<Props> {
|
||||
|
||||
// Numeric id of the previously focused text input
|
||||
// When a gesture didn't change the tab, we can restore the focused input with this
|
||||
private previouslyFocusedTextInput: any = null;
|
||||
private previouslyFocusedTextInput: any | null = null;
|
||||
private startTimestamp: number = 0;
|
||||
private keyboardTimeout: any;
|
||||
|
||||
|
||||
1
packages/stack/src/vendor/views/MaskedView.android.tsx
vendored
Normal file
1
packages/stack/src/vendor/views/MaskedView.android.tsx
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './MaskedViewNative';
|
||||
1
packages/stack/src/vendor/views/MaskedView.ios.tsx
vendored
Normal file
1
packages/stack/src/vendor/views/MaskedView.ios.tsx
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './MaskedViewNative';
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* Use a stub for MaskedView on all Platforms that don't support it.
|
||||
*/
|
||||
import type * as React from 'react';
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* The native MaskedView that we explicitly re-export for supported platforms: Android, iOS.
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import { UIManager } from 'react-native';
|
||||
|
||||
@@ -10,6 +13,8 @@ type Props = React.ComponentProps<MaskedViewType> & {
|
||||
let RNCMaskedView: MaskedViewType | undefined;
|
||||
|
||||
try {
|
||||
// Add try/catch to support usage even if it's not installed, since it's optional.
|
||||
// Newer versions of Metro will handle it properly.
|
||||
RNCMaskedView = require('@react-native-community/masked-view').default;
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
@@ -49,6 +49,9 @@ type Props = TransitionPreset & {
|
||||
onPageChangeStart?: () => void;
|
||||
onPageChangeConfirm?: () => void;
|
||||
onPageChangeCancel?: () => void;
|
||||
onGestureStart?: (props: { route: Route<string> }) => void;
|
||||
onGestureEnd?: (props: { route: Route<string> }) => void;
|
||||
onGestureCancel?: (props: { route: Route<string> }) => void;
|
||||
gestureEnabled?: boolean;
|
||||
gestureResponseDistance?: {
|
||||
vertical?: number;
|
||||
@@ -98,6 +101,9 @@ function CardContainer({
|
||||
onPageChangeCancel,
|
||||
onPageChangeConfirm,
|
||||
onPageChangeStart,
|
||||
onGestureCancel,
|
||||
onGestureEnd,
|
||||
onGestureStart,
|
||||
onTransitionEnd,
|
||||
onTransitionStart,
|
||||
renderHeader,
|
||||
@@ -123,6 +129,20 @@ function CardContainer({
|
||||
onCloseRoute({ route: scene.route });
|
||||
};
|
||||
|
||||
const handleGestureBegin = () => {
|
||||
onPageChangeStart?.();
|
||||
onGestureStart?.({ route: scene.route });
|
||||
};
|
||||
|
||||
const handleGestureCanceled = () => {
|
||||
onPageChangeCancel?.();
|
||||
onGestureCancel?.({ route: scene.route });
|
||||
};
|
||||
|
||||
const handleGestureEnd = () => {
|
||||
onGestureEnd?.({ route: scene.route });
|
||||
};
|
||||
|
||||
const handleTransitionStart = ({ closing }: { closing: boolean }) => {
|
||||
if (active && closing) {
|
||||
onPageChangeConfirm?.();
|
||||
@@ -182,8 +202,9 @@ function CardContainer({
|
||||
overlayEnabled={cardOverlayEnabled}
|
||||
shadowEnabled={cardShadowEnabled}
|
||||
onTransitionStart={handleTransitionStart}
|
||||
onGestureBegin={onPageChangeStart}
|
||||
onGestureCanceled={onPageChangeCancel}
|
||||
onGestureBegin={handleGestureBegin}
|
||||
onGestureCanceled={handleGestureCanceled}
|
||||
onGestureEnd={handleGestureEnd}
|
||||
gestureEnabled={gestureEnabled}
|
||||
gestureResponseDistance={gestureResponseDistance}
|
||||
gestureVelocityImpact={gestureVelocityImpact}
|
||||
|
||||
@@ -61,6 +61,9 @@ type Props = {
|
||||
onPageChangeStart?: () => void;
|
||||
onPageChangeConfirm?: () => void;
|
||||
onPageChangeCancel?: () => void;
|
||||
onGestureStart?: (props: { route: Route<string> }) => void;
|
||||
onGestureEnd?: (props: { route: Route<string> }) => void;
|
||||
onGestureCancel?: (props: { route: Route<string> }) => void;
|
||||
};
|
||||
|
||||
type State = {
|
||||
@@ -373,6 +376,9 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
onPageChangeStart,
|
||||
onPageChangeConfirm,
|
||||
onPageChangeCancel,
|
||||
onGestureStart,
|
||||
onGestureEnd,
|
||||
onGestureCancel,
|
||||
} = this.props;
|
||||
|
||||
const { scenes, layout, gestures, headerHeights } = this.state;
|
||||
@@ -569,6 +575,9 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
onPageChangeStart={onPageChangeStart}
|
||||
onPageChangeConfirm={onPageChangeConfirm}
|
||||
onPageChangeCancel={onPageChangeCancel}
|
||||
onGestureStart={onGestureStart}
|
||||
onGestureCancel={onGestureCancel}
|
||||
onGestureEnd={onGestureEnd}
|
||||
gestureResponseDistance={gestureResponseDistance}
|
||||
headerHeight={headerHeight}
|
||||
onHeaderHeightChange={this.handleHeaderLayout}
|
||||
|
||||
@@ -433,6 +433,18 @@ export default class StackView extends React.Component<Props, State> {
|
||||
descriptor?.options.onTransitionEnd?.({ closing });
|
||||
};
|
||||
|
||||
private handleGestureStart = () => {
|
||||
// Do nothing
|
||||
};
|
||||
|
||||
private handleGestureEnd = () => {
|
||||
// Do nothing
|
||||
};
|
||||
|
||||
private handleGestureCancel = () => {
|
||||
// Do nothing
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
state,
|
||||
@@ -480,6 +492,9 @@ export default class StackView extends React.Component<Props, State> {
|
||||
headerMode={headerMode}
|
||||
state={state}
|
||||
descriptors={descriptors}
|
||||
onGestureStart={this.handleGestureStart}
|
||||
onGestureEnd={this.handleGestureEnd}
|
||||
onGestureCancel={this.handleGestureCancel}
|
||||
{...rest}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
50
packages/stack/src/vendor/views/TouchableItem.ios.tsx
vendored
Normal file
50
packages/stack/src/vendor/views/TouchableItem.ios.tsx
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as React from 'react';
|
||||
import { Animated, Platform } from 'react-native';
|
||||
import { BaseButton } from 'react-native-gesture-handler';
|
||||
|
||||
const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);
|
||||
|
||||
type Props = React.ComponentProps<typeof BaseButton> & {
|
||||
activeOpacity: number;
|
||||
};
|
||||
|
||||
const useNativeDriver = Platform.OS !== 'web';
|
||||
|
||||
export default class TouchableItem extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
activeOpacity: 0.3,
|
||||
borderless: true,
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
private opacity = new Animated.Value(1);
|
||||
|
||||
private handleActiveStateChange = (active: boolean) => {
|
||||
Animated.spring(this.opacity, {
|
||||
stiffness: 1000,
|
||||
damping: 500,
|
||||
mass: 3,
|
||||
overshootClamping: true,
|
||||
restDisplacementThreshold: 0.01,
|
||||
restSpeedThreshold: 0.01,
|
||||
toValue: active ? this.props.activeOpacity : 1,
|
||||
useNativeDriver,
|
||||
}).start();
|
||||
|
||||
this.props.onActiveStateChange?.(active);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children, style, enabled, ...rest } = this.props;
|
||||
|
||||
return (
|
||||
<AnimatedBaseButton
|
||||
{...rest}
|
||||
onActiveStateChange={this.handleActiveStateChange}
|
||||
style={[style, enabled && { opacity: this.opacity }]}
|
||||
>
|
||||
{children}
|
||||
</AnimatedBaseButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* TouchableItem renders a touchable that looks native on both iOS and Android.
|
||||
*
|
||||
* It provides an abstraction on top of TouchableNativeFeedback and
|
||||
* TouchableOpacity.
|
||||
*
|
||||
* On iOS you can pass the props of TouchableOpacity, on Android pass the props
|
||||
* of TouchableNativeFeedback.
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Platform,
|
||||
TouchableNativeFeedback,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ViewProps,
|
||||
} from 'react-native';
|
||||
|
||||
import BorderlessButton from './BorderlessButton';
|
||||
|
||||
export type Props = ViewProps & {
|
||||
pressColor: string;
|
||||
disabled?: boolean;
|
||||
borderless?: boolean;
|
||||
delayPressIn?: number;
|
||||
onPress?: () => void;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const ANDROID_VERSION_LOLLIPOP = 21;
|
||||
|
||||
export class TouchableItem extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
borderless: false,
|
||||
pressColor: 'rgba(0, 0, 0, .32)',
|
||||
};
|
||||
|
||||
render() {
|
||||
/*
|
||||
* TouchableNativeFeedback.Ripple causes a crash on old Android versions,
|
||||
* therefore only enable it on Android Lollipop and above.
|
||||
*
|
||||
* All touchables on Android should have the ripple effect according to
|
||||
* platform design guidelines.
|
||||
* We need to pass the background prop to specify a borderless ripple effect.
|
||||
*/
|
||||
if (
|
||||
Platform.OS === 'android' &&
|
||||
Platform.Version >= ANDROID_VERSION_LOLLIPOP
|
||||
) {
|
||||
const { style, pressColor, borderless, children, ...rest } = this.props;
|
||||
|
||||
return (
|
||||
<TouchableNativeFeedback
|
||||
{...rest}
|
||||
useForeground={TouchableNativeFeedback.canUseNativeForeground()}
|
||||
background={TouchableNativeFeedback.Ripple(pressColor, borderless)}
|
||||
>
|
||||
<View style={style}>{React.Children.only(children)}</View>
|
||||
</TouchableNativeFeedback>
|
||||
);
|
||||
} else if (Platform.OS === 'ios') {
|
||||
return (
|
||||
<BorderlessButton
|
||||
hitSlop={{ top: 10, bottom: 10, right: 10, left: 10 }}
|
||||
disallowInterruption
|
||||
enabled={!this.props.disabled}
|
||||
{...this.props}
|
||||
>
|
||||
{this.props.children}
|
||||
</BorderlessButton>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<TouchableOpacity {...this.props}>
|
||||
{this.props.children}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,63 @@
|
||||
import { TouchableOpacity } from 'react-native';
|
||||
/**
|
||||
* TouchableItem provides an abstraction on top of TouchableNativeFeedback and
|
||||
* TouchableOpacity to handle platform differences.
|
||||
*
|
||||
* On Android, you can pass the props of TouchableNativeFeedback.
|
||||
* On other platforms, you can pass the props of TouchableOpacity.
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Platform,
|
||||
TouchableNativeFeedback,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ViewProps,
|
||||
} from 'react-native';
|
||||
|
||||
export const TouchableItem = (TouchableOpacity as any) as typeof import('./TouchableItem.native').TouchableItem;
|
||||
export type Props = ViewProps & {
|
||||
pressColor?: string;
|
||||
disabled?: boolean;
|
||||
borderless?: boolean;
|
||||
delayPressIn?: number;
|
||||
onPress?: () => void;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const ANDROID_VERSION_LOLLIPOP = 21;
|
||||
|
||||
export default function TouchableItem({
|
||||
borderless = false,
|
||||
pressColor = 'rgba(0, 0, 0, .32)',
|
||||
style,
|
||||
children,
|
||||
...rest
|
||||
}: Props) {
|
||||
/*
|
||||
* TouchableNativeFeedback.Ripple causes a crash on old Android versions,
|
||||
* therefore only enable it on Android Lollipop and above.
|
||||
*
|
||||
* All touchables on Android should have the ripple effect according to
|
||||
* platform design guidelines.
|
||||
* We need to pass the background prop to specify a borderless ripple effect.
|
||||
*/
|
||||
if (
|
||||
Platform.OS === 'android' &&
|
||||
Platform.Version >= ANDROID_VERSION_LOLLIPOP
|
||||
) {
|
||||
return (
|
||||
<TouchableNativeFeedback
|
||||
{...rest}
|
||||
useForeground={TouchableNativeFeedback.canUseNativeForeground()}
|
||||
background={TouchableNativeFeedback.Ripple(pressColor, borderless)}
|
||||
>
|
||||
<View style={style}>{React.Children.only(children)}</View>
|
||||
</TouchableNativeFeedback>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<TouchableOpacity style={style} {...rest}>
|
||||
{children}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user