Compare commits

...

4 Commits

Author SHA1 Message Date
Satyajit Sahoo
3677818f63 chore: publish
- @react-navigation/bottom-tabs@5.1.0
 - @react-navigation/compat@5.1.0
 - @react-navigation/core@5.2.0
 - @react-navigation/drawer@5.1.0
 - @react-navigation/material-bottom-tabs@5.1.0
 - @react-navigation/material-top-tabs@5.1.0
 - @react-navigation/native@5.0.8
 - @react-navigation/routers@5.0.3
 - @react-navigation/stack@5.1.0
2020-02-26 13:57:42 +01:00
Satyajit Sahoo
162410843c feat: add ability add listeners with listeners prop
This adds ability to listen to events from the component where the navigator is defined, even if the screen is not rendered.

```js
<Tabs.Screen
  name="Chat"
  component={Chat}
  options={{ title: 'Chat' }}
  listeners={{
    tabPress: e => console.log('Tab press', e.target),
  }}
/>
```

Closes #6756
2020-02-26 13:02:22 +01:00
Satyajit Sahoo
028c2887c6 refactor: tweak error messages more 2020-02-25 20:58:14 +01:00
Satyajit Sahoo
7a44cda136 refactor: tweak error messages 2020-02-25 17:58:09 +01:00
44 changed files with 513 additions and 74 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.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.7...@react-navigation/bottom-tabs@5.1.0) (2020-02-26)
### Features
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/issues/6756)
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.6...@react-navigation/bottom-tabs@5.0.7) (2020-02-21) ## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.6...@react-navigation/bottom-tabs@5.0.7) (2020-02-21)
**Note:** Version bump only for package @react-navigation/bottom-tabs **Note:** Version bump only for package @react-navigation/bottom-tabs

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/bottom-tabs", "name": "@react-navigation/bottom-tabs",
"description": "Bottom tab navigator following iOS design guidelines", "description": "Bottom tab navigator following iOS design guidelines",
"version": "5.0.7", "version": "5.1.0",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -35,7 +35,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.9.3", "@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.7", "@react-navigation/native": "^5.0.8",
"@types/color": "^3.0.1", "@types/color": "^3.0.1",
"@types/react": "^16.9.19", "@types/react": "^16.9.19",
"@types/react-native": "^0.60.30", "@types/react-native": "^0.60.30",

View File

@@ -48,6 +48,8 @@ function BottomTabNavigator({
} }
export default createNavigatorFactory< export default createNavigatorFactory<
TabNavigationState,
BottomTabNavigationOptions, BottomTabNavigationOptions,
BottomTabNavigationEventMap,
typeof BottomTabNavigator typeof BottomTabNavigator
>(BottomTabNavigator); >(BottomTabNavigator);

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.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.7...@react-navigation/compat@5.1.0) (2020-02-26)
### Features
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/issues/6756)
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.6...@react-navigation/compat@5.0.7) (2020-02-21) ## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/compat/compare/@react-navigation/compat@5.0.6...@react-navigation/compat@5.0.7) (2020-02-21)
**Note:** Version bump only for package @react-navigation/compat **Note:** Version bump only for package @react-navigation/compat

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.7", "version": "5.1.0",
"license": "MIT", "license": "MIT",
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat", "repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
"bugs": { "bugs": {
@@ -26,7 +26,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.9.3", "@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.7", "@react-navigation/native": "^5.0.8",
"@types/react": "^16.9.19", "@types/react": "^16.9.19",
"react": "~16.9.0", "react": "~16.9.0",
"typescript": "^3.7.5" "typescript": "^3.7.5"

View File

@@ -6,6 +6,7 @@ import {
TypedNavigator, TypedNavigator,
NavigationProp, NavigationProp,
RouteProp, RouteProp,
EventMapBase,
} from '@react-navigation/native'; } from '@react-navigation/native';
import CompatScreen from './CompatScreen'; import CompatScreen from './CompatScreen';
import ScreenPropsContext from './ScreenPropsContext'; import ScreenPropsContext from './ScreenPropsContext';
@@ -15,7 +16,9 @@ import { CompatScreenType, CompatRouteConfig } from './types';
export default function createCompatNavigatorFactory< export default function createCompatNavigatorFactory<
CreateNavigator extends () => TypedNavigator< CreateNavigator extends () => TypedNavigator<
ParamListBase, ParamListBase,
NavigationState,
{}, {},
EventMapBase,
React.ComponentType<any> React.ComponentType<any>
> >
>(createNavigator: CreateNavigator) { >(createNavigator: CreateNavigator) {

View File

@@ -22,5 +22,7 @@ function SwitchNavigator(props: Props) {
} }
export default createCompatNavigatorFactory( export default createCompatNavigatorFactory(
createNavigatorFactory<{}, typeof SwitchNavigator>(SwitchNavigator) createNavigatorFactory<TabNavigationState, {}, {}, typeof SwitchNavigator>(
SwitchNavigator
)
); );

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.2.0](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.6...@react-navigation/core@5.2.0) (2020-02-26)
### Features
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/core/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/core/issues/6756)
## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.5...@react-navigation/core@5.1.6) (2020-02-21) ## [5.1.6](https://github.com/react-navigation/react-navigation/tree/master/packages/core/compare/@react-navigation/core@5.1.5...@react-navigation/core@5.1.6) (2020-02-21)

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/core", "name": "@react-navigation/core",
"description": "Core utilities for building navigators", "description": "Core utilities for building navigators",
"version": "5.1.6", "version": "5.2.0",
"keywords": [ "keywords": [
"react", "react",
"react-native", "react-native",
@@ -29,7 +29,7 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/routers": "^5.0.2", "@react-navigation/routers": "^5.0.3",
"escape-string-regexp": "^2.0.0", "escape-string-regexp": "^2.0.0",
"query-string": "^6.10.1", "query-string": "^6.10.1",
"react-is": "^16.12.0", "react-is": "^16.12.0",

View File

@@ -21,10 +21,10 @@ import useSyncState from './useSyncState';
type State = NavigationState | PartialState<NavigationState> | undefined; type State = NavigationState | PartialState<NavigationState> | undefined;
const MISSING_CONTEXT_ERROR = const MISSING_CONTEXT_ERROR =
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/en/getting-started.html for setup instructions."; "Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started.html for setup instructions.";
const NOT_INITIALIZED_ERROR = const NOT_INITIALIZED_ERROR =
"The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html#handling-initialization for more details."; "The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop.html#handling-initialization for more details.";
export const NavigationStateContext = React.createContext<{ export const NavigationStateContext = React.createContext<{
isDefault?: true; isDefault?: true;
@@ -238,7 +238,7 @@ const BaseNavigationContainer = React.forwardRef(
hasWarnedForSerialization = true; hasWarnedForSerialization = true;
console.warn( console.warn(
"We found non-serializable values in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/en/troubleshooting.html#i-get-the-warning-we-found-non-serializable-values-in-the-navigation-state for more details." "Non-serializable values were found in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead. See https://reactnavigation.org/docs/troubleshooting.html#i-get-the-warning-we-found-non-serializable-values-in-the-navigation-state for more details."
); );
} }
} }

View File

@@ -4,7 +4,7 @@ type Props = {
children: React.ReactNode; children: React.ReactNode;
}; };
const MULTIPLE_NAVIGATOR_ERROR = `Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/en/nesting-navigators.html for a guide on nesting.`; const MULTIPLE_NAVIGATOR_ERROR = `Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/nesting-navigators.html for a guide on nesting.`;
export const SingleNavigatorContext = React.createContext< export const SingleNavigatorContext = React.createContext<
| { | {

View File

@@ -10,10 +10,14 @@ import NavigationContext from './NavigationContext';
import NavigationRouteContext from './NavigationRouteContext'; import NavigationRouteContext from './NavigationRouteContext';
import StaticContainer from './StaticContainer'; import StaticContainer from './StaticContainer';
import EnsureSingleNavigator from './EnsureSingleNavigator'; import EnsureSingleNavigator from './EnsureSingleNavigator';
import { NavigationProp, RouteConfig } from './types'; import { NavigationProp, RouteConfig, EventMapBase } from './types';
type Props<State extends NavigationState, ScreenOptions extends object> = { type Props<
screen: RouteConfig<ParamListBase, string, ScreenOptions>; State extends NavigationState,
ScreenOptions extends object,
EventMap extends EventMapBase
> = {
screen: RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>;
navigation: NavigationProp<ParamListBase, string, State, ScreenOptions>; navigation: NavigationProp<ParamListBase, string, State, ScreenOptions>;
route: Route<string> & { route: Route<string> & {
state?: NavigationState | PartialState<NavigationState>; state?: NavigationState | PartialState<NavigationState>;
@@ -28,14 +32,15 @@ type Props<State extends NavigationState, ScreenOptions extends object> = {
*/ */
export default function SceneView< export default function SceneView<
State extends NavigationState, State extends NavigationState,
ScreenOptions extends object ScreenOptions extends object,
EventMap extends EventMapBase
>({ >({
screen, screen,
route, route,
navigation, navigation,
getState, getState,
setState, setState,
}: Props<State, ScreenOptions>) { }: Props<State, ScreenOptions, EventMap>) {
const navigatorKeyRef = React.useRef<string | undefined>(); const navigatorKeyRef = React.useRef<string | undefined>();
const getKey = React.useCallback(() => navigatorKeyRef.current, []); const getKey = React.useCallback(() => navigatorKeyRef.current, []);

View File

@@ -1,5 +1,5 @@
import { ParamListBase } from '@react-navigation/routers'; import { ParamListBase, NavigationState } from '@react-navigation/routers';
import { RouteConfig } from './types'; import { RouteConfig, EventMapBase } from './types';
/** /**
* Empty component used for specifying route configuration. * Empty component used for specifying route configuration.
@@ -7,8 +7,10 @@ import { RouteConfig } from './types';
export default function Screen< export default function Screen<
ParamList extends ParamListBase, ParamList extends ParamListBase,
RouteName extends keyof ParamList, RouteName extends keyof ParamList,
ScreenOptions extends object State extends NavigationState,
>(_: RouteConfig<ParamList, RouteName, ScreenOptions>) { ScreenOptions extends object,
EventMap extends EventMapBase
>(_: RouteConfig<ParamList, RouteName, State, ScreenOptions, EventMap>) {
/* istanbul ignore next */ /* istanbul ignore next */
return null; return null;
} }

View File

@@ -28,7 +28,7 @@ it('throws when getState is accessed without a container', () => {
const element = <Test />; const element = <Test />;
expect(() => render(element).update(element)).toThrowError( expect(() => render(element).update(element)).toThrowError(
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?" "Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
); );
}); });
@@ -47,7 +47,7 @@ it('throws when setState is accessed without a container', () => {
const element = <Test />; const element = <Test />;
expect(() => render(element).update(element)).toThrowError( expect(() => render(element).update(element)).toThrowError(
"We couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?" "Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'?"
); );
}); });

View File

@@ -372,7 +372,7 @@ it("doesn't update state if action wasn't handled", () => {
expect(onStateChange).toBeCalledTimes(0); expect(onStateChange).toBeCalledTimes(0);
expect(spy.mock.calls[0][0]).toMatch( expect(spy.mock.calls[0][0]).toMatch(
"The action 'INVALID' with payload 'undefined' was not handled by any navigator." "The action 'INVALID' was not handled by any navigator."
); );
spy.mockRestore(); spy.mockRestore();
@@ -1085,7 +1085,7 @@ it('throws descriptive error for invalid screen component', () => {
); );
expect(() => render(element).update(element)).toThrowError( expect(() => render(element).update(element)).toThrowError(
"Got an invalid value for 'component' prop for the screen 'foo'. It must be a a valid React Component." "Got an invalid value for 'component' prop for the screen 'foo'. It must be a valid React Component."
); );
}); });

View File

@@ -362,7 +362,7 @@ it('fires blur event when a route is removed with a delay', async () => {
expect(blurCallback).toBeCalledTimes(1); expect(blurCallback).toBeCalledTimes(1);
}); });
it('fires custom events', () => { it('fires custom events added with addListener', () => {
const eventName = 'someSuperCoolEvent'; const eventName = 'someSuperCoolEvent';
const TestNavigator = React.forwardRef((props: any, ref: any): any => { const TestNavigator = React.forwardRef((props: any, ref: any): any => {
@@ -409,10 +409,13 @@ it('fires custom events', () => {
expect(secondCallback).toBeCalledTimes(0); expect(secondCallback).toBeCalledTimes(0);
expect(thirdCallback).toBeCalledTimes(0); expect(thirdCallback).toBeCalledTimes(0);
const target =
ref.current.state.routes[ref.current.state.routes.length - 1].key;
act(() => { act(() => {
ref.current.navigation.emit({ ref.current.navigation.emit({
type: eventName, type: eventName,
target: ref.current.state.routes[ref.current.state.routes.length - 1].key, target,
data: 42, data: 42,
}); });
}); });
@@ -422,6 +425,7 @@ it('fires custom events', () => {
expect(thirdCallback).toBeCalledTimes(1); expect(thirdCallback).toBeCalledTimes(1);
expect(thirdCallback.mock.calls[0][0].type).toBe('someSuperCoolEvent'); expect(thirdCallback.mock.calls[0][0].type).toBe('someSuperCoolEvent');
expect(thirdCallback.mock.calls[0][0].data).toBe(42); expect(thirdCallback.mock.calls[0][0].data).toBe(42);
expect(thirdCallback.mock.calls[0][0].target).toBe(target);
expect(thirdCallback.mock.calls[0][0].defaultPrevented).toBe(undefined); expect(thirdCallback.mock.calls[0][0].defaultPrevented).toBe(undefined);
expect(thirdCallback.mock.calls[0][0].preventDefault).toBe(undefined); expect(thirdCallback.mock.calls[0][0].preventDefault).toBe(undefined);
@@ -429,11 +433,197 @@ it('fires custom events', () => {
ref.current.navigation.emit({ type: eventName }); ref.current.navigation.emit({ type: eventName });
}); });
expect(firstCallback.mock.calls[0][0].target).toBe(undefined);
expect(secondCallback.mock.calls[0][0].target).toBe(undefined);
expect(thirdCallback.mock.calls[1][0].target).toBe(undefined);
expect(firstCallback).toBeCalledTimes(1); expect(firstCallback).toBeCalledTimes(1);
expect(secondCallback).toBeCalledTimes(1); expect(secondCallback).toBeCalledTimes(1);
expect(thirdCallback).toBeCalledTimes(2); expect(thirdCallback).toBeCalledTimes(2);
}); });
it("doesn't call same listener multiple times with addListener", () => {
const eventName = 'someSuperCoolEvent';
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
const { state, navigation, descriptors } = useNavigationBuilder(
MockRouter,
props
);
React.useImperativeHandle(ref, () => ({ navigation, state }), [
navigation,
state,
]);
return state.routes.map(route => descriptors[route.key].render());
});
const callback = jest.fn();
const Test = ({ navigation }: any) => {
React.useEffect(() => navigation.addListener(eventName, callback), [
navigation,
]);
return null;
};
const ref = React.createRef<any>();
const element = (
<BaseNavigationContainer>
<TestNavigator ref={ref}>
<Screen name="first" component={Test} />
<Screen name="second" component={Test} />
<Screen name="third" component={Test} />
</TestNavigator>
</BaseNavigationContainer>
);
render(element);
expect(callback).toBeCalledTimes(0);
act(() => {
ref.current.navigation.emit({ type: eventName });
});
expect(callback).toBeCalledTimes(1);
});
it('fires custom events added with listeners prop', () => {
const eventName = 'someSuperCoolEvent';
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
const { state, navigation } = useNavigationBuilder(MockRouter, props);
React.useImperativeHandle(ref, () => ({ navigation, state }), [
navigation,
state,
]);
return null;
});
const firstCallback = jest.fn();
const secondCallback = jest.fn();
const thirdCallback = jest.fn();
const ref = React.createRef<any>();
const element = (
<BaseNavigationContainer>
<TestNavigator ref={ref}>
<Screen
name="first"
listeners={{ someSuperCoolEvent: firstCallback }}
component={jest.fn()}
/>
<Screen
name="second"
listeners={{ someSuperCoolEvent: secondCallback }}
component={jest.fn()}
/>
<Screen
name="third"
listeners={{ someSuperCoolEvent: thirdCallback }}
component={jest.fn()}
/>
</TestNavigator>
</BaseNavigationContainer>
);
render(element);
expect(firstCallback).toBeCalledTimes(0);
expect(secondCallback).toBeCalledTimes(0);
expect(thirdCallback).toBeCalledTimes(0);
const target =
ref.current.state.routes[ref.current.state.routes.length - 1].key;
act(() => {
ref.current.navigation.emit({
type: eventName,
target,
data: 42,
});
});
expect(firstCallback).toBeCalledTimes(0);
expect(secondCallback).toBeCalledTimes(0);
expect(thirdCallback).toBeCalledTimes(1);
expect(thirdCallback.mock.calls[0][0].type).toBe('someSuperCoolEvent');
expect(thirdCallback.mock.calls[0][0].data).toBe(42);
expect(thirdCallback.mock.calls[0][0].target).toBe(target);
expect(thirdCallback.mock.calls[0][0].defaultPrevented).toBe(undefined);
expect(thirdCallback.mock.calls[0][0].preventDefault).toBe(undefined);
act(() => {
ref.current.navigation.emit({ type: eventName });
});
expect(firstCallback.mock.calls[0][0].target).toBe(undefined);
expect(secondCallback.mock.calls[0][0].target).toBe(undefined);
expect(thirdCallback.mock.calls[1][0].target).toBe(undefined);
expect(firstCallback).toBeCalledTimes(1);
expect(secondCallback).toBeCalledTimes(1);
expect(thirdCallback).toBeCalledTimes(2);
});
it("doesn't call same listener multiple times with listeners", () => {
const eventName = 'someSuperCoolEvent';
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
const { state, navigation } = useNavigationBuilder(MockRouter, props);
React.useImperativeHandle(ref, () => ({ navigation, state }), [
navigation,
state,
]);
return null;
});
const callback = jest.fn();
const ref = React.createRef<any>();
const element = (
<BaseNavigationContainer>
<TestNavigator ref={ref}>
<Screen
name="first"
listeners={{ someSuperCoolEvent: callback }}
component={jest.fn()}
/>
<Screen
name="second"
listeners={{ someSuperCoolEvent: callback }}
component={jest.fn()}
/>
<Screen
name="third"
listeners={{ someSuperCoolEvent: callback }}
component={jest.fn()}
/>
</TestNavigator>
</BaseNavigationContainer>
);
render(element);
expect(callback).toBeCalledTimes(0);
act(() => {
ref.current.navigation.emit({ type: eventName });
});
expect(callback).toBeCalledTimes(1);
});
it('has option to prevent default', () => { it('has option to prevent default', () => {
expect.assertions(5); expect.assertions(5);

View File

@@ -112,7 +112,7 @@ it('throws if called outside a navigation context', () => {
const Test = () => { const Test = () => {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
expect(() => useNavigation()).toThrow( expect(() => useNavigation()).toThrow(
"We couldn't find a navigation object. Is your component inside a screen in a navigator?" "Couldn't find a navigation object. Is your component inside a screen in a navigator?"
); );
return null; return null;

View File

@@ -374,7 +374,7 @@ it('logs error if no navigator handled the action', () => {
render(element).update(element); render(element).update(element);
expect(spy.mock.calls[0][0]).toMatch( expect(spy.mock.calls[0][0]).toMatch(
"The action 'UNKNOWN' with payload 'undefined' was not handled by any navigator." "The action 'UNKNOWN' was not handled by any navigator."
); );
spy.mockRestore(); spy.mockRestore();

View File

@@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import { ParamListBase } from '@react-navigation/routers'; import { ParamListBase, NavigationState } from '@react-navigation/routers';
import Screen from './Screen'; import Screen from './Screen';
import { TypedNavigator } from './types'; import { TypedNavigator, EventMapBase } from './types';
/** /**
* Higher order component to create a `Navigator` and `Screen` pair. * Higher order component to create a `Navigator` and `Screen` pair.
@@ -11,17 +11,21 @@ import { TypedNavigator } from './types';
* @returns Factory method to create a `Navigator` and `Screen` pair. * @returns Factory method to create a `Navigator` and `Screen` pair.
*/ */
export default function createNavigatorFactory< export default function createNavigatorFactory<
State extends NavigationState,
ScreenOptions extends object, ScreenOptions extends object,
EventMap extends EventMapBase,
NavigatorComponent extends React.ComponentType<any> NavigatorComponent extends React.ComponentType<any>
>(Navigator: NavigatorComponent) { >(Navigator: NavigatorComponent) {
return function<ParamList extends ParamListBase>(): TypedNavigator< return function<ParamList extends ParamListBase>(): TypedNavigator<
ParamList, ParamList,
State,
ScreenOptions, ScreenOptions,
EventMap,
typeof Navigator typeof Navigator
> { > {
if (arguments[0] !== undefined) { if (arguments[0] !== undefined) {
throw new Error( throw new Error(
"Creating a navigator doesn't take an argument. Maybe you are trying to use React Navigation 4 API with React Navigation 5? See https://reactnavigation.org/docs/en/upgrading-from-4.x.html for migration guide." "Creating a navigator doesn't take an argument. Maybe you are trying to use React Navigation 4 API with React Navigation 5? See https://reactnavigation.org/docs/upgrading-from-4.x.html for migration guide."
); );
} }

View File

@@ -48,6 +48,7 @@ export type EventArg<
* Type of the event (e.g. `focus`, `blur`) * Type of the event (e.g. `focus`, `blur`)
*/ */
readonly type: EventName; readonly type: EventName;
readonly target?: string;
} & (CanPreventDefault extends true } & (CanPreventDefault extends true
? { ? {
/** /**
@@ -360,7 +361,9 @@ export type Descriptor<
export type RouteConfig< export type RouteConfig<
ParamList extends ParamListBase, ParamList extends ParamListBase,
RouteName extends keyof ParamList, RouteName extends keyof ParamList,
ScreenOptions extends object State extends NavigationState,
ScreenOptions extends object,
EventMap extends EventMapBase
> = { > = {
/** /**
* Route name of this screen. * Route name of this screen.
@@ -377,6 +380,16 @@ export type RouteConfig<
navigation: any; navigation: any;
}) => ScreenOptions); }) => ScreenOptions);
/**
* Event listeners for this screen.
*/
listeners?: Partial<
{
[EventName in keyof (EventMap &
EventMapCore<State>)]: EventListenerCallback<EventMap, EventName>;
}
>;
/** /**
* Initial params object for the route. * Initial params object for the route.
*/ */
@@ -420,7 +433,9 @@ export type NavigationContainerRef =
export type TypedNavigator< export type TypedNavigator<
ParamList extends ParamListBase, ParamList extends ParamListBase,
State extends NavigationState,
ScreenOptions extends object, ScreenOptions extends object,
EventMap extends EventMapBase,
Navigator extends React.ComponentType<any> Navigator extends React.ComponentType<any>
> = { > = {
/** /**
@@ -451,6 +466,6 @@ export type TypedNavigator<
* Component used for specifying route configuration. * Component used for specifying route configuration.
*/ */
Screen: <RouteName extends keyof ParamList>( Screen: <RouteName extends keyof ParamList>(
_: RouteConfig<ParamList, RouteName, ScreenOptions> _: RouteConfig<ParamList, RouteName, State, ScreenOptions, EventMap>
) => null; ) => null;
}; };

View File

@@ -13,11 +13,24 @@ import NavigationBuilderContext, {
} from './NavigationBuilderContext'; } from './NavigationBuilderContext';
import { NavigationEventEmitter } from './useEventEmitter'; import { NavigationEventEmitter } from './useEventEmitter';
import useNavigationCache from './useNavigationCache'; import useNavigationCache from './useNavigationCache';
import { Descriptor, NavigationHelpers, RouteConfig, RouteProp } from './types'; import {
Descriptor,
NavigationHelpers,
RouteConfig,
RouteProp,
EventMapBase,
} from './types';
type Options<State extends NavigationState, ScreenOptions extends object> = { type Options<
State extends NavigationState,
ScreenOptions extends object,
EventMap extends EventMapBase
> = {
state: State; state: State;
screens: Record<string, RouteConfig<ParamListBase, string, ScreenOptions>>; screens: Record<
string,
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>
>;
navigation: NavigationHelpers<ParamListBase>; navigation: NavigationHelpers<ParamListBase>;
screenOptions?: screenOptions?:
| ScreenOptions | ScreenOptions
@@ -49,7 +62,8 @@ type Options<State extends NavigationState, ScreenOptions extends object> = {
*/ */
export default function useDescriptors< export default function useDescriptors<
State extends NavigationState, State extends NavigationState,
ScreenOptions extends object ScreenOptions extends object,
EventMap extends EventMapBase
>({ >({
state, state,
screens, screens,
@@ -64,7 +78,7 @@ export default function useDescriptors<
onRouteFocus, onRouteFocus,
router, router,
emitter, emitter,
}: Options<State, ScreenOptions>) { }: Options<State, ScreenOptions, EventMap>) {
const [options, setOptions] = React.useState<Record<string, object>>({}); const [options, setOptions] = React.useState<Record<string, object>>({});
const { trackAction } = React.useContext(NavigationBuilderContext); const { trackAction } = React.useContext(NavigationBuilderContext);
@@ -133,6 +147,7 @@ export default function useDescriptors<
: screen.options({ : screen.options({
// @ts-ignore // @ts-ignore
route, route,
// @ts-ignore
navigation, navigation,
})), })),
// The options set via `navigation.setOptions` // The options set via `navigation.setOptions`

View File

@@ -5,12 +5,20 @@ export type NavigationEventEmitter = EventEmitter<Record<string, any>> & {
create: (target: string) => EventConsumer<Record<string, any>>; create: (target: string) => EventConsumer<Record<string, any>>;
}; };
type Listeners = ((data: any) => void)[]; type Listeners = ((e: any) => void)[];
/** /**
* Hook to manage the event system used by the navigator to notify screens of various events. * Hook to manage the event system used by the navigator to notify screens of various events.
*/ */
export default function useEventEmitter(): NavigationEventEmitter { export default function useEventEmitter(
listen?: (e: any) => void
): NavigationEventEmitter {
const listenRef = React.useRef(listen);
React.useEffect(() => {
listenRef.current = listen;
});
const listeners = React.useRef<Record<string, Record<string, Listeners>>>({}); const listeners = React.useRef<Record<string, Record<string, Listeners>>>({});
const create = React.useCallback((target: string) => { const create = React.useCallback((target: string) => {
@@ -60,7 +68,9 @@ export default function useEventEmitter(): NavigationEventEmitter {
const callbacks = const callbacks =
target !== undefined target !== undefined
? items[target] && items[target].slice() ? items[target] && items[target].slice()
: ([] as Listeners).concat(...Object.keys(items).map(t => items[t])); : ([] as Listeners)
.concat(...Object.keys(items).map(t => items[t]))
.filter((cb, i, self) => self.lastIndexOf(cb) === i);
const event: EventArg<any, any, any> = { const event: EventArg<any, any, any> = {
get type() { get type() {
@@ -68,8 +78,18 @@ export default function useEventEmitter(): NavigationEventEmitter {
}, },
}; };
if (target !== undefined) {
Object.defineProperty(event, 'target', {
enumerable: true,
get() {
return target;
},
});
}
if (data !== undefined) { if (data !== undefined) {
Object.defineProperty(event, 'data', { Object.defineProperty(event, 'data', {
enumerable: true,
get() { get() {
return data; return data;
}, },
@@ -81,11 +101,13 @@ export default function useEventEmitter(): NavigationEventEmitter {
Object.defineProperties(event, { Object.defineProperties(event, {
defaultPrevented: { defaultPrevented: {
enumerable: true,
get() { get() {
return defaultPrevented; return defaultPrevented;
}, },
}, },
preventDefault: { preventDefault: {
enumerable: true,
value() { value() {
defaultPrevented = true; defaultPrevented = true;
}, },
@@ -93,6 +115,8 @@ export default function useEventEmitter(): NavigationEventEmitter {
}); });
} }
listenRef.current?.(event);
callbacks?.forEach(cb => cb(event)); callbacks?.forEach(cb => cb(event));
return event as any; return event as any;

View File

@@ -46,7 +46,7 @@ export default function useFocusEffect(effect: EffectCallback) {
' fetchData();\n' + ' fetchData();\n' +
' }, [someId])\n' + ' }, [someId])\n' +
'};\n\n' + '};\n\n' +
'See usage guide: https://reactnavigation.org/docs/en/use-focus-effect.html'; 'See usage guide: https://reactnavigation.org/docs/use-focus-effect.html';
} else { } else {
message += ` You returned: '${JSON.stringify(destroy)}'`; message += ` You returned: '${JSON.stringify(destroy)}'`;
} }

View File

@@ -15,7 +15,7 @@ export default function useNavigation<
if (navigation === undefined) { if (navigation === undefined) {
throw new Error( throw new Error(
"We couldn't find a navigation object. Is your component inside a screen in a navigator?" "Couldn't find a navigation object. Is your component inside a screen in a navigator?"
); );
} }

View File

@@ -27,6 +27,7 @@ import {
DefaultNavigatorOptions, DefaultNavigatorOptions,
RouteConfig, RouteConfig,
PrivateValueStore, PrivateValueStore,
EventMapBase,
} from './types'; } from './types';
import useStateGetters from './useStateGetters'; import useStateGetters from './useStateGetters';
import useOnGetState from './useOnGetState'; import useOnGetState from './useOnGetState';
@@ -55,18 +56,28 @@ const isArrayEqual = (a: any[], b: any[]) =>
* *
* @param children React Elements to extract the config from. * @param children React Elements to extract the config from.
*/ */
const getRouteConfigsFromChildren = <ScreenOptions extends object>( const getRouteConfigsFromChildren = <
State extends NavigationState,
ScreenOptions extends object,
EventMap extends EventMapBase
>(
children: React.ReactNode children: React.ReactNode
) => { ) => {
const configs = React.Children.toArray(children).reduce< const configs = React.Children.toArray(children).reduce<
RouteConfig<ParamListBase, string, ScreenOptions>[] RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>[]
>((acc, child) => { >((acc, child) => {
if (React.isValidElement(child)) { if (React.isValidElement(child)) {
if (child.type === Screen) { if (child.type === Screen) {
// We can only extract the config from `Screen` elements // We can only extract the config from `Screen` elements
// If something else was rendered, it's probably a bug // If something else was rendered, it's probably a bug
acc.push( acc.push(
child.props as RouteConfig<ParamListBase, string, ScreenOptions> child.props as RouteConfig<
ParamListBase,
string,
State,
ScreenOptions,
EventMap
>
); );
return acc; return acc;
} }
@@ -75,7 +86,9 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
// When we encounter a fragment, we need to dive into its children to extract the configs // When we encounter a fragment, we need to dive into its children to extract the configs
// This is handy to conditionally define a group of screens // This is handy to conditionally define a group of screens
acc.push( acc.push(
...getRouteConfigsFromChildren<ScreenOptions>(child.props.children) ...getRouteConfigsFromChildren<State, ScreenOptions, EventMap>(
child.props.children
)
); );
return acc; return acc;
} }
@@ -116,7 +129,7 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
if (component !== undefined && !isValidElementType(component)) { if (component !== undefined && !isValidElementType(component)) {
throw new Error( throw new Error(
`Got an invalid value for 'component' prop for the screen '${name}'. It must be a a valid React Component.` `Got an invalid value for 'component' prop for the screen '${name}'. It must be a valid React Component.`
); );
} }
@@ -177,9 +190,17 @@ export default function useNavigationBuilder<
}) })
); );
const routeConfigs = getRouteConfigsFromChildren<ScreenOptions>(children); const routeConfigs = getRouteConfigsFromChildren<
State,
ScreenOptions,
EventMap
>(children);
const screens = routeConfigs.reduce< const screens = routeConfigs.reduce<
Record<string, RouteConfig<ParamListBase, string, ScreenOptions>> Record<
string,
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>
>
>((acc, config) => { >((acc, config) => {
if (config.name in acc) { if (config.name in acc) {
throw new Error( throw new Error(
@@ -344,7 +365,35 @@ export default function useNavigationBuilder<
: (initializedStateRef.current as State); : (initializedStateRef.current as State);
}, [getCurrentState, isStateInitialized]); }, [getCurrentState, isStateInitialized]);
const emitter = useEventEmitter(); const emitter = useEventEmitter(e => {
let routeNames = [];
if (e.target) {
const name = state.routes.find(route => route.key === e.target)?.name;
if (name) {
routeNames.push(name);
}
} else {
routeNames.push(...Object.keys(screens));
}
const listeners = ([] as (((e: any) => void) | undefined)[])
.concat(
...routeNames.map(name => {
const { listeners } = screens[name];
return listeners
? Object.keys(listeners)
.filter(type => type === e.type)
.map(type => listeners[type])
: undefined;
})
)
.filter((cb, i, self) => cb && self.lastIndexOf(cb) === i);
listeners.forEach(listener => listener?.(e));
});
useFocusEvents({ state, emitter }); useFocusEvents({ state, emitter });
@@ -400,7 +449,7 @@ export default function useNavigationBuilder<
getStateForRoute, getStateForRoute,
}); });
const descriptors = useDescriptors<State, ScreenOptions>({ const descriptors = useDescriptors<State, ScreenOptions, EventMap>({
state, state,
screens, screens,
navigation, navigation,

View File

@@ -36,18 +36,45 @@ export default function useNavigationHelpers<
const parentNavigationHelpers = React.useContext(NavigationContext); const parentNavigationHelpers = React.useContext(NavigationContext);
return React.useMemo(() => { return React.useMemo(() => {
const dispatch = (action: Action | ((state: State) => Action)) => { const dispatch = (op: Action | ((state: State) => Action)) => {
const payload = const action = typeof op === 'function' ? op(getState()) : op;
typeof action === 'function' ? action(getState()) : action;
const handled = onAction(payload); const handled = onAction(action);
if (!handled && process.env.NODE_ENV !== 'production') { if (!handled && process.env.NODE_ENV !== 'production') {
console.error( const payload: Record<string, any> | undefined = action.payload;
`The action '${payload.type}' with payload '${JSON.stringify(
payload.payload let message = `The action '${action.type}'${
)}' was not handled by any navigator. If you are trying to navigate to a screen, check if the screen exists in your navigator. If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/en/nesting-navigators.html#navigating-to-a-screen-in-a-nested-navigator.` payload ? ` with payload ${JSON.stringify(action.payload)}` : ''
); } was not handled by any navigator.`;
switch (action.type) {
case 'NAVIGATE':
case 'PUSH':
case 'REPLACE':
case 'JUMP_TO':
if (payload?.name) {
message += `\n\nDo you have a screen named '${payload.name}'?\n\nIf you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators.html#navigating-to-a-screen-in-a-nested-navigator.`;
} else {
message += `\n\nYou need to pass the name of the screen to navigate to.\n\nSee https://reactnavigation.org/docs/navigation-actions.html for usage.`;
}
break;
case 'GO_BACK':
case 'POP':
case 'POP_TO_TOP':
message += `\n\nIs there any screen to go back to?`;
break;
case 'OPEN_DRAWER':
case 'CLOSE_DRAWER':
case 'TOGGLE_DRAWER':
message += `\n\nIs your screen inside a Drawer navigator?`;
break;
}
message += `\n\nThis is a development-only warning and won't be shown in production.`;
console.error(message);
} }
}; };

View File

@@ -15,7 +15,7 @@ export default function useRoute<
if (route === undefined) { if (route === undefined) {
throw new Error( throw new Error(
"We couldn't find a route object. Is your component inside a screen in a navigator?" "Couldn't find a route object. Is your component inside a screen in a navigator?"
); );
} }

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.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.7...@react-navigation/drawer@5.1.0) (2020-02-26)
### Features
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/issues/6756)
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.6...@react-navigation/drawer@5.0.7) (2020-02-21) ## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.6...@react-navigation/drawer@5.0.7) (2020-02-21)
**Note:** Version bump only for package @react-navigation/drawer **Note:** Version bump only for package @react-navigation/drawer

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/drawer", "name": "@react-navigation/drawer",
"description": "Drawer navigator component with animated transitions and gesturess", "description": "Drawer navigator component with animated transitions and gesturess",
"version": "5.0.7", "version": "5.1.0",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -40,7 +40,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.9.3", "@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.7", "@react-navigation/native": "^5.0.8",
"@types/react": "^16.9.19", "@types/react": "^16.9.19",
"@types/react-native": "^0.60.30", "@types/react-native": "^0.60.30",
"del-cli": "^3.0.0", "del-cli": "^3.0.0",

View File

@@ -49,6 +49,8 @@ function DrawerNavigator({
} }
export default createNavigatorFactory< export default createNavigatorFactory<
DrawerNavigationState,
DrawerNavigationOptions, DrawerNavigationOptions,
DrawerNavigationEventMap,
typeof DrawerNavigator typeof DrawerNavigator
>(DrawerNavigator); >(DrawerNavigator);

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.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.7...@react-navigation/material-bottom-tabs@5.1.0) (2020-02-26)
### Features
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/issues/6756)
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.6...@react-navigation/material-bottom-tabs@5.0.7) (2020-02-21) ## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.6...@react-navigation/material-bottom-tabs@5.0.7) (2020-02-21)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs **Note:** Version bump only for package @react-navigation/material-bottom-tabs

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/material-bottom-tabs", "name": "@react-navigation/material-bottom-tabs",
"description": "Integration for bottom navigation component from react-native-paper", "description": "Integration for bottom navigation component from react-native-paper",
"version": "5.0.7", "version": "5.1.0",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -36,7 +36,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.9.3", "@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.7", "@react-navigation/native": "^5.0.8",
"@types/react": "^16.9.19", "@types/react": "^16.9.19",
"@types/react-native": "^0.60.30", "@types/react-native": "^0.60.30",
"@types/react-native-vector-icons": "^6.4.5", "@types/react-native-vector-icons": "^6.4.5",

View File

@@ -49,6 +49,8 @@ function MaterialBottomTabNavigator({
} }
export default createNavigatorFactory< export default createNavigatorFactory<
TabNavigationState,
MaterialBottomTabNavigationOptions, MaterialBottomTabNavigationOptions,
MaterialBottomTabNavigationEventMap,
typeof MaterialBottomTabNavigator typeof MaterialBottomTabNavigator
>(MaterialBottomTabNavigator); >(MaterialBottomTabNavigator);

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.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.7...@react-navigation/material-top-tabs@5.1.0) (2020-02-26)
### Features
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/issues/6756)
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.6...@react-navigation/material-top-tabs@5.0.7) (2020-02-21) ## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.6...@react-navigation/material-top-tabs@5.0.7) (2020-02-21)
**Note:** Version bump only for package @react-navigation/material-top-tabs **Note:** Version bump only for package @react-navigation/material-top-tabs

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/material-top-tabs", "name": "@react-navigation/material-top-tabs",
"description": "Integration for the animated tab view component from react-native-tab-view", "description": "Integration for the animated tab view component from react-native-tab-view",
"version": "5.0.7", "version": "5.1.0",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -39,7 +39,7 @@
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.9.3", "@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.7", "@react-navigation/native": "^5.0.8",
"@types/react": "^16.9.19", "@types/react": "^16.9.19",
"@types/react-native": "^0.60.30", "@types/react-native": "^0.60.30",
"del-cli": "^3.0.0", "del-cli": "^3.0.0",

View File

@@ -48,6 +48,8 @@ function MaterialTopTabNavigator({
} }
export default createNavigatorFactory< export default createNavigatorFactory<
TabNavigationState,
MaterialTopTabNavigationOptions, MaterialTopTabNavigationOptions,
MaterialTopTabNavigationEventMap,
typeof MaterialTopTabNavigator typeof MaterialTopTabNavigator
>(MaterialTopTabNavigator); >(MaterialTopTabNavigator);

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.8](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.7...@react-navigation/native@5.0.8) (2020-02-26)
**Note:** Version bump only for package @react-navigation/native
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.6...@react-navigation/native@5.0.7) (2020-02-21) ## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/native/compare/@react-navigation/native@5.0.6...@react-navigation/native@5.0.7) (2020-02-21)
**Note:** Version bump only for package @react-navigation/native **Note:** Version bump only for package @react-navigation/native

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/native", "name": "@react-navigation/native",
"description": "React Native integration for React Navigation", "description": "React Native integration for React Navigation",
"version": "5.0.7", "version": "5.0.8",
"keywords": [ "keywords": [
"react-native", "react-native",
"react-navigation", "react-navigation",
@@ -31,7 +31,7 @@
"clean": "del lib" "clean": "del lib"
}, },
"dependencies": { "dependencies": {
"@react-navigation/core": "^5.1.6" "@react-navigation/core": "^5.2.0"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.9.3", "@react-native-community/bob": "^0.9.3",

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.3](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.2...@react-navigation/routers@5.0.3) (2020-02-26)
**Note:** Version bump only for package @react-navigation/routers
## [5.0.2](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.1...@react-navigation/routers@5.0.2) (2020-02-21) ## [5.0.2](https://github.com/react-navigation/react-navigation/tree/master/packages/routers/compare/@react-navigation/routers@5.0.1...@react-navigation/routers@5.0.2) (2020-02-21)

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/routers", "name": "@react-navigation/routers",
"description": "Routers to help build custom navigators", "description": "Routers to help build custom navigators",
"version": "5.0.2", "version": "5.0.3",
"keywords": [ "keywords": [
"react", "react",
"react-native", "react-native",

View File

@@ -41,7 +41,7 @@ export function navigate(...args: any): Action {
if (typeof args[0] === 'string') { if (typeof args[0] === 'string') {
return { type: 'NAVIGATE', payload: { name: args[0], params: args[1] } }; return { type: 'NAVIGATE', payload: { name: args[0], params: args[1] } };
} else { } else {
const payload = args[0]; const payload = args[0] || {};
if (!payload.hasOwnProperty('key') && !payload.hasOwnProperty('name')) { if (!payload.hasOwnProperty('key') && !payload.hasOwnProperty('name')) {
throw new Error( throw new Error(

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.1.0](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.9...@react-navigation/stack@5.1.0) (2020-02-26)
### Features
* add ability add listeners with listeners prop ([1624108](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/162410843c4f175ae107756de1c3af04d1d47aa7)), closes [#6756](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6756)
## [5.0.9](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.8...@react-navigation/stack@5.0.9) (2020-02-24) ## [5.0.9](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.8...@react-navigation/stack@5.0.9) (2020-02-24)

View File

@@ -1,7 +1,7 @@
{ {
"name": "@react-navigation/stack", "name": "@react-navigation/stack",
"description": "Stack navigator component for iOS and Android with animated transitions and gestures", "description": "Stack navigator component for iOS and Android with animated transitions and gestures",
"version": "5.0.9", "version": "5.1.0",
"keywords": [ "keywords": [
"react-native-component", "react-native-component",
"react-component", "react-component",
@@ -40,7 +40,7 @@
"devDependencies": { "devDependencies": {
"@react-native-community/bob": "^0.9.3", "@react-native-community/bob": "^0.9.3",
"@react-native-community/masked-view": "^0.1.6", "@react-native-community/masked-view": "^0.1.6",
"@react-navigation/native": "^5.0.7", "@react-navigation/native": "^5.0.8",
"@types/color": "^3.0.1", "@types/color": "^3.0.1",
"@types/react": "^16.9.19", "@types/react": "^16.9.19",
"@types/react-native": "^0.60.30", "@types/react-native": "^0.60.30",

View File

@@ -74,6 +74,8 @@ function StackNavigator({
} }
export default createNavigatorFactory< export default createNavigatorFactory<
StackNavigationState,
StackNavigationOptions, StackNavigationOptions,
StackNavigationEventMap,
typeof StackNavigator typeof StackNavigator
>(StackNavigator); >(StackNavigator);