Compare commits
22 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31565d5576 | ||
|
|
2c31d1705c | ||
|
|
8f9a250958 | ||
|
|
87d28ca430 | ||
|
|
fa4411a14d | ||
|
|
77b757091c | ||
|
|
6b9b999c5b | ||
|
|
8c5f84094f | ||
|
|
21709f7674 | ||
|
|
22742e4a7f | ||
|
|
3cd1aedcf4 | ||
|
|
797d3a798e | ||
|
|
59803f54d6 | ||
|
|
935659899f | ||
|
|
ef0f5d6567 | ||
|
|
499f66dba4 | ||
|
|
2ef2f1a86f | ||
|
|
0252bdc222 | ||
|
|
282f62c258 | ||
|
|
f462d67270 | ||
|
|
873afec9fe | ||
|
|
878297e52f |
@@ -13,5 +13,8 @@ module.exports = {
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
],
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 900 B |
@@ -28,6 +28,7 @@
|
||||
"react-dom": "~16.9.0",
|
||||
"react-native": "~0.61.5",
|
||||
"react-native-gesture-handler": "~1.5.0",
|
||||
"react-native-iphone-x-helper": "^1.2.1",
|
||||
"react-native-paper": "^3.3.0",
|
||||
"react-native-reanimated": "^1.4.0",
|
||||
"react-native-safe-area-context": "^0.6.0",
|
||||
|
||||
@@ -16,10 +16,10 @@ const getTabBarIcon = (name: string) => ({
|
||||
}) => <MaterialCommunityIcons name={name} color={color} size={size} />;
|
||||
|
||||
type BottomTabParams = {
|
||||
article: undefined;
|
||||
albums: undefined;
|
||||
contacts: undefined;
|
||||
chat: undefined;
|
||||
Article: undefined;
|
||||
Albums: undefined;
|
||||
Contacts: undefined;
|
||||
Chat: undefined;
|
||||
};
|
||||
|
||||
const BottomTabs = createBottomTabNavigator<BottomTabParams>();
|
||||
@@ -32,7 +32,7 @@ export default function BottomTabsScreen() {
|
||||
}}
|
||||
>
|
||||
<BottomTabs.Screen
|
||||
name="article"
|
||||
name="Article"
|
||||
options={{
|
||||
title: 'Article',
|
||||
tabBarIcon: getTabBarIcon('file-document-box'),
|
||||
@@ -41,7 +41,7 @@ export default function BottomTabsScreen() {
|
||||
{props => <SimpleStackScreen {...props} headerMode="none" />}
|
||||
</BottomTabs.Screen>
|
||||
<BottomTabs.Screen
|
||||
name="chat"
|
||||
name="Chat"
|
||||
component={Chat}
|
||||
options={{
|
||||
tabBarLabel: 'Chat',
|
||||
@@ -49,7 +49,7 @@ export default function BottomTabsScreen() {
|
||||
}}
|
||||
/>
|
||||
<BottomTabs.Screen
|
||||
name="contacts"
|
||||
name="Contacts"
|
||||
component={Contacts}
|
||||
options={{
|
||||
title: 'Contacts',
|
||||
@@ -57,7 +57,7 @@ export default function BottomTabsScreen() {
|
||||
}}
|
||||
/>
|
||||
<BottomTabs.Screen
|
||||
name="albums"
|
||||
name="Albums"
|
||||
component={Albums}
|
||||
options={{
|
||||
title: 'Albums',
|
||||
|
||||
@@ -7,10 +7,10 @@ import Chat from '../Shared/Chat';
|
||||
import SimpleStackScreen from './SimpleStack';
|
||||
|
||||
type MaterialBottomTabParams = {
|
||||
article: undefined;
|
||||
albums: undefined;
|
||||
contacts: undefined;
|
||||
chat: undefined;
|
||||
Article: undefined;
|
||||
Albums: undefined;
|
||||
Contacts: undefined;
|
||||
Chat: undefined;
|
||||
};
|
||||
|
||||
const MaterialBottomTabs = createMaterialBottomTabNavigator<
|
||||
@@ -21,7 +21,7 @@ export default function MaterialBottomTabsScreen() {
|
||||
return (
|
||||
<MaterialBottomTabs.Navigator barStyle={styles.tabBar}>
|
||||
<MaterialBottomTabs.Screen
|
||||
name="article"
|
||||
name="Article"
|
||||
options={{
|
||||
tabBarLabel: 'Article',
|
||||
tabBarIcon: 'file-document-box',
|
||||
@@ -31,7 +31,7 @@ export default function MaterialBottomTabsScreen() {
|
||||
{props => <SimpleStackScreen {...props} headerMode="none" />}
|
||||
</MaterialBottomTabs.Screen>
|
||||
<MaterialBottomTabs.Screen
|
||||
name="chat"
|
||||
name="Chat"
|
||||
component={Chat}
|
||||
options={{
|
||||
tabBarLabel: 'Chat',
|
||||
@@ -41,7 +41,7 @@ export default function MaterialBottomTabsScreen() {
|
||||
}}
|
||||
/>
|
||||
<MaterialBottomTabs.Screen
|
||||
name="contacts"
|
||||
name="Contacts"
|
||||
component={Contacts}
|
||||
options={{
|
||||
tabBarLabel: 'Contacts',
|
||||
@@ -50,7 +50,7 @@ export default function MaterialBottomTabsScreen() {
|
||||
}}
|
||||
/>
|
||||
<MaterialBottomTabs.Screen
|
||||
name="albums"
|
||||
name="Albums"
|
||||
component={Albums}
|
||||
options={{
|
||||
tabBarLabel: 'Albums',
|
||||
|
||||
@@ -5,9 +5,9 @@ import Contacts from '../Shared/Contacts';
|
||||
import Chat from '../Shared/Chat';
|
||||
|
||||
type MaterialTopTabParams = {
|
||||
albums: undefined;
|
||||
contacts: undefined;
|
||||
chat: undefined;
|
||||
Albums: undefined;
|
||||
Contacts: undefined;
|
||||
Chat: undefined;
|
||||
};
|
||||
|
||||
const MaterialTopTabs = createMaterialTopTabNavigator<MaterialTopTabParams>();
|
||||
@@ -16,17 +16,17 @@ export default function MaterialTopTabsScreen() {
|
||||
return (
|
||||
<MaterialTopTabs.Navigator>
|
||||
<MaterialTopTabs.Screen
|
||||
name="chat"
|
||||
name="Chat"
|
||||
component={Chat}
|
||||
options={{ title: 'Chat' }}
|
||||
/>
|
||||
<MaterialTopTabs.Screen
|
||||
name="contacts"
|
||||
name="Contacts"
|
||||
component={Contacts}
|
||||
options={{ title: 'Contacts' }}
|
||||
/>
|
||||
<MaterialTopTabs.Screen
|
||||
name="albums"
|
||||
name="Albums"
|
||||
component={Albums}
|
||||
options={{ title: 'Albums' }}
|
||||
/>
|
||||
|
||||
@@ -11,19 +11,19 @@ import {
|
||||
import Article from '../Shared/Article';
|
||||
import Albums from '../Shared/Albums';
|
||||
|
||||
type SimpleStackParams = {
|
||||
article: { author: string };
|
||||
album: undefined;
|
||||
type ModalStackParams = {
|
||||
Article: { author: string };
|
||||
Album: undefined;
|
||||
};
|
||||
|
||||
type SimpleStackNavigation = StackNavigationProp<SimpleStackParams>;
|
||||
type ModalStackNavigation = StackNavigationProp<ModalStackParams>;
|
||||
|
||||
const ArticleScreen = ({
|
||||
navigation,
|
||||
route,
|
||||
}: {
|
||||
navigation: SimpleStackNavigation;
|
||||
route: RouteProp<SimpleStackParams, 'article'>;
|
||||
navigation: ModalStackNavigation;
|
||||
route: RouteProp<ModalStackParams, 'Article'>;
|
||||
}) => {
|
||||
const insets = useSafeArea();
|
||||
|
||||
@@ -32,7 +32,7 @@ const ArticleScreen = ({
|
||||
<View style={[styles.buttons, { marginTop: insets.top }]}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('album')}
|
||||
onPress={() => navigation.push('Album')}
|
||||
style={styles.button}
|
||||
>
|
||||
Push album
|
||||
@@ -50,11 +50,7 @@ const ArticleScreen = ({
|
||||
);
|
||||
};
|
||||
|
||||
const AlbumsScreen = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: SimpleStackNavigation;
|
||||
}) => {
|
||||
const AlbumsScreen = ({ navigation }: { navigation: ModalStackNavigation }) => {
|
||||
const insets = useSafeArea();
|
||||
|
||||
return (
|
||||
@@ -62,7 +58,7 @@ const AlbumsScreen = ({
|
||||
<View style={[styles.buttons, { marginTop: insets.top }]}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('article', { author: 'Babel fish' })}
|
||||
onPress={() => navigation.push('Article', { author: 'Babel fish' })}
|
||||
style={styles.button}
|
||||
>
|
||||
Push article
|
||||
@@ -80,7 +76,7 @@ const AlbumsScreen = ({
|
||||
);
|
||||
};
|
||||
|
||||
const ModalPresentationStack = createStackNavigator<SimpleStackParams>();
|
||||
const ModalPresentationStack = createStackNavigator<ModalStackParams>();
|
||||
|
||||
type Props = {
|
||||
options?: React.ComponentProps<typeof ModalPresentationStack.Navigator>;
|
||||
@@ -104,7 +100,7 @@ export default function SimpleStackScreen({ navigation, options }: Props) {
|
||||
{...options}
|
||||
>
|
||||
<ModalPresentationStack.Screen
|
||||
name="article"
|
||||
name="Article"
|
||||
component={ArticleScreen}
|
||||
options={({ route }) => ({
|
||||
title: `Article by ${route.params.author}`,
|
||||
@@ -112,7 +108,7 @@ export default function SimpleStackScreen({ navigation, options }: Props) {
|
||||
initialParams={{ author: 'Gandalf' }}
|
||||
/>
|
||||
<ModalPresentationStack.Screen
|
||||
name="album"
|
||||
name="Album"
|
||||
component={AlbumsScreen}
|
||||
options={{ title: 'Album' }}
|
||||
/>
|
||||
|
||||
@@ -18,8 +18,8 @@ import {
|
||||
import Albums from '../Shared/Albums';
|
||||
|
||||
type NativeStackParams = {
|
||||
article: { author: string };
|
||||
album: undefined;
|
||||
Article: { author: string };
|
||||
Album: undefined;
|
||||
};
|
||||
|
||||
type NativeStackNavigation = NativeStackNavigationProp<NativeStackParams>;
|
||||
@@ -42,7 +42,7 @@ const ArticleScreen = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: NativeStackNavigation;
|
||||
route: RouteProp<NativeStackParams, 'article'>;
|
||||
route: RouteProp<NativeStackParams, 'Article'>;
|
||||
}) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
@@ -54,7 +54,7 @@ const ArticleScreen = ({
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('album')}
|
||||
onPress={() => navigation.push('Album')}
|
||||
style={styles.button}
|
||||
>
|
||||
Push album
|
||||
@@ -141,7 +141,7 @@ const AlbumsScreen = ({
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('article', { author: 'Babel fish' })}
|
||||
onPress={() => navigation.push('Article', { author: 'Babel fish' })}
|
||||
style={styles.button}
|
||||
>
|
||||
Push article
|
||||
@@ -188,7 +188,7 @@ export default function NativeStackScreen({ navigation }: Props) {
|
||||
return (
|
||||
<NativeStack.Navigator>
|
||||
<NativeStack.Screen
|
||||
name="article"
|
||||
name="Article"
|
||||
component={ArticleScreen}
|
||||
options={{
|
||||
title: 'Lorem Ipsum',
|
||||
@@ -197,7 +197,7 @@ export default function NativeStackScreen({ navigation }: Props) {
|
||||
}}
|
||||
/>
|
||||
<NativeStack.Screen
|
||||
name="album"
|
||||
name="Album"
|
||||
component={AlbumsScreen}
|
||||
options={{ title: 'Album' }}
|
||||
/>
|
||||
|
||||
@@ -10,8 +10,8 @@ import Article from '../Shared/Article';
|
||||
import Albums from '../Shared/Albums';
|
||||
|
||||
type SimpleStackParams = {
|
||||
article: { author: string };
|
||||
album: undefined;
|
||||
Article: { author: string };
|
||||
Album: undefined;
|
||||
};
|
||||
|
||||
type SimpleStackNavigation = StackNavigationProp<SimpleStackParams>;
|
||||
@@ -21,14 +21,14 @@ const ArticleScreen = ({
|
||||
route,
|
||||
}: {
|
||||
navigation: SimpleStackNavigation;
|
||||
route: RouteProp<SimpleStackParams, 'article'>;
|
||||
route: RouteProp<SimpleStackParams, 'Article'>;
|
||||
}) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('album')}
|
||||
onPress={() => navigation.push('Album')}
|
||||
style={styles.button}
|
||||
>
|
||||
Push album
|
||||
@@ -56,7 +56,7 @@ const AlbumsScreen = ({
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('article', { author: 'Babel fish' })}
|
||||
onPress={() => navigation.push('Article', { author: 'Babel fish' })}
|
||||
style={styles.button}
|
||||
>
|
||||
Push article
|
||||
@@ -88,7 +88,7 @@ export default function SimpleStackScreen({ navigation, ...rest }: Props) {
|
||||
return (
|
||||
<SimpleStack.Navigator {...rest}>
|
||||
<SimpleStack.Screen
|
||||
name="article"
|
||||
name="Article"
|
||||
component={ArticleScreen}
|
||||
options={({ route }) => ({
|
||||
title: `Article by ${route.params.author}`,
|
||||
@@ -96,7 +96,7 @@ export default function SimpleStackScreen({ navigation, ...rest }: Props) {
|
||||
initialParams={{ author: 'Gandalf' }}
|
||||
/>
|
||||
<SimpleStack.Screen
|
||||
name="album"
|
||||
name="Album"
|
||||
component={AlbumsScreen}
|
||||
options={{ title: 'Album' }}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
|
||||
import * as React from 'react';
|
||||
import { Image, Dimensions, ScrollView, StyleSheet } from 'react-native';
|
||||
import { useScrollToTop } from '@react-navigation/native';
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
import { Asset } from 'expo-asset';
|
||||
import {
|
||||
InitialState,
|
||||
getStateFromPath,
|
||||
useLinking,
|
||||
NavigationContainerRef,
|
||||
NavigationNativeContainer,
|
||||
@@ -104,20 +103,19 @@ export default function App() {
|
||||
// The first segment of the link is the the scheme + host (returned by `Linking.makeUrl`)
|
||||
const { getInitialState } = useLinking(containerRef, {
|
||||
prefixes: LinkingPrefixes,
|
||||
getStateFromPath: path => {
|
||||
const state = getStateFromPath(path);
|
||||
config: {
|
||||
Root: Object.keys(SCREENS).reduce<{ [key: string]: string }>(
|
||||
(acc, name) => {
|
||||
// Convert screen names such as SimpleStack to kebab case (simple-stack)
|
||||
acc[name] = name
|
||||
.replace(/([A-Z]+)/g, '-$1')
|
||||
.replace(/^-/, '')
|
||||
.toLowerCase();
|
||||
|
||||
return {
|
||||
routes: [
|
||||
{
|
||||
name: 'root',
|
||||
state: {
|
||||
...state,
|
||||
routes: [{ name: 'home' }, ...(state ? state.routes : [])],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -252,19 +250,19 @@ export default function App() {
|
||||
/>
|
||||
</View>
|
||||
<Divider />
|
||||
{(Object.keys(SCREENS) as Array<
|
||||
keyof typeof SCREENS
|
||||
>).map(name => (
|
||||
<List.Item
|
||||
key={name}
|
||||
title={SCREENS[name].title}
|
||||
onPress={() => navigation.push(name)}
|
||||
/>
|
||||
))}
|
||||
{(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map(
|
||||
name => (
|
||||
<List.Item
|
||||
key={name}
|
||||
title={SCREENS[name].title}
|
||||
onPress={() => navigation.push(name)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</ScrollView>
|
||||
)}
|
||||
</Stack.Screen>
|
||||
{(Object.keys(SCREENS) as Array<keyof typeof SCREENS>).map(
|
||||
{(Object.keys(SCREENS) as (keyof typeof SCREENS)[]).map(
|
||||
name => (
|
||||
<Stack.Screen
|
||||
key={name}
|
||||
|
||||
@@ -2,7 +2,7 @@ const error = console.error;
|
||||
|
||||
console.error = (...args) =>
|
||||
// Supress error messages regarding error boundary in tests
|
||||
/Consider adding an error boundary to your tree to customize error handling behavior/m.test(
|
||||
/(Consider adding an error boundary to your tree to customize error handling behavior|React will try to recreate this component tree from scratch using the error boundary you provided|Error boundaries should implement getDerivedStateFromError)/m.test(
|
||||
args[0]
|
||||
)
|
||||
? void 0
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.7.0",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.7.5",
|
||||
"@babel/preset-env": "^7.7.6",
|
||||
"@babel/preset-react": "^7.7.0",
|
||||
"@babel/preset-typescript": "^7.7.2",
|
||||
@@ -34,7 +35,7 @@
|
||||
"commitlint": "^8.2.0",
|
||||
"core-js": "^3.5.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-config-satya164": "^3.1.2",
|
||||
"eslint-config-satya164": "^3.1.5",
|
||||
"husky": "^3.0.9",
|
||||
"jest": "^24.8.0",
|
||||
"lerna": "^3.18.4",
|
||||
|
||||
@@ -3,6 +3,33 @@
|
||||
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.31](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.30...@react-navigation/bottom-tabs@5.0.0-alpha.31) (2020-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* provide initial values for safe area to prevent blank screen ([#238](https://github.com/react-navigation/navigation-ex/issues/238)) ([77b7570](https://github.com/react-navigation/navigation-ex/commit/77b757091c0451e20bca01138629669c7da544a8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.30](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.29...@react-navigation/bottom-tabs@5.0.0-alpha.30) (2020-01-03)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.28...@react-navigation/bottom-tabs@5.0.0-alpha.29) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.28](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/bottom-tabs@5.0.0-alpha.27...@react-navigation/bottom-tabs@5.0.0-alpha.28) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"android",
|
||||
"tab"
|
||||
],
|
||||
"version": "5.0.0-alpha.28",
|
||||
"version": "5.0.0-alpha.31",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -33,8 +33,9 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.18",
|
||||
"color": "^3.1.2"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.19",
|
||||
"color": "^3.1.2",
|
||||
"react-native-iphone-x-helper": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
@@ -51,7 +52,7 @@
|
||||
"@react-navigation/native": "^5.0.0-alpha.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": "^0.3.6"
|
||||
"react-native-safe-area-context": "^0.6.0"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
"source": "src",
|
||||
|
||||
@@ -14,7 +14,7 @@ const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view o
|
||||
|
||||
export default class ResourceSavingScene extends React.Component<Props> {
|
||||
render() {
|
||||
if (screensEnabled && screensEnabled()) {
|
||||
if (screensEnabled?.()) {
|
||||
const { isVisible, ...rest } = this.props;
|
||||
// @ts-ignore
|
||||
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
||||
|
||||
@@ -3,6 +3,17 @@ import {
|
||||
SafeAreaProvider,
|
||||
SafeAreaConsumer,
|
||||
} from 'react-native-safe-area-context';
|
||||
import {
|
||||
getStatusBarHeight,
|
||||
getBottomSpace,
|
||||
} from 'react-native-iphone-x-helper';
|
||||
|
||||
const initialSafeAreaInsets = {
|
||||
top: getStatusBarHeight(true),
|
||||
bottom: getBottomSpace(),
|
||||
right: 0,
|
||||
left: 0,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
@@ -19,7 +30,11 @@ export default function SafeAreaProviderCompat({ children }: Props) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return <SafeAreaProvider>{children}</SafeAreaProvider>;
|
||||
return (
|
||||
<SafeAreaProvider initialSafeAreaInsets={initialSafeAreaInsets}>
|
||||
{children}
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}}
|
||||
</SafeAreaConsumer>
|
||||
);
|
||||
|
||||
@@ -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.20](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.19...@react-navigation/compat@5.0.0-alpha.20) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/compat
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/compat@5.0.0-alpha.18...@react-navigation/compat@5.0.0-alpha.19) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/compat
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@react-navigation/compat",
|
||||
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
||||
"version": "5.0.0-alpha.19",
|
||||
"version": "5.0.0-alpha.20",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -24,7 +24,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.18"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.9.16",
|
||||
|
||||
@@ -25,7 +25,7 @@ export function navigate({
|
||||
}
|
||||
|
||||
export function back(options?: { key?: null | string }) {
|
||||
return options && options.key != null
|
||||
return options?.key != null
|
||||
? (state: NavigationState) => ({
|
||||
...CommonActions.goBack(),
|
||||
source: options.key,
|
||||
|
||||
@@ -109,17 +109,17 @@ export default function createCompatNavigationProp<
|
||||
break;
|
||||
case 'didFocus': {
|
||||
const unsubscribe = focusSubscriptions.get(callback);
|
||||
unsubscribe && unsubscribe();
|
||||
unsubscribe?.();
|
||||
break;
|
||||
}
|
||||
case 'didBlur': {
|
||||
const unsubscribe = blurSubscriptions.get(callback);
|
||||
unsubscribe && unsubscribe();
|
||||
unsubscribe?.();
|
||||
break;
|
||||
}
|
||||
case 'refocus': {
|
||||
const unsubscribe = refocusSubscriptions.get(callback);
|
||||
unsubscribe && unsubscribe();
|
||||
unsubscribe?.();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -47,7 +47,7 @@ export default function createCompatNavigatorFactory<
|
||||
>(
|
||||
routeConfig: CompatRouteConfig<NavigationPropType>,
|
||||
navigationConfig: Partial<Omit<NavigationConfig, 'screenOptions'>> & {
|
||||
order?: Array<Extract<keyof ParamList, string>>;
|
||||
order?: Extract<keyof ParamList, string>[];
|
||||
defaultNavigationOptions?: ScreenOptions;
|
||||
navigationOptions?: Record<string, any>;
|
||||
} = {}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
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.30](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.29...@react-navigation/core@5.0.0-alpha.30) (2020-01-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cleanup transaction even if action wasn't handled ([f462d67](https://github.com/react-navigation/navigation-ex/commit/f462d672708cabfb0477c3a48505bd194ea626fd))
|
||||
* show error if an action was not handled ([0252bdc](https://github.com/react-navigation/navigation-ex/commit/0252bdc2222ebe7410a0ed593bf03b2bdf5dc7ca))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/core@5.0.0-alpha.28...@react-navigation/core@5.0.0-alpha.29) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/core
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"react-native",
|
||||
"react-navigation"
|
||||
],
|
||||
"version": "5.0.0-alpha.29",
|
||||
"version": "5.0.0-alpha.30",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { NavigationState, PartialState } from './types';
|
||||
|
||||
export type Action =
|
||||
|
||||
@@ -123,9 +123,11 @@ const Container = React.forwardRef(function NavigationContainer(
|
||||
isTransactionActiveRef.current = true;
|
||||
transactionStateRef.current = navigationState;
|
||||
|
||||
callback();
|
||||
|
||||
isTransactionActiveRef.current = false;
|
||||
try {
|
||||
callback();
|
||||
} finally {
|
||||
isTransactionActiveRef.current = false;
|
||||
}
|
||||
|
||||
return transactionStateRef.current;
|
||||
});
|
||||
@@ -202,7 +204,7 @@ const Container = React.forwardRef(function NavigationContainer(
|
||||
}, [getStateForRoute]);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
...(Object.keys(CommonActions) as Array<keyof typeof CommonActions>).reduce<
|
||||
...(Object.keys(CommonActions) as (keyof typeof CommonActions)[]).reduce<
|
||||
any
|
||||
>((acc, name) => {
|
||||
acc[name] = (...args: any[]) =>
|
||||
|
||||
75
packages/core/src/__tests__/getActionFromState.test.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import getActionFromState from '../getActionFromState';
|
||||
|
||||
it('gets navigate action from state', () => {
|
||||
const state = {
|
||||
routes: [
|
||||
{
|
||||
name: 'foo',
|
||||
state: {
|
||||
routes: [
|
||||
{
|
||||
name: 'bar',
|
||||
params: { answer: 42 },
|
||||
state: {
|
||||
routes: [
|
||||
{
|
||||
name: 'qux',
|
||||
params: { author: 'jane' },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(getActionFromState(state)).toEqual({
|
||||
payload: {
|
||||
name: 'foo',
|
||||
params: {
|
||||
params: {
|
||||
answer: 42,
|
||||
params: {
|
||||
author: 'jane',
|
||||
},
|
||||
screen: 'qux',
|
||||
},
|
||||
screen: 'bar',
|
||||
},
|
||||
},
|
||||
type: 'NAVIGATE',
|
||||
});
|
||||
});
|
||||
|
||||
it('gets reset action from state', () => {
|
||||
const state = {
|
||||
routes: [
|
||||
{
|
||||
name: 'foo',
|
||||
state: {
|
||||
routes: [
|
||||
{
|
||||
name: 'bar',
|
||||
state: {
|
||||
routes: [
|
||||
{
|
||||
name: 'qux',
|
||||
params: { author: 'jane' },
|
||||
},
|
||||
{ name: 'quz' },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(getActionFromState(state)).toEqual({
|
||||
payload: state,
|
||||
type: 'RESET_ROOT',
|
||||
});
|
||||
});
|
||||
@@ -357,6 +357,8 @@ it("doesn't update state if action wasn't handled", () => {
|
||||
|
||||
const onStateChange = jest.fn();
|
||||
|
||||
const spy = jest.spyOn(console, 'error').mockImplementation();
|
||||
|
||||
render(
|
||||
<NavigationContainer onStateChange={onStateChange}>
|
||||
<TestNavigator initialRouteName="foo">
|
||||
@@ -367,6 +369,12 @@ 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."
|
||||
);
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it('cleans up state when the navigator unmounts', () => {
|
||||
|
||||
@@ -305,8 +305,7 @@ it("action doesn't bubble if target is specified", () => {
|
||||
expect(onStateChange).not.toBeCalled();
|
||||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it("doesn't crash if no navigator handled the action", () => {
|
||||
it('logs error if no navigator handled the action', () => {
|
||||
const TestRouter = MockRouter;
|
||||
|
||||
const TestNavigator = (props: any) => {
|
||||
@@ -366,5 +365,13 @@ it("doesn't crash if no navigator handled the action", () => {
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
const spy = jest.spyOn(console, 'error').mockImplementation();
|
||||
|
||||
render(element).update(element);
|
||||
|
||||
expect(spy.mock.calls[0][0]).toMatch(
|
||||
"The action 'UNKNOWN' with payload 'undefined' was not handled by any navigator."
|
||||
);
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ it('gets route prop from context', () => {
|
||||
const Test = () => {
|
||||
const route = useRoute<RouteProp<{ sample: { x: string } }, 'sample'>>();
|
||||
|
||||
expect(route && route.params && route.params.x).toEqual(1);
|
||||
expect(route?.params?.x).toEqual(1);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
67
packages/core/src/getActionFromState.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { PartialState, NavigationState } from './types';
|
||||
|
||||
type NavigateParams = {
|
||||
screen?: string;
|
||||
params?: NavigateParams;
|
||||
};
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: 'NAVIGATE';
|
||||
payload: { name: string; params: NavigateParams };
|
||||
}
|
||||
| {
|
||||
type: 'RESET_ROOT';
|
||||
payload: PartialState<NavigationState>;
|
||||
};
|
||||
|
||||
export default function getActionFromState(
|
||||
state: PartialState<NavigationState>
|
||||
): Action {
|
||||
let payload: { name: string; params: NavigateParams } | undefined;
|
||||
|
||||
if (state.routes.length === 1) {
|
||||
// Try to construct payload for a `NAVIGATE` action from the state
|
||||
// This lets us preserve the navigation state and not lose it
|
||||
let route = state.routes[0];
|
||||
|
||||
payload = {
|
||||
name: route.name,
|
||||
params: { ...route.params },
|
||||
};
|
||||
|
||||
let current = state.routes[0].state;
|
||||
let params = payload.params;
|
||||
|
||||
while (current) {
|
||||
if (current.routes.length === 1) {
|
||||
route = current.routes[0];
|
||||
params.screen = route.name;
|
||||
|
||||
if (route.state) {
|
||||
params.params = { ...route.params };
|
||||
params = params.params;
|
||||
} else {
|
||||
params.params = route.params;
|
||||
}
|
||||
|
||||
current = route.state;
|
||||
} else {
|
||||
payload = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (payload) {
|
||||
return {
|
||||
type: 'NAVIGATE',
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'RESET_ROOT',
|
||||
payload: state,
|
||||
};
|
||||
}
|
||||
@@ -60,7 +60,7 @@ export default function getPathFromState(
|
||||
Object.entries(route.params).reduce<{
|
||||
[key: string]: string;
|
||||
}>((acc, [key, value]) => {
|
||||
acc[key] = config && config[key] ? config[key](value) : String(value);
|
||||
acc[key] = config?.[key] ? config[key](value) : String(value);
|
||||
return acc;
|
||||
}, {})
|
||||
: undefined;
|
||||
@@ -80,6 +80,7 @@ export default function getPathFromState(
|
||||
if (params && name in params && p.startsWith(':')) {
|
||||
const value = params[name];
|
||||
// Remove the used value from the params object since we'll use the rest for query string
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete params[name];
|
||||
return encodeURIComponent(value);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ type RouteConfig = {
|
||||
parse: Record<string, (value: string) => any> | undefined;
|
||||
};
|
||||
|
||||
type ResultState = PartialState<NavigationState> & {
|
||||
state?: ResultState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility to parse a path string to initial state object accepted by the container.
|
||||
* This is useful for deep linking when we need to handle the incoming URL.
|
||||
@@ -37,7 +41,7 @@ type RouteConfig = {
|
||||
export default function getStateFromPath(
|
||||
path: string,
|
||||
options: Options = {}
|
||||
): PartialState<NavigationState> | undefined {
|
||||
): ResultState | undefined {
|
||||
// Create a normalized configs array which will be easier to use
|
||||
const configs = ([] as RouteConfig[]).concat(
|
||||
...Object.keys(options).map(key => createNormalizedConfigs(key, options))
|
||||
|
||||
@@ -17,5 +17,6 @@ export { default as useIsFocused } from './useIsFocused';
|
||||
|
||||
export { default as getStateFromPath } from './getStateFromPath';
|
||||
export { default as getPathFromState } from './getPathFromState';
|
||||
export { default as getActionFromState } from './getActionFromState';
|
||||
|
||||
export * from './types';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import * as CommonActions from './CommonActions';
|
||||
import * as React from 'react';
|
||||
|
||||
@@ -20,9 +19,9 @@ export type NavigationState = {
|
||||
/**
|
||||
* List of rendered routes.
|
||||
*/
|
||||
routes: Array<
|
||||
Route<string> & { state?: NavigationState | PartialState<NavigationState> }
|
||||
>;
|
||||
routes: (Route<string> & {
|
||||
state?: NavigationState | PartialState<NavigationState>;
|
||||
})[];
|
||||
/**
|
||||
* Custom type for the state, whether it's for tab, stack, drawer etc.
|
||||
* During rehydration, the state will be discarded if type doesn't match with router type.
|
||||
@@ -38,7 +37,7 @@ export type NavigationState = {
|
||||
export type InitialState = Partial<
|
||||
Omit<NavigationState, 'stale' | 'routes'>
|
||||
> & {
|
||||
routes: Array<Omit<Route<string>, 'key'> & { state?: InitialState }>;
|
||||
routes: (Omit<Route<string>, 'key'> & { state?: InitialState })[];
|
||||
};
|
||||
|
||||
export type PartialState<State extends NavigationState> = Partial<
|
||||
@@ -46,9 +45,10 @@ export type PartialState<State extends NavigationState> = Partial<
|
||||
> & {
|
||||
stale?: true;
|
||||
type?: string;
|
||||
routes: Array<
|
||||
Omit<Route<string>, 'key'> & { key?: string; state?: InitialState }
|
||||
>;
|
||||
routes: (Omit<Route<string>, 'key'> & {
|
||||
key?: string;
|
||||
state?: InitialState;
|
||||
})[];
|
||||
};
|
||||
|
||||
export type Route<RouteName extends string> = {
|
||||
@@ -71,6 +71,10 @@ export type NavigationAction = {
|
||||
* Type of the action (e.g. `NAVIGATE`)
|
||||
*/
|
||||
type: string;
|
||||
/**
|
||||
* Additional data for the action
|
||||
*/
|
||||
payload?: object;
|
||||
/**
|
||||
* Key of the route which dispatched this action.
|
||||
*/
|
||||
|
||||
@@ -44,16 +44,15 @@ export default function useDevTools({ name, reset, state }: Options) {
|
||||
|
||||
const devTools = devToolsRef.current;
|
||||
const lastStateRef = React.useRef<State>(state);
|
||||
const actions = React.useRef<Array<NavigationAction | string>>([]);
|
||||
const actions = React.useRef<(NavigationAction | string)[]>([]);
|
||||
|
||||
React.useEffect(() => {
|
||||
devTools && devTools.init(lastStateRef.current);
|
||||
devTools?.init(lastStateRef.current);
|
||||
}, [devTools]);
|
||||
|
||||
React.useEffect(
|
||||
() =>
|
||||
devTools &&
|
||||
devTools.subscribe(message => {
|
||||
devTools?.subscribe(message => {
|
||||
if (message.type === 'DISPATCH' && message.state) {
|
||||
reset(JSON.parse(message.state));
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ export type NavigationEventEmitter = EventEmitter<Record<string, any>> & {
|
||||
create: (target: string) => EventConsumer<Record<string, any>>;
|
||||
};
|
||||
|
||||
type Listeners = Array<(data: any) => void>;
|
||||
type Listeners = ((data: any) => void)[];
|
||||
|
||||
/**
|
||||
* Hook to manage the event system used by the navigator to notify screens of various events.
|
||||
@@ -69,7 +69,7 @@ export default function useEventEmitter(): NavigationEventEmitter {
|
||||
},
|
||||
};
|
||||
|
||||
callbacks && callbacks.forEach(cb => cb(event));
|
||||
callbacks?.forEach(cb => cb(event));
|
||||
|
||||
return event;
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import useNavigation from './useNavigation';
|
||||
|
||||
type EffectCallback = (() => void) | (() => () => void);
|
||||
type EffectCallback = (() => undefined) | (() => () => void);
|
||||
|
||||
/**
|
||||
* Hook to run an effect in a focused screen, similar to `React.useEffect`.
|
||||
@@ -15,7 +15,7 @@ export default function useFocusEffect(callback: EffectCallback) {
|
||||
|
||||
React.useEffect(() => {
|
||||
let isFocused = false;
|
||||
let cleanup: (() => void) | void;
|
||||
let cleanup: (() => void) | undefined;
|
||||
|
||||
// We need to run the effect on intial render/dep changes if the screen is focused
|
||||
if (navigation.isFocused()) {
|
||||
@@ -30,19 +30,19 @@ export default function useFocusEffect(callback: EffectCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
cleanup && cleanup();
|
||||
cleanup?.();
|
||||
cleanup = callback();
|
||||
isFocused = true;
|
||||
});
|
||||
|
||||
const unsubscribeBlur = navigation.addListener('blur', () => {
|
||||
cleanup && cleanup();
|
||||
cleanup?.();
|
||||
cleanup = undefined;
|
||||
isFocused = false;
|
||||
});
|
||||
|
||||
return () => {
|
||||
cleanup && cleanup();
|
||||
cleanup?.();
|
||||
unsubscribeFocus();
|
||||
unsubscribeBlur();
|
||||
};
|
||||
|
||||
@@ -21,8 +21,7 @@ export default function useFocusEvents({ state, emitter }: Options) {
|
||||
// Coz the child screen can't be focused if the parent screen is out of fcous
|
||||
React.useEffect(
|
||||
() =>
|
||||
navigation &&
|
||||
navigation.addListener('focus', () =>
|
||||
navigation?.addListener('focus', () =>
|
||||
emitter.emit({ type: 'focus', target: currentFocusedKey })
|
||||
),
|
||||
[currentFocusedKey, emitter, navigation]
|
||||
@@ -30,8 +29,7 @@ export default function useFocusEvents({ state, emitter }: Options) {
|
||||
|
||||
React.useEffect(
|
||||
() =>
|
||||
navigation &&
|
||||
navigation.addListener('blur', () =>
|
||||
navigation?.addListener('blur', () =>
|
||||
emitter.emit({ type: 'blur', target: currentFocusedKey })
|
||||
),
|
||||
[currentFocusedKey, emitter, navigation]
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function useFocusedListenersChildrenAdapter({
|
||||
[focusedListeners, navigation]
|
||||
);
|
||||
|
||||
React.useEffect(() => addFocusedListener && addFocusedListener(listener), [
|
||||
React.useEffect(() => addFocusedListener?.(listener), [
|
||||
addFocusedListener,
|
||||
listener,
|
||||
]);
|
||||
|
||||
@@ -117,7 +117,7 @@ export default function useNavigationBuilder<
|
||||
const { current: router } = React.useRef<Router<State, any>>(
|
||||
createRouter({
|
||||
...((rest as unknown) as RouterOptions),
|
||||
...(route && route.params && typeof route.params.screen === 'string'
|
||||
...(route?.params && typeof route.params.screen === 'string'
|
||||
? { initialRouteName: route.params.screen }
|
||||
: null),
|
||||
})
|
||||
@@ -141,7 +141,7 @@ export default function useNavigationBuilder<
|
||||
(acc, curr) => {
|
||||
const { initialParams } = screens[curr];
|
||||
const initialParamsFromParams =
|
||||
route && route.params && route.params.screen === curr
|
||||
route?.params && route.params.screen === curr
|
||||
? route.params.params
|
||||
: undefined;
|
||||
|
||||
|
||||
@@ -42,13 +42,22 @@ export default function useNavigationHelpers<
|
||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||
|
||||
return React.useMemo(() => {
|
||||
const dispatch = (action: Action | ((state: State) => Action)) =>
|
||||
const dispatch = (action: Action | ((state: State) => Action)) => {
|
||||
performTransaction(() => {
|
||||
const payload =
|
||||
typeof action === 'function' ? action(getState()) : action;
|
||||
|
||||
onAction(payload);
|
||||
const handled = onAction(payload);
|
||||
|
||||
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.`
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const actions = {
|
||||
...router.actionCreators,
|
||||
@@ -81,7 +90,7 @@ export default function useNavigationHelpers<
|
||||
routeNames: state.routeNames,
|
||||
routeParamList: {},
|
||||
}) !== null ||
|
||||
(parentNavigationHelpers && parentNavigationHelpers.canGoBack()) ||
|
||||
parentNavigationHelpers?.canGoBack() ||
|
||||
false
|
||||
);
|
||||
},
|
||||
|
||||
@@ -130,10 +130,10 @@ export default function useOnAction({
|
||||
]
|
||||
);
|
||||
|
||||
React.useEffect(
|
||||
() => addActionListenerParent && addActionListenerParent(onAction),
|
||||
[addActionListenerParent, onAction]
|
||||
);
|
||||
React.useEffect(() => addActionListenerParent?.(onAction), [
|
||||
addActionListenerParent,
|
||||
onAction,
|
||||
]);
|
||||
|
||||
return onAction;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,6 @@ export default function useOnGetState({
|
||||
}, [getState, getStateForRoute]);
|
||||
|
||||
React.useEffect(() => {
|
||||
return addStateGetter && addStateGetter(key, getRehydratedState);
|
||||
return addStateGetter?.(key, getRehydratedState);
|
||||
}, [addStateGetter, getRehydratedState, key]);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,41 @@
|
||||
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.33](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.32...@react-navigation/drawer@5.0.0-alpha.33) (2020-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* provide initial values for safe area to prevent blank screen ([#238](https://github.com/react-navigation/navigation-ex/issues/238)) ([77b7570](https://github.com/react-navigation/navigation-ex/commit/77b757091c0451e20bca01138629669c7da544a8))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add interaction handle to drawer ([#239](https://github.com/react-navigation/navigation-ex/issues/239)) ([fa4411a](https://github.com/react-navigation/navigation-ex/commit/fa4411a14dc4aae568794e4b884088e3276a2876))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.32](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.31...@react-navigation/drawer@5.0.0-alpha.32) (2020-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* pass backBehavior to the router in drawer. fixes [#230](https://github.com/react-navigation/navigation-ex/issues/230) ([3cd1aed](https://github.com/react-navigation/navigation-ex/commit/3cd1aedcf490a4c7962b2d36873d714637f3b9b0))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.31](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.30...@react-navigation/drawer@5.0.0-alpha.31) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/drawer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.30](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/drawer@5.0.0-alpha.29...@react-navigation/drawer@5.0.0-alpha.30) (2019-12-19)
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"material",
|
||||
"drawer"
|
||||
],
|
||||
"version": "5.0.0-alpha.30",
|
||||
"version": "5.0.0-alpha.33",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -34,8 +34,9 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.18",
|
||||
"color": "^3.1.2"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.19",
|
||||
"color": "^3.1.2",
|
||||
"react-native-iphone-x-helper": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
|
||||
@@ -23,6 +23,7 @@ type Props = DefaultNavigatorOptions<DrawerNavigationOptions> &
|
||||
|
||||
function DrawerNavigator({
|
||||
initialRouteName,
|
||||
backBehavior,
|
||||
children,
|
||||
screenOptions,
|
||||
...rest
|
||||
@@ -34,6 +35,7 @@ function DrawerNavigator({
|
||||
DrawerNavigationEventMap
|
||||
>(DrawerRouter, {
|
||||
initialRouteName,
|
||||
backBehavior,
|
||||
children,
|
||||
screenOptions,
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
StatusBar,
|
||||
StyleProp,
|
||||
View,
|
||||
InteractionManager,
|
||||
} from 'react-native';
|
||||
import {
|
||||
PanGestureHandler,
|
||||
@@ -161,9 +162,24 @@ export default class DrawerView extends React.PureComponent<Props> {
|
||||
|
||||
componentWillUnmount() {
|
||||
this.toggleStatusBar(false);
|
||||
this.handleEndInteraction();
|
||||
}
|
||||
|
||||
private handleEndInteraction = () => {
|
||||
if (this.interactionHandle !== undefined) {
|
||||
InteractionManager.clearInteractionHandle(this.interactionHandle);
|
||||
this.interactionHandle = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
private handleStartInteraction = () => {
|
||||
if (this.interactionHandle === undefined) {
|
||||
this.interactionHandle = InteractionManager.createInteractionHandle();
|
||||
}
|
||||
};
|
||||
|
||||
private clock = new Clock();
|
||||
private interactionHandle: number | undefined;
|
||||
|
||||
private isDrawerTypeFront = new Value<Binary>(
|
||||
this.props.drawerType === 'front' ? TRUE : FALSE
|
||||
@@ -277,6 +293,7 @@ export default class DrawerView extends React.PureComponent<Props> {
|
||||
set(state.velocity, this.velocityX),
|
||||
set(this.isOpen, isOpen),
|
||||
startClock(this.clock),
|
||||
call([], this.handleStartInteraction),
|
||||
set(this.manuallyTriggerSpring, FALSE),
|
||||
]),
|
||||
spring(this.clock, state, { ...SPRING_CONFIG, toValue }),
|
||||
@@ -288,8 +305,9 @@ export default class DrawerView extends React.PureComponent<Props> {
|
||||
set(this.offsetX, 0),
|
||||
// When the animation finishes, stop the clock
|
||||
stopClock(this.clock),
|
||||
call([this.isOpen], ([value]: ReadonlyArray<Binary>) => {
|
||||
call([this.isOpen], ([value]: readonly Binary[]) => {
|
||||
const open = Boolean(value);
|
||||
this.handleEndInteraction();
|
||||
|
||||
if (open !== this.props.open) {
|
||||
// Sync drawer's state after animation finished
|
||||
@@ -304,7 +322,7 @@ export default class DrawerView extends React.PureComponent<Props> {
|
||||
private dragX = block([
|
||||
onChange(
|
||||
this.isOpen,
|
||||
call([this.isOpen], ([value]: ReadonlyArray<Binary>) => {
|
||||
call([this.isOpen], ([value]: readonly Binary[]) => {
|
||||
const open = Boolean(value);
|
||||
|
||||
this.currentOpenValue = open;
|
||||
@@ -344,7 +362,7 @@ export default class DrawerView extends React.PureComponent<Props> {
|
||||
// Listen to updates for this value only when it changes
|
||||
// Without `onChange`, this will fire even if the value didn't change
|
||||
// We don't want to call the listeners if the value didn't change
|
||||
call([this.isSwiping], ([value]: ReadonlyArray<Binary>) => {
|
||||
call([this.isSwiping], ([value]: readonly Binary[]) => {
|
||||
const { keyboardDismissMode } = this.props;
|
||||
|
||||
if (value === TRUE) {
|
||||
@@ -358,6 +376,13 @@ export default class DrawerView extends React.PureComponent<Props> {
|
||||
}
|
||||
})
|
||||
),
|
||||
onChange(
|
||||
this.gestureState,
|
||||
cond(
|
||||
eq(this.gestureState, State.ACTIVE),
|
||||
call([], this.handleStartInteraction)
|
||||
)
|
||||
),
|
||||
cond(
|
||||
eq(this.gestureState, State.ACTIVE),
|
||||
[
|
||||
|
||||
@@ -13,7 +13,7 @@ const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view o
|
||||
|
||||
export default class ResourceSavingScene extends React.Component<Props> {
|
||||
render() {
|
||||
if (screensEnabled && screensEnabled()) {
|
||||
if (screensEnabled?.()) {
|
||||
const { isVisible, ...rest } = this.props;
|
||||
|
||||
// @ts-ignore
|
||||
|
||||
@@ -3,6 +3,17 @@ import {
|
||||
SafeAreaProvider,
|
||||
SafeAreaConsumer,
|
||||
} from 'react-native-safe-area-context';
|
||||
import {
|
||||
getStatusBarHeight,
|
||||
getBottomSpace,
|
||||
} from 'react-native-iphone-x-helper';
|
||||
|
||||
const initialSafeAreaInsets = {
|
||||
top: getStatusBarHeight(true),
|
||||
bottom: getBottomSpace(),
|
||||
right: 0,
|
||||
left: 0,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
@@ -19,7 +30,11 @@ export default function SafeAreaProviderCompat({ children }: Props) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return <SafeAreaProvider>{children}</SafeAreaProvider>;
|
||||
return (
|
||||
<SafeAreaProvider initialSafeAreaInsets={initialSafeAreaInsets}>
|
||||
{children}
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}}
|
||||
</SafeAreaConsumer>
|
||||
);
|
||||
|
||||
@@ -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/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.27...@react-navigation/material-bottom-tabs@5.0.0-alpha.28) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.27](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.26...@react-navigation/material-bottom-tabs@5.0.0-alpha.27) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"material",
|
||||
"tab"
|
||||
],
|
||||
"version": "5.0.0-alpha.27",
|
||||
"version": "5.0.0-alpha.28",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -34,7 +34,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.18"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
|
||||
@@ -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.26](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.25...@react-navigation/material-top-tabs@5.0.0-alpha.26) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/material-top-tabs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.25](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/material-top-tabs@5.0.0-alpha.24...@react-navigation/material-top-tabs@5.0.0-alpha.25) (2019-12-19)
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"material",
|
||||
"tab"
|
||||
],
|
||||
"version": "5.0.0-alpha.25",
|
||||
"version": "5.0.0-alpha.26",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -34,7 +34,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.18",
|
||||
"@react-navigation/routers": "^5.0.0-alpha.19",
|
||||
"color": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
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.21](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.20...@react-navigation/native-stack@5.0.0-alpha.21) (2020-01-03)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.20](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.19...@react-navigation/native-stack@5.0.0-alpha.20) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native-stack@5.0.0-alpha.18...@react-navigation/native-stack@5.0.0-alpha.19) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native-stack
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"react-native",
|
||||
"react-navigation"
|
||||
],
|
||||
"version": "5.0.0-alpha.19",
|
||||
"version": "5.0.0-alpha.21",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -29,7 +29,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.18"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function HeaderConfig(props: Props) {
|
||||
? headerTintColor
|
||||
: colors.text
|
||||
}
|
||||
backTitle={headerBackTitleVisible ? headerBackTitle : ''}
|
||||
backTitle={headerBackTitleVisible ? headerBackTitle : ' '}
|
||||
backTitleFontFamily={headerBackTitleStyle.fontFamily}
|
||||
backTitleFontSize={headerBackTitleStyle.fontSize}
|
||||
color={headerTintColor !== undefined ? headerTintColor : colors.primary}
|
||||
|
||||
@@ -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.22](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.21...@react-navigation/native@5.0.0-alpha.22) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.21](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/native@5.0.0-alpha.20...@react-navigation/native@5.0.0-alpha.21) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/native
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"ios",
|
||||
"android"
|
||||
],
|
||||
"version": "5.0.0-alpha.21",
|
||||
"version": "5.0.0-alpha.22",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -30,7 +30,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^5.0.0-alpha.29"
|
||||
"@react-navigation/core": "^5.0.0-alpha.30"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Linking } from 'react-native';
|
||||
import {
|
||||
getActionFromState,
|
||||
getStateFromPath as getStateFromPathDefault,
|
||||
NavigationContainerRef,
|
||||
} from '@react-navigation/core';
|
||||
@@ -82,7 +83,13 @@ export default function useLinking(
|
||||
const state = getStateFromPathRef.current(path, configRef.current);
|
||||
|
||||
if (state) {
|
||||
navigation.resetRoot(state);
|
||||
const action = getActionFromState(state);
|
||||
|
||||
if (action.type === 'RESET_ROOT') {
|
||||
navigation.resetRoot(action.payload);
|
||||
} else {
|
||||
navigation.dispatch(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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.19](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.18...@react-navigation/routers@5.0.0-alpha.19) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/routers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.18](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/routers@5.0.0-alpha.17...@react-navigation/routers@5.0.0-alpha.18) (2019-12-19)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/routers
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"react-native",
|
||||
"react-navigation"
|
||||
],
|
||||
"version": "5.0.0-alpha.18",
|
||||
"version": "5.0.0-alpha.19",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -29,7 +29,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^5.0.0-alpha.29",
|
||||
"@react-navigation/core": "^5.0.0-alpha.30",
|
||||
"shortid": "^2.2.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -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.0.0-alpha.49](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.48...@react-navigation/stack@5.0.0-alpha.49) (2020-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* dismiss keyboard on page change ([2c31d17](https://github.com/react-navigation/navigation-ex/commit/2c31d1705c4e5827b19b9cc7f3e5b05207c3238a))
|
||||
* interaction manager in stack ([#237](https://github.com/react-navigation/navigation-ex/issues/237)) ([6b9b999](https://github.com/react-navigation/navigation-ex/commit/6b9b999c5b60a67ed683b84484928700d4260585))
|
||||
* provide initial values for safe area to prevent blank screen ([#238](https://github.com/react-navigation/navigation-ex/issues/238)) ([77b7570](https://github.com/react-navigation/navigation-ex/commit/77b757091c0451e20bca01138629669c7da544a8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.48](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.47...@react-navigation/stack@5.0.0-alpha.48) (2020-01-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve gesture performance ([59803f5](https://github.com/react-navigation/navigation-ex/commit/59803f54d64f85c8e46c1ebc70613a70a812f53a))
|
||||
* use native driver for gestures ([9356598](https://github.com/react-navigation/navigation-ex/commit/935659899f1d4084c601fbefea4a935f9b6ce087))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.47](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.46...@react-navigation/stack@5.0.0-alpha.47) (2020-01-01)
|
||||
|
||||
**Note:** Version bump only for package @react-navigation/stack
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [5.0.0-alpha.46](https://github.com/react-navigation/navigation-ex/compare/@react-navigation/stack@5.0.0-alpha.45...@react-navigation/stack@5.0.0-alpha.46) (2019-12-19)
|
||||
|
||||
|
||||
|
||||
@@ -10,18 +10,18 @@ Open a Terminal in your project's folder and run,
|
||||
yarn add @react-navigation/native @react-navigation/stack @react-native-community/masked-view
|
||||
```
|
||||
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler), [`react-native-reanimated`](https://github.com/kmagiera/react-native-reanimated), [`react-native-screens`](https://github.com/kmagiera/react-native-screens) and [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context).
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler), [`react-native-screens`](https://github.com/kmagiera/react-native-screens) and [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context).
|
||||
|
||||
If you are using Expo, to ensure that you get the compatible versions of the libraries, run:
|
||||
|
||||
```sh
|
||||
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context
|
||||
expo install react-native-gesture-handler react-native-screens react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are not using Expo, run the following:
|
||||
|
||||
```sh
|
||||
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context
|
||||
yarn add react-native-gesture-handler react-native-screens react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are using Expo, you are done. Otherwise, continue to the next steps.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"android",
|
||||
"stack"
|
||||
],
|
||||
"version": "5.0.0-alpha.46",
|
||||
"version": "5.0.0-alpha.49",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -33,8 +33,9 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.18",
|
||||
"color": "^3.1.2"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.19",
|
||||
"color": "^3.1.2",
|
||||
"react-native-iphone-x-helper": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
@@ -46,7 +47,6 @@
|
||||
"react": "~16.9.0",
|
||||
"react-native": "~0.61.5",
|
||||
"react-native-gesture-handler": "^1.5.0",
|
||||
"react-native-reanimated": "^1.4.0",
|
||||
"react-native-safe-area-context": "^0.6.0",
|
||||
"react-native-screens": "^2.0.0-alpha.19",
|
||||
"typescript": "^3.7.3"
|
||||
@@ -57,7 +57,6 @@
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": "^1.0.0",
|
||||
"react-native-reanimated": "^1.0.0",
|
||||
"react-native-safe-area-context": "^0.6.0",
|
||||
"react-native-screens": "^1.0.0-alpha.0 || ^2.0.0-alpha.0"
|
||||
},
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { Animated } from 'react-native';
|
||||
import conditional from '../utils/conditional';
|
||||
import {
|
||||
StackCardInterpolationProps,
|
||||
StackCardInterpolatedStyle,
|
||||
} from '../types';
|
||||
|
||||
const { cond, add, multiply, interpolate } = Animated;
|
||||
const { add, multiply } = Animated;
|
||||
|
||||
/**
|
||||
* Standard iOS-style slide in from the right.
|
||||
@@ -16,7 +17,7 @@ export function forHorizontalIOS({
|
||||
layouts: { screen },
|
||||
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
|
||||
const translateFocused = multiply(
|
||||
interpolate(current.progress, {
|
||||
current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [screen.width, 0],
|
||||
}),
|
||||
@@ -25,20 +26,20 @@ export function forHorizontalIOS({
|
||||
|
||||
const translateUnfocused = next
|
||||
? multiply(
|
||||
interpolate(next.progress, {
|
||||
next.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, multiply(screen.width, -0.3)],
|
||||
outputRange: [0, screen.width * -0.3],
|
||||
}),
|
||||
inverted
|
||||
)
|
||||
: 0;
|
||||
|
||||
const overlayOpacity = interpolate(current.progress, {
|
||||
const overlayOpacity = current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, 0.07],
|
||||
});
|
||||
|
||||
const shadowOpacity = interpolate(current.progress, {
|
||||
const shadowOpacity = current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, 0.3],
|
||||
});
|
||||
@@ -66,7 +67,7 @@ export function forVerticalIOS({
|
||||
layouts: { screen },
|
||||
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
|
||||
const translateY = multiply(
|
||||
interpolate(current.progress, {
|
||||
current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [screen.height, 0],
|
||||
}),
|
||||
@@ -102,7 +103,7 @@ export function forModalPresentationIOS({
|
||||
const progress = add(current.progress, next ? next.progress : 0);
|
||||
|
||||
const translateY = multiply(
|
||||
interpolate(progress, {
|
||||
progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: [
|
||||
screen.height,
|
||||
@@ -113,14 +114,14 @@ export function forModalPresentationIOS({
|
||||
inverted
|
||||
);
|
||||
|
||||
const overlayOpacity = interpolate(progress, {
|
||||
const overlayOpacity = progress.interpolate({
|
||||
inputRange: [0, 1, 1.0001, 2],
|
||||
outputRange: [0, 0.3, 1, 1],
|
||||
});
|
||||
|
||||
const scale = isLandscape
|
||||
? 1
|
||||
: interpolate(progress, {
|
||||
: progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: [
|
||||
1,
|
||||
@@ -132,7 +133,7 @@ export function forModalPresentationIOS({
|
||||
const borderRadius = isLandscape
|
||||
? 0
|
||||
: index === 0
|
||||
? interpolate(progress, {
|
||||
? progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: [0, 0, 10],
|
||||
})
|
||||
@@ -160,17 +161,17 @@ export function forFadeFromBottomAndroid({
|
||||
closing,
|
||||
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
|
||||
const translateY = multiply(
|
||||
interpolate(current.progress, {
|
||||
current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [multiply(screen.height, 0.08), 0],
|
||||
outputRange: [screen.height * 0.08, 0],
|
||||
}),
|
||||
inverted
|
||||
);
|
||||
|
||||
const opacity = cond(
|
||||
const opacity = conditional(
|
||||
closing,
|
||||
current.progress,
|
||||
interpolate(current.progress, {
|
||||
current.progress.interpolate({
|
||||
inputRange: [0, 0.5, 0.9, 1],
|
||||
outputRange: [0, 0.25, 0.7, 1],
|
||||
})
|
||||
@@ -194,7 +195,7 @@ export function forRevealFromBottomAndroid({
|
||||
layouts: { screen },
|
||||
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
|
||||
const containerTranslateY = multiply(
|
||||
interpolate(current.progress, {
|
||||
current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [screen.height, 0],
|
||||
}),
|
||||
@@ -202,24 +203,24 @@ export function forRevealFromBottomAndroid({
|
||||
);
|
||||
|
||||
const cardTranslateYFocused = multiply(
|
||||
interpolate(current.progress, {
|
||||
current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [multiply(screen.height, 95.9 / 100, -1), 0],
|
||||
outputRange: [screen.height * (95.9 / 100) * -1, 0],
|
||||
}),
|
||||
inverted
|
||||
);
|
||||
|
||||
const cardTranslateYUnfocused = next
|
||||
? multiply(
|
||||
interpolate(next.progress, {
|
||||
next.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0, multiply(screen.height, 2 / 100, -1)],
|
||||
outputRange: [0, screen.height * (2 / 100) * -1],
|
||||
}),
|
||||
inverted
|
||||
)
|
||||
: 0;
|
||||
|
||||
const overlayOpacity = interpolate(current.progress, {
|
||||
const overlayOpacity = current.progress.interpolate({
|
||||
inputRange: [0, 0.36, 1],
|
||||
outputRange: [0, 0.1, 0.1],
|
||||
});
|
||||
@@ -249,18 +250,18 @@ export function forScaleFromCenterAndroid({
|
||||
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
|
||||
const progress = add(current.progress, next ? next.progress : 0);
|
||||
|
||||
const opacity = interpolate(progress, {
|
||||
const opacity = progress.interpolate({
|
||||
inputRange: [0, 0.8, 1, 1.2, 2],
|
||||
outputRange: [0, 0.5, 1, 0.33, 0],
|
||||
});
|
||||
|
||||
const scale = cond(
|
||||
const scale = conditional(
|
||||
closing,
|
||||
interpolate(current.progress, {
|
||||
current.progress.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0.9, 1],
|
||||
}),
|
||||
interpolate(progress, {
|
||||
progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: [0.85, 1, 1.1],
|
||||
})
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { I18nManager } from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { Animated, I18nManager } from 'react-native';
|
||||
import {
|
||||
StackHeaderInterpolationProps,
|
||||
StackHeaderInterpolatedStyle,
|
||||
} from '../types';
|
||||
|
||||
const { interpolate, add } = Animated;
|
||||
const { add } = Animated;
|
||||
|
||||
/**
|
||||
* Standard UIKit style animation for the header where the title fades into the back button label.
|
||||
@@ -38,7 +37,7 @@ export function forUIKit({
|
||||
|
||||
return {
|
||||
leftButtonStyle: {
|
||||
opacity: interpolate(progress, {
|
||||
opacity: progress.interpolate({
|
||||
inputRange: [0.3, 1, 1.5],
|
||||
outputRange: [0, 1, 0],
|
||||
}),
|
||||
@@ -46,7 +45,7 @@ export function forUIKit({
|
||||
leftLabelStyle: {
|
||||
transform: [
|
||||
{
|
||||
translateX: interpolate(progress, {
|
||||
translateX: progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: I18nManager.isRTL
|
||||
? [-rightOffset, 0, leftLabelOffset]
|
||||
@@ -56,19 +55,19 @@ export function forUIKit({
|
||||
],
|
||||
},
|
||||
rightButtonStyle: {
|
||||
opacity: interpolate(progress, {
|
||||
opacity: progress.interpolate({
|
||||
inputRange: [0.3, 1, 1.5],
|
||||
outputRange: [0, 1, 0],
|
||||
}),
|
||||
},
|
||||
titleStyle: {
|
||||
opacity: interpolate(progress, {
|
||||
opacity: progress.interpolate({
|
||||
inputRange: [0, 0.4, 1, 1.5],
|
||||
outputRange: [0, 0.1, 1, 0],
|
||||
}),
|
||||
transform: [
|
||||
{
|
||||
translateX: interpolate(progress, {
|
||||
translateX: progress.interpolate({
|
||||
inputRange: [0.5, 1, 2],
|
||||
outputRange: I18nManager.isRTL
|
||||
? [-titleLeftOffset, 0, rightOffset]
|
||||
@@ -80,7 +79,7 @@ export function forUIKit({
|
||||
backgroundStyle: {
|
||||
transform: [
|
||||
{
|
||||
translateX: interpolate(progress, {
|
||||
translateX: progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: I18nManager.isRTL
|
||||
? [-layouts.screen.width, 0, layouts.screen.width]
|
||||
@@ -100,7 +99,7 @@ export function forFade({
|
||||
next,
|
||||
}: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
|
||||
const progress = add(current.progress, next ? next.progress : 0);
|
||||
const opacity = interpolate(progress, {
|
||||
const opacity = progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: [0, 1, 0],
|
||||
});
|
||||
@@ -110,7 +109,7 @@ export function forFade({
|
||||
rightButtonStyle: { opacity },
|
||||
titleStyle: { opacity },
|
||||
backgroundStyle: {
|
||||
opacity: interpolate(progress, {
|
||||
opacity: progress.interpolate({
|
||||
inputRange: [0, 1, 1.9, 2],
|
||||
outputRange: [0, 1, 1, 0],
|
||||
}),
|
||||
@@ -127,7 +126,7 @@ export function forStatic({
|
||||
layouts: { screen },
|
||||
}: StackHeaderInterpolationProps): StackHeaderInterpolatedStyle {
|
||||
const progress = add(current.progress, next ? next.progress : 0);
|
||||
const translateX = interpolate(progress, {
|
||||
const translateX = progress.interpolate({
|
||||
inputRange: [0, 1, 2],
|
||||
outputRange: I18nManager.isRTL
|
||||
? [-screen.width, 0, screen.width]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Easing } from 'react-native-reanimated';
|
||||
import { Easing } from 'react-native';
|
||||
import { TransitionSpec } from '../types';
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,9 @@ import * as TransitionPresets from './TransitionConfigs/TransitionPresets';
|
||||
export { default as createStackNavigator } from './navigators/createStackNavigator';
|
||||
|
||||
export const Assets = [
|
||||
// eslint-disable-next-line import/no-commonjs
|
||||
require('./views/assets/back-icon.png'),
|
||||
// eslint-disable-next-line import/no-commonjs
|
||||
require('./views/assets/back-icon-mask.png'),
|
||||
];
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import {
|
||||
Animated,
|
||||
EasingFunction,
|
||||
StyleProp,
|
||||
TextStyle,
|
||||
ViewStyle,
|
||||
LayoutChangeEvent,
|
||||
} from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
import {
|
||||
NavigationProp,
|
||||
@@ -88,22 +89,24 @@ export type Scene<T> = {
|
||||
/**
|
||||
* Progress value of the current screen.
|
||||
*/
|
||||
current: Animated.Node<number>;
|
||||
current: Animated.AnimatedInterpolation;
|
||||
/**
|
||||
* Progress value for the screen after this one in the stack.
|
||||
* This can be `undefined` in case the screen animating is the last one.
|
||||
*/
|
||||
next?: Animated.Node<number>;
|
||||
next?: Animated.AnimatedInterpolation;
|
||||
/**
|
||||
* Progress value for the screen before this one in the stack.
|
||||
* This can be `undefined` in case the screen animating is the first one.
|
||||
*/
|
||||
previous?: Animated.Node<number>;
|
||||
previous?: Animated.AnimatedInterpolation;
|
||||
};
|
||||
};
|
||||
|
||||
export type StackHeaderMode = 'float' | 'screen' | 'none';
|
||||
|
||||
export type StackCardMode = 'card' | 'modal';
|
||||
|
||||
export type StackHeaderOptions = {
|
||||
/**
|
||||
* String or a function that returns a React Element to be used by the header.
|
||||
@@ -322,7 +325,7 @@ export type StackNavigationOptions = StackHeaderOptions &
|
||||
};
|
||||
|
||||
export type StackNavigationConfig = {
|
||||
mode?: 'card' | 'modal';
|
||||
mode?: StackCardMode;
|
||||
headerMode?: StackHeaderMode;
|
||||
/**
|
||||
* If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen.
|
||||
@@ -433,7 +436,7 @@ export type SpringConfig = {
|
||||
|
||||
export type TimingConfig = {
|
||||
duration: number;
|
||||
easing: Animated.EasingFunction;
|
||||
easing: EasingFunction;
|
||||
};
|
||||
|
||||
export type TransitionSpec =
|
||||
@@ -448,7 +451,7 @@ export type StackCardInterpolationProps = {
|
||||
/**
|
||||
* Animated node representing the progress value of the current screen.
|
||||
*/
|
||||
progress: Animated.Node<number>;
|
||||
progress: Animated.AnimatedInterpolation;
|
||||
};
|
||||
/**
|
||||
* Values for the current screen the screen after this one in the stack.
|
||||
@@ -458,24 +461,24 @@ export type StackCardInterpolationProps = {
|
||||
/**
|
||||
* Animated node representing the progress value of the next screen.
|
||||
*/
|
||||
progress: Animated.Node<number>;
|
||||
progress: Animated.AnimatedInterpolation;
|
||||
};
|
||||
/**
|
||||
* The index of the card in the stack.
|
||||
*/
|
||||
index: number;
|
||||
/**
|
||||
* Animated node representing whether the card is closing.
|
||||
* Animated node representing whether the card is closing (1 - closing, 0 - not closing).
|
||||
*/
|
||||
closing: Animated.Node<0 | 1>;
|
||||
closing: Animated.AnimatedInterpolation;
|
||||
/**
|
||||
* Animated node representing whether the card is being swiped.
|
||||
* Animated node representing whether the card is being swiped (1 - swiping, 0 - not swiping).
|
||||
*/
|
||||
swiping: Animated.Node<0 | 1>;
|
||||
swiping: Animated.AnimatedInterpolation;
|
||||
/**
|
||||
* Animated node representing multiplier when direction is inverted.
|
||||
* Animated node representing multiplier when direction is inverted (-1 - inverted, 1 - normal).
|
||||
*/
|
||||
inverted: Animated.Node<-1 | 1>;
|
||||
inverted: Animated.AnimatedInterpolation;
|
||||
/**
|
||||
* Layout measurements for various items we use for animation.
|
||||
*/
|
||||
@@ -527,7 +530,7 @@ export type StackHeaderInterpolationProps = {
|
||||
/**
|
||||
* Animated node representing the progress value of the current screen.
|
||||
*/
|
||||
progress: Animated.Node<number>;
|
||||
progress: Animated.AnimatedInterpolation;
|
||||
};
|
||||
/**
|
||||
* Values for the current screen the screen after this one in the stack.
|
||||
@@ -537,7 +540,7 @@ export type StackHeaderInterpolationProps = {
|
||||
/**
|
||||
* Animated node representing the progress value of the next screen.
|
||||
*/
|
||||
progress: Animated.Node<number>;
|
||||
progress: Animated.AnimatedInterpolation;
|
||||
};
|
||||
/**
|
||||
* Layout measurements for various items we use for animation.
|
||||
|
||||
33
packages/stack/src/utils/conditional.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Animated } from 'react-native';
|
||||
|
||||
const { add, multiply } = Animated;
|
||||
|
||||
/**
|
||||
* Use an Animated Node based on a condition. Similar to Reanimated's `cond`.
|
||||
*
|
||||
* @param condition Animated Node representing the condition, must be 0 or 1, 1 means `true`, 0 means `false`
|
||||
* @param main Animated Node to use if the condition is `true`
|
||||
* @param fallback Animated Node to use if the condition is `false`
|
||||
*/
|
||||
export default function conditional(
|
||||
condition: Animated.AnimatedInterpolation,
|
||||
main: Animated.AnimatedInterpolation,
|
||||
fallback: Animated.AnimatedInterpolation
|
||||
) {
|
||||
// To implement this behavior, we multiply the main node with the condition.
|
||||
// So if condition is 0, result will be 0, and if condition is 1, result will be main node.
|
||||
// Then we multiple reverse of the condition (0 if condition is 1) with the fallback.
|
||||
// So if condition is 0, result will be fallback node, and if condition is 1, result will be 0,
|
||||
// This way, one of them will always be 0, and other one will be the value we need.
|
||||
// In the end we add them both together, 0 + value we need = value we need
|
||||
return add(
|
||||
multiply(condition, main),
|
||||
multiply(
|
||||
condition.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [1, 0],
|
||||
}),
|
||||
fallback
|
||||
)
|
||||
);
|
||||
}
|
||||
18
packages/stack/src/utils/getDistanceForDirection.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import getInvertedMultiplier from './getInvertedMultiplier';
|
||||
import { GestureDirection, Layout } from '../types';
|
||||
|
||||
export default function getDistanceForDirection(
|
||||
layout: Layout,
|
||||
gestureDirection: GestureDirection
|
||||
): number {
|
||||
const multiplier = getInvertedMultiplier(gestureDirection);
|
||||
|
||||
switch (gestureDirection) {
|
||||
case 'vertical':
|
||||
case 'vertical-inverted':
|
||||
return layout.height * multiplier;
|
||||
case 'horizontal':
|
||||
case 'horizontal-inverted':
|
||||
return layout.width * multiplier;
|
||||
}
|
||||
}
|
||||
17
packages/stack/src/utils/getInvertedMultiplier.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { I18nManager } from 'react-native';
|
||||
import { GestureDirection } from '../types';
|
||||
|
||||
export default function getInvertedMultiplier(
|
||||
gestureDirection: GestureDirection
|
||||
): 1 | -1 {
|
||||
switch (gestureDirection) {
|
||||
case 'vertical':
|
||||
return 1;
|
||||
case 'vertical-inverted':
|
||||
return -1;
|
||||
case 'horizontal':
|
||||
return I18nManager.isRTL ? -1 : 1;
|
||||
case 'horizontal-inverted':
|
||||
return I18nManager.isRTL ? 1 : -1;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export default function memoize<Result, Deps extends ReadonlyArray<any>>(
|
||||
export default function memoize<Result, Deps extends readonly any[]>(
|
||||
callback: (...deps: Deps) => Result
|
||||
) {
|
||||
let previous: Deps | undefined;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Animated,
|
||||
I18nManager,
|
||||
Image,
|
||||
View,
|
||||
@@ -7,7 +8,6 @@ import {
|
||||
StyleSheet,
|
||||
LayoutChangeEvent,
|
||||
} from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
import MaskedView from '../MaskedView';
|
||||
import TouchableItem from '../TouchableItem';
|
||||
@@ -52,7 +52,7 @@ export default function HeaderBackButton({
|
||||
: 'rgba(0, 0, 0, .32)';
|
||||
|
||||
const handleLabelLayout = (e: LayoutChangeEvent) => {
|
||||
onLabelLayout && onLabelLayout(e);
|
||||
onLabelLayout?.(e);
|
||||
|
||||
setInitialLabelWidth(e.nativeEvent.layout.x + e.nativeEvent.layout.width);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { StyleSheet, Platform, ViewProps } from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { Animated, StyleSheet, Platform, ViewProps } from 'react-native';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
|
||||
export default function HeaderBackground({ style, ...rest }: ViewProps) {
|
||||
|
||||
@@ -21,7 +21,7 @@ export type Props = {
|
||||
mode: 'float' | 'screen';
|
||||
layout: Layout;
|
||||
insets: EdgeInsets;
|
||||
scenes: Array<Scene<Route<string>> | undefined>;
|
||||
scenes: (Scene<Route<string>> | undefined)[];
|
||||
state: StackNavigationState;
|
||||
getPreviousRoute: (props: {
|
||||
route: Route<string>;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Animated,
|
||||
View,
|
||||
StyleSheet,
|
||||
LayoutChangeEvent,
|
||||
Platform,
|
||||
ViewStyle,
|
||||
} from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
import { Route } from '@react-navigation/native';
|
||||
import HeaderBackButton from './HeaderBackButton';
|
||||
@@ -114,8 +114,8 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
(
|
||||
styleInterpolator: StackHeaderStyleInterpolator,
|
||||
layout: Layout,
|
||||
current: Animated.Node<number>,
|
||||
next: Animated.Node<number> | undefined,
|
||||
current: Animated.AnimatedInterpolation,
|
||||
next: Animated.AnimatedInterpolation | undefined,
|
||||
titleLayout: Layout | undefined,
|
||||
leftLabelLayout: Layout | undefined
|
||||
) =>
|
||||
@@ -272,6 +272,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
// @ts-ignore
|
||||
if (safeStyles[styleProp] === undefined) {
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete safeStyles[styleProp];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { StyleSheet, Platform, TextProps } from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { Animated, StyleSheet, Platform, TextProps } from 'react-native';
|
||||
import { useTheme } from '@react-navigation/native';
|
||||
|
||||
type Props = TextProps & {
|
||||
|
||||
@@ -11,9 +11,10 @@ type Props = {
|
||||
};
|
||||
|
||||
export default class KeyboardManager extends React.Component<Props> {
|
||||
componentWillUnmount = () => {
|
||||
componentWillUnmount() {
|
||||
this.clearKeyboardTimeout();
|
||||
};
|
||||
}
|
||||
|
||||
// Numeric id of the previously focused text input
|
||||
// When a gesture didn't change the tab, we can restore the focused input with this
|
||||
private previouslyFocusedTextInput: number | null = null;
|
||||
@@ -31,6 +32,7 @@ export default class KeyboardManager extends React.Component<Props> {
|
||||
if (!this.props.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearKeyboardTimeout();
|
||||
|
||||
const input = TextInput.State.currentlyFocusedField();
|
||||
@@ -49,6 +51,7 @@ export default class KeyboardManager extends React.Component<Props> {
|
||||
if (!this.props.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearKeyboardTimeout();
|
||||
|
||||
Keyboard.dismiss();
|
||||
@@ -61,6 +64,7 @@ export default class KeyboardManager extends React.Component<Props> {
|
||||
if (!this.props.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearKeyboardTimeout();
|
||||
|
||||
// The page didn't change, we should restore the focus of text input
|
||||
|
||||
@@ -3,6 +3,17 @@ import {
|
||||
SafeAreaProvider,
|
||||
SafeAreaConsumer,
|
||||
} from 'react-native-safe-area-context';
|
||||
import {
|
||||
getStatusBarHeight,
|
||||
getBottomSpace,
|
||||
} from 'react-native-iphone-x-helper';
|
||||
|
||||
const initialSafeAreaInsets = {
|
||||
top: getStatusBarHeight(true),
|
||||
bottom: getBottomSpace(),
|
||||
right: 0,
|
||||
left: 0,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
@@ -19,7 +30,11 @@ export default function SafeAreaProviderCompat({ children }: Props) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return <SafeAreaProvider>{children}</SafeAreaProvider>;
|
||||
return (
|
||||
<SafeAreaProvider initialSafeAreaInsets={initialSafeAreaInsets}>
|
||||
{children}
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}}
|
||||
</SafeAreaConsumer>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Animated,
|
||||
View,
|
||||
I18nManager,
|
||||
StyleSheet,
|
||||
ViewProps,
|
||||
StyleProp,
|
||||
@@ -9,35 +9,38 @@ import {
|
||||
Platform,
|
||||
InteractionManager,
|
||||
} from 'react-native';
|
||||
import Animated, { Easing } from 'react-native-reanimated';
|
||||
import { PanGestureHandler } from 'react-native-gesture-handler';
|
||||
import {
|
||||
PanGestureHandler,
|
||||
State as GestureState,
|
||||
PanGestureHandlerGestureEvent,
|
||||
} from 'react-native-gesture-handler';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
import Color from 'color';
|
||||
import animate, { Binary } from './CardAnimation';
|
||||
import PointerEventsView from './PointerEventsView';
|
||||
import memoize from '../../utils/memoize';
|
||||
import StackGestureContext from '../../utils/StackGestureContext';
|
||||
import StackCardAnimationContext from '../../utils/StackCardAnimationContext';
|
||||
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
||||
import getInvertedMultiplier from '../../utils/getInvertedMultiplier';
|
||||
import memoize from '../../utils/memoize';
|
||||
import {
|
||||
TransitionSpec,
|
||||
StackCardStyleInterpolator,
|
||||
GestureDirection,
|
||||
Layout,
|
||||
TimingConfig,
|
||||
SpringConfig,
|
||||
} from '../../types';
|
||||
|
||||
type Props = ViewProps & {
|
||||
index: number;
|
||||
active: boolean;
|
||||
closing?: boolean;
|
||||
next?: Animated.Node<number>;
|
||||
current: Animated.Value<number>;
|
||||
next?: Animated.AnimatedInterpolation;
|
||||
current: Animated.AnimatedInterpolation;
|
||||
gesture: Animated.Value;
|
||||
layout: Layout;
|
||||
insets: EdgeInsets;
|
||||
gestureDirection: GestureDirection;
|
||||
onOpen: (isFinished: boolean) => void;
|
||||
onClose: (isFinished: boolean) => void;
|
||||
onOpen: () => void;
|
||||
onClose: () => void;
|
||||
onTransitionStart?: (props: { closing: boolean }) => void;
|
||||
onGestureBegin?: () => void;
|
||||
onGestureCanceled?: () => void;
|
||||
@@ -60,30 +63,10 @@ type Props = ViewProps & {
|
||||
contentStyle?: StyleProp<ViewStyle>;
|
||||
};
|
||||
|
||||
type AnimatedSpringConfig = {
|
||||
damping: Animated.Value<number>;
|
||||
mass: Animated.Value<number>;
|
||||
stiffness: Animated.Value<number>;
|
||||
restSpeedThreshold: Animated.Value<number>;
|
||||
restDisplacementThreshold: Animated.Value<number>;
|
||||
overshootClamping: Animated.Value<boolean>;
|
||||
};
|
||||
|
||||
type AnimatedTimingConfig = {
|
||||
duration: Animated.Value<number>;
|
||||
};
|
||||
|
||||
const ANIMATION_SPRING = 0;
|
||||
const ANIMATION_TIMING = 1;
|
||||
|
||||
const DIRECTION_VERTICAL = -1;
|
||||
const DIRECTION_HORIZONTAL = 1;
|
||||
|
||||
const GESTURE_VELOCITY_IMPACT = 0.3;
|
||||
|
||||
const TRUE = 1;
|
||||
const FALSE = 0;
|
||||
const UNSET = -1;
|
||||
|
||||
/**
|
||||
* The distance of touch start from the edge of the screen where the gesture will be recognized
|
||||
@@ -91,169 +74,6 @@ const UNSET = -1;
|
||||
const GESTURE_RESPONSE_DISTANCE_HORIZONTAL = 50;
|
||||
const GESTURE_RESPONSE_DISTANCE_VERTICAL = 135;
|
||||
|
||||
const {
|
||||
clockRunning,
|
||||
startClock,
|
||||
stopClock,
|
||||
spring,
|
||||
timing,
|
||||
call,
|
||||
set,
|
||||
multiply,
|
||||
cond,
|
||||
eq,
|
||||
Clock,
|
||||
Value,
|
||||
} = Animated;
|
||||
|
||||
const springHelper = Animated.proc(
|
||||
(
|
||||
clock: Animated.Clock,
|
||||
prevPosition: Animated.Value<number>,
|
||||
position: Animated.Value<number>,
|
||||
finished: Animated.Value<number>,
|
||||
velocity: Animated.Value<number>,
|
||||
time: Animated.Value<number>,
|
||||
toValue: Animated.Adaptable<number>,
|
||||
damping: Animated.Adaptable<number>,
|
||||
mass: Animated.Adaptable<number>,
|
||||
stiffness: Animated.Adaptable<number>,
|
||||
overshootClamping: Animated.Adaptable<number>,
|
||||
restSpeedThreshold: Animated.Adaptable<number>,
|
||||
restDisplacementThreshold: Animated.Adaptable<number>
|
||||
) =>
|
||||
spring(
|
||||
clock,
|
||||
{
|
||||
// @ts-ignore
|
||||
prevPosition,
|
||||
position,
|
||||
finished,
|
||||
velocity,
|
||||
time,
|
||||
},
|
||||
{
|
||||
toValue,
|
||||
damping,
|
||||
mass,
|
||||
stiffness,
|
||||
overshootClamping,
|
||||
restDisplacementThreshold,
|
||||
restSpeedThreshold,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const runSpring = (
|
||||
clock: Animated.Clock,
|
||||
state: {
|
||||
finished: Animated.Value<number>;
|
||||
velocity: Animated.Value<number>;
|
||||
position: Animated.Value<number>;
|
||||
time: Animated.Value<number>;
|
||||
},
|
||||
config: {
|
||||
toValue: Animated.Adaptable<number>;
|
||||
damping: Animated.Adaptable<number>;
|
||||
mass: Animated.Adaptable<number>;
|
||||
stiffness: Animated.Adaptable<number>;
|
||||
overshootClamping: Animated.Adaptable<boolean>;
|
||||
restSpeedThreshold: Animated.Adaptable<number>;
|
||||
restDisplacementThreshold: Animated.Adaptable<number>;
|
||||
}
|
||||
) =>
|
||||
springHelper(
|
||||
clock,
|
||||
new Value(0),
|
||||
state.position,
|
||||
state.finished,
|
||||
state.velocity,
|
||||
state.time,
|
||||
config.toValue,
|
||||
config.damping,
|
||||
config.mass,
|
||||
config.stiffness,
|
||||
config.overshootClamping as any,
|
||||
config.restSpeedThreshold,
|
||||
config.restDisplacementThreshold
|
||||
);
|
||||
|
||||
function transformSpringConfigToAnimatedValues(
|
||||
spec: TransitionSpec,
|
||||
current?: AnimatedSpringConfig
|
||||
): AnimatedSpringConfig {
|
||||
if (current) {
|
||||
if (spec.animation !== 'spring') {
|
||||
return current;
|
||||
}
|
||||
|
||||
const { config } = spec;
|
||||
|
||||
current.damping.setValue(config.damping);
|
||||
current.stiffness.setValue(config.stiffness);
|
||||
current.mass.setValue(config.mass);
|
||||
current.restDisplacementThreshold.setValue(
|
||||
config.restDisplacementThreshold
|
||||
);
|
||||
current.restSpeedThreshold.setValue(config.restSpeedThreshold);
|
||||
current.overshootClamping.setValue(config.overshootClamping);
|
||||
|
||||
return current;
|
||||
} else {
|
||||
const config: Partial<SpringConfig> =
|
||||
spec.animation !== 'spring' ? {} : spec.config;
|
||||
|
||||
return {
|
||||
damping: new Animated.Value(config.damping || 0),
|
||||
mass: new Animated.Value(config.mass || 0),
|
||||
overshootClamping: new Animated.Value(config.overshootClamping !== false),
|
||||
restDisplacementThreshold: new Animated.Value(
|
||||
config.restDisplacementThreshold || 0
|
||||
),
|
||||
restSpeedThreshold: new Animated.Value(config.restSpeedThreshold || 0),
|
||||
stiffness: new Animated.Value(config.stiffness || 0),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function transformTimingConfigToAnimatedValues(
|
||||
spec: TransitionSpec,
|
||||
current?: AnimatedTimingConfig & { easing: Animated.EasingFunction }
|
||||
): AnimatedTimingConfig & { easing: Animated.EasingFunction } {
|
||||
if (current) {
|
||||
if (spec.animation !== 'timing') {
|
||||
return current;
|
||||
}
|
||||
|
||||
const { config } = spec;
|
||||
|
||||
current.duration.setValue(config.duration);
|
||||
|
||||
return current;
|
||||
} else {
|
||||
const config: Partial<TimingConfig> =
|
||||
spec.animation !== 'timing' ? {} : spec.config;
|
||||
|
||||
return {
|
||||
duration: new Animated.Value(config.duration || 0),
|
||||
easing: config.easing !== undefined ? config.easing : Easing.linear,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getInvertedMultiplier(gestureDirection: GestureDirection): 1 | -1 {
|
||||
switch (gestureDirection) {
|
||||
case 'vertical':
|
||||
return 1;
|
||||
case 'vertical-inverted':
|
||||
return -1;
|
||||
case 'horizontal':
|
||||
return I18nManager.isRTL ? -1 : 1;
|
||||
case 'horizontal-inverted':
|
||||
return I18nManager.isRTL ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
export default class Card extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
overlayEnabled: Platform.OS !== 'ios',
|
||||
@@ -262,15 +82,12 @@ export default class Card extends React.Component<Props> {
|
||||
gestureVelocityImpact: GESTURE_VELOCITY_IMPACT,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.animate({ closing: this.props.closing });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
const {
|
||||
layout,
|
||||
gestureEnabled,
|
||||
gestureDirection,
|
||||
gestureVelocityImpact,
|
||||
transitionSpec,
|
||||
closing,
|
||||
} = this.props;
|
||||
const { layout, gestureDirection, closing } = this.props;
|
||||
const { width, height } = layout;
|
||||
|
||||
if (width !== prevProps.layout.width) {
|
||||
@@ -281,179 +98,104 @@ export default class Card extends React.Component<Props> {
|
||||
this.layout.height.setValue(height);
|
||||
}
|
||||
|
||||
if (gestureEnabled !== prevProps.gestureEnabled) {
|
||||
this.isGestureEnabled.setValue(gestureEnabled ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
if (gestureVelocityImpact !== prevProps.gestureVelocityImpact) {
|
||||
this.gestureVelocityImpact.setValue(gestureVelocityImpact);
|
||||
}
|
||||
|
||||
if (gestureDirection !== prevProps.gestureDirection) {
|
||||
this.direction.setValue(
|
||||
gestureDirection === 'vertical' ||
|
||||
gestureDirection === 'vertical-inverted'
|
||||
? DIRECTION_VERTICAL
|
||||
: DIRECTION_HORIZONTAL
|
||||
);
|
||||
|
||||
this.inverted.setValue(getInvertedMultiplier(gestureDirection));
|
||||
}
|
||||
|
||||
if (transitionSpec.open !== prevProps.transitionSpec.open) {
|
||||
if (
|
||||
transitionSpec.open.animation !==
|
||||
prevProps.transitionSpec.open.animation
|
||||
) {
|
||||
this.animationTypeOpen.setValue(
|
||||
transitionSpec.open.animation === 'spring'
|
||||
? ANIMATION_SPRING
|
||||
: ANIMATION_TIMING
|
||||
);
|
||||
}
|
||||
|
||||
transformTimingConfigToAnimatedValues(
|
||||
transitionSpec.open,
|
||||
this.timingConfigOpen
|
||||
);
|
||||
|
||||
transformSpringConfigToAnimatedValues(
|
||||
transitionSpec.open,
|
||||
this.springConfigOpen
|
||||
);
|
||||
}
|
||||
|
||||
if (transitionSpec.close !== prevProps.transitionSpec.close) {
|
||||
if (
|
||||
transitionSpec.close.animation !==
|
||||
prevProps.transitionSpec.close.animation
|
||||
) {
|
||||
this.animationTypeClose.setValue(
|
||||
transitionSpec.close.animation === 'spring'
|
||||
? ANIMATION_SPRING
|
||||
: ANIMATION_TIMING
|
||||
);
|
||||
}
|
||||
|
||||
transformTimingConfigToAnimatedValues(
|
||||
transitionSpec.close,
|
||||
this.timingConfigClose
|
||||
);
|
||||
|
||||
transformSpringConfigToAnimatedValues(
|
||||
transitionSpec.close,
|
||||
this.springConfigClose
|
||||
);
|
||||
}
|
||||
|
||||
if (closing !== prevProps.closing) {
|
||||
// If the style updates during render, setting the value here doesn't work
|
||||
// We need to defer it a bit so the animation starts properly
|
||||
requestAnimationFrame(() =>
|
||||
requestAnimationFrame(() =>
|
||||
this.isClosing.setValue(closing ? TRUE : FALSE)
|
||||
)
|
||||
);
|
||||
if (
|
||||
this.getAnimateToValue(this.props) !== this.getAnimateToValue(prevProps)
|
||||
) {
|
||||
// We need to trigger the animation when route was closed
|
||||
// Thr route might have been closed by a `POP` action or by a gesture
|
||||
// When route was closed due to a gesture, the animation would've happened already
|
||||
// It's still important to trigger the animation so that `onClose` is called
|
||||
// If `onClose` is not called, cleanup step won't be performed for gestures
|
||||
this.animate({ closing });
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
componentWillUnmount() {
|
||||
this.handleEndInteraction();
|
||||
|
||||
// It might sometimes happen than animation will be unmounted
|
||||
// during running. However, we need to invoke listener onClose
|
||||
// manually in this case
|
||||
if (this.isRunningAnimation || this.noAnimationStartedSoFar) {
|
||||
this.props.onClose(false);
|
||||
}
|
||||
}
|
||||
|
||||
private isVisible = new Value<Binary>(TRUE);
|
||||
private nextIsVisible = new Value<Binary | -1>(UNSET);
|
||||
private isClosing = new Animated.Value(FALSE);
|
||||
|
||||
private animationTypeOpen = new Value<Binary>(
|
||||
this.props.transitionSpec.open.animation === 'spring'
|
||||
? ANIMATION_SPRING
|
||||
: ANIMATION_TIMING
|
||||
);
|
||||
|
||||
private animationTypeClose = new Value<Binary>(
|
||||
this.props.transitionSpec.open.animation === 'spring'
|
||||
? ANIMATION_SPRING
|
||||
: ANIMATION_TIMING
|
||||
);
|
||||
|
||||
private isGestureEnabled = new Value<Binary>(
|
||||
this.props.gestureEnabled ? TRUE : FALSE
|
||||
);
|
||||
|
||||
private isClosing = new Value<Binary>(FALSE);
|
||||
private noAnimationStartedSoFar = true;
|
||||
private isRunningAnimation = false;
|
||||
|
||||
private clock = new Clock();
|
||||
|
||||
private direction = new Value(
|
||||
this.props.gestureDirection === 'vertical' ||
|
||||
this.props.gestureDirection === 'vertical-inverted'
|
||||
? DIRECTION_VERTICAL
|
||||
: DIRECTION_HORIZONTAL
|
||||
);
|
||||
|
||||
private inverted = new Value(
|
||||
private inverted = new Animated.Value(
|
||||
getInvertedMultiplier(this.props.gestureDirection)
|
||||
);
|
||||
|
||||
private layout = {
|
||||
width: new Value(this.props.layout.width),
|
||||
height: new Value(this.props.layout.height),
|
||||
width: new Animated.Value(this.props.layout.width),
|
||||
height: new Animated.Value(this.props.layout.height),
|
||||
};
|
||||
|
||||
private gestureVelocityImpact = new Value<number>(
|
||||
this.props.gestureVelocityImpact
|
||||
);
|
||||
|
||||
private springConfigOpen = transformSpringConfigToAnimatedValues(
|
||||
this.props.transitionSpec.open
|
||||
);
|
||||
|
||||
private springConfigClose = transformSpringConfigToAnimatedValues(
|
||||
this.props.transitionSpec.close
|
||||
);
|
||||
|
||||
private timingConfigOpen = transformTimingConfigToAnimatedValues(
|
||||
this.props.transitionSpec.open
|
||||
);
|
||||
|
||||
private timingConfigClose = transformTimingConfigToAnimatedValues(
|
||||
this.props.transitionSpec.close
|
||||
);
|
||||
|
||||
private distance = cond(
|
||||
eq(this.direction, DIRECTION_VERTICAL),
|
||||
this.layout.height,
|
||||
this.layout.width
|
||||
);
|
||||
|
||||
private gesture = new Value(0);
|
||||
private offset = new Value(0);
|
||||
private velocity = new Value(0);
|
||||
|
||||
private gestureState = new Value(0);
|
||||
|
||||
private isSwiping = new Value(FALSE);
|
||||
private isSwipeCancelled = new Value(FALSE);
|
||||
private isSwipeGesture = new Value(FALSE);
|
||||
|
||||
private transitionConfig = {
|
||||
time: new Value(0),
|
||||
frameTime: new Value(0),
|
||||
finished: new Value(FALSE),
|
||||
velocity: new Value(0),
|
||||
};
|
||||
private isSwiping = new Animated.Value(FALSE);
|
||||
|
||||
private interactionHandle: number | undefined;
|
||||
|
||||
private animate = ({
|
||||
closing,
|
||||
velocity,
|
||||
}: {
|
||||
closing?: boolean;
|
||||
velocity?: number;
|
||||
}) => {
|
||||
const {
|
||||
gesture,
|
||||
transitionSpec,
|
||||
onOpen,
|
||||
onClose,
|
||||
onTransitionStart,
|
||||
} = this.props;
|
||||
|
||||
const toValue = this.getAnimateToValue({
|
||||
...this.props,
|
||||
closing,
|
||||
});
|
||||
|
||||
const spec = closing ? transitionSpec.close : transitionSpec.open;
|
||||
|
||||
const animation =
|
||||
spec.animation === 'spring' ? Animated.spring : Animated.timing;
|
||||
|
||||
this.handleStartInteraction();
|
||||
|
||||
onTransitionStart?.({ closing: Boolean(closing) });
|
||||
animation(gesture, {
|
||||
...spec.config,
|
||||
velocity,
|
||||
toValue,
|
||||
useNativeDriver: true,
|
||||
isInteraction: false,
|
||||
}).start(({ finished }) => {
|
||||
this.handleEndInteraction();
|
||||
|
||||
if (finished) {
|
||||
if (closing) {
|
||||
onClose();
|
||||
} else {
|
||||
onOpen();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
private getAnimateToValue = ({
|
||||
closing,
|
||||
layout,
|
||||
gestureDirection,
|
||||
}: {
|
||||
closing?: boolean;
|
||||
layout: Layout;
|
||||
gestureDirection: GestureDirection;
|
||||
}) => {
|
||||
if (!closing) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getDistanceForDirection(layout, gestureDirection);
|
||||
};
|
||||
|
||||
private handleStartInteraction = () => {
|
||||
if (this.interactionHandle === undefined) {
|
||||
this.interactionHandle = InteractionManager.createInteractionHandle();
|
||||
@@ -467,221 +209,68 @@ export default class Card extends React.Component<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
private handleTransitionEnd = () => {
|
||||
this.handleEndInteraction();
|
||||
private handleGestureStateChange = ({
|
||||
nativeEvent,
|
||||
}: PanGestureHandlerGestureEvent) => {
|
||||
const {
|
||||
layout,
|
||||
onGestureBegin,
|
||||
onGestureCanceled,
|
||||
onGestureEnd,
|
||||
gestureDirection,
|
||||
gestureVelocityImpact,
|
||||
} = this.props;
|
||||
|
||||
this.isRunningAnimation = false;
|
||||
this.interpolatedStyle = this.getInterpolatedStyle(
|
||||
this.props.styleInterpolator,
|
||||
this.props.index,
|
||||
this.props.current,
|
||||
this.props.next,
|
||||
this.props.layout,
|
||||
this.props.insets.top,
|
||||
this.props.insets.right,
|
||||
this.props.insets.bottom,
|
||||
this.props.insets.left
|
||||
);
|
||||
};
|
||||
|
||||
private listenerOnStart = call(
|
||||
[this.isVisible],
|
||||
([value]: ReadonlyArray<Binary>) => {
|
||||
this.handleStartInteraction();
|
||||
|
||||
const { onTransitionStart } = this.props;
|
||||
this.noAnimationStartedSoFar = false;
|
||||
this.isRunningAnimation = true;
|
||||
onTransitionStart && onTransitionStart({ closing: !value });
|
||||
}
|
||||
);
|
||||
|
||||
private listenerOnEnd = call(
|
||||
[this.isVisible],
|
||||
([value]: ReadonlyArray<Binary>) => {
|
||||
const isOpen = Boolean(value);
|
||||
const { onOpen, onClose } = this.props;
|
||||
|
||||
this.handleTransitionEnd();
|
||||
|
||||
if (isOpen) {
|
||||
onOpen(true);
|
||||
} else {
|
||||
onClose(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private listenerOnCancel = call([], () => {
|
||||
this.isRunningAnimation = false;
|
||||
});
|
||||
|
||||
private listenerOnSwipe = call(
|
||||
[this.isSwiping, this.isSwipeCancelled],
|
||||
([isSwiping, isSwipeCancelled]: readonly Binary[]) => {
|
||||
const { onGestureBegin, onGestureEnd, onGestureCanceled } = this.props;
|
||||
|
||||
if (isSwiping === TRUE) {
|
||||
switch (nativeEvent.state) {
|
||||
case GestureState.BEGAN:
|
||||
this.isSwiping.setValue(TRUE);
|
||||
this.handleStartInteraction();
|
||||
|
||||
onGestureBegin && onGestureBegin();
|
||||
} else {
|
||||
onGestureBegin?.();
|
||||
break;
|
||||
case GestureState.CANCELLED:
|
||||
this.isSwiping.setValue(FALSE);
|
||||
this.handleEndInteraction();
|
||||
onGestureCanceled?.();
|
||||
break;
|
||||
case GestureState.END: {
|
||||
this.isSwiping.setValue(FALSE);
|
||||
|
||||
if (isSwipeCancelled === TRUE) {
|
||||
onGestureCanceled && onGestureCanceled();
|
||||
let distance;
|
||||
let translation;
|
||||
let velocity;
|
||||
|
||||
if (
|
||||
gestureDirection === 'vertical' ||
|
||||
gestureDirection === 'vertical-inverted'
|
||||
) {
|
||||
distance = layout.height;
|
||||
translation = nativeEvent.translationY;
|
||||
velocity = nativeEvent.velocityY;
|
||||
} else {
|
||||
onGestureEnd && onGestureEnd();
|
||||
distance = layout.width;
|
||||
translation = nativeEvent.translationX;
|
||||
velocity = nativeEvent.velocityX;
|
||||
}
|
||||
|
||||
const closing =
|
||||
Math.abs(translation + velocity * gestureVelocityImpact) >
|
||||
distance / 2
|
||||
? velocity !== 0 || translation !== 0
|
||||
: false;
|
||||
|
||||
this.animate({ closing, velocity });
|
||||
onGestureEnd?.();
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private listenerOnTransitionEnd = call([], this.handleTransitionEnd);
|
||||
|
||||
private runAnimation = () => {
|
||||
const state = {
|
||||
position: this.props.current,
|
||||
...this.transitionConfig,
|
||||
};
|
||||
|
||||
return cond(
|
||||
eq(this.isVisible, TRUE),
|
||||
cond(
|
||||
eq(this.animationTypeOpen, ANIMATION_SPRING),
|
||||
runSpring(this.clock, state, {
|
||||
...this.springConfigOpen,
|
||||
toValue: this.isVisible,
|
||||
}),
|
||||
timing(this.clock, state, {
|
||||
...this.timingConfigOpen,
|
||||
toValue: this.isVisible,
|
||||
})
|
||||
),
|
||||
cond(
|
||||
eq(this.animationTypeClose, ANIMATION_SPRING),
|
||||
runSpring(this.clock, state, {
|
||||
...this.springConfigClose,
|
||||
toValue: this.isVisible,
|
||||
}),
|
||||
timing(this.clock, state, {
|
||||
...this.timingConfigClose,
|
||||
toValue: this.isVisible,
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
private exec = animate(
|
||||
clockRunning(this.clock),
|
||||
startClock(this.clock),
|
||||
stopClock(this.clock),
|
||||
this.distance,
|
||||
this.gesture,
|
||||
this.gestureState,
|
||||
this.gestureVelocityImpact,
|
||||
this.isClosing,
|
||||
this.isGestureEnabled,
|
||||
this.isSwipeCancelled,
|
||||
this.isSwipeGesture,
|
||||
this.isSwiping,
|
||||
this.isVisible,
|
||||
this.listenerOnCancel,
|
||||
this.listenerOnEnd,
|
||||
this.listenerOnStart,
|
||||
this.listenerOnSwipe,
|
||||
this.listenerOnTransitionEnd,
|
||||
this.nextIsVisible,
|
||||
this.offset,
|
||||
this.props.current,
|
||||
this.runAnimation(),
|
||||
this.transitionConfig.finished,
|
||||
this.transitionConfig.frameTime,
|
||||
this.transitionConfig.time,
|
||||
this.transitionConfig.velocity,
|
||||
this.velocity
|
||||
);
|
||||
|
||||
private handleGestureEventHorizontal = Animated.event([
|
||||
{
|
||||
nativeEvent: {
|
||||
translationX: (x: Animated.Node<number>) =>
|
||||
set(this.gesture, multiply(x, this.inverted)),
|
||||
velocityX: (x: Animated.Node<number>) =>
|
||||
set(this.velocity, multiply(x, this.inverted)),
|
||||
state: this.gestureState,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
private handleGestureEventVertical = Animated.event([
|
||||
{
|
||||
nativeEvent: {
|
||||
translationY: (y: Animated.Node<number>) =>
|
||||
set(this.gesture, multiply(y, this.inverted)),
|
||||
velocityY: (y: Animated.Node<number>) =>
|
||||
set(this.velocity, multiply(y, this.inverted)),
|
||||
state: this.gestureState,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
// We need to ensure that this style doesn't change unless absolutely needs to
|
||||
// Changing it too often will result in huge frame drops due to detaching and attaching
|
||||
// Changing it during an animations can result in unexpected results
|
||||
private getInterpolatedStyle = memoize(
|
||||
(
|
||||
styleInterpolator: StackCardStyleInterpolator,
|
||||
index: number,
|
||||
current: Animated.Node<number>,
|
||||
next: Animated.Node<number> | undefined,
|
||||
layout: Layout,
|
||||
insetTop: number,
|
||||
insetRight: number,
|
||||
insetBottom: number,
|
||||
insetLeft: number
|
||||
) =>
|
||||
styleInterpolator({
|
||||
index,
|
||||
current: { progress: current },
|
||||
next: next && { progress: next },
|
||||
closing: this.isClosing,
|
||||
swiping: this.isSwiping,
|
||||
inverted: this.inverted,
|
||||
layouts: {
|
||||
screen: layout,
|
||||
},
|
||||
insets: {
|
||||
top: insetTop,
|
||||
right: insetRight,
|
||||
bottom: insetBottom,
|
||||
left: insetLeft,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Keep track of the style in a property to avoid changing the animated node when deps change
|
||||
// The style shouldn't change in the middle of the animation and should refer to what was there at the start of it
|
||||
// Which will be the last value when just before the render which started the animation
|
||||
// We need to make sure to update this when the running animation ends
|
||||
private interpolatedStyle = this.getInterpolatedStyle(
|
||||
this.props.styleInterpolator,
|
||||
this.props.index,
|
||||
this.props.current,
|
||||
this.props.next,
|
||||
this.props.layout,
|
||||
this.props.insets.top,
|
||||
this.props.insets.right,
|
||||
this.props.insets.bottom,
|
||||
this.props.insets.left
|
||||
);
|
||||
|
||||
// Keep track of the animation context when deps changes.
|
||||
private getCardAnimationContext = memoize(
|
||||
(
|
||||
index: number,
|
||||
current: Animated.Node<number>,
|
||||
next: Animated.Node<number> | undefined,
|
||||
current: Animated.AnimatedInterpolation,
|
||||
next: Animated.AnimatedInterpolation | undefined,
|
||||
layout: Layout,
|
||||
insetTop: number,
|
||||
insetRight: number,
|
||||
@@ -712,12 +301,10 @@ export default class Card extends React.Component<Props> {
|
||||
const distance =
|
||||
gestureDirection === 'vertical' ||
|
||||
gestureDirection === 'vertical-inverted'
|
||||
? gestureResponseDistance &&
|
||||
gestureResponseDistance.vertical !== undefined
|
||||
? gestureResponseDistance?.vertical !== undefined
|
||||
? gestureResponseDistance.vertical
|
||||
: GESTURE_RESPONSE_DISTANCE_VERTICAL
|
||||
: gestureResponseDistance &&
|
||||
gestureResponseDistance.horizontal !== undefined
|
||||
: gestureResponseDistance?.horizontal !== undefined
|
||||
? gestureResponseDistance.horizontal
|
||||
: GESTURE_RESPONSE_DISTANCE_HORIZONTAL;
|
||||
|
||||
@@ -761,6 +348,7 @@ export default class Card extends React.Component<Props> {
|
||||
styleInterpolator,
|
||||
index,
|
||||
current,
|
||||
gesture,
|
||||
next,
|
||||
layout,
|
||||
insets,
|
||||
@@ -774,19 +362,18 @@ export default class Card extends React.Component<Props> {
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
if (!this.isRunningAnimation) {
|
||||
this.interpolatedStyle = this.getInterpolatedStyle(
|
||||
styleInterpolator,
|
||||
index,
|
||||
current,
|
||||
next,
|
||||
layout,
|
||||
insets.top,
|
||||
insets.right,
|
||||
insets.bottom,
|
||||
insets.left
|
||||
);
|
||||
}
|
||||
const interpolatedStyle = styleInterpolator({
|
||||
index,
|
||||
current: { progress: current },
|
||||
next: next && { progress: next },
|
||||
closing: this.isClosing,
|
||||
swiping: this.isSwiping,
|
||||
inverted: this.inverted,
|
||||
layouts: {
|
||||
screen: layout,
|
||||
},
|
||||
insets,
|
||||
});
|
||||
|
||||
const animationContext = this.getCardAnimationContext(
|
||||
index,
|
||||
@@ -804,12 +391,21 @@ export default class Card extends React.Component<Props> {
|
||||
cardStyle,
|
||||
overlayStyle,
|
||||
shadowStyle,
|
||||
} = this.interpolatedStyle;
|
||||
} = interpolatedStyle;
|
||||
|
||||
const handleGestureEvent = gestureEnabled
|
||||
? gestureDirection === 'vertical'
|
||||
? this.handleGestureEventVertical
|
||||
: this.handleGestureEventHorizontal
|
||||
? Animated.event(
|
||||
[
|
||||
{
|
||||
nativeEvent:
|
||||
gestureDirection === 'vertical' ||
|
||||
gestureDirection === 'vertical-inverted'
|
||||
? { translationY: gesture }
|
||||
: { translationX: gesture },
|
||||
},
|
||||
],
|
||||
{ useNativeDriver: true }
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const { backgroundColor } = StyleSheet.flatten(contentStyle || {});
|
||||
@@ -820,10 +416,6 @@ export default class Card extends React.Component<Props> {
|
||||
return (
|
||||
<StackGestureContext.Provider value={this.gestureRef}>
|
||||
<View pointerEvents="box-none" {...rest}>
|
||||
<Animated.Code
|
||||
key={gestureEnabled ? 'gesture-code' : 'no-gesture-code'}
|
||||
exec={this.exec}
|
||||
/>
|
||||
{overlayEnabled && overlayStyle ? (
|
||||
<Animated.View
|
||||
pointerEvents="none"
|
||||
@@ -838,7 +430,7 @@ export default class Card extends React.Component<Props> {
|
||||
ref={this.gestureRef}
|
||||
enabled={layout.width !== 0 && gestureEnabled}
|
||||
onGestureEvent={handleGestureEvent}
|
||||
onHandlerStateChange={handleGestureEvent}
|
||||
onHandlerStateChange={this.handleGestureStateChange}
|
||||
{...this.gestureActivationCriteria()}
|
||||
>
|
||||
<Animated.View style={[styles.container, cardStyle]}>
|
||||
@@ -856,7 +448,7 @@ export default class Card extends React.Component<Props> {
|
||||
) : null}
|
||||
<PointerEventsView
|
||||
active={active}
|
||||
progress={this.props.current}
|
||||
progress={current}
|
||||
style={[styles.content, contentStyle]}
|
||||
>
|
||||
<StackCardAnimationContext.Provider value={animationContext}>
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { State as GestureState } from 'react-native-gesture-handler';
|
||||
|
||||
export type Binary = 0 | 1;
|
||||
|
||||
const TRUE_NODE = new Animated.Value(1);
|
||||
const FALSE_NODE = new Animated.Value(0);
|
||||
const UNSET_NODE = new Animated.Value(-1);
|
||||
|
||||
const NOOP_NODE = FALSE_NODE;
|
||||
|
||||
const {
|
||||
abs,
|
||||
add,
|
||||
and,
|
||||
block,
|
||||
cond,
|
||||
divide,
|
||||
eq,
|
||||
greaterThan,
|
||||
lessThan,
|
||||
max,
|
||||
min,
|
||||
multiply,
|
||||
neq,
|
||||
onChange,
|
||||
set,
|
||||
sub,
|
||||
proc,
|
||||
} = Animated;
|
||||
|
||||
const proc2 = proc(
|
||||
(
|
||||
clockIsRunning: Animated.Node<number>,
|
||||
clockStart: Animated.Node<number>,
|
||||
clockStop: Animated.Node<number>,
|
||||
distance: Animated.Node<number>,
|
||||
gesture: Animated.Value<number>,
|
||||
gestureState: Animated.Node<number>,
|
||||
gestureVelocityImpact: Animated.Node<number>,
|
||||
isGestureEnabled: Animated.Node<number>,
|
||||
isSwipeCancelled: Animated.Value<number>,
|
||||
isSwipeGesture: Animated.Value<number>,
|
||||
isSwiping: Animated.Value<number>,
|
||||
isVisible: Animated.Value<number>,
|
||||
listenerOnCancel: Animated.Node<number>,
|
||||
listenerOnEnd: Animated.Node<number>,
|
||||
listenerOnStart: Animated.Node<number>,
|
||||
listenerOnSwipe: Animated.Node<number>,
|
||||
offset: Animated.Value<number>,
|
||||
position: Animated.Value<number>,
|
||||
runAnimation: Animated.Node<number>,
|
||||
transitionFinished: Animated.Value<number>,
|
||||
transitionFrameTime: Animated.Value<number>,
|
||||
transitionTime: Animated.Value<number>,
|
||||
transitionVelocity: Animated.Value<number>,
|
||||
velocity: Animated.Value<number>
|
||||
) => {
|
||||
const runTransition = (transitionTo: Binary | Animated.Node<number>) => {
|
||||
return cond(eq(position, transitionTo), NOOP_NODE, [
|
||||
cond(clockIsRunning, NOOP_NODE, [
|
||||
// The velocity value is ideal for translating the whole screen
|
||||
// But since we have 0-1 scale, we need to adjust the velocity
|
||||
set(
|
||||
transitionVelocity,
|
||||
multiply(cond(distance, divide(velocity, distance), 0), -1)
|
||||
),
|
||||
// Animation wasn't running before
|
||||
// Set the initial values and start the clock
|
||||
set(transitionFrameTime, 0),
|
||||
set(transitionTime, 0),
|
||||
set(transitionFinished, FALSE_NODE),
|
||||
set(isVisible, transitionTo),
|
||||
clockStart,
|
||||
listenerOnStart,
|
||||
]),
|
||||
runAnimation,
|
||||
cond(transitionFinished, [
|
||||
// Reset values
|
||||
set(isSwipeGesture, FALSE_NODE),
|
||||
set(gesture, FALSE_NODE),
|
||||
set(velocity, FALSE_NODE),
|
||||
// When the animation finishes, stop the clock
|
||||
clockStop,
|
||||
listenerOnEnd,
|
||||
]),
|
||||
]);
|
||||
};
|
||||
return block([
|
||||
cond(
|
||||
isGestureEnabled,
|
||||
[
|
||||
onChange(isSwiping, listenerOnSwipe),
|
||||
cond(
|
||||
eq(gestureState, GestureState.ACTIVE),
|
||||
[
|
||||
cond(isSwiping, NOOP_NODE, [
|
||||
// We weren't dragging before, set it to true
|
||||
set(isSwipeCancelled, FALSE_NODE),
|
||||
set(isSwiping, TRUE_NODE),
|
||||
set(isSwipeGesture, TRUE_NODE),
|
||||
// Also update the drag offset to the last position
|
||||
set(offset, position),
|
||||
]),
|
||||
// Update position with next offset + gesture distance
|
||||
set(
|
||||
position,
|
||||
min(
|
||||
max(
|
||||
sub(
|
||||
offset,
|
||||
cond(distance, divide(gesture, distance), TRUE_NODE)
|
||||
),
|
||||
FALSE_NODE
|
||||
),
|
||||
TRUE_NODE
|
||||
)
|
||||
),
|
||||
// Stop animations while we're dragging
|
||||
cond(clockIsRunning, listenerOnCancel),
|
||||
clockStop,
|
||||
],
|
||||
[
|
||||
set(isSwipeCancelled, eq(gestureState, GestureState.CANCELLED)),
|
||||
set(isSwiping, FALSE_NODE),
|
||||
runTransition(
|
||||
cond(
|
||||
greaterThan(
|
||||
abs(
|
||||
add(gesture, multiply(velocity, gestureVelocityImpact))
|
||||
),
|
||||
divide(distance, 2)
|
||||
),
|
||||
cond(
|
||||
lessThan(cond(eq(velocity, 0), gesture, velocity), 0),
|
||||
TRUE_NODE,
|
||||
FALSE_NODE
|
||||
),
|
||||
isVisible
|
||||
)
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
runTransition(isVisible)
|
||||
),
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
const proc1 = proc(
|
||||
(
|
||||
nextIsVisible: Animated.Value<number>,
|
||||
isVisible: Animated.Value<number>,
|
||||
clockIsRunning: Animated.Node<number>,
|
||||
listenerOnTransitionEnd: Animated.Node<number>,
|
||||
clockStop: Animated.Node<number>,
|
||||
gesture: Animated.Value<number>
|
||||
) => {
|
||||
return cond(
|
||||
and(neq(nextIsVisible, UNSET_NODE), neq(nextIsVisible, isVisible)),
|
||||
[
|
||||
// Stop any running animations
|
||||
cond(clockIsRunning, [listenerOnTransitionEnd, clockStop]),
|
||||
set(gesture, FALSE_NODE),
|
||||
// Update the index to trigger the transition
|
||||
set(isVisible, nextIsVisible),
|
||||
set(nextIsVisible, UNSET_NODE),
|
||||
]
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// For a reason which I'm currently not understanding
|
||||
// Animated nodes behave incorrectly in procs in some cases, so
|
||||
// by bisecting I figured out that some lines need to be outside procs.
|
||||
// I split the rest of lines into 3 procs in order to make it work correctly.
|
||||
// Probably it's an error in native reanimated code,
|
||||
// but I have no proof for that.
|
||||
|
||||
export default (
|
||||
clockIsRunning: Animated.Node<number>,
|
||||
clockStart: Animated.Node<number>,
|
||||
clockStop: Animated.Node<number>,
|
||||
distance: Animated.Node<number>,
|
||||
gesture: Animated.Value<number>,
|
||||
gestureState: Animated.Node<number>,
|
||||
gestureVelocityImpact: Animated.Node<number>,
|
||||
isClosing: Animated.Node<number>,
|
||||
isGestureEnabled: Animated.Node<number>,
|
||||
isSwipeCancelled: Animated.Value<number>,
|
||||
isSwipeGesture: Animated.Value<number>,
|
||||
isSwiping: Animated.Value<number>,
|
||||
isVisible: Animated.Value<number>,
|
||||
listenerOnCancel: Animated.Node<number>,
|
||||
listenerOnEnd: Animated.Node<number>,
|
||||
listenerOnStart: Animated.Node<number>,
|
||||
listenerOnSwipe: Animated.Node<number>,
|
||||
listenerOnTransitionEnd: Animated.Node<number>,
|
||||
nextIsVisible: Animated.Value<number>,
|
||||
offset: Animated.Value<number>,
|
||||
position: Animated.Value<number>,
|
||||
runAnimation: Animated.Node<number>,
|
||||
transitionFinished: Animated.Value<number>,
|
||||
transitionFrameTime: Animated.Value<number>,
|
||||
transitionTime: Animated.Value<number>,
|
||||
transitionVelocity: Animated.Value<number>,
|
||||
velocity: Animated.Value<number>
|
||||
) => {
|
||||
return block([
|
||||
onChange(isClosing, cond(isClosing, set(nextIsVisible, FALSE_NODE))),
|
||||
onChange(
|
||||
nextIsVisible,
|
||||
proc1(
|
||||
nextIsVisible,
|
||||
isVisible,
|
||||
clockIsRunning,
|
||||
listenerOnTransitionEnd,
|
||||
clockStop,
|
||||
gesture
|
||||
)
|
||||
),
|
||||
proc2(
|
||||
clockIsRunning,
|
||||
clockStart,
|
||||
clockStop,
|
||||
distance,
|
||||
gesture,
|
||||
gestureState,
|
||||
gestureVelocityImpact,
|
||||
isGestureEnabled,
|
||||
isSwipeCancelled,
|
||||
isSwipeGesture,
|
||||
isSwiping,
|
||||
isVisible,
|
||||
listenerOnCancel,
|
||||
listenerOnEnd,
|
||||
listenerOnStart,
|
||||
listenerOnSwipe,
|
||||
offset,
|
||||
position,
|
||||
runAnimation,
|
||||
transitionFinished,
|
||||
transitionFrameTime,
|
||||
transitionTime,
|
||||
transitionVelocity,
|
||||
velocity
|
||||
),
|
||||
]);
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||
import { StackNavigationState } from '@react-navigation/routers';
|
||||
import { Route, useTheme } from '@react-navigation/native';
|
||||
import { Props as HeaderContainerProps } from '../Header/HeaderContainer';
|
||||
@@ -13,7 +12,7 @@ type Props = TransitionPreset & {
|
||||
focused: boolean;
|
||||
closing: boolean;
|
||||
layout: Layout;
|
||||
current: Animated.Value<number>;
|
||||
gesture: Animated.Value;
|
||||
previousScene?: Scene<Route<string>>;
|
||||
scene: Scene<Route<string>>;
|
||||
state: StackNavigationState;
|
||||
@@ -31,7 +30,6 @@ type Props = TransitionPreset & {
|
||||
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
||||
onOpenRoute: (props: { route: Route<string> }) => void;
|
||||
onCloseRoute: (props: { route: Route<string> }) => void;
|
||||
onGoBack: (props: { route: Route<string> }) => void;
|
||||
onTransitionStart?: (
|
||||
props: { route: Route<string> },
|
||||
closing: boolean
|
||||
@@ -59,7 +57,7 @@ export default function CardContainer({
|
||||
cardStyle,
|
||||
cardStyleInterpolator,
|
||||
closing,
|
||||
current,
|
||||
gesture,
|
||||
floatingHeaderHeight,
|
||||
focused,
|
||||
gestureDirection,
|
||||
@@ -74,7 +72,6 @@ export default function CardContainer({
|
||||
index,
|
||||
layout,
|
||||
onCloseRoute,
|
||||
onGoBack,
|
||||
onOpenRoute,
|
||||
onPageChangeCancel,
|
||||
onPageChangeConfirm,
|
||||
@@ -92,25 +89,28 @@ export default function CardContainer({
|
||||
state,
|
||||
transitionSpec,
|
||||
}: Props) {
|
||||
React.useEffect(() => {
|
||||
onPageChangeConfirm?.();
|
||||
}, [active, onPageChangeConfirm]);
|
||||
|
||||
const handleOpen = () => {
|
||||
onTransitionEnd && onTransitionEnd({ route: scene.route }, false);
|
||||
onTransitionEnd?.({ route: scene.route }, false);
|
||||
onOpenRoute({ route: scene.route });
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
onTransitionEnd && onTransitionEnd({ route: scene.route }, true);
|
||||
onTransitionEnd?.({ route: scene.route }, true);
|
||||
onCloseRoute({ route: scene.route });
|
||||
};
|
||||
|
||||
const handleTransitionStart = ({ closing }: { closing: boolean }) => {
|
||||
if (closing) {
|
||||
onPageChangeConfirm && onPageChangeConfirm();
|
||||
if (active && closing) {
|
||||
onPageChangeConfirm?.();
|
||||
} else {
|
||||
onPageChangeCancel && onPageChangeCancel();
|
||||
onPageChangeCancel?.();
|
||||
}
|
||||
|
||||
onTransitionStart && onTransitionStart({ route: scene.route }, closing);
|
||||
closing && onGoBack({ route: scene.route });
|
||||
onTransitionStart?.({ route: scene.route }, closing);
|
||||
};
|
||||
|
||||
const insets = {
|
||||
@@ -129,7 +129,8 @@ export default function CardContainer({
|
||||
gestureDirection={gestureDirection}
|
||||
layout={layout}
|
||||
insets={insets}
|
||||
current={current}
|
||||
gesture={gesture}
|
||||
current={scene.progress.current}
|
||||
next={scene.progress.next}
|
||||
closing={closing}
|
||||
onOpen={handleOpen}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Animated,
|
||||
View,
|
||||
StyleSheet,
|
||||
LayoutChangeEvent,
|
||||
@@ -7,10 +8,9 @@ import {
|
||||
Platform,
|
||||
ViewProps,
|
||||
} from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import * as Screens from 'react-native-screens'; // Import with * as to prevent getters being called
|
||||
import { ScreenContainer, Screen, screensEnabled } from 'react-native-screens'; // Import with * as to prevent getters being called
|
||||
import { Route } from '@react-navigation/native';
|
||||
import { StackNavigationState } from '@react-navigation/routers';
|
||||
|
||||
@@ -23,27 +23,29 @@ import {
|
||||
} from '../../TransitionConfigs/TransitionPresets';
|
||||
import { forNoAnimation as forNoAnimationHeader } from '../../TransitionConfigs/HeaderStyleInterpolators';
|
||||
import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
|
||||
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
||||
import {
|
||||
Layout,
|
||||
StackHeaderMode,
|
||||
StackCardMode,
|
||||
Scene,
|
||||
StackDescriptorMap,
|
||||
StackNavigationOptions,
|
||||
StackDescriptor,
|
||||
} from '../../types';
|
||||
|
||||
type ProgressValues = {
|
||||
[key: string]: Animated.Value<number>;
|
||||
type GestureValues = {
|
||||
[key: string]: Animated.Value;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
mode: 'card' | 'modal';
|
||||
mode: StackCardMode;
|
||||
insets: EdgeInsets;
|
||||
state: StackNavigationState;
|
||||
descriptors: StackDescriptorMap;
|
||||
routes: Route<string>[];
|
||||
openingRouteKeys: string[];
|
||||
closingRouteKeys: string[];
|
||||
onGoBack: (props: { route: Route<string> }) => void;
|
||||
onOpenRoute: (props: { route: Route<string> }) => void;
|
||||
onCloseRoute: (props: { route: Route<string> }) => void;
|
||||
getPreviousRoute: (props: {
|
||||
@@ -67,18 +69,16 @@ type State = {
|
||||
routes: Route<string>[];
|
||||
descriptors: StackDescriptorMap;
|
||||
scenes: Scene<Route<string>>[];
|
||||
progress: ProgressValues;
|
||||
gestures: GestureValues;
|
||||
layout: Layout;
|
||||
floatingHeaderHeights: Record<string, number>;
|
||||
};
|
||||
|
||||
const EPSILON = 1e-5;
|
||||
|
||||
const dimensions = Dimensions.get('window');
|
||||
const layout = { width: dimensions.width, height: dimensions.height };
|
||||
|
||||
let AnimatedScreen: React.ComponentType<ViewProps & {
|
||||
active: number | Animated.Node<number>;
|
||||
}>;
|
||||
|
||||
const MaybeScreenContainer = ({
|
||||
enabled,
|
||||
...rest
|
||||
@@ -86,8 +86,8 @@ const MaybeScreenContainer = ({
|
||||
enabled: boolean;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
if (Platform.OS !== 'ios' && enabled && Screens.screensEnabled()) {
|
||||
return <Screens.ScreenContainer {...rest} />;
|
||||
if (Platform.OS !== 'ios' && enabled && screensEnabled()) {
|
||||
return <ScreenContainer {...rest} />;
|
||||
}
|
||||
|
||||
return <View {...rest} />;
|
||||
@@ -99,23 +99,17 @@ const MaybeScreen = ({
|
||||
...rest
|
||||
}: ViewProps & {
|
||||
enabled: boolean;
|
||||
active: number | Animated.Node<number>;
|
||||
active: number | Animated.AnimatedInterpolation;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
if (Platform.OS !== 'ios' && enabled && Screens.screensEnabled()) {
|
||||
AnimatedScreen =
|
||||
AnimatedScreen || Animated.createAnimatedComponent(Screens.NativeScreen);
|
||||
|
||||
return <AnimatedScreen active={active} {...rest} />;
|
||||
if (Platform.OS !== 'ios' && enabled && screensEnabled()) {
|
||||
// @ts-ignore
|
||||
return <Screen active={active} {...rest} />;
|
||||
}
|
||||
|
||||
return <View {...rest} />;
|
||||
};
|
||||
|
||||
const { cond, eq } = Animated;
|
||||
|
||||
const ANIMATED_ONE = new Animated.Value(1);
|
||||
|
||||
const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
|
||||
|
||||
const getFloatingHeaderHeights = (
|
||||
@@ -143,6 +137,43 @@ const getFloatingHeaderHeights = (
|
||||
}, {});
|
||||
};
|
||||
|
||||
const getDistanceFromOptions = (
|
||||
mode: StackCardMode,
|
||||
layout: Layout,
|
||||
descriptor?: StackDescriptor
|
||||
) => {
|
||||
const {
|
||||
gestureDirection = mode === 'modal'
|
||||
? ModalTransition.gestureDirection
|
||||
: DefaultTransition.gestureDirection,
|
||||
} = descriptor?.options || {};
|
||||
|
||||
return getDistanceForDirection(layout, gestureDirection);
|
||||
};
|
||||
|
||||
const getProgressFromGesture = (
|
||||
mode: StackCardMode,
|
||||
gesture: Animated.Value,
|
||||
layout: Layout,
|
||||
descriptor?: StackDescriptor
|
||||
) => {
|
||||
const distance = getDistanceFromOptions(mode, layout, descriptor);
|
||||
|
||||
if (distance > 0) {
|
||||
return gesture.interpolate({
|
||||
inputRange: [0, distance],
|
||||
outputRange: [1, 0],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
}
|
||||
|
||||
return gesture.interpolate({
|
||||
inputRange: [distance, 0],
|
||||
outputRange: [0, 1],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
};
|
||||
|
||||
export default class CardStack extends React.Component<Props, State> {
|
||||
static getDerivedStateFromProps(props: Props, state: State) {
|
||||
if (
|
||||
@@ -152,17 +183,17 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const progress = props.routes.reduce<ProgressValues>((acc, curr) => {
|
||||
const gestures = props.routes.reduce<GestureValues>((acc, curr) => {
|
||||
const descriptor = props.descriptors[curr.key];
|
||||
const { animationEnabled } = descriptor?.options || {};
|
||||
|
||||
acc[curr.key] =
|
||||
state.progress[curr.key] ||
|
||||
state.gestures[curr.key] ||
|
||||
new Animated.Value(
|
||||
props.openingRouteKeys.includes(curr.key) &&
|
||||
descriptor &&
|
||||
descriptor.options.animationEnabled !== false
|
||||
? 0
|
||||
: 1
|
||||
animationEnabled !== false
|
||||
? getDistanceFromOptions(props.mode, state.layout, descriptor)
|
||||
: 0
|
||||
);
|
||||
|
||||
return acc;
|
||||
@@ -174,41 +205,79 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
const previousRoute = self[index - 1];
|
||||
const nextRoute = self[index + 1];
|
||||
|
||||
const current = progress[route.key];
|
||||
const previous = previousRoute
|
||||
? progress[previousRoute.key]
|
||||
: undefined;
|
||||
const next = nextRoute ? progress[nextRoute.key] : undefined;
|
||||
|
||||
const oldScene = state.scenes[index];
|
||||
|
||||
const currentGesture = gestures[route.key];
|
||||
const previousGesture = previousRoute
|
||||
? gestures[previousRoute.key]
|
||||
: undefined;
|
||||
const nextGesture = nextRoute ? gestures[nextRoute.key] : undefined;
|
||||
|
||||
const descriptor =
|
||||
props.descriptors[route.key] ||
|
||||
state.descriptors[route.key] ||
|
||||
(oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR);
|
||||
|
||||
const nextDescriptor =
|
||||
props.descriptors[nextRoute?.key] ||
|
||||
state.descriptors[nextRoute?.key];
|
||||
|
||||
const previousDescriptor =
|
||||
props.descriptors[previousRoute?.key] ||
|
||||
state.descriptors[previousRoute?.key];
|
||||
|
||||
const scene = {
|
||||
route,
|
||||
previous: previousRoute,
|
||||
descriptor:
|
||||
props.descriptors[route.key] ||
|
||||
state.descriptors[route.key] ||
|
||||
(oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR),
|
||||
descriptor,
|
||||
progress: {
|
||||
current,
|
||||
next,
|
||||
previous,
|
||||
current: getProgressFromGesture(
|
||||
props.mode,
|
||||
currentGesture,
|
||||
state.layout,
|
||||
descriptor
|
||||
),
|
||||
next: nextGesture
|
||||
? getProgressFromGesture(
|
||||
props.mode,
|
||||
nextGesture,
|
||||
state.layout,
|
||||
nextDescriptor
|
||||
)
|
||||
: undefined,
|
||||
previous: previousGesture
|
||||
? getProgressFromGesture(
|
||||
props.mode,
|
||||
previousGesture,
|
||||
state.layout,
|
||||
previousDescriptor
|
||||
)
|
||||
: undefined,
|
||||
},
|
||||
__memo: [
|
||||
route,
|
||||
state.layout,
|
||||
descriptor,
|
||||
nextDescriptor,
|
||||
previousDescriptor,
|
||||
currentGesture,
|
||||
nextGesture,
|
||||
previousGesture,
|
||||
],
|
||||
};
|
||||
|
||||
if (
|
||||
oldScene &&
|
||||
scene.route === oldScene.route &&
|
||||
scene.progress.current === oldScene.progress.current &&
|
||||
scene.progress.next === oldScene.progress.next &&
|
||||
scene.progress.previous === oldScene.progress.previous &&
|
||||
scene.descriptor === oldScene.descriptor
|
||||
scene.__memo.every((it, i) => {
|
||||
// @ts-ignore
|
||||
return oldScene.__memo[i] === it;
|
||||
})
|
||||
) {
|
||||
return oldScene;
|
||||
}
|
||||
|
||||
return scene;
|
||||
}),
|
||||
progress,
|
||||
gestures,
|
||||
descriptors: props.descriptors,
|
||||
floatingHeaderHeights: getFloatingHeaderHeights(
|
||||
props.routes,
|
||||
@@ -223,7 +292,7 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
state: State = {
|
||||
routes: [],
|
||||
scenes: [],
|
||||
progress: {},
|
||||
gestures: {},
|
||||
layout,
|
||||
descriptors: this.props.descriptors,
|
||||
// Used when card's header is null and mode is float to make transition
|
||||
@@ -290,7 +359,6 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
closingRouteKeys,
|
||||
onOpenRoute,
|
||||
onCloseRoute,
|
||||
onGoBack,
|
||||
getPreviousRoute,
|
||||
getGesturesEnabled,
|
||||
renderHeader,
|
||||
@@ -303,7 +371,7 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
onPageChangeCancel,
|
||||
} = this.props;
|
||||
|
||||
const { scenes, layout, progress, floatingHeaderHeights } = this.state;
|
||||
const { scenes, layout, gestures, floatingHeaderHeights } = this.state;
|
||||
|
||||
const focusedRoute = state.routes[state.index];
|
||||
const focusedDescriptor = descriptors[focusedRoute.key];
|
||||
@@ -335,18 +403,22 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
>
|
||||
{routes.map((route, index, self) => {
|
||||
const focused = focusedRoute.key === route.key;
|
||||
const current = progress[route.key];
|
||||
const gesture = gestures[route.key];
|
||||
const scene = scenes[index];
|
||||
const next = self[index + 1]
|
||||
? progress[self[index + 1].key]
|
||||
: ANIMATED_ONE;
|
||||
|
||||
// Display current screen and a screen beneath. On Android screen beneath is hidden on animation finished bs of RNS's issue.
|
||||
// Display current screen and a screen beneath.
|
||||
// On Android screen beneath is hidden on animation finished bs of RNS's issue.
|
||||
const isScreenActive =
|
||||
index === self.length - 1
|
||||
? 1
|
||||
: Platform.OS === 'android'
|
||||
? cond(eq(next, 1), 0, 1)
|
||||
? 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;
|
||||
@@ -427,7 +499,7 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
focused={focused}
|
||||
closing={closingRouteKeys.includes(route.key)}
|
||||
layout={layout}
|
||||
current={current}
|
||||
gesture={gesture}
|
||||
scene={scene}
|
||||
previousScene={scenes[index - 1]}
|
||||
state={state}
|
||||
@@ -453,7 +525,6 @@ export default class CardStack extends React.Component<Props, State> {
|
||||
onCloseRoute={onCloseRoute}
|
||||
onTransitionStart={onTransitionStart}
|
||||
onTransitionEnd={onTransitionEnd}
|
||||
onGoBack={onGoBack}
|
||||
gestureEnabled={index !== 0 && getGesturesEnabled({ route })}
|
||||
gestureVelocityImpact={gestureVelocityImpact}
|
||||
gestureDirection={gestureDirection}
|
||||
|
||||
@@ -1,74 +1,36 @@
|
||||
import * as React from 'react';
|
||||
import { View, ViewProps } from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
|
||||
type Binary = 0 | 1;
|
||||
import { Animated, View, ViewProps } from 'react-native';
|
||||
|
||||
type Props = ViewProps & {
|
||||
active: boolean;
|
||||
progress: Animated.Node<number>;
|
||||
progress: Animated.AnimatedInterpolation;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const MIN_PROGRESS = 0.99;
|
||||
|
||||
const TRUE = 1;
|
||||
const FALSE = 0;
|
||||
const NOOP = 0;
|
||||
|
||||
const { block, greaterThan, cond, set, call, onChange } = Animated;
|
||||
|
||||
/**
|
||||
* Component that automatically computes the `pointerEvents` property
|
||||
* whenever position changes.
|
||||
*/
|
||||
export default class PointerEventsView extends React.Component<Props> {
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (this.props.active !== prevProps.active) {
|
||||
this.pointerEventsEnabled.setValue(this.props.active ? TRUE : FALSE);
|
||||
this.setPointerEventsEnabled(this.props.active);
|
||||
}
|
||||
}
|
||||
|
||||
private pointerEventsEnabled = new Animated.Value<Binary>(
|
||||
this.props.active ? TRUE : FALSE
|
||||
export default function PointerEventsView({ active, ...rest }: Props) {
|
||||
const [pointerEventsEnabled] = React.useState(
|
||||
() => new Animated.Value(active ? TRUE : FALSE)
|
||||
);
|
||||
|
||||
private exec = block([
|
||||
cond(
|
||||
greaterThan(this.props.progress, MIN_PROGRESS),
|
||||
cond(
|
||||
this.pointerEventsEnabled,
|
||||
NOOP,
|
||||
set(this.pointerEventsEnabled, TRUE)
|
||||
),
|
||||
cond(this.pointerEventsEnabled, set(this.pointerEventsEnabled, FALSE))
|
||||
),
|
||||
onChange(
|
||||
this.pointerEventsEnabled,
|
||||
call([this.pointerEventsEnabled], ([value]) => {
|
||||
this.setPointerEventsEnabled(Boolean(this.props.active && value));
|
||||
})
|
||||
),
|
||||
]);
|
||||
const root = React.useRef<View | null>(null);
|
||||
|
||||
private setPointerEventsEnabled = (enabled: boolean) => {
|
||||
const setPointerEventsEnabled = React.useCallback((enabled: boolean) => {
|
||||
const pointerEvents = enabled ? 'box-none' : 'none';
|
||||
|
||||
this.root && this.root.setNativeProps({ pointerEvents });
|
||||
};
|
||||
root.current && root.current.setNativeProps({ pointerEvents });
|
||||
}, []);
|
||||
|
||||
private root: View | null = null;
|
||||
React.useEffect(() => {
|
||||
pointerEventsEnabled.setValue(active ? TRUE : FALSE);
|
||||
setPointerEventsEnabled(active);
|
||||
}, [active, pointerEventsEnabled, setPointerEventsEnabled]);
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { active, progress, ...rest } = this.props;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Animated.Code exec={this.exec} />
|
||||
<View ref={c => (this.root = c)} {...rest} />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
return <View ref={root} {...rest} />;
|
||||
}
|
||||
|
||||
@@ -266,18 +266,6 @@ class StackView extends React.Component<Props, State> {
|
||||
return <HeaderContainer {...props} />;
|
||||
};
|
||||
|
||||
private handleGoBack = ({ route }: { route: Route<string> }) => {
|
||||
const { state, navigation } = this.props;
|
||||
|
||||
// This event will trigger when a gesture ends
|
||||
// We need to perform the transition before removing the route completely
|
||||
navigation.dispatch({
|
||||
...StackActions.pop(),
|
||||
source: route.key,
|
||||
target: state.key,
|
||||
});
|
||||
};
|
||||
|
||||
private handleOpenRoute = ({ route }: { route: Route<string> }) => {
|
||||
this.setState(state => ({
|
||||
routes: state.replacingRouteKeys.length
|
||||
@@ -290,15 +278,33 @@ class StackView extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
private handleCloseRoute = ({ route }: { route: Route<string> }) => {
|
||||
// This event will trigger when the animation for closing the route ends
|
||||
// In this case, we need to clean up any state tracking the route and pop it immediately
|
||||
const { state, navigation } = this.props;
|
||||
|
||||
// @ts-ignore
|
||||
this.setState(state => ({
|
||||
routes: state.routes.filter(r => r.key !== route.key),
|
||||
openingRouteKeys: state.openingRouteKeys.filter(key => key !== route.key),
|
||||
closingRouteKeys: state.closingRouteKeys.filter(key => key !== route.key),
|
||||
}));
|
||||
if (state.routes.find(r => r.key === route.key)) {
|
||||
// If a route exists in state, trigger a pop
|
||||
// This will happen in when the route was closed from the card component
|
||||
// e.g. When the close animation triggered from a gesture ends
|
||||
// For the cleanup, the card needs to call this function again from its componentDidUpdate
|
||||
navigation.dispatch({
|
||||
...StackActions.pop(),
|
||||
source: route.key,
|
||||
target: state.key,
|
||||
});
|
||||
} else {
|
||||
// Otherwise, the animation was triggered due to a route removal
|
||||
// In this case, we need to clean up any state tracking the route and pop it immediately
|
||||
|
||||
// @ts-ignore
|
||||
this.setState(state => ({
|
||||
routes: state.routes.filter(r => r.key !== route.key),
|
||||
openingRouteKeys: state.openingRouteKeys.filter(
|
||||
key => key !== route.key
|
||||
),
|
||||
closingRouteKeys: state.closingRouteKeys.filter(
|
||||
key => key !== route.key
|
||||
),
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
private handleTransitionStart = (
|
||||
@@ -355,7 +361,6 @@ class StackView extends React.Component<Props, State> {
|
||||
routes={routes}
|
||||
openingRouteKeys={openingRouteKeys}
|
||||
closingRouteKeys={closingRouteKeys}
|
||||
onGoBack={this.handleGoBack}
|
||||
onOpenRoute={this.handleOpenRoute}
|
||||
onCloseRoute={this.handleCloseRoute}
|
||||
onTransitionStart={this.handleTransitionStart}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 913 B |
217
yarn.lock
@@ -371,6 +371,14 @@
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-optional-chaining" "^7.7.4"
|
||||
|
||||
"@babel/plugin-proposal-optional-chaining@^7.7.5":
|
||||
version "7.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.7.5.tgz#f0835f044cef85b31071a924010a2a390add11d4"
|
||||
integrity sha512-sOwFqT8JSchtJeDD+CjmWCaiFoLxY4Ps7NjvwHC/U7l4e9i5pTRNt8nDMIFSOUL+ncFbYSwruHM8WknYItWdXw==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-optional-chaining" "^7.7.4"
|
||||
|
||||
"@babel/plugin-proposal-unicode-property-regex@^7.7.4":
|
||||
version "7.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz#7c239ccaf09470dbe1d453d50057460e84517ebb"
|
||||
@@ -2991,57 +2999,40 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.26.tgz#2e7065384ac2b7711271d8790f26ac7d73f6a33d"
|
||||
integrity sha512-5cLJLd8NIT7OfJLi7ScquRn/NWfmewBqJ92nT/FYfdpgKzyUNcR4n2BKEOQ7mOG8WuJXgomIvNl5P3sn9Akd4A==
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^2.3.1":
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.9.0.tgz#fa810282c0e45f6c2310b9c0dfcd25bff97ab7e9"
|
||||
integrity sha512-98rfOt3NYn5Gr9wekTB8TexxN6oM8ZRvYuphPs1Atfsy419SDLYCaE30aJkRiiTCwGEY98vOhFsEVm7Zs4toQQ==
|
||||
"@typescript-eslint/eslint-plugin@^2.12.0":
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.12.0.tgz#0da7cbca7b24f4c6919e9eb31c704bfb126f90ad"
|
||||
integrity sha512-1t4r9rpLuEwl3hgt90jY18wJHSyb0E3orVL3DaqwmpiSDHmHiSspVsvsFF78BJ/3NNG3qmeso836jpuBWYziAA==
|
||||
dependencies:
|
||||
"@typescript-eslint/experimental-utils" "2.9.0"
|
||||
"@typescript-eslint/experimental-utils" "2.12.0"
|
||||
eslint-utils "^1.4.3"
|
||||
functional-red-black-tree "^1.0.1"
|
||||
regexpp "^3.0.0"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/experimental-utils@2.9.0":
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.9.0.tgz#bbe99a8d9510240c055fc4b17230dd0192ba3c7f"
|
||||
integrity sha512-0lOLFdpdJsCMqMSZT7l7W2ta0+GX8A3iefG3FovJjrX+QR8y6htFlFdU7aOVPL6pDvt6XcsOb8fxk5sq+girTw==
|
||||
"@typescript-eslint/experimental-utils@2.12.0", "@typescript-eslint/experimental-utils@^2.5.0":
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.12.0.tgz#e0a76ffb6293e058748408a191921e453c31d40d"
|
||||
integrity sha512-jv4gYpw5N5BrWF3ntROvCuLe1IjRenLy5+U57J24NbPGwZFAjhnM45qpq0nDH1y/AZMb3Br25YiNVwyPbz6RkA==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.3"
|
||||
"@typescript-eslint/typescript-estree" "2.9.0"
|
||||
"@typescript-eslint/typescript-estree" "2.12.0"
|
||||
eslint-scope "^5.0.0"
|
||||
|
||||
"@typescript-eslint/experimental-utils@^1.13.0":
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz#b08c60d780c0067de2fb44b04b432f540138301e"
|
||||
integrity sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.3"
|
||||
"@typescript-eslint/typescript-estree" "1.13.0"
|
||||
eslint-scope "^4.0.0"
|
||||
|
||||
"@typescript-eslint/parser@^2.3.1":
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.9.0.tgz#2e9cf438de119b143f642a3a406e1e27eb70b7cd"
|
||||
integrity sha512-fJ+dNs3CCvEsJK2/Vg5c2ZjuQ860ySOAsodDPwBaVlrGvRN+iCNC8kUfLFL8cT49W4GSiLPa/bHiMjYXA7EhKQ==
|
||||
"@typescript-eslint/parser@^2.12.0":
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.12.0.tgz#393f1604943a4ca570bb1a45bc8834e9b9158884"
|
||||
integrity sha512-lPdkwpdzxEfjI8TyTzZqPatkrswLSVu4bqUgnB03fHSOwpC7KSerPgJRgIAf11UGNf7HKjJV6oaPZI4AghLU6g==
|
||||
dependencies:
|
||||
"@types/eslint-visitor-keys" "^1.0.0"
|
||||
"@typescript-eslint/experimental-utils" "2.9.0"
|
||||
"@typescript-eslint/typescript-estree" "2.9.0"
|
||||
"@typescript-eslint/experimental-utils" "2.12.0"
|
||||
"@typescript-eslint/typescript-estree" "2.12.0"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@1.13.0":
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz#8140f17d0f60c03619798f1d628b8434913dc32e"
|
||||
integrity sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==
|
||||
dependencies:
|
||||
lodash.unescape "4.0.1"
|
||||
semver "5.5.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@2.9.0":
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.9.0.tgz#09138daf8f47d0e494ba7db9e77394e928803017"
|
||||
integrity sha512-v6btSPXEWCP594eZbM+JCXuFoXWXyF/z8kaSBSdCb83DF+Y7+xItW29SsKtSULgLemqJBT+LpT+0ZqdfH7QVmA==
|
||||
"@typescript-eslint/typescript-estree@2.12.0":
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz#bd9e547ccffd17dfab0c3ab0947c80c8e2eb914c"
|
||||
integrity sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
@@ -3633,12 +3624,12 @@ array-ify@^1.0.0:
|
||||
integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=
|
||||
|
||||
array-includes@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
|
||||
integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.0.tgz#48a929ef4c6bb1fa6dc4a92c9b023a261b0ca404"
|
||||
integrity sha512-ONOEQoKrvXPKk7Su92Co0YMqYO32FfqJTzkKU9u2UpIXyYZIzLSvpdg4AwvSw4mSUW0czu6inK+zby6Oj6gDjQ==
|
||||
dependencies:
|
||||
define-properties "^1.1.2"
|
||||
es-abstract "^1.7.0"
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.0-next.0"
|
||||
|
||||
array-map@~0.0.0:
|
||||
version "0.0.0"
|
||||
@@ -3677,6 +3668,14 @@ array-unique@^0.3.2:
|
||||
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
|
||||
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
|
||||
|
||||
array.prototype.flat@^1.2.1:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
|
||||
integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.0-next.1"
|
||||
|
||||
arrify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
|
||||
@@ -5680,7 +5679,7 @@ debounce@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"
|
||||
integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==
|
||||
|
||||
debug@2, debug@2.6.9, debug@2.6.x, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9:
|
||||
debug@2, debug@2.6.9, debug@2.6.x, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
@@ -6360,7 +6359,7 @@ errorhandler@^1.5.0:
|
||||
accepts "~1.3.7"
|
||||
escape-html "~1.0.3"
|
||||
|
||||
es-abstract@^1.12.0, es-abstract@^1.15.0, es-abstract@^1.5.1, es-abstract@^1.7.0:
|
||||
es-abstract@^1.12.0, es-abstract@^1.5.1:
|
||||
version "1.16.2"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.2.tgz#4e874331645e9925edef141e74fc4bd144669d34"
|
||||
integrity sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA==
|
||||
@@ -6376,6 +6375,23 @@ es-abstract@^1.12.0, es-abstract@^1.15.0, es-abstract@^1.5.1, es-abstract@^1.7.0
|
||||
string.prototype.trimleft "^2.1.0"
|
||||
string.prototype.trimright "^2.1.0"
|
||||
|
||||
es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1:
|
||||
version "1.17.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.0-next.1.tgz#94acc93e20b05a6e96dacb5ab2f1cb3a81fc2172"
|
||||
integrity sha512-7MmGr03N7Rnuid6+wyhD9sHNE2n4tFSwExnU2lQl3lIo2ShXWGePY80zYaoMOmILWv57H0amMjZGHNzzGG70Rw==
|
||||
dependencies:
|
||||
es-to-primitive "^1.2.1"
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
is-callable "^1.1.4"
|
||||
is-regex "^1.0.4"
|
||||
object-inspect "^1.7.0"
|
||||
object-keys "^1.1.1"
|
||||
object.assign "^4.1.0"
|
||||
string.prototype.trimleft "^2.1.0"
|
||||
string.prototype.trimright "^2.1.0"
|
||||
|
||||
es-to-primitive@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
|
||||
@@ -6442,31 +6458,31 @@ escodegen@^1.9.1:
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
eslint-config-prettier@^6.3.0:
|
||||
eslint-config-prettier@^6.7.0:
|
||||
version "6.7.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz#9a876952e12df2b284adbd3440994bf1f39dfbb9"
|
||||
integrity sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ==
|
||||
dependencies:
|
||||
get-stdin "^6.0.0"
|
||||
|
||||
eslint-config-satya164@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-satya164/-/eslint-config-satya164-3.1.2.tgz#b17f08a8f76d6694331cdbf36a6e3dc543a4bf43"
|
||||
integrity sha512-ON18lbaBKLtqu2wh8nFIf5+lFi8+zdIrkyjT28NMwYu5goWDZ/EyHUgKhW5ASUQNYLtgRJuF+GOU+Pb3SMM+XQ==
|
||||
eslint-config-satya164@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-satya164/-/eslint-config-satya164-3.1.5.tgz#52ef0cdbdf89a4bb1f2b2448081bacb45fbcd211"
|
||||
integrity sha512-ZAVavXO6qY+11uUlsxsAp5a25GTWder/dU3RIO3cS8mzL3fFl5WrgtQ5W9B4iUwpooRMUY8w6V5yVtUs4dMnaA==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "^2.3.1"
|
||||
"@typescript-eslint/parser" "^2.3.1"
|
||||
"@typescript-eslint/eslint-plugin" "^2.12.0"
|
||||
"@typescript-eslint/parser" "^2.12.0"
|
||||
babel-eslint "^10.0.3"
|
||||
eslint-config-prettier "^6.3.0"
|
||||
eslint-config-prettier "^6.7.0"
|
||||
eslint-plugin-babel "^5.3.0"
|
||||
eslint-plugin-eslint-comments "^3.1.2"
|
||||
eslint-plugin-flowtype "^4.3.0"
|
||||
eslint-plugin-import "^2.18.2"
|
||||
eslint-plugin-jest "^22.17.0"
|
||||
eslint-plugin-prettier "^3.1.1"
|
||||
eslint-plugin-react "^7.14.3"
|
||||
eslint-plugin-react-hooks "^2.1.0"
|
||||
eslint-plugin-react-native "^3.7.0"
|
||||
eslint-plugin-flowtype "^4.5.2"
|
||||
eslint-plugin-import "^2.19.1"
|
||||
eslint-plugin-jest "^23.1.1"
|
||||
eslint-plugin-prettier "^3.1.2"
|
||||
eslint-plugin-react "^7.17.0"
|
||||
eslint-plugin-react-hooks "^2.3.0"
|
||||
eslint-plugin-react-native "^3.8.1"
|
||||
|
||||
eslint-import-resolver-node@^0.3.2:
|
||||
version "0.3.2"
|
||||
@@ -6476,12 +6492,12 @@ eslint-import-resolver-node@^0.3.2:
|
||||
debug "^2.6.9"
|
||||
resolve "^1.5.0"
|
||||
|
||||
eslint-module-utils@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz#7b4675875bf96b0dbf1b21977456e5bb1f5e018c"
|
||||
integrity sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==
|
||||
eslint-module-utils@^2.4.1:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz#cdf0b40d623032274ccd2abd7e64c4e524d6e19c"
|
||||
integrity sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==
|
||||
dependencies:
|
||||
debug "^2.6.8"
|
||||
debug "^2.6.9"
|
||||
pkg-dir "^2.0.0"
|
||||
|
||||
eslint-plugin-babel@^5.3.0:
|
||||
@@ -6504,45 +6520,46 @@ eslint-plugin-eslint-plugin@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-2.1.0.tgz#a7a00f15a886957d855feacaafee264f039e62d5"
|
||||
integrity sha512-kT3A/ZJftt28gbl/Cv04qezb/NQ1dwYIbi8lyf806XMxkus7DvOVCLIfTXMrorp322Pnoez7+zabXH29tADIDg==
|
||||
|
||||
eslint-plugin-flowtype@^4.3.0:
|
||||
eslint-plugin-flowtype@^4.5.2:
|
||||
version "4.5.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.5.2.tgz#5353449692663ef70e8fc8c2386cebdecac7e86b"
|
||||
integrity sha512-ByV0EtEQOqiCl6bsrtXtTGnXlIXoyvDrvUq3Nz28huODAhnRDuMotyTrwP+TjAKZMPWbtaNGFHMoUxW3DktGOw==
|
||||
dependencies:
|
||||
lodash "^4.17.15"
|
||||
|
||||
eslint-plugin-import@^2.18.2:
|
||||
version "2.18.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6"
|
||||
integrity sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==
|
||||
eslint-plugin-import@^2.19.1:
|
||||
version "2.19.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz#5654e10b7839d064dd0d46cd1b88ec2133a11448"
|
||||
integrity sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw==
|
||||
dependencies:
|
||||
array-includes "^3.0.3"
|
||||
array.prototype.flat "^1.2.1"
|
||||
contains-path "^0.1.0"
|
||||
debug "^2.6.9"
|
||||
doctrine "1.5.0"
|
||||
eslint-import-resolver-node "^0.3.2"
|
||||
eslint-module-utils "^2.4.0"
|
||||
eslint-module-utils "^2.4.1"
|
||||
has "^1.0.3"
|
||||
minimatch "^3.0.4"
|
||||
object.values "^1.1.0"
|
||||
read-pkg-up "^2.0.0"
|
||||
resolve "^1.11.0"
|
||||
resolve "^1.12.0"
|
||||
|
||||
eslint-plugin-jest@^22.17.0:
|
||||
version "22.21.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.21.0.tgz#8137294645866636160487d9764224b9a43e2eb1"
|
||||
integrity sha512-OaqnSS7uBgcGiqXUiEnjoqxPNKvR4JWG5mSRkzVoR6+vDwlqqp11beeql1hYs0HTbdhiwrxWLxbX0Vx7roG3Ew==
|
||||
eslint-plugin-jest@^23.1.1:
|
||||
version "23.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.1.1.tgz#1220ab53d5a4bf5c3c4cd07c0dabc6199d4064dd"
|
||||
integrity sha512-2oPxHKNh4j1zmJ6GaCBuGcb8FVZU7YjFUOJzGOPnl9ic7VA/MGAskArLJiRIlnFUmi1EUxY+UiATAy8dv8s5JA==
|
||||
dependencies:
|
||||
"@typescript-eslint/experimental-utils" "^1.13.0"
|
||||
"@typescript-eslint/experimental-utils" "^2.5.0"
|
||||
|
||||
eslint-plugin-prettier@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.1.tgz#507b8562410d02a03f0ddc949c616f877852f2ba"
|
||||
integrity sha512-A+TZuHZ0KU0cnn56/9mfR7/KjUJ9QNVXUhwvRFSR7PGPe0zQR6PTkmyqg1AtUUEOzTqeRsUwyKFh0oVZKVCrtA==
|
||||
eslint-plugin-prettier@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba"
|
||||
integrity sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==
|
||||
dependencies:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
|
||||
eslint-plugin-react-hooks@^2.1.0:
|
||||
eslint-plugin-react-hooks@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.3.0.tgz#53e073961f1f5ccf8dd19558036c1fac8c29d99a"
|
||||
integrity sha512-gLKCa52G4ee7uXzdLiorca7JIQZPPXRAQDXV83J4bUEeUuc5pIEyZYAZ45Xnxe5IuupxEqHS+hUhSLIimK1EMw==
|
||||
@@ -6552,14 +6569,14 @@ eslint-plugin-react-native-globals@^0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2"
|
||||
integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==
|
||||
|
||||
eslint-plugin-react-native@^3.7.0:
|
||||
eslint-plugin-react-native@^3.8.1:
|
||||
version "3.8.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-3.8.1.tgz#92811e37191ecb0d29c0f0a0c9e5c943ee573821"
|
||||
integrity sha512-6Z4s4nvgFRdda/1s1+uu4a6EMZwEjjJ9Bk/1yBImv0fd9U2CsGu2cUakAtV83cZKhizbWhSouXoaK4JtlScdFg==
|
||||
dependencies:
|
||||
eslint-plugin-react-native-globals "^0.1.1"
|
||||
|
||||
eslint-plugin-react@^7.14.3:
|
||||
eslint-plugin-react@^7.17.0:
|
||||
version "7.17.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.17.0.tgz#a31b3e134b76046abe3cd278e7482bd35a1d12d7"
|
||||
integrity sha512-ODB7yg6lxhBVMeiH1c7E95FLD4E/TwmFjltiU+ethv7KPdCwgiFuOZg9zNRHyufStTDLl/dEFqI2Q1VPmCd78A==
|
||||
@@ -6580,7 +6597,7 @@ eslint-rule-composer@^0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9"
|
||||
integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==
|
||||
|
||||
eslint-scope@^4.0.0, eslint-scope@^4.0.3:
|
||||
eslint-scope@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
|
||||
integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
|
||||
@@ -8756,9 +8773,9 @@ inquirer@^6.2.0, inquirer@^6.2.2:
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.0.tgz#9e2b032dde77da1db5db804758b8fea3a970519a"
|
||||
integrity sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.1.tgz#13f7980eedc73c689feff3994b109c4e799c6ebb"
|
||||
integrity sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==
|
||||
dependencies:
|
||||
ansi-escapes "^4.2.1"
|
||||
chalk "^2.4.2"
|
||||
@@ -8769,7 +8786,7 @@ inquirer@^7.0.0:
|
||||
lodash "^4.17.15"
|
||||
mute-stream "0.0.8"
|
||||
run-async "^2.2.0"
|
||||
rxjs "^6.4.0"
|
||||
rxjs "^6.5.3"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^5.1.0"
|
||||
through "^2.3.6"
|
||||
@@ -11603,12 +11620,12 @@ object.entries@^1.1.0:
|
||||
has "^1.0.3"
|
||||
|
||||
object.fromentries@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.1.tgz#050f077855c7af8ae6649f45c80b16ee2d31e704"
|
||||
integrity sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9"
|
||||
integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.15.0"
|
||||
es-abstract "^1.17.0-next.1"
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
|
||||
@@ -13174,6 +13191,11 @@ react-native-gesture-handler@^1.5.0, react-native-gesture-handler@~1.5.0:
|
||||
invariant "^2.2.4"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-native-iphone-x-helper@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.2.1.tgz#645e2ffbbb49e80844bb4cbbe34a126fda1e6772"
|
||||
integrity sha512-/VbpIEp8tSNNHIvstuA3Swx610whci1Zpc9mqNkqn14DkMbw+ORviln2u0XyHG1kPvvwTNGZY6QpeFwxYaSdbQ==
|
||||
|
||||
react-native-paper@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-3.3.0.tgz#c2a1e9b793b7063aa1848c1ce7db5719912e215a"
|
||||
@@ -13844,13 +13866,20 @@ resolve@1.1.7:
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
||||
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
|
||||
|
||||
resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1:
|
||||
resolve@^1.10.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16"
|
||||
integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
resolve@^1.12.0, resolve@^1.13.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.1.tgz#9e018c540fcf0c427d678b9931cbf45e984bcaff"
|
||||
integrity sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
responselike@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
|
||||
@@ -13993,7 +14022,7 @@ rxjs@^5.4.3, rxjs@^5.5.2:
|
||||
dependencies:
|
||||
symbol-observable "1.0.1"
|
||||
|
||||
rxjs@^6.4.0:
|
||||
rxjs@^6.4.0, rxjs@^6.5.3:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
|
||||
integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==
|
||||
|
||||