Compare commits

..

10 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
Satyajit Sahoo
a046db536f chore: publish
- @react-navigation/stack@5.0.9
2020-02-24 14:45:00 +01:00
Satyajit Sahoo
d115787b1c chore: mark yarn script as binary 2020-02-24 14:44:29 +01:00
Michał Osadnik
80a337024a fix: enhance border radius in modals on new iPhones (#6945)
Co-authored-by: Satyajit Sahoo <satyajit.happy@gmail.com>
2020-02-24 14:44:20 +01:00
Satyajit Sahoo
c19da31240 refactor: enable screens only for last screen
This will avoid issues such as https://github.com/react-navigation/react-navigation/issues/6909
2020-02-24 11:37:25 +01:00
Satyajit Sahoo
85e9376302 chore: publish
- @react-navigation/stack@5.0.8
2020-02-21 20:09:06 +01:00
Satyajit Sahoo
a67b49477e fix: fix transparent header on Android 2020-02-21 20:07:38 +01:00
49 changed files with 558 additions and 153 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
yarn-*.js binary

View File

@@ -7,7 +7,11 @@ import {
StatusBar,
I18nManager,
} from 'react-native';
// eslint-disable-next-line import/no-unresolved
import { enableScreens } from 'react-native-screens';
import RNRestart from 'react-native-restart';
import { Updates } from 'expo';
import { Asset } from 'expo-asset';
import { MaterialIcons } from '@expo/vector-icons';
import {
Provider as PaperProvider,
@@ -17,7 +21,6 @@ import {
List,
Divider,
} from 'react-native-paper';
import { Asset } from 'expo-asset';
import {
InitialState,
useLinking,
@@ -49,10 +52,11 @@ import DynamicTabs from './Screens/DynamicTabs';
import AuthFlow from './Screens/AuthFlow';
import CompatAPI from './Screens/CompatAPI';
import SettingsItem from './Shared/SettingsItem';
import { Updates } from 'expo';
YellowBox.ignoreWarnings(['Require cycle:', 'Warning: Async Storage']);
enableScreens();
type RootDrawerParamList = {
Root: undefined;
Another: undefined;

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.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)
**Note:** Version bump only for package @react-navigation/bottom-tabs

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/bottom-tabs",
"description": "Bottom tab navigator following iOS design guidelines",
"version": "5.0.7",
"version": "5.1.0",
"keywords": [
"react-native-component",
"react-component",
@@ -35,7 +35,7 @@
},
"devDependencies": {
"@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/react": "^16.9.19",
"@types/react-native": "^0.60.30",

View File

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

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.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)
**Note:** Version bump only for package @react-navigation/compat

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/compat",
"description": "Compatibility layer to write navigator definitions in static configuration format",
"version": "5.0.7",
"version": "5.1.0",
"license": "MIT",
"repository": "https://github.com/react-navigation/react-navigation/tree/master/packages/compat",
"bugs": {
@@ -26,7 +26,7 @@
},
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@react-navigation/native": "^5.0.7",
"@react-navigation/native": "^5.0.8",
"@types/react": "^16.9.19",
"react": "~16.9.0",
"typescript": "^3.7.5"

View File

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

View File

@@ -22,5 +22,7 @@ function SwitchNavigator(props: Props) {
}
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.
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)

View File

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

View File

@@ -21,10 +21,10 @@ import useSyncState from './useSyncState';
type State = NavigationState | PartialState<NavigationState> | undefined;
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 =
"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<{
isDefault?: true;
@@ -238,7 +238,7 @@ const BaseNavigationContainer = React.forwardRef(
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 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;
};
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<
| {

View File

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

View File

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

View File

@@ -28,7 +28,7 @@ it('throws when getState is accessed without a container', () => {
const element = <Test />;
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 />;
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(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();
@@ -1085,7 +1085,7 @@ it('throws descriptive error for invalid screen component', () => {
);
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);
});
it('fires custom events', () => {
it('fires custom events added with addListener', () => {
const eventName = 'someSuperCoolEvent';
const TestNavigator = React.forwardRef((props: any, ref: any): any => {
@@ -409,10 +409,13 @@ it('fires custom events', () => {
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: ref.current.state.routes[ref.current.state.routes.length - 1].key,
target,
data: 42,
});
});
@@ -422,6 +425,7 @@ it('fires custom events', () => {
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);
@@ -429,11 +433,197 @@ it('fires custom events', () => {
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 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', () => {
expect.assertions(5);

View File

@@ -112,7 +112,7 @@ it('throws if called outside a navigation context', () => {
const Test = () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
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;

View File

@@ -374,7 +374,7 @@ it('logs error if no navigator handled the action', () => {
render(element).update(element);
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();

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { ParamListBase } from '@react-navigation/routers';
import { ParamListBase, NavigationState } from '@react-navigation/routers';
import Screen from './Screen';
import { TypedNavigator } from './types';
import { TypedNavigator, EventMapBase } from './types';
/**
* 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.
*/
export default function createNavigatorFactory<
State extends NavigationState,
ScreenOptions extends object,
EventMap extends EventMapBase,
NavigatorComponent extends React.ComponentType<any>
>(Navigator: NavigatorComponent) {
return function<ParamList extends ParamListBase>(): TypedNavigator<
ParamList,
State,
ScreenOptions,
EventMap,
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? 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`)
*/
readonly type: EventName;
readonly target?: string;
} & (CanPreventDefault extends true
? {
/**
@@ -360,7 +361,9 @@ export type Descriptor<
export type RouteConfig<
ParamList extends ParamListBase,
RouteName extends keyof ParamList,
ScreenOptions extends object
State extends NavigationState,
ScreenOptions extends object,
EventMap extends EventMapBase
> = {
/**
* Route name of this screen.
@@ -377,6 +380,16 @@ export type RouteConfig<
navigation: any;
}) => ScreenOptions);
/**
* Event listeners for this screen.
*/
listeners?: Partial<
{
[EventName in keyof (EventMap &
EventMapCore<State>)]: EventListenerCallback<EventMap, EventName>;
}
>;
/**
* Initial params object for the route.
*/
@@ -420,7 +433,9 @@ export type NavigationContainerRef =
export type TypedNavigator<
ParamList extends ParamListBase,
State extends NavigationState,
ScreenOptions extends object,
EventMap extends EventMapBase,
Navigator extends React.ComponentType<any>
> = {
/**
@@ -451,6 +466,6 @@ export type TypedNavigator<
* Component used for specifying route configuration.
*/
Screen: <RouteName extends keyof ParamList>(
_: RouteConfig<ParamList, RouteName, ScreenOptions>
_: RouteConfig<ParamList, RouteName, State, ScreenOptions, EventMap>
) => null;
};

View File

@@ -13,11 +13,24 @@ import NavigationBuilderContext, {
} from './NavigationBuilderContext';
import { NavigationEventEmitter } from './useEventEmitter';
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;
screens: Record<string, RouteConfig<ParamListBase, string, ScreenOptions>>;
screens: Record<
string,
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>
>;
navigation: NavigationHelpers<ParamListBase>;
screenOptions?:
| ScreenOptions
@@ -49,7 +62,8 @@ type Options<State extends NavigationState, ScreenOptions extends object> = {
*/
export default function useDescriptors<
State extends NavigationState,
ScreenOptions extends object
ScreenOptions extends object,
EventMap extends EventMapBase
>({
state,
screens,
@@ -64,7 +78,7 @@ export default function useDescriptors<
onRouteFocus,
router,
emitter,
}: Options<State, ScreenOptions>) {
}: Options<State, ScreenOptions, EventMap>) {
const [options, setOptions] = React.useState<Record<string, object>>({});
const { trackAction } = React.useContext(NavigationBuilderContext);
@@ -133,6 +147,7 @@ export default function useDescriptors<
: screen.options({
// @ts-ignore
route,
// @ts-ignore
navigation,
})),
// 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>>;
};
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.
*/
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 create = React.useCallback((target: string) => {
@@ -60,7 +68,9 @@ export default function useEventEmitter(): NavigationEventEmitter {
const callbacks =
target !== undefined
? 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> = {
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) {
Object.defineProperty(event, 'data', {
enumerable: true,
get() {
return data;
},
@@ -81,11 +101,13 @@ export default function useEventEmitter(): NavigationEventEmitter {
Object.defineProperties(event, {
defaultPrevented: {
enumerable: true,
get() {
return defaultPrevented;
},
},
preventDefault: {
enumerable: true,
value() {
defaultPrevented = true;
},
@@ -93,6 +115,8 @@ export default function useEventEmitter(): NavigationEventEmitter {
});
}
listenRef.current?.(event);
callbacks?.forEach(cb => cb(event));
return event as any;

View File

@@ -46,7 +46,7 @@ export default function useFocusEffect(effect: EffectCallback) {
' fetchData();\n' +
' }, [someId])\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 {
message += ` You returned: '${JSON.stringify(destroy)}'`;
}

View File

@@ -15,7 +15,7 @@ export default function useNavigation<
if (navigation === undefined) {
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,
RouteConfig,
PrivateValueStore,
EventMapBase,
} from './types';
import useStateGetters from './useStateGetters';
import useOnGetState from './useOnGetState';
@@ -55,18 +56,28 @@ const isArrayEqual = (a: any[], b: any[]) =>
*
* @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
) => {
const configs = React.Children.toArray(children).reduce<
RouteConfig<ParamListBase, string, ScreenOptions>[]
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>[]
>((acc, child) => {
if (React.isValidElement(child)) {
if (child.type === Screen) {
// We can only extract the config from `Screen` elements
// If something else was rendered, it's probably a bug
acc.push(
child.props as RouteConfig<ParamListBase, string, ScreenOptions>
child.props as RouteConfig<
ParamListBase,
string,
State,
ScreenOptions,
EventMap
>
);
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
// This is handy to conditionally define a group of screens
acc.push(
...getRouteConfigsFromChildren<ScreenOptions>(child.props.children)
...getRouteConfigsFromChildren<State, ScreenOptions, EventMap>(
child.props.children
)
);
return acc;
}
@@ -116,7 +129,7 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
if (component !== undefined && !isValidElementType(component)) {
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<
Record<string, RouteConfig<ParamListBase, string, ScreenOptions>>
Record<
string,
RouteConfig<ParamListBase, string, State, ScreenOptions, EventMap>
>
>((acc, config) => {
if (config.name in acc) {
throw new Error(
@@ -344,7 +365,35 @@ export default function useNavigationBuilder<
: (initializedStateRef.current as State);
}, [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 });
@@ -400,7 +449,7 @@ export default function useNavigationBuilder<
getStateForRoute,
});
const descriptors = useDescriptors<State, ScreenOptions>({
const descriptors = useDescriptors<State, ScreenOptions, EventMap>({
state,
screens,
navigation,

View File

@@ -36,18 +36,45 @@ export default function useNavigationHelpers<
const parentNavigationHelpers = React.useContext(NavigationContext);
return React.useMemo(() => {
const dispatch = (action: Action | ((state: State) => Action)) => {
const payload =
typeof action === 'function' ? action(getState()) : action;
const dispatch = (op: Action | ((state: State) => Action)) => {
const action = typeof op === 'function' ? op(getState()) : op;
const handled = onAction(payload);
const handled = onAction(action);
if (!handled && process.env.NODE_ENV !== 'production') {
console.error(
`The action '${payload.type}' with payload '${JSON.stringify(
payload.payload
)}' 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.`
);
const payload: Record<string, any> | undefined = action.payload;
let message = `The action '${action.type}'${
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) {
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.
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)
**Note:** Version bump only for package @react-navigation/drawer

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/drawer",
"description": "Drawer navigator component with animated transitions and gesturess",
"version": "5.0.7",
"version": "5.1.0",
"keywords": [
"react-native-component",
"react-component",
@@ -40,7 +40,7 @@
},
"devDependencies": {
"@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-native": "^0.60.30",
"del-cli": "^3.0.0",

View File

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

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.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)
**Note:** Version bump only for package @react-navigation/material-bottom-tabs

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/material-bottom-tabs",
"description": "Integration for bottom navigation component from react-native-paper",
"version": "5.0.7",
"version": "5.1.0",
"keywords": [
"react-native-component",
"react-component",
@@ -36,7 +36,7 @@
},
"devDependencies": {
"@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-native": "^0.60.30",
"@types/react-native-vector-icons": "^6.4.5",

View File

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

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.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)
**Note:** Version bump only for package @react-navigation/material-top-tabs

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/material-top-tabs",
"description": "Integration for the animated tab view component from react-native-tab-view",
"version": "5.0.7",
"version": "5.1.0",
"keywords": [
"react-native-component",
"react-component",
@@ -39,7 +39,7 @@
},
"devDependencies": {
"@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-native": "^0.60.30",
"del-cli": "^3.0.0",

View File

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

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.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)
**Note:** Version bump only for package @react-navigation/native

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/native",
"description": "React Native integration for React Navigation",
"version": "5.0.7",
"version": "5.0.8",
"keywords": [
"react-native",
"react-navigation",
@@ -31,7 +31,7 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/core": "^5.1.6"
"@react-navigation/core": "^5.2.0"
},
"devDependencies": {
"@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.
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)

View File

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

View File

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

View File

@@ -3,6 +3,39 @@
All notable changes to this project will be documented in this file.
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)
### Bug Fixes
* enhance border radius in modals on new iPhones ([#6945](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/issues/6945)) ([80a3370](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/80a337024abc53537ff4a63916cea38bb4f374bf))
## [5.0.8](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.7...@react-navigation/stack@5.0.8) (2020-02-21)
### Bug Fixes
* fix transparent header on Android ([a67b494](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/commit/a67b49477eb500c81fedcd73bbd8102901a95170))
## [5.0.7](https://github.com/react-navigation/react-navigation/tree/master/packages/stack/compare/@react-navigation/stack@5.0.6...@react-navigation/stack@5.0.7) (2020-02-21)

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/stack",
"description": "Stack navigator component for iOS and Android with animated transitions and gestures",
"version": "5.0.7",
"version": "5.1.0",
"keywords": [
"react-native-component",
"react-component",
@@ -40,7 +40,7 @@
"devDependencies": {
"@react-native-community/bob": "^0.9.3",
"@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/react": "^16.9.19",
"@types/react-native": "^0.60.30",

View File

@@ -1,4 +1,5 @@
import { Animated } from 'react-native';
import { isIphoneX } from 'react-native-iphone-x-helper';
import conditional from '../utils/conditional';
import {
StackCardInterpolationProps,
@@ -152,8 +153,8 @@ export function forModalPresentationIOS({
? 0
: index === 0
? progress.interpolate({
inputRange: [0, 1, 2],
outputRange: [0, 0, 10],
inputRange: [0, 1, 1.0001, 2],
outputRange: [0, 0, isIphoneX() ? 38 : 0, 10],
})
: 10;

View File

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

View File

@@ -139,7 +139,7 @@ export default function HeaderContainer({
style={
// Avoid positioning the focused header absolutely
// Otherwise accessibility tools don't seem to be able to find it
(mode === 'float' || options.headerTransparent) && !isFocused
(mode === 'float' && !isFocused) || options.headerTransparent
? styles.header
: null
}

View File

@@ -37,14 +37,6 @@ type GestureValues = {
[key: string]: Animated.Value;
};
// @ts-ignore
const maybeExpoVersion = global.Expo?.Constants.manifest.sdkVersion.split(
'.'
)[0];
const isInsufficientExpoVersion = maybeExpoVersion
? Number(maybeExpoVersion) <= 36
: maybeExpoVersion === 'UNVERSIONED';
type Props = {
mode: StackCardMode;
insets: EdgeInsets;
@@ -82,37 +74,27 @@ type State = {
};
const EPSILON = 0.01;
const FAR_FAR_AWAY = 9000;
const dimensions = Dimensions.get('window');
const layout = { width: dimensions.width, height: dimensions.height };
const MaybeScreenContainer = ({
enabled,
style,
...rest
}: ViewProps & {
enabled: boolean;
children: React.ReactNode;
}) => {
if (enabled && screensEnabled()) {
return <ScreenContainer style={style} {...rest} />;
return <ScreenContainer {...rest} />;
}
return (
<View
collapsable={!enabled}
removeClippedSubviews={Platform.OS !== 'ios' && enabled}
style={[style, { overflow: 'hidden' }]}
{...rest}
/>
);
return <View {...rest} />;
};
const MaybeScreen = ({
enabled,
active,
style,
...rest
}: ViewProps & {
enabled: boolean;
@@ -121,39 +103,10 @@ const MaybeScreen = ({
}) => {
if (enabled && screensEnabled()) {
// @ts-ignore
return <Screen active={active} style={style} {...rest} />;
return <Screen active={active} {...rest} />;
}
return (
<Animated.View
style={[
style,
{
overflow: 'hidden',
// Position the screen offscreen to take advantage of offscreen perf optimization
// https://facebook.github.io/react-native/docs/view#removeclippedsubviews
// This can be useful if screens is not enabled
// It's buggy on iOS, so we don't enable it there
top:
enabled && typeof active === 'number' && !active ? FAR_FAR_AWAY : 0,
transform: [
{
// If the `active` prop is animated node, we can't use the `left` property due to native driver
// So we use `translateY` instead
translateY:
enabled && typeof active !== 'number'
? active.interpolate({
inputRange: [0, 1],
outputRange: [FAR_FAR_AWAY, 0],
})
: 0,
},
],
},
]}
{...rest}
/>
);
return <View {...rest} />;
};
const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
@@ -450,9 +403,7 @@ export default class CardStack extends React.Component<Props, State> {
// Screens is buggy on iOS, so we don't enable it there
// For modals, usually we want the screen underneath to be visible, so also disable it there
const isScreensEnabled =
Platform.OS !== 'ios' &&
(isInsufficientExpoVersion ? mode !== 'modal' : true);
const isScreensEnabled = Platform.OS !== 'ios' && mode !== 'modal';
return (
<React.Fragment>
@@ -466,26 +417,13 @@ export default class CardStack extends React.Component<Props, State> {
const gesture = gestures[route.key];
const scene = scenes[index];
// Display current screen and a screen beneath.
let isScreenActive: Animated.AnimatedInterpolation | 0 | 1 =
index >= self.length - 2 ? 1 : 0;
if (isInsufficientExpoVersion) {
isScreenActive =
index === self.length - 1
? 1
: Platform.OS === 'android'
? scene.progress.next
? scene.progress.next.interpolate({
inputRange: [0, 1 - EPSILON, 1],
outputRange: [1, 1, 0],
extrapolate: 'clamp',
})
: 1
: index === self.length - 2
? 1
: 0;
}
const isScreenActive = scene.progress.next
? scene.progress.next.interpolate({
inputRange: [0, 1 - EPSILON, 1],
outputRange: [1, 1, 0],
extrapolate: 'clamp',
})
: 1;
const {
safeAreaInsets,