Compare commits

...

8 Commits

Author SHA1 Message Date
Satyajit Sahoo
5e7cfc4ac0 chore: publish
- @react-navigation/bottom-tabs@5.0.0-alpha.39
 - @react-navigation/compat@5.0.0-alpha.28
 - @react-navigation/core@5.0.0-alpha.37
 - @react-navigation/drawer@5.0.0-alpha.41
 - @react-navigation/material-bottom-tabs@5.0.0-alpha.36
 - @react-navigation/material-top-tabs@5.0.0-alpha.35
 - @react-navigation/native-stack@5.0.0-alpha.29
 - @react-navigation/native@5.0.0-alpha.29
 - @react-navigation/routers@5.0.0-alpha.27
 - @react-navigation/stack@5.0.0-alpha.63
2020-01-24 13:01:24 +01:00
NoemiRozpara
5751e7f97a fix: warn if non-serializable values found in state 2020-01-24 12:58:06 +01:00
Satyajit Sahoo
179e807a64 fix: add error message when trying to use v4 API with v5 2020-01-24 00:01:35 +01:00
Satyajit Sahoo
2f1f0af862 fix: validate screen configs 2020-01-23 23:52:27 +01:00
Satyajit Sahoo
9976a888a0 refactor: move replace to stack router 2020-01-23 20:13:40 +01:00
Satyajit Sahoo
16c64e7298 fix: pass correct previous scene to header with headerMode: screen 2020-01-23 15:29:40 +01:00
Satyajit Sahoo
f1fe951cf9 fix: use layout instead of dimensions for determining tab bar layout 2020-01-23 15:10:27 +01:00
Satyajit Sahoo
14250851d1 refactor: remove resetRoot from the navigation prop
Using `resetRoot` requires knowledge of the whole navigation tree that a specific screen shouldn't have. It's better to remove it to discourage resetting whole navigator state from inside a screen.

It's still possible if the user needs it:
- Expose `resetRoot` from container's ref via context
- Use `reset` with the target set to the root navigation state's key
2020-01-23 14:44:34 +01:00
40 changed files with 535 additions and 176 deletions

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.39](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.38...@react-navigation/bottom-tabs@5.0.0-alpha.39) (2020-01-24)
### Bug Fixes
* use layout instead of dimensions for determining tab bar layout ([f1fe951](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/commit/f1fe951cf9d602e1b6d4932e3c6c77bbeaaec5c0))
# [5.0.0-alpha.38](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.37...@react-navigation/bottom-tabs@5.0.0-alpha.38) (2020-01-23)

View File

@@ -10,7 +10,7 @@
"android",
"tab"
],
"version": "5.0.0-alpha.38",
"version": "5.0.0-alpha.39",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs",
"main": "lib/commonjs/index.js",
@@ -30,7 +30,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.26",
"@react-navigation/routers": "^5.0.0-alpha.27",
"color": "^3.1.2",
"react-native-iphone-x-helper": "^1.2.1"
},

View File

@@ -176,14 +176,9 @@ export type BottomTabBarOptions = {
tabStyle?: StyleProp<ViewStyle>;
/**
* Whether the label is renderd below the icon or beside the icon.
* When a function is passed, it receives the device dimensions to render the label differently.
* By default, in `vertical` orinetation, label is rendered below and in `horizontal` orientation, it's renderd beside.
*/
labelPosition?:
| LabelPosition
| ((options: {
dimensions: { height: number; width: number };
}) => LabelPosition);
labelPosition?: LabelPosition;
/**
* Whether the label position should adapt to the orientation.
*/

View File

@@ -50,7 +50,10 @@ export default function BottomTabBar({
const { colors } = useTheme();
const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
const [layout, setLayout] = React.useState({ height: 0, width: 0 });
const [layout, setLayout] = React.useState({
height: 0,
width: dimensions.width,
});
const [keyboardShown, setKeyboardShown] = React.useState(false);
const [visible] = React.useState(() => new Animated.Value(0));
@@ -124,27 +127,15 @@ export default function BottomTabBar({
};
const shouldUseHorizontalLabels = () => {
const isLandscape = dimensions.width > dimensions.height;
if (labelPosition) {
let position;
if (typeof labelPosition === 'string') {
position = labelPosition;
} else {
position = labelPosition({ dimensions });
}
if (position) {
return position === 'beside-icon';
}
return labelPosition === 'beside-icon';
}
if (!adaptive) {
return false;
}
if (dimensions.width >= 768) {
if (layout.width >= 768) {
// Screen size matches a tablet
let maxTabItemWidth = DEFAULT_MAX_TAB_ITEM_WIDTH;
@@ -158,8 +149,10 @@ export default function BottomTabBar({
}
}
return routes.length * maxTabItemWidth <= dimensions.width;
return routes.length * maxTabItemWidth <= layout.width;
} else {
const isLandscape = dimensions.width > dimensions.height;
return isLandscape;
}
};

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.28](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.27...@react-navigation/compat@5.0.0-alpha.28) (2020-01-24)
**Note:** Version bump only for package @react-navigation/compat
# [5.0.0-alpha.27](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.26...@react-navigation/compat@5.0.0-alpha.27) (2020-01-23)

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/compat",
"description": "Compatibility layer to write navigator definitions in static configuration format",
"version": "5.0.0-alpha.27",
"version": "5.0.0-alpha.28",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/compat",
"main": "lib/commonjs/index.js",
@@ -21,7 +21,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.26"
"@react-navigation/routers": "^5.0.0-alpha.27"
},
"devDependencies": {
"@types/react": "^16.9.17",

View File

@@ -19,7 +19,7 @@ export function replace({
key?: string;
newKey?: string;
action?: never;
}): CommonActions.Action {
}): StackActionType {
if (action !== undefined) {
throw new Error(
'Sub-actions are not supported for `replace`. Remove the `action` key from the options.'

View File

@@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.37](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.36...@react-navigation/core@5.0.0-alpha.37) (2020-01-24)
### Bug Fixes
* add error message when trying to use v4 API with v5 ([179e807](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/179e807a64a7d031d671c2c4b12edaee3c3440c5))
* validate screen configs ([2f1f0af](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/2f1f0af862ef8625da4c2aaf463d45fe17a4ac88))
* warn if non-serializable values found in state ([5751e7f](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/5751e7f97a1731a5c71862174dfd931b6ffe13e2))
# [5.0.0-alpha.36](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.35...@react-navigation/core@5.0.0-alpha.36) (2020-01-23)

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.36",
"version": "5.0.0-alpha.37",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/core",
"main": "lib/commonjs/index.js",
@@ -27,6 +27,7 @@
"dependencies": {
"escape-string-regexp": "^2.0.0",
"query-string": "^6.9.0",
"react-is": "^16.12.0",
"shortid": "^2.2.15",
"use-subscription": "^1.3.0"
},
@@ -34,6 +35,7 @@
"@babel/core": "^7.7.7",
"@react-native-community/bob": "^0.8.0",
"@types/react": "^16.9.17",
"@types/react-is": "^16.7.1",
"@types/shortid": "^0.0.29",
"@types/use-subscription": "^1.0.0",
"del-cli": "^3.0.0",

View File

@@ -1,4 +1,3 @@
import shortid from 'shortid';
import { CommonAction, NavigationState, PartialState } from './types';
/**
@@ -11,35 +10,6 @@ const BaseRouter = {
action: CommonAction
): State | PartialState<State> | null {
switch (action.type) {
case 'REPLACE': {
const index = action.source
? state.routes.findIndex(r => r.key === action.source)
: state.index;
if (index === -1) {
return null;
}
const { name, key, params } = action.payload;
if (!state.routeNames.includes(name)) {
return null;
}
return {
...state,
routes: state.routes.map((route, i) =>
i === index
? {
key: key !== undefined ? key : `${name}-${shortid()}`,
name,
params,
}
: route
),
};
}
case 'SET_PARAMS': {
const index = action.source
? state.routes.findIndex(r => r.key === action.source)

View File

@@ -14,12 +14,6 @@ export type Action =
source?: string;
target?: string;
}
| {
type: 'REPLACE';
payload: { name: string; key?: string; params?: object };
source?: string;
target?: string;
}
| {
type: 'RESET';
payload: PartialState<NavigationState>;
@@ -59,10 +53,6 @@ export function navigate(...args: any): Action {
}
}
export function replace(name: string, params?: object): Action {
return { type: 'REPLACE', payload: { name, params } };
}
export function reset(state: PartialState<NavigationState>): Action {
return { type: 'RESET', payload: state };
}

View File

@@ -2,10 +2,10 @@ import * as React from 'react';
import * as CommonActions from './CommonActions';
import EnsureSingleNavigator from './EnsureSingleNavigator';
import NavigationBuilderContext from './NavigationBuilderContext';
import ResetRootContext from './ResetRootContext';
import useFocusedListeners from './useFocusedListeners';
import useDevTools from './useDevTools';
import useStateGetters from './useStateGetters';
import isSerializable from './isSerializable';
import {
Route,
@@ -45,6 +45,8 @@ export const NavigationStateContext = React.createContext<{
},
});
let hasWarnedForSerialization = false;
/**
* Remove `key` and `routeNames` from the state objects recursively to get partial state.
*
@@ -242,6 +244,20 @@ const Container = React.forwardRef(function NavigationContainer(
);
React.useEffect(() => {
if (process.env.NODE_ENV !== 'production') {
if (
state !== undefined &&
!isSerializable(state) &&
!hasWarnedForSerialization
) {
hasWarnedForSerialization = true;
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 functions in your options, you can use 'navigation.setOptions' instead."
);
}
}
if (skipTrackingRef.current) {
skipTrackingRef.current = false;
} else {
@@ -261,9 +277,7 @@ const Container = React.forwardRef(function NavigationContainer(
return (
<NavigationBuilderContext.Provider value={builderContext}>
<NavigationStateContext.Provider value={context}>
<ResetRootContext.Provider value={resetRoot}>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</ResetRootContext.Provider>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</NavigationStateContext.Provider>
</NavigationBuilderContext.Provider>
);

View File

@@ -1,15 +0,0 @@
import * as React from 'react';
import { NavigationState, PartialState } from './types';
/**
* Context which holds the method to reset root navigator state.
*/
const ResetRootContext = React.createContext<
(state: PartialState<NavigationState> | NavigationState) => void
>(() => {
throw new Error(
"We couldn't find a way to reset root state. Have you wrapped your app with 'NavigationContainer'?"
);
});
export default ResetRootContext;

View File

@@ -16,64 +16,6 @@ const STATE = {
routeNames: ['foo', 'bar', 'baz', 'qux'],
};
it('replaces focused screen with REPLACE', () => {
const result = BaseRouter.getStateForAction(
STATE,
CommonActions.replace('qux', { answer: 42 })
);
expect(result).toEqual({
stale: false,
type: 'test',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'qux-test', name: 'qux', params: { answer: 42 } },
{ key: 'baz', name: 'baz' },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
});
});
it('replaces source screen with REPLACE', () => {
const result = BaseRouter.getStateForAction(STATE, {
...CommonActions.replace('qux', { answer: 42 }),
source: 'baz',
});
expect(result).toEqual({
stale: false,
type: 'test',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'qux-test', name: 'qux', params: { answer: 42 } },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
});
});
it("doesn't handle REPLACE if source key isn't present", () => {
const result = BaseRouter.getStateForAction(STATE, {
...CommonActions.replace('qux', { answer: 42 }),
source: 'magic',
});
expect(result).toBe(null);
});
it("doesn't handle REPLACE if screen to replace with isn't present", () => {
const result = BaseRouter.getStateForAction(
STATE,
CommonActions.replace('nonexistent', { answer: 42 })
);
expect(result).toBe(null);
});
it('sets params for the focused screen with SET_PARAMS', () => {
const result = BaseRouter.getStateForAction(
STATE,

View File

@@ -0,0 +1,12 @@
import createNavigatorFactory from '../createNavigatorFactory';
it('throws descriptive error if an argument is passed', () => {
const createDummyNavigator = createNavigatorFactory(() => null);
expect(() => createDummyNavigator()).not.toThrowError();
// @ts-ignore
expect(() => createDummyNavigator({})).toThrowError(
"Creating a navigator doesn't take an argument."
);
});

View File

@@ -936,3 +936,100 @@ it('switches rendered navigators', () => {
'Another navigator is already registered for this container.'
);
});
it('throws if both children and component are passed', () => {
const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props);
return null;
};
const element = (
<NavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()}>
{jest.fn()}
</Screen>
</TestNavigator>
</NavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
"We got both 'component' and 'children' props for 'Screen'. You must pass only one of them."
);
});
it('throws descriptive error for undefined screen component', () => {
const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props);
return null;
};
const element = (
<NavigationContainer>
<TestNavigator>
<Screen name="foo" component={undefined as any} />
</TestNavigator>
</NavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
"We couldn't find a 'component' or 'children' prop for 'Screen'"
);
});
it('throws descriptive error for invalid screen component', () => {
const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props);
return null;
};
const element = (
<NavigationContainer>
<TestNavigator>
<Screen name="foo" component={{} as any} />
</TestNavigator>
</NavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
"We got an invalid value for 'component' prop for 'Screen'. It must be a a valid React Component."
);
});
it('throws descriptive error for invalid children', () => {
const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props);
return null;
};
const element = (
<NavigationContainer>
<TestNavigator>
<Screen name="foo">{[] as any}</Screen>
</TestNavigator>
</NavigationContainer>
);
expect(() => render(element).update(element)).toThrowError(
"We got an invalid value for 'children' prop for 'Screen'. It must be a function returning a React Element."
);
});
it("doesn't throw if children is null", () => {
const TestNavigator = (props: any) => {
useNavigationBuilder(MockRouter, props);
return null;
};
const element = (
<NavigationContainer>
<TestNavigator>
<Screen name="foo" component={jest.fn()}>
{null as any}
</Screen>
</TestNavigator>
</NavigationContainer>
);
expect(() => render(element).update(element)).not.toThrowError();
});

View File

@@ -13,11 +13,17 @@ export default function createNavigatorFactory<
ScreenOptions extends object,
NavigatorComponent extends React.ComponentType<any>
>(Navigator: NavigatorComponent) {
return <ParamList extends ParamListBase>(): TypedNavigator<
return function<ParamList extends ParamListBase>(): TypedNavigator<
ParamList,
ScreenOptions,
typeof Navigator
> => {
> {
if (arguments[0] !== undefined) {
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?"
);
}
return {
Navigator,
Screen,

View File

@@ -0,0 +1,34 @@
export default function isSerializable(o: { [key: string]: any }): boolean {
if (
o === undefined ||
o === null ||
typeof o === 'boolean' ||
typeof o === 'number' ||
typeof o === 'string'
) {
return true;
}
if (
Object.prototype.toString.call(o) !== '[object Object]' &&
!Array.isArray(o)
) {
return false;
}
if (Array.isArray(o)) {
for (const it of o) {
if (!isSerializable(it)) {
return false;
}
}
} else {
for (const key in o) {
if (!isSerializable(o[key])) {
return false;
}
}
}
return true;
}

View File

@@ -365,13 +365,6 @@ type NavigationHelpersCommon<
*/
reset(state: PartialState<State> | State): void;
/**
* Reset the navigation state of the root navigator to the provided state.
*
* @param state Navigation state object.
*/
resetRoot(state?: PartialState<NavigationState> | NavigationState): void;
/**
* Go back to the previous route in history.
*/
@@ -593,6 +586,9 @@ export type NavigationContainerRef =
* @param state Navigation state object.
*/
resetRoot(state?: PartialState<NavigationState> | NavigationState): void;
/**
* Get the rehydrated navigation state of the navigation tree.
*/
getRootState(): NavigationState;
})
| undefined

View File

@@ -1,4 +1,5 @@
import * as React from 'react';
import { isValidElementType } from 'react-is';
import { NavigationStateContext } from './NavigationContainer';
import NavigationRouteContext from './NavigationRouteContext';
import Screen from './Screen';
@@ -53,8 +54,8 @@ const isArrayEqual = (a: any[], b: any[]) =>
*/
const getRouteConfigsFromChildren = <ScreenOptions extends object>(
children: React.ReactNode
) =>
React.Children.toArray(children).reduce<
) => {
const configs = React.Children.toArray(children).reduce<
RouteConfig<ParamListBase, string, ScreenOptions>[]
>((acc, child) => {
if (React.isValidElement(child)) {
@@ -85,6 +86,39 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
);
}, []);
if (process.env.NODE_ENV !== 'production') {
configs.forEach(config => {
const { children, component } = config as any;
if (children != null || component !== undefined) {
if (children != null && component !== undefined) {
throw new Error(
"We got both 'component' and 'children' props for 'Screen'. You must pass only one of them."
);
}
if (children != null && typeof children !== 'function') {
throw new Error(
`We got an invalid value for 'children' prop for 'Screen'. It must be a function returning a React Element.`
);
}
if (component !== undefined && !isValidElementType(component)) {
throw new Error(
`We got an invalid value for 'component' prop for 'Screen'. It must be a a valid React Component.`
);
}
} else {
throw new Error(
"We couldn't find a 'component' or 'children' prop for 'Screen'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing."
);
}
});
}
return configs;
};
/**
* Hook for building navigators.
*

View File

@@ -1,7 +1,6 @@
import * as React from 'react';
import * as CommonActions from './CommonActions';
import NavigationContext from './NavigationContext';
import ResetRootContext from './ResetRootContext';
import { NavigationStateContext } from './NavigationContainer';
import { NavigationEventEmitter } from './useEventEmitter';
import {
@@ -37,7 +36,6 @@ export default function useNavigationHelpers<
Action extends NavigationAction,
EventMap extends Record<string, any>
>({ onAction, getState, emitter, router }: Options<State, Action>) {
const resetRoot = React.useContext(ResetRootContext);
const parentNavigationHelpers = React.useContext(NavigationContext);
const { performTransaction } = React.useContext(NavigationStateContext);
@@ -76,7 +74,6 @@ export default function useNavigationHelpers<
return {
...parentNavigationHelpers,
...helpers,
resetRoot,
dispatch,
emit: emitter.emit,
isFocused: parentNavigationHelpers
@@ -100,7 +97,6 @@ export default function useNavigationHelpers<
router,
getState,
parentNavigationHelpers,
resetRoot,
emitter.emit,
performTransaction,
onAction,

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.41](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.40...@react-navigation/drawer@5.0.0-alpha.41) (2020-01-24)
**Note:** Version bump only for package @react-navigation/drawer
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.39...@react-navigation/drawer@5.0.0-alpha.40) (2020-01-23)

View File

@@ -11,7 +11,7 @@
"material",
"drawer"
],
"version": "5.0.0-alpha.40",
"version": "5.0.0-alpha.41",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer",
"main": "lib/commonjs/index.js",
@@ -31,7 +31,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.26",
"@react-navigation/routers": "^5.0.0-alpha.27",
"color": "^3.1.2",
"react-native-iphone-x-helper": "^1.2.1"
},

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.36](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.35...@react-navigation/material-bottom-tabs@5.0.0-alpha.36) (2020-01-24)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
# [5.0.0-alpha.35](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.34...@react-navigation/material-bottom-tabs@5.0.0-alpha.35) (2020-01-23)

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.35",
"version": "5.0.0-alpha.36",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs",
"main": "lib/commonjs/index.js",
@@ -31,7 +31,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.26"
"@react-navigation/routers": "^5.0.0-alpha.27"
},
"devDependencies": {
"@react-native-community/bob": "^0.8.0",

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.35](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.0-alpha.34...@react-navigation/material-top-tabs@5.0.0-alpha.35) (2020-01-24)
**Note:** Version bump only for package @react-navigation/material-top-tabs
# [5.0.0-alpha.34](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs/compare/@react-navigation/material-top-tabs@5.0.0-alpha.33...@react-navigation/material-top-tabs@5.0.0-alpha.34) (2020-01-23)

View File

@@ -11,7 +11,7 @@
"material",
"tab"
],
"version": "5.0.0-alpha.34",
"version": "5.0.0-alpha.35",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-top-tabs",
"main": "lib/commonjs/index.js",
@@ -31,7 +31,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.26",
"@react-navigation/routers": "^5.0.0-alpha.27",
"color": "^3.1.2"
},
"devDependencies": {

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.28...@react-navigation/native-stack@5.0.0-alpha.29) (2020-01-24)
**Note:** Version bump only for package @react-navigation/native-stack
# [5.0.0-alpha.28](https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack/compare/@react-navigation/native-stack@5.0.0-alpha.27...@react-navigation/native-stack@5.0.0-alpha.28) (2020-01-23)

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.28",
"version": "5.0.0-alpha.29",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/native-stack",
"main": "lib/commonjs/index.js",
@@ -26,7 +26,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.26"
"@react-navigation/routers": "^5.0.0-alpha.27"
},
"devDependencies": {
"@react-native-community/bob": "^0.8.0",

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/tree/master/packages/native/compare/@react-navigation/native@5.0.0-alpha.28...@react-navigation/native@5.0.0-alpha.29) (2020-01-24)
**Note:** Version bump only for package @react-navigation/native
# [5.0.0-alpha.28](https://github.com/react-navigation/navigation-ex/tree/master/packages/native/compare/@react-navigation/native@5.0.0-alpha.27...@react-navigation/native@5.0.0-alpha.28) (2020-01-23)

View File

@@ -7,7 +7,7 @@
"ios",
"android"
],
"version": "5.0.0-alpha.28",
"version": "5.0.0-alpha.29",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/native",
"main": "lib/commonjs/index.js",
@@ -27,7 +27,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/core": "^5.0.0-alpha.36"
"@react-navigation/core": "^5.0.0-alpha.37"
},
"devDependencies": {
"@react-native-community/bob": "^0.8.0",

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.27](https://github.com/react-navigation/navigation-ex/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.26...@react-navigation/routers@5.0.0-alpha.27) (2020-01-24)
**Note:** Version bump only for package @react-navigation/routers
# [5.0.0-alpha.26](https://github.com/react-navigation/navigation-ex/tree/master/packages/routers/compare/@react-navigation/routers@5.0.0-alpha.25...@react-navigation/routers@5.0.0-alpha.26) (2020-01-23)

View File

@@ -683,6 +683,145 @@ it('handles pop to top action', () => {
});
});
it('replaces focused screen with replace', () => {
const router = StackRouter({});
const options = {
routeNames: ['foo', 'bar', 'baz', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'baz', name: 'baz' },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
},
StackActions.replace('qux', { answer: 42 }),
options
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'qux-test', name: 'qux', params: { answer: 42 } },
{ key: 'baz', name: 'baz' },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
});
});
it('replaces source screen with replace', () => {
const router = StackRouter({});
const options = {
routeNames: ['foo', 'bar', 'baz', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'baz', name: 'baz' },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
},
{
...StackActions.replace('qux', { answer: 42 }),
source: 'baz',
},
options
)
).toEqual({
stale: false,
type: 'stack',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'qux-test', name: 'qux', params: { answer: 42 } },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
});
});
it("doesn't handle replace if source key isn't present", () => {
const router = StackRouter({});
const options = {
routeNames: ['foo', 'bar', 'baz', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'baz', name: 'baz' },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
},
{
...StackActions.replace('qux', { answer: 42 }),
source: 'magic',
},
options
)
).toBe(null);
});
it("doesn't handle replace if screen to replace with isn't present", () => {
const router = StackRouter({});
const options = {
routeNames: ['foo', 'bar', 'baz', 'qux'],
routeParamList: {},
};
expect(
router.getStateForAction(
{
stale: false,
type: 'stack',
key: 'root',
index: 1,
routes: [
{ key: 'foo', name: 'foo' },
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
{ key: 'baz', name: 'baz' },
],
routeNames: ['foo', 'bar', 'baz', 'qux'],
},
{
...StackActions.replace('nonexistent', { answer: 42 }),
source: 'magic',
},
options
)
).toBe(null);
});
it('handles push action', () => {
const router = StackRouter({});
const options = {

View File

@@ -6,7 +6,7 @@
"react-native",
"react-navigation"
],
"version": "5.0.0-alpha.26",
"version": "5.0.0-alpha.27",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/routers",
"main": "lib/commonjs/index.js",
@@ -26,7 +26,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/core": "^5.0.0-alpha.36",
"@react-navigation/core": "^5.0.0-alpha.37",
"shortid": "^2.2.15"
},
"devDependencies": {

View File

@@ -9,6 +9,12 @@ import {
} from '@react-navigation/core';
export type StackActionType =
| {
type: 'REPLACE';
payload: { name: string; key?: string | undefined; params?: object };
source?: string;
target?: string;
}
| {
type: 'PUSH';
payload: { name: string; key?: string | undefined; params?: object };
@@ -37,6 +43,9 @@ export type StackNavigationState = NavigationState & {
};
export const StackActions = {
replace(name: string, params?: object): StackActionType {
return { type: 'REPLACE', payload: { name, params } };
},
push(name: string, params?: object): StackActionType {
return { type: 'PUSH', payload: { name, params } };
},
@@ -169,6 +178,35 @@ export default function StackRouter(options: StackRouterOptions) {
const { routeParamList } = options;
switch (action.type) {
case 'REPLACE': {
const index = action.source
? state.routes.findIndex(r => r.key === action.source)
: state.index;
if (index === -1) {
return null;
}
const { name, key, params } = action.payload;
if (!state.routeNames.includes(name)) {
return null;
}
return {
...state,
routes: state.routes.map((route, i) =>
i === index
? {
key: key !== undefined ? key : `${name}-${shortid()}`,
name,
params,
}
: route
),
};
}
case 'PUSH':
if (state.routeNames.includes(action.payload.name)) {
return {

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.63](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.62...@react-navigation/stack@5.0.0-alpha.63) (2020-01-24)
### Bug Fixes
* pass correct previous scene to header with headerMode: screen ([16c64e7](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/commit/16c64e729896a157b2b5bb96d6e3eead827626a0))
# [5.0.0-alpha.62](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack/compare/@react-navigation/stack@5.0.0-alpha.61...@react-navigation/stack@5.0.0-alpha.62) (2020-01-23)

View File

@@ -10,7 +10,7 @@
"android",
"stack"
],
"version": "5.0.0-alpha.62",
"version": "5.0.0-alpha.63",
"license": "MIT",
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/stack",
"main": "lib/commonjs/index.js",
@@ -30,7 +30,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^5.0.0-alpha.26",
"@react-navigation/routers": "^5.0.0-alpha.27",
"color": "^3.1.2",
"react-native-iphone-x-helper": "^1.2.1"
},

View File

@@ -533,6 +533,23 @@ export default class CardStack extends React.Component<Props, State> {
left: safeAreaInsetLeft = insets.left,
} = safeAreaInsets || {};
const previousRoute = getPreviousRoute({ route: scene.route });
let previousScene = scenes[index - 1];
if (previousRoute) {
// The previous scene will be shortly before the current scene in the array
// So loop back from current index to avoid looping over the full array
for (let j = index - 1; j >= 0; j--) {
const s = scenes[j];
if (s && s.route.key === previousRoute.key) {
previousScene = s;
break;
}
}
}
return (
<MaybeScreen
key={route.key}
@@ -549,7 +566,7 @@ export default class CardStack extends React.Component<Props, State> {
layout={layout}
gesture={gesture}
scene={scene}
previousScene={scenes[index - 1]}
previousScene={previousScene}
state={state}
safeAreaInsetTop={safeAreaInsetTop}
safeAreaInsetRight={safeAreaInsetRight}

View File

@@ -244,6 +244,7 @@ class StackView extends React.Component<Props, State> {
(!closingRouteKeys.includes(r.key) &&
!replacingRouteKeys.includes(r.key))
);
const index = routes.findIndex(r => r.key === route.key);
return routes[index - 1];

View File

@@ -3081,6 +3081,13 @@
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.0.tgz#2a5fa918786d07d3725726f7f650527e1cfeaffd"
integrity sha512-c4zji5CjWv1tJxIZkz1oUtGcdOlsH3aza28Nqmm+uNDWBRHoMsjooBEN4czZp1V3iXPihE/VRUOBqg+4Xq0W4g==
"@types/react-is@^16.7.1":
version "16.7.1"
resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-16.7.1.tgz#d3f1c68c358c00ce116b55ef5410cf486dd08539"
integrity sha512-dMLFD2cCsxtDgMkTydQCM0PxDq8vwc6uN5M/jRktDfYvH3nQj6pjC9OrCXS2lKlYoYTNJorI/dI8x9dpLshexQ==
dependencies:
"@types/react" "*"
"@types/react-native-vector-icons@^6.4.5":
version "6.4.5"
resolved "https://registry.yarnpkg.com/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.5.tgz#74cbfc564bd8435e43ad6728572a0e5b49c335d1"
@@ -13535,7 +13542,7 @@ react-error-overlay@^6.0.1:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.4.tgz#0d165d6d27488e660bc08e57bdabaad741366f7a"
integrity sha512-ueZzLmHltszTshDMwyfELDq8zOA803wQ1ZuzCccXa1m57k1PxSHfflPD5W9YIiTXLs0JTLzoj6o1LuM5N6zzNA==
react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
version "16.12.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"
integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==