Compare commits

...

6 Commits

Author SHA1 Message Date
satyajit.happy
98a9487cda chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.9
 - @react-navigation/compat@5.0.0-alpha.2
 - @react-navigation/core@5.0.0-alpha.10
 - @react-navigation/stack@5.0.0-alpha.17
2019-09-17 18:44:55 +02:00
satyajit.happy
ff502820c7 feat: add createSwitchNavigator 2019-09-17 18:32:07 +02:00
satyajit.happy
30e510d123 fix: provide navigation prop in header 2019-09-17 18:13:42 +02:00
satyajit.happy
114a5dc888 feat: add withNavigation and withNavigationFocus 2019-09-17 17:57:01 +02:00
Ryan Stelly
b4bbf9b0c3 fix: add fallbacks for non-web modules
closes #95, #96
2019-09-17 16:58:17 +02:00
satyajit.happy
98f0de088f refactor: make dispatch accept thunks 2019-09-17 13:05:45 +02:00
34 changed files with 352 additions and 124 deletions

View File

@@ -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)

View File

@@ -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",

View File

@@ -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;

View File

@@ -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>

View File

@@ -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}

View File

@@ -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)

View File

@@ -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",

View File

@@ -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]
); );

View File

@@ -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;
} }

View File

@@ -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,
} }

View 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)
);

View File

@@ -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';

View 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]
);
}

View 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;
}

View 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;
}

View File

@@ -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)

View File

@@ -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",

View File

@@ -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));
}; };

View File

@@ -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;
}; };
/** /**

View File

@@ -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' }],
}); });
}); });

View File

@@ -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.

View File

@@ -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);

View File

@@ -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,
}); });

View File

@@ -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 => ({

View File

@@ -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,
]); ]);
} }

View File

@@ -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)

View File

@@ -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",

View File

@@ -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;

View 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;

View File

@@ -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;

View File

@@ -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>

View File

@@ -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,

View 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;
}

View File

@@ -0,0 +1,7 @@
type Props = {
children: React.ReactElement;
};
export default function MaskedView({ children }: Props) {
return children;
}