import React from 'react'; import { Animated, requireNativeComponent, View, UIManager, StyleSheet, } from 'react-native'; import { version } from 'react-native/Libraries/Core/ReactNativeVersion'; let USE_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]; function useScreens(shouldUseScreens = true) { USE_SCREENS = shouldUseScreens; if (USE_SCREENS && !getViewManagerConfigCompat('RNSScreen')) { console.error( `Screen native module hasn't been linked. Please check the react-native-screens README for more details` ); } } function screensEnabled() { return USE_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 AnimatedNativeScreen; const ScreensNativeModules = { get NativeScreen() { NativeScreenValue = NativeScreenValue || requireNativeComponent('RNSScreen', null); return NativeScreenValue; }, get NativeScreenContainer() { NativeScreenContainerValue = NativeScreenContainerValue || requireNativeComponent('RNSScreenContainer', null); return NativeScreenContainerValue; }, }; 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 (!USE_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); if (version.minor >= 57) { 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 (!USE_SCREENS) { return <View {...this.props} />; } else { return <ScreensNativeModules.NativeScreenContainer {...this.props} />; } } } module.exports = { ScreenContainer, Screen, get NativeScreen() { return ScreensNativeModules.NativeScreen; }, get NativeScreenContainer() { return ScreensNativeModules.NativeScreenContainer; }, useScreens, screensEnabled, };