Files
react-navigation/src/screens.native.js
2019-10-21 09:01:43 +02:00

208 lines
5.7 KiB
JavaScript

import React from 'react';
import {
Animated,
requireNativeComponent,
View,
UIManager,
StyleSheet,
} from 'react-native';
import { version } from 'react-native/Libraries/Core/ReactNativeVersion';
let ENABLE_SCREENS = false;
// UIManager[`${moduleName}`] is deprecated in RN 0.58 and `getViewManagerConfig` is added.
// We can remove this when we drop support for RN < 0.58.
const getViewManagerConfigCompat = name =>
typeof UIManager.getViewManagerConfig !== 'undefined'
? UIManager.getViewManagerConfig(name)
: UIManager[name];
export function enableScreens(shouldEnableScreens = true) {
ENABLE_SCREENS = shouldEnableScreens;
if (ENABLE_SCREENS && !getViewManagerConfigCompat('RNSScreen')) {
console.error(
`Screen native module hasn't been linked. Please check the react-native-screens README for more details`
);
}
}
// we should remove this at some point
export function useScreens(shouldUseScreens = true) {
enableScreens(shouldUseScreens);
}
export function screensEnabled() {
return ENABLE_SCREENS;
}
// We initialize these lazily so that importing the module doesn't throw error when not linked
// This is necessary coz libraries such as React Navigation import the library where it may not be enabled
let NativeScreenValue;
let NativeScreenContainerValue;
let NativeScreenStack;
let NativeScreenStackHeaderConfig;
let NativeScreenStackHeaderSubview;
let AnimatedNativeScreen;
const ScreensNativeModules = {
get NativeScreen() {
NativeScreenValue =
NativeScreenValue || requireNativeComponent('RNSScreen', null);
return NativeScreenValue;
},
get NativeScreenContainer() {
NativeScreenContainerValue =
NativeScreenContainerValue ||
requireNativeComponent('RNSScreenContainer', null);
return NativeScreenContainerValue;
},
get NativeScreenStack() {
NativeScreenStack =
NativeScreenStack || requireNativeComponent('RNSScreenStack', null);
return NativeScreenStack;
},
get NativeScreenStackHeaderConfig() {
NativeScreenStackHeaderConfig =
NativeScreenStackHeaderConfig ||
requireNativeComponent('RNSScreenStackHeaderConfig', null);
return NativeScreenStackHeaderConfig;
},
get NativeScreenStackHeaderSubview() {
NativeScreenStackHeaderSubview =
NativeScreenStackHeaderSubview ||
requireNativeComponent('RNSScreenStackHeaderSubview', null);
return NativeScreenStackHeaderSubview;
},
};
class Screen extends React.Component {
setNativeProps(props) {
this._ref.setNativeProps(props);
}
setRef = ref => {
this._ref = ref;
this.props.onComponentRef && this.props.onComponentRef(ref);
};
render() {
if (!ENABLE_SCREENS) {
// Filter out active prop in this case because it is unused and
// can cause problems depending on react-native version:
// https://github.com/react-navigation/react-navigation/issues/4886
/* eslint-disable no-unused-vars */
const { active, onComponentRef, ...props } = this.props;
return <Animated.View {...props} ref={this.setRef} />;
} else {
AnimatedNativeScreen =
AnimatedNativeScreen ||
Animated.createAnimatedComponent(ScreensNativeModules.NativeScreen);
// When using RN from master version is 0.0.0
if (version.minor >= 57 || version.minor === 0) {
return <AnimatedNativeScreen {...this.props} ref={this.setRef} />;
} else {
// On RN version below 0.57 we need to wrap screen's children with an
// additional View because of a bug fixed in react-native/pull/20658 which
// was preventing a view from having both styles and some other props being
// "animated" (using Animated native driver)
const { style, children, ...rest } = this.props;
return (
<AnimatedNativeScreen
{...rest}
ref={this.setRef}
style={StyleSheet.absoluteFill}>
<Animated.View style={style}>{children}</Animated.View>
</AnimatedNativeScreen>
);
}
}
}
}
class ScreenContainer extends React.Component {
render() {
if (!ENABLE_SCREENS) {
return <View {...this.props} />;
} else {
return <ScreensNativeModules.NativeScreenContainer {...this.props} />;
}
}
}
const styles = StyleSheet.create({
headerSubview: {
position: 'absolute',
top: 0,
right: 0,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
});
const ScreenStackHeaderRightView = props => (
<ScreensNativeModules.NativeScreenStackHeaderSubview
{...props}
type="right"
style={styles.headerSubview}
/>
);
const ScreenStackHeaderLeftView = props => (
<ScreensNativeModules.NativeScreenStackHeaderSubview
{...props}
type="left"
style={styles.headerSubview}
/>
);
const ScreenStackHeaderTitleView = props => (
<ScreensNativeModules.NativeScreenStackHeaderSubview
{...props}
type="title"
style={styles.headerSubview}
/>
);
const ScreenStackHeaderCenterView = props => (
<ScreensNativeModules.NativeScreenStackHeaderSubview
{...props}
type="center"
style={styles.headerSubview}
/>
);
module.exports = {
ScreenContainer,
Screen,
get NativeScreen() {
return ScreensNativeModules.NativeScreen;
},
get NativeScreenContainer() {
return ScreensNativeModules.NativeScreenContainer;
},
get ScreenStack() {
return ScreensNativeModules.NativeScreenStack;
},
get ScreenStackHeaderConfig() {
return ScreensNativeModules.NativeScreenStackHeaderConfig;
},
get ScreenStackHeaderSubview() {
return ScreensNativeModules.NativeScreenStackHeaderSubview;
},
ScreenStackHeaderRightView,
ScreenStackHeaderLeftView,
ScreenStackHeaderTitleView,
ScreenStackHeaderCenterView,
useScreens,
screensEnabled,
};