mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-22 11:58:16 +08:00
Compare commits
6 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98a9487cda | ||
|
|
ff502820c7 | ||
|
|
30e510d123 | ||
|
|
114a5dc888 | ||
|
|
b4bbf9b0c3 | ||
|
|
98f0de088f |
@@ -3,6 +3,17 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.8...@react-navigation/bottom-tabs@5.0.0-alpha.9) (2019-09-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* provide navigation prop in header ([30e510d](https://github.com/react-navigation/navigation-ex/commit/30e510d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.7...@react-navigation/bottom-tabs@5.0.0-alpha.8) (2019-09-16)
|
# [5.0.0-alpha.8](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.7...@react-navigation/bottom-tabs@5.0.0-alpha.8) (2019-09-16)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"android",
|
"android",
|
||||||
"tab"
|
"tab"
|
||||||
],
|
],
|
||||||
"version": "5.0.0-alpha.8",
|
"version": "5.0.0-alpha.9",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ export type BottomTabBarOptions = {
|
|||||||
|
|
||||||
export type BottomTabBarProps = BottomTabBarOptions & {
|
export type BottomTabBarProps = BottomTabBarOptions & {
|
||||||
state: TabNavigationState;
|
state: TabNavigationState;
|
||||||
|
descriptors: BottomTabDescriptorMap;
|
||||||
navigation: NavigationHelpers<ParamListBase>;
|
navigation: NavigationHelpers<ParamListBase>;
|
||||||
onTabPress: (props: { route: Route<string> }) => void;
|
onTabPress: (props: { route: Route<string> }) => void;
|
||||||
onTabLongPress: (props: { route: Route<string> }) => void;
|
onTabLongPress: (props: { route: Route<string> }) => void;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
Dimensions,
|
Dimensions,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import SafeAreaView from 'react-native-safe-area-view';
|
import SafeAreaView from 'react-native-safe-area-view';
|
||||||
import { Route } from '@react-navigation/core';
|
import { Route, NavigationContext } from '@react-navigation/core';
|
||||||
|
|
||||||
import TabBarIcon from './TabBarIcon';
|
import TabBarIcon from './TabBarIcon';
|
||||||
import TouchableWithoutFeedbackWrapper from './TouchableWithoutFeedbackWrapper';
|
import TouchableWithoutFeedbackWrapper from './TouchableWithoutFeedbackWrapper';
|
||||||
@@ -261,6 +261,7 @@ export default class TabBarBottom extends React.Component<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
state,
|
state,
|
||||||
|
descriptors,
|
||||||
keyboardHidesTabBar,
|
keyboardHidesTabBar,
|
||||||
activeBackgroundColor,
|
activeBackgroundColor,
|
||||||
inactiveBackgroundColor,
|
inactiveBackgroundColor,
|
||||||
@@ -337,26 +338,30 @@ export default class TabBarBottom extends React.Component<Props, State> {
|
|||||||
getButtonComponent({ route }) || TouchableWithoutFeedbackWrapper;
|
getButtonComponent({ route }) || TouchableWithoutFeedbackWrapper;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonComponent
|
<NavigationContext.Provider
|
||||||
key={route.key}
|
key={route.key}
|
||||||
onPress={() => onTabPress({ route })}
|
value={descriptors[route.key].navigation}
|
||||||
onLongPress={() => onTabLongPress({ route })}
|
|
||||||
testID={testID}
|
|
||||||
accessibilityLabel={accessibilityLabel}
|
|
||||||
accessibilityRole={accessibilityRole}
|
|
||||||
accessibilityStates={accessibilityStates}
|
|
||||||
style={[
|
|
||||||
styles.tab,
|
|
||||||
{ backgroundColor },
|
|
||||||
this.shouldUseHorizontalLabels()
|
|
||||||
? styles.tabLandscape
|
|
||||||
: styles.tabPortrait,
|
|
||||||
tabStyle,
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
{this.renderIcon(scene)}
|
<ButtonComponent
|
||||||
{this.renderLabel(scene)}
|
onPress={() => onTabPress({ route })}
|
||||||
</ButtonComponent>
|
onLongPress={() => onTabLongPress({ route })}
|
||||||
|
testID={testID}
|
||||||
|
accessibilityLabel={accessibilityLabel}
|
||||||
|
accessibilityRole={accessibilityRole}
|
||||||
|
accessibilityStates={accessibilityStates}
|
||||||
|
style={[
|
||||||
|
styles.tab,
|
||||||
|
{ backgroundColor },
|
||||||
|
this.shouldUseHorizontalLabels()
|
||||||
|
? styles.tabLandscape
|
||||||
|
: styles.tabPortrait,
|
||||||
|
tabStyle,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{this.renderIcon(scene)}
|
||||||
|
{this.renderLabel(scene)}
|
||||||
|
</ButtonComponent>
|
||||||
|
</NavigationContext.Provider>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ export default class BottomTabView extends React.Component<Props, State> {
|
|||||||
<TabBarComponent
|
<TabBarComponent
|
||||||
{...tabBarOptions}
|
{...tabBarOptions}
|
||||||
state={state}
|
state={state}
|
||||||
|
descriptors={descriptors}
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
onTabPress={this.handleTabPress}
|
onTabPress={this.handleTabPress}
|
||||||
onTabLongPress={this.handleTabLongPress}
|
onTabLongPress={this.handleTabLongPress}
|
||||||
|
|||||||
@@ -3,6 +3,23 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.2](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.1...@react-navigation/compat@5.0.0-alpha.2) (2019-09-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* provide navigation prop in header ([30e510d](https://github.com/react-navigation/navigation-ex/commit/30e510d))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add createSwitchNavigator ([ff50282](https://github.com/react-navigation/navigation-ex/commit/ff50282))
|
||||||
|
* add withNavigation and withNavigationFocus ([114a5dc](https://github.com/react-navigation/navigation-ex/commit/114a5dc))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 5.0.0-alpha.1 (2019-09-16)
|
# 5.0.0-alpha.1 (2019-09-16)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/compat",
|
"name": "@react-navigation/compat",
|
||||||
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
||||||
"version": "5.0.0-alpha.1",
|
"version": "5.0.0-alpha.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -7,15 +7,18 @@ import {
|
|||||||
import ScreenPropsContext from './ScreenPropsContext';
|
import ScreenPropsContext from './ScreenPropsContext';
|
||||||
import createCompatNavigationProp from './createCompatNavigationProp';
|
import createCompatNavigationProp from './createCompatNavigationProp';
|
||||||
|
|
||||||
type Props = {
|
type Props<ParamList extends ParamListBase> = {
|
||||||
navigation: NavigationProp<ParamListBase>;
|
navigation: NavigationProp<ParamList>;
|
||||||
route: RouteProp<ParamListBase, string>;
|
route: RouteProp<ParamList, string>;
|
||||||
component: React.ComponentType<any>;
|
component: React.ComponentType<any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ScreenComponent(props: Props) {
|
function ScreenComponent<ParamList extends ParamListBase>(
|
||||||
|
props: Props<ParamList>
|
||||||
|
) {
|
||||||
const navigation = React.useMemo(
|
const navigation = React.useMemo(
|
||||||
() => createCompatNavigationProp(props.navigation, props.route),
|
() =>
|
||||||
|
createCompatNavigationProp(props.navigation as any, props.route as any),
|
||||||
[props.navigation, props.route]
|
[props.navigation, props.route]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
RouteProp,
|
RouteProp,
|
||||||
} from '@react-navigation/core';
|
} from '@react-navigation/core';
|
||||||
import * as helpers from './helpers';
|
import * as helpers from './helpers';
|
||||||
|
import { CompatNavigationProp } from './types';
|
||||||
|
|
||||||
type EventName = 'willFocus' | 'willBlur' | 'didFocus' | 'didBlur' | 'refocus';
|
type EventName = 'willFocus' | 'willBlur' | 'didFocus' | 'didBlur' | 'refocus';
|
||||||
|
|
||||||
@@ -14,32 +15,28 @@ const blurSubscriptions = new WeakMap<() => void, () => void>();
|
|||||||
const refocusSubscriptions = new WeakMap<() => void, () => void>();
|
const refocusSubscriptions = new WeakMap<() => void, () => void>();
|
||||||
|
|
||||||
export default function createCompatNavigationProp<
|
export default function createCompatNavigationProp<
|
||||||
ParamList extends ParamListBase
|
NavigationPropType extends NavigationProp<ParamListBase>,
|
||||||
|
ParamList extends ParamListBase = NavigationPropType extends NavigationProp<
|
||||||
|
infer P
|
||||||
|
>
|
||||||
|
? P
|
||||||
|
: ParamListBase
|
||||||
>(
|
>(
|
||||||
navigation: NavigationProp<ParamList>,
|
navigation: NavigationPropType,
|
||||||
state:
|
state:
|
||||||
| (RouteProp<ParamList, keyof ParamList> & {
|
| (RouteProp<ParamList, keyof ParamList> & {
|
||||||
state?: NavigationState | PartialState<NavigationState>;
|
state?: NavigationState | PartialState<NavigationState>;
|
||||||
})
|
})
|
||||||
| NavigationState
|
| NavigationState
|
||||||
| PartialState<NavigationState>
|
| PartialState<NavigationState>
|
||||||
) {
|
): CompatNavigationProp<NavigationPropType> {
|
||||||
return {
|
return {
|
||||||
...navigation,
|
...navigation,
|
||||||
...Object.entries(helpers).reduce<{
|
...Object.entries(helpers).reduce<{
|
||||||
[key: string]: (...args: any[]) => void;
|
[key: string]: (...args: any[]) => void;
|
||||||
}>((acc, [name, method]) => {
|
}>((acc, [name, method]: [string, Function]) => {
|
||||||
if (name in navigation) {
|
if (name in navigation) {
|
||||||
acc[name] = (...args: any[]) => {
|
acc[name] = (...args: any[]) => navigation.dispatch(method(...args));
|
||||||
// @ts-ignore
|
|
||||||
const payload = method(...args);
|
|
||||||
|
|
||||||
navigation.dispatch(
|
|
||||||
typeof payload === 'function'
|
|
||||||
? payload(navigation.dangerouslyGetState())
|
|
||||||
: payload
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
@@ -188,5 +185,5 @@ export default function createCompatNavigationProp<
|
|||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
};
|
} as any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export default function createCompatNavigatorFactory<
|
|||||||
navigation,
|
navigation,
|
||||||
route,
|
route,
|
||||||
}: {
|
}: {
|
||||||
navigation: NavigationProp<ParamList>;
|
navigation: NavigationPropType;
|
||||||
route: RouteProp<ParamList, keyof ParamList> & {
|
route: RouteProp<ParamList, keyof ParamList> & {
|
||||||
state?: NavigationState | PartialState<NavigationState>;
|
state?: NavigationState | PartialState<NavigationState>;
|
||||||
};
|
};
|
||||||
@@ -101,10 +101,9 @@ export default function createCompatNavigatorFactory<
|
|||||||
typeof routeNavigationOptions === 'function' ||
|
typeof routeNavigationOptions === 'function' ||
|
||||||
typeof screenNavigationOptions === 'function'
|
typeof screenNavigationOptions === 'function'
|
||||||
? {
|
? {
|
||||||
navigation: createCompatNavigationProp<ParamList>(
|
navigation: createCompatNavigationProp<
|
||||||
navigation,
|
NavigationPropType
|
||||||
route
|
>(navigation, route),
|
||||||
),
|
|
||||||
navigationOptions: defaultNavigationOptions || {},
|
navigationOptions: defaultNavigationOptions || {},
|
||||||
screenProps,
|
screenProps,
|
||||||
}
|
}
|
||||||
|
|||||||
28
packages/compat/src/createSwitchNavigator.tsx
Normal file
28
packages/compat/src/createSwitchNavigator.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
useNavigationBuilder,
|
||||||
|
createNavigator,
|
||||||
|
DefaultNavigatorOptions,
|
||||||
|
} from '@react-navigation/core';
|
||||||
|
import {
|
||||||
|
TabRouter,
|
||||||
|
TabRouterOptions,
|
||||||
|
TabNavigationState,
|
||||||
|
} from '@react-navigation/routers';
|
||||||
|
import createCompatNavigatorFactory from './createCompatNavigatorFactory';
|
||||||
|
|
||||||
|
type Props = DefaultNavigatorOptions<{}> & TabRouterOptions;
|
||||||
|
|
||||||
|
function SwitchNavigator(props: Props) {
|
||||||
|
const { state, descriptors } = useNavigationBuilder<
|
||||||
|
TabNavigationState,
|
||||||
|
TabRouterOptions,
|
||||||
|
{},
|
||||||
|
{}
|
||||||
|
>(TabRouter, props);
|
||||||
|
|
||||||
|
return descriptors[state.routes[state.index].key].render();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createCompatNavigatorFactory(
|
||||||
|
createNavigator<{}, typeof SwitchNavigator>(SwitchNavigator)
|
||||||
|
);
|
||||||
@@ -9,4 +9,13 @@ export {
|
|||||||
default as createCompatNavigatorFactory,
|
default as createCompatNavigatorFactory,
|
||||||
} from './createCompatNavigatorFactory';
|
} from './createCompatNavigatorFactory';
|
||||||
|
|
||||||
|
export {
|
||||||
|
default as createCompatNavigationProp,
|
||||||
|
} from './createCompatNavigationProp';
|
||||||
|
|
||||||
|
export { default as createSwitchNavigator } from './createSwitchNavigator';
|
||||||
|
|
||||||
|
export { default as withNavigation } from './withNavigation';
|
||||||
|
export { default as withNavigationFocus } from './withNavigationFocus';
|
||||||
|
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|||||||
25
packages/compat/src/useCompatNavigation.tsx
Normal file
25
packages/compat/src/useCompatNavigation.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import {
|
||||||
|
useNavigation,
|
||||||
|
useRoute,
|
||||||
|
NavigationProp,
|
||||||
|
ParamListBase,
|
||||||
|
} from '@react-navigation/core';
|
||||||
|
import createCompatNavigationProp from './createCompatNavigationProp';
|
||||||
|
import { CompatNavigationProp } from './types';
|
||||||
|
|
||||||
|
export default function useCompatNavigation<
|
||||||
|
T extends NavigationProp<ParamListBase>
|
||||||
|
>() {
|
||||||
|
const navigation = useNavigation();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
return React.useMemo(
|
||||||
|
() =>
|
||||||
|
createCompatNavigationProp(
|
||||||
|
navigation,
|
||||||
|
route as any
|
||||||
|
) as CompatNavigationProp<T>,
|
||||||
|
[navigation, route]
|
||||||
|
);
|
||||||
|
}
|
||||||
33
packages/compat/src/withNavigation.tsx
Normal file
33
packages/compat/src/withNavigation.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { NavigationProp, ParamListBase } from '@react-navigation/core';
|
||||||
|
import useCompatNavigation from './useCompatNavigation';
|
||||||
|
import { CompatNavigationProp } from './types';
|
||||||
|
|
||||||
|
type InjectedProps<T extends NavigationProp<ParamListBase>> = {
|
||||||
|
navigation: CompatNavigationProp<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function withNavigation<
|
||||||
|
T extends NavigationProp<ParamListBase>,
|
||||||
|
P extends InjectedProps<T>,
|
||||||
|
C extends React.ComponentType<P>
|
||||||
|
>(Comp: C) {
|
||||||
|
const WrappedComponent = ({
|
||||||
|
onRef,
|
||||||
|
...rest
|
||||||
|
}: Exclude<P, InjectedProps<T>> & {
|
||||||
|
onRef?: C extends React.ComponentClass<any>
|
||||||
|
? React.Ref<InstanceType<C>>
|
||||||
|
: never;
|
||||||
|
}): React.ReactElement => {
|
||||||
|
const navigation = useCompatNavigation<T>();
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
return <Comp ref={onRef} navigation={navigation} {...rest} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
WrappedComponent.displayName = `withNavigation(${Comp.displayName ||
|
||||||
|
Comp.name})`;
|
||||||
|
|
||||||
|
return WrappedComponent;
|
||||||
|
}
|
||||||
30
packages/compat/src/withNavigationFocus.tsx
Normal file
30
packages/compat/src/withNavigationFocus.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { useIsFocused } from '@react-navigation/core';
|
||||||
|
|
||||||
|
type InjectedProps = {
|
||||||
|
isFocused: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function withNavigationFocus<
|
||||||
|
P extends InjectedProps,
|
||||||
|
C extends React.ComponentType<P>
|
||||||
|
>(Comp: C) {
|
||||||
|
const WrappedComponent = ({
|
||||||
|
onRef,
|
||||||
|
...rest
|
||||||
|
}: Exclude<P, InjectedProps> & {
|
||||||
|
onRef?: C extends React.ComponentClass<any>
|
||||||
|
? React.Ref<InstanceType<C>>
|
||||||
|
: never;
|
||||||
|
}): React.ReactElement => {
|
||||||
|
const isFocused = useIsFocused();
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
return <Comp ref={onRef} isFocused={isFocused} {...rest} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
WrappedComponent.displayName = `withNavigationFocus(${Comp.displayName ||
|
||||||
|
Comp.name})`;
|
||||||
|
|
||||||
|
return WrappedComponent;
|
||||||
|
}
|
||||||
@@ -3,6 +3,14 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.10](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.9...@react-navigation/core@5.0.0-alpha.10) (2019-09-17)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.8...@react-navigation/core@5.0.0-alpha.9) (2019-09-16)
|
# [5.0.0-alpha.9](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.8...@react-navigation/core@5.0.0-alpha.9) (2019-09-16)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"react-native",
|
"react-native",
|
||||||
"react-navigation"
|
"react-navigation"
|
||||||
],
|
],
|
||||||
"version": "5.0.0-alpha.9",
|
"version": "5.0.0-alpha.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -88,7 +88,9 @@ const Container = React.forwardRef(function NavigationContainer(
|
|||||||
|
|
||||||
const { listeners, addListener: addFocusedListener } = useFocusedListeners();
|
const { listeners, addListener: addFocusedListener } = useFocusedListeners();
|
||||||
|
|
||||||
const dispatch = (action: NavigationAction) => {
|
const dispatch = (
|
||||||
|
action: NavigationAction | ((state: NavigationState) => NavigationAction)
|
||||||
|
) => {
|
||||||
listeners[0](navigation => navigation.dispatch(action));
|
listeners[0](navigation => navigation.dispatch(action));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ type Props<State extends NavigationState, ScreenOptions extends object> = {
|
|||||||
route: Route<string> & {
|
route: Route<string> & {
|
||||||
state?: NavigationState | PartialState<NavigationState>;
|
state?: NavigationState | PartialState<NavigationState>;
|
||||||
};
|
};
|
||||||
getState: () => NavigationState;
|
getState: () => State;
|
||||||
setState: (state: NavigationState) => void;
|
setState: (state: State) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ it('cleans up state when the navigator unmounts', () => {
|
|||||||
expect(onStateChange).lastCalledWith(undefined);
|
expect(onStateChange).lastCalledWith(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows arbitrary state updates by dispatching a function', () => {
|
it('allows state updates by dispatching a function returning an action', () => {
|
||||||
const TestNavigator = (props: any) => {
|
const TestNavigator = (props: any) => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
@@ -332,11 +332,11 @@ it('allows arbitrary state updates by dispatching a function', () => {
|
|||||||
|
|
||||||
const FooScreen = (props: any) => {
|
const FooScreen = (props: any) => {
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
props.navigation.dispatch((state: any) => ({
|
props.navigation.dispatch((state: NavigationState) =>
|
||||||
...state,
|
state.index === 0
|
||||||
routes: state.routes.slice().reverse(),
|
? { type: 'NAVIGATE', payload: { name: state.routeNames[1] } }
|
||||||
index: 1,
|
: { type: 'NOOP' }
|
||||||
}));
|
);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -364,7 +364,7 @@ it('allows arbitrary state updates by dispatching a function', () => {
|
|||||||
index: 1,
|
index: 1,
|
||||||
key: '0',
|
key: '0',
|
||||||
routeNames: ['foo', 'bar'],
|
routeNames: ['foo', 'bar'],
|
||||||
routes: [{ key: 'bar', name: 'bar' }, { key: 'foo', name: 'foo' }],
|
routes: [{ key: 'foo', name: 'foo' }, { key: 'bar', name: 'bar' }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -270,7 +270,9 @@ type NavigationHelpersCommon<
|
|||||||
*
|
*
|
||||||
* @param action Action object or update function.
|
* @param action Action object or update function.
|
||||||
*/
|
*/
|
||||||
dispatch(action: NavigationAction | ((state: State) => State)): void;
|
dispatch(
|
||||||
|
action: NavigationAction | ((state: State) => NavigationAction)
|
||||||
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to a route in current navigation tree.
|
* Navigate to a route in current navigation tree.
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import {
|
|||||||
Router,
|
Router,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
type Options<ScreenOptions extends object> = {
|
type Options<State extends NavigationState, ScreenOptions extends object> = {
|
||||||
state: NavigationState;
|
state: State;
|
||||||
screens: { [key: string]: RouteConfig<ParamListBase, string, ScreenOptions> };
|
screens: { [key: string]: RouteConfig<ParamListBase, string, ScreenOptions> };
|
||||||
navigation: NavigationHelpers<ParamListBase>;
|
navigation: NavigationHelpers<ParamListBase>;
|
||||||
screenOptions?:
|
screenOptions?:
|
||||||
@@ -31,12 +31,12 @@ type Options<ScreenOptions extends object> = {
|
|||||||
action: NavigationAction,
|
action: NavigationAction,
|
||||||
visitedNavigators?: Set<string>
|
visitedNavigators?: Set<string>
|
||||||
) => boolean;
|
) => boolean;
|
||||||
getState: () => NavigationState;
|
getState: () => State;
|
||||||
setState: (state: NavigationState) => void;
|
setState: (state: State) => void;
|
||||||
addActionListener: (listener: ChildActionListener) => void;
|
addActionListener: (listener: ChildActionListener) => void;
|
||||||
addFocusedListener: (listener: FocusedNavigationListener) => void;
|
addFocusedListener: (listener: FocusedNavigationListener) => void;
|
||||||
onRouteFocus: (key: string) => void;
|
onRouteFocus: (key: string) => void;
|
||||||
router: Router<NavigationState, NavigationAction>;
|
router: Router<State, NavigationAction>;
|
||||||
emitter: NavigationEventEmitter;
|
emitter: NavigationEventEmitter;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export default function useDescriptors<
|
|||||||
onRouteFocus,
|
onRouteFocus,
|
||||||
router,
|
router,
|
||||||
emitter,
|
emitter,
|
||||||
}: Options<ScreenOptions>) {
|
}: Options<State, ScreenOptions>) {
|
||||||
const [options, setOptions] = React.useState<{ [key: string]: object }>({});
|
const [options, setOptions] = React.useState<{ [key: string]: object }>({});
|
||||||
const { trackAction } = React.useContext(NavigationBuilderContext);
|
const { trackAction } = React.useContext(NavigationBuilderContext);
|
||||||
|
|
||||||
|
|||||||
@@ -245,7 +245,6 @@ export default function useNavigationBuilder<
|
|||||||
const navigation = useNavigationHelpers<State, NavigationAction, EventMap>({
|
const navigation = useNavigationHelpers<State, NavigationAction, EventMap>({
|
||||||
onAction,
|
onAction,
|
||||||
getState,
|
getState,
|
||||||
setState,
|
|
||||||
emitter,
|
emitter,
|
||||||
router,
|
router,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ import {
|
|||||||
Router,
|
Router,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
type Options = {
|
type Options<State extends NavigationState> = {
|
||||||
state: NavigationState;
|
state: State;
|
||||||
getState: () => NavigationState;
|
getState: () => State;
|
||||||
navigation: NavigationHelpers<ParamListBase> &
|
navigation: NavigationHelpers<ParamListBase> &
|
||||||
Partial<NavigationProp<ParamListBase, string, any, any, any>>;
|
Partial<NavigationProp<ParamListBase, string, any, any, any>>;
|
||||||
setOptions: (
|
setOptions: (
|
||||||
cb: (options: { [key: string]: object }) => { [key: string]: object }
|
cb: (options: { [key: string]: object }) => { [key: string]: object }
|
||||||
) => void;
|
) => void;
|
||||||
router: Router<NavigationState, NavigationAction>;
|
router: Router<State, NavigationAction>;
|
||||||
emitter: NavigationEventEmitter;
|
emitter: NavigationEventEmitter;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,7 +39,14 @@ type NavigationCache<
|
|||||||
export default function useNavigationCache<
|
export default function useNavigationCache<
|
||||||
State extends NavigationState,
|
State extends NavigationState,
|
||||||
ScreenOptions extends object
|
ScreenOptions extends object
|
||||||
>({ state, getState, navigation, setOptions, router, emitter }: Options) {
|
>({
|
||||||
|
state,
|
||||||
|
getState,
|
||||||
|
navigation,
|
||||||
|
setOptions,
|
||||||
|
router,
|
||||||
|
emitter,
|
||||||
|
}: Options<State>) {
|
||||||
// Cache object which holds navigation objects for each screen
|
// Cache object which holds navigation objects for each screen
|
||||||
// We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
|
// We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
|
||||||
// In reality, these deps will rarely change, if ever
|
// In reality, these deps will rarely change, if ever
|
||||||
@@ -70,13 +77,17 @@ export default function useNavigationCache<
|
|||||||
const { emit, ...rest } = navigation;
|
const { emit, ...rest } = navigation;
|
||||||
|
|
||||||
const dispatch = (
|
const dispatch = (
|
||||||
action: NavigationAction | ((state: State) => State)
|
action: NavigationAction | ((state: State) => NavigationAction)
|
||||||
) =>
|
) => {
|
||||||
|
const payload =
|
||||||
|
typeof action === 'function' ? action(getState()) : action;
|
||||||
|
|
||||||
navigation.dispatch(
|
navigation.dispatch(
|
||||||
typeof action === 'object' && action != null
|
typeof payload === 'object' && payload != null
|
||||||
? { source: route.key, ...action }
|
? { source: route.key, ...payload }
|
||||||
: action
|
: payload
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const helpers = Object.keys(actions).reduce(
|
const helpers = Object.keys(actions).reduce(
|
||||||
(acc, name) => {
|
(acc, name) => {
|
||||||
@@ -92,7 +103,7 @@ export default function useNavigationCache<
|
|||||||
...helpers,
|
...helpers,
|
||||||
...emitter.create(route.key),
|
...emitter.create(route.key),
|
||||||
dangerouslyGetParent: () => parentNavigation as any,
|
dangerouslyGetParent: () => parentNavigation as any,
|
||||||
dangerouslyGetState: getState as () => State,
|
dangerouslyGetState: getState,
|
||||||
dispatch,
|
dispatch,
|
||||||
setOptions: (options: object) =>
|
setOptions: (options: object) =>
|
||||||
setOptions(o => ({
|
setOptions(o => ({
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ type Options<State extends NavigationState, Action extends NavigationAction> = {
|
|||||||
visitedNavigators?: Set<string>
|
visitedNavigators?: Set<string>
|
||||||
) => boolean;
|
) => boolean;
|
||||||
getState: () => State;
|
getState: () => State;
|
||||||
setState: (state: State) => void;
|
|
||||||
emitter: NavigationEventEmitter;
|
emitter: NavigationEventEmitter;
|
||||||
router: Router<State, Action>;
|
router: Router<State, Action>;
|
||||||
};
|
};
|
||||||
@@ -36,18 +35,17 @@ export default function useNavigationHelpers<
|
|||||||
State extends NavigationState,
|
State extends NavigationState,
|
||||||
Action extends NavigationAction,
|
Action extends NavigationAction,
|
||||||
EventMap extends { [key: string]: any }
|
EventMap extends { [key: string]: any }
|
||||||
>({ onAction, getState, setState, emitter, router }: Options<State, Action>) {
|
>({ onAction, getState, emitter, router }: Options<State, Action>) {
|
||||||
const parentNavigationHelpers = React.useContext(NavigationContext);
|
const parentNavigationHelpers = React.useContext(NavigationContext);
|
||||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||||
|
|
||||||
return React.useMemo(() => {
|
return React.useMemo(() => {
|
||||||
const dispatch = (action: Action | ((state: State) => State)) =>
|
const dispatch = (action: Action | ((state: State) => Action)) =>
|
||||||
performTransaction(() => {
|
performTransaction(() => {
|
||||||
if (typeof action === 'function') {
|
const payload =
|
||||||
setState(action(getState()));
|
typeof action === 'function' ? action(getState()) : action;
|
||||||
} else {
|
|
||||||
onAction(action);
|
onAction(payload);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
@@ -87,7 +85,6 @@ export default function useNavigationHelpers<
|
|||||||
parentNavigationHelpers,
|
parentNavigationHelpers,
|
||||||
emitter.emit,
|
emitter.emit,
|
||||||
performTransaction,
|
performTransaction,
|
||||||
setState,
|
|
||||||
onAction,
|
onAction,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,18 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.17](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.16...@react-navigation/stack@5.0.0-alpha.17) (2019-09-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add fallbacks for non-web modules ([b4bbf9b](https://github.com/react-navigation/navigation-ex/commit/b4bbf9b)), closes [#95](https://github.com/react-navigation/navigation-ex/issues/95) [#96](https://github.com/react-navigation/navigation-ex/issues/96)
|
||||||
|
* provide navigation prop in header ([30e510d](https://github.com/react-navigation/navigation-ex/commit/30e510d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.15...@react-navigation/stack@5.0.0-alpha.16) (2019-09-16)
|
# [5.0.0-alpha.16](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.15...@react-navigation/stack@5.0.0-alpha.16) (2019-09-16)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"android",
|
"android",
|
||||||
"stack"
|
"stack"
|
||||||
],
|
],
|
||||||
"version": "5.0.0-alpha.16",
|
"version": "5.0.0-alpha.17",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { I18nManager } from 'react-native';
|
import { I18nManager } from 'react-native';
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
|
import getStatusBarHeight from '../utils/getStatusBarHeight';
|
||||||
import { CardInterpolationProps, CardInterpolatedStyle } from '../types';
|
import { CardInterpolationProps, CardInterpolatedStyle } from '../types';
|
||||||
import { getStatusBarHeight } from 'react-native-safe-area-view';
|
|
||||||
|
|
||||||
const { cond, add, multiply, interpolate } = Animated;
|
const { cond, add, multiply, interpolate } = Animated;
|
||||||
|
|
||||||
|
|||||||
9
packages/stack/src/utils/getStatusBarHeight.tsx
Normal file
9
packages/stack/src/utils/getStatusBarHeight.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { Platform } from 'react-native';
|
||||||
|
import { getStatusBarHeight as getStatusBarHeightNative } from 'react-native-safe-area-view';
|
||||||
|
|
||||||
|
const getStatusBarHeight = Platform.select({
|
||||||
|
default: getStatusBarHeightNative,
|
||||||
|
web: () => 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getStatusBarHeight;
|
||||||
@@ -6,17 +6,12 @@ import {
|
|||||||
Platform,
|
Platform,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
LayoutChangeEvent,
|
LayoutChangeEvent,
|
||||||
UIManager,
|
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
import MaskedView from '@react-native-community/masked-view';
|
import MaskedView from '../MaskedView';
|
||||||
import TouchableItem from '../TouchableItem';
|
import TouchableItem from '../TouchableItem';
|
||||||
import { HeaderLeftButtonProps } from '../../types';
|
import { HeaderLeftButtonProps } from '../../types';
|
||||||
|
|
||||||
const isMaskedViewAvailable =
|
|
||||||
// @ts-ignore
|
|
||||||
UIManager.getViewManagerConfig('RNCMaskedView') != null;
|
|
||||||
|
|
||||||
type Props = HeaderLeftButtonProps & {
|
type Props = HeaderLeftButtonProps & {
|
||||||
tintColor: string;
|
tintColor: string;
|
||||||
};
|
};
|
||||||
@@ -129,7 +124,7 @@ class HeaderBackButton extends React.Component<Props, State> {
|
|||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isMaskedViewAvailable || backImage || Platform.OS !== 'ios') {
|
if (backImage || Platform.OS !== 'ios') {
|
||||||
// When a custom backimage is specified, we can't mask the label
|
// When a custom backimage is specified, we can't mask the label
|
||||||
// Otherwise there might be weird effect due to our mask not being the same as the image
|
// Otherwise there might be weird effect due to our mask not being the same as the image
|
||||||
return labelElement;
|
return labelElement;
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||||
import { Route, ParamListBase } from '@react-navigation/core';
|
import {
|
||||||
|
NavigationContext,
|
||||||
|
Route,
|
||||||
|
ParamListBase,
|
||||||
|
} from '@react-navigation/core';
|
||||||
import { StackNavigationState } from '@react-navigation/routers';
|
import { StackNavigationState } from '@react-navigation/routers';
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
@@ -92,36 +96,40 @@ export default function HeaderContainer({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<NavigationContext.Provider
|
||||||
key={scene.route.key}
|
key={scene.route.key}
|
||||||
onLayout={
|
value={scene.descriptor.navigation}
|
||||||
onContentHeightChange
|
|
||||||
? e =>
|
|
||||||
onContentHeightChange({
|
|
||||||
route: scene.route,
|
|
||||||
height: e.nativeEvent.layout.height,
|
|
||||||
})
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
pointerEvents="box-none"
|
|
||||||
accessibilityElementsHidden={!isFocused}
|
|
||||||
importantForAccessibility={
|
|
||||||
isFocused ? 'auto' : 'no-hide-descendants'
|
|
||||||
}
|
|
||||||
style={
|
|
||||||
mode === 'float' || options.headerTransparent
|
|
||||||
? styles.header
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{options.header !== undefined ? (
|
<View
|
||||||
options.header === null ? null : (
|
onLayout={
|
||||||
options.header(props)
|
onContentHeightChange
|
||||||
)
|
? e =>
|
||||||
) : (
|
onContentHeightChange({
|
||||||
<Header {...props} />
|
route: scene.route,
|
||||||
)}
|
height: e.nativeEvent.layout.height,
|
||||||
</View>
|
})
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
pointerEvents="box-none"
|
||||||
|
accessibilityElementsHidden={!isFocused}
|
||||||
|
importantForAccessibility={
|
||||||
|
isFocused ? 'auto' : 'no-hide-descendants'
|
||||||
|
}
|
||||||
|
style={
|
||||||
|
mode === 'float' || options.headerTransparent
|
||||||
|
? styles.header
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{options.header !== undefined ? (
|
||||||
|
options.header === null ? null : (
|
||||||
|
options.header(props)
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<Header {...props} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</NavigationContext.Provider>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import {
|
|||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
import { getStatusBarHeight } from 'react-native-safe-area-view';
|
|
||||||
import { Route } from '@react-navigation/core';
|
import { Route } from '@react-navigation/core';
|
||||||
import HeaderBackButton from './HeaderBackButton';
|
import HeaderBackButton from './HeaderBackButton';
|
||||||
import HeaderBackground from './HeaderBackground';
|
import HeaderBackground from './HeaderBackground';
|
||||||
|
import getStatusBarHeight from '../../utils/getStatusBarHeight';
|
||||||
import memoize from '../../utils/memoize';
|
import memoize from '../../utils/memoize';
|
||||||
import {
|
import {
|
||||||
Layout,
|
Layout,
|
||||||
|
|||||||
19
packages/stack/src/views/MaskedView.tsx
Normal file
19
packages/stack/src/views/MaskedView.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { UIManager } from 'react-native';
|
||||||
|
import RNCMaskedView from '@react-native-community/masked-view';
|
||||||
|
|
||||||
|
type Props = React.ComponentProps<typeof RNCMaskedView> & {
|
||||||
|
children: React.ReactElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isMaskedViewAvailable =
|
||||||
|
// @ts-ignore
|
||||||
|
UIManager.getViewManagerConfig('RNCMaskedView') != null;
|
||||||
|
|
||||||
|
export default function MaskedView({ children, ...rest }: Props) {
|
||||||
|
if (isMaskedViewAvailable) {
|
||||||
|
return <RNCMaskedView {...rest}>{children}</RNCMaskedView>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
||||||
7
packages/stack/src/views/MaskedView.web.tsx
Normal file
7
packages/stack/src/views/MaskedView.web.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
type Props = {
|
||||||
|
children: React.ReactElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function MaskedView({ children }: Props) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user