From c0474bb644b08d760e3e5d57e07cef487b11f05c Mon Sep 17 00:00:00 2001 From: Dave Pack Date: Thu, 2 Nov 2017 18:14:15 -0700 Subject: [PATCH] SafeAreaView padding from style prop (#2889) * SafeAreaView now adds padding from style object. If height is specified, inset padding is added to height. * Header now only accepts headerStyle prop, backgroundColor works as expected. * TabBarBottom now only accepts style prop, backgroundColor works as expected. Fixes top inset bug. * Update snapshot. * Add clarifying comment. * Support padding with percentage. --- docs/api/navigators/StackNavigator.md | 4 - docs/api/navigators/TabNavigator.md | 1 - src/TypeDefinition.js | 1 - .../DrawerNavigator-test.js.snap | 33 +-- .../__snapshots__/StackNavigator-test.js.snap | 232 ++++++++---------- .../__snapshots__/TabNavigator-test.js.snap | 34 +-- src/views/Header/Header.js | 21 +- src/views/SafeAreaView.js | 87 ++++++- src/views/TabView/TabBarBottom.js | 21 +- .../__snapshots__/TabView-test.js.snap | 34 +-- 10 files changed, 240 insertions(+), 228 deletions(-) diff --git a/docs/api/navigators/StackNavigator.md b/docs/api/navigators/StackNavigator.md index 3572fa1e..f76538ae 100644 --- a/docs/api/navigators/StackNavigator.md +++ b/docs/api/navigators/StackNavigator.md @@ -135,10 +135,6 @@ Style object for the header Style object for the title component -### `headerBackgroundColor` - -Color string that overrides default background color. - #### `headerBackTitleStyle` Style object for the back title diff --git a/docs/api/navigators/TabNavigator.md b/docs/api/navigators/TabNavigator.md index cabfa7e8..b279b0b8 100644 --- a/docs/api/navigators/TabNavigator.md +++ b/docs/api/navigators/TabNavigator.md @@ -106,7 +106,6 @@ Several options get passed to the underlying router to modify navigation logic: - `inactiveBackgroundColor` - Background color of the inactive tab. - `showLabel` - Whether to show label for tab, default is true. - `style` - Style object for the tab bar. -- `backgroundColor` - Color string that overrides default backgroundColor. - `labelStyle` - Style object for the tab label. - `tabStyle` - Style object for the tab. - `allowFontScaling` - Whether label font should scale to respect Text Size accessibility settings, default is true. diff --git a/src/TypeDefinition.js b/src/TypeDefinition.js index fb9f80d5..fae64943 100644 --- a/src/TypeDefinition.js +++ b/src/TypeDefinition.js @@ -360,7 +360,6 @@ export type NavigationStackScreenOptions = {| headerPressColorAndroid?: string, headerRight?: React.Node, headerStyle?: ViewStyleProp, - headerBackgroundColor?: string, gesturesEnabled?: boolean, gestureResponseDistance?: { vertical?: number, horizontal?: number }, |}; diff --git a/src/navigators/__tests__/__snapshots__/DrawerNavigator-test.js.snap b/src/navigators/__tests__/__snapshots__/DrawerNavigator-test.js.snap index 724ffd63..34462de9 100644 --- a/src/navigators/__tests__/__snapshots__/DrawerNavigator-test.js.snap +++ b/src/navigators/__tests__/__snapshots__/DrawerNavigator-test.js.snap @@ -94,15 +94,12 @@ exports[`DrawerNavigator renders successfully 1`] = ` + - + - + - diff --git a/src/views/Header/Header.js b/src/views/Header/Header.js index 1c3d2752..e29ca19e 100644 --- a/src/views/Header/Header.js +++ b/src/views/Header/Header.js @@ -302,12 +302,10 @@ class Header extends React.PureComponent { } = this.props; const { options } = this.props.getScreenDetails(scene); - const { - headerStyle, - headerBackgroundColor = Platform.OS === 'ios' ? '#F7F7F7' : '#FFF', - } = options; + const { headerStyle } = options; const appBarHeight = Platform.OS === 'ios' ? (isLandscape ? 32 : 44) : 56; const containerStyles = [ + styles.container, { height: appBarHeight, }, @@ -315,14 +313,14 @@ class Header extends React.PureComponent { ]; return ( - - + + {appBar} - - + + ); } } @@ -347,6 +345,7 @@ if (Platform.OS === 'ios') { const styles = StyleSheet.create({ container: { + backgroundColor: Platform.OS === 'ios' ? '#F7F7F7' : '#FFF', ...platformContainerStyles, }, appBar: { diff --git a/src/views/SafeAreaView.js b/src/views/SafeAreaView.js index 621e14e8..efd08fb1 100644 --- a/src/views/SafeAreaView.js +++ b/src/views/SafeAreaView.js @@ -6,6 +6,7 @@ import { NativeModules, Platform, SafeAreaView, + StyleSheet, View, } from 'react-native'; import withOrientation from './withOrientation'; @@ -62,6 +63,18 @@ const statusBarHeight = isLandscape => { return isLandscape ? 0 : 20; }; +const doubleFromPercentString = percent => { + if (!percent.includes('%')) { + return 0; + } + + const dbl = parseFloat(percent) / 100; + + if (isNaN(dbl)) return 0; + + return dbl; +}; + class SafeView extends Component { state = { touchesTop: true, @@ -69,6 +82,8 @@ class SafeView extends Component { touchesLeft: true, touchesRight: true, orientation: null, + viewWidth: 0, + viewHeight: 0, }; componentDidMount() { @@ -88,17 +103,13 @@ class SafeView extends Component { return {this.props.children}; } - if (!forceInset && minor >= 50) { - return {this.props.children}; - } - const safeAreaStyle = this._getSafeAreaStyle(); return ( (this.view = c)} onLayout={this._onLayout} - style={[style, safeAreaStyle]} + style={safeAreaStyle} > {this.props.children} @@ -145,6 +156,8 @@ class SafeView extends Component { touchesLeft, touchesRight, orientation: newOrientation, + viewWidth: winWidth, + viewHeight: winHeight, }); }); }; @@ -153,7 +166,16 @@ class SafeView extends Component { const { touchesTop, touchesBottom, touchesLeft, touchesRight } = this.state; const { forceInset, isLandscape } = this.props; + const { + paddingTop, + paddingBottom, + paddingLeft, + paddingRight, + viewStyle, + } = this._getViewStyles(); + const style = { + ...viewStyle, paddingTop: touchesTop ? this._getInset('top') : 0, paddingBottom: touchesBottom ? this._getInset('bottom') : 0, paddingLeft: touchesLeft ? this._getInset('left') : 0, @@ -195,9 +217,64 @@ class SafeView extends Component { }); } + // new height/width should only include padding from insets + // height/width should not be affected by padding from style obj + if (style.height && typeof style.height === 'number') { + style.height += style.paddingTop + style.paddingBottom; + } + + if (style.width && typeof style.width === 'number') { + style.width += style.paddingLeft + style.paddingRight; + } + + style.paddingTop += paddingTop; + style.paddingBottom += paddingBottom; + style.paddingLeft += paddingLeft; + style.paddingRight += paddingRight; + return style; }; + _getViewStyles = () => { + const { viewWidth } = this.state; + // get padding values from style to add back in after insets are determined + // default precedence: padding[Side] -> vertical | horizontal -> padding -> 0 + let { + padding = 0, + paddingVertical = padding, + paddingHorizontal = padding, + paddingTop = paddingVertical, + paddingBottom = paddingVertical, + paddingLeft = paddingHorizontal, + paddingRight = paddingHorizontal, + ...viewStyle + } = StyleSheet.flatten(this.props.style || {}); + + if (typeof paddingTop !== 'number') { + paddingTop = doubleFromPercentString(paddingTop) * viewWidth; + } + + if (typeof paddingBottom !== 'number') { + paddingBottom = doubleFromPercentString(paddingBottom) * viewWidth; + } + + if (typeof paddingLeft !== 'number') { + paddingLeft = doubleFromPercentString(paddingLeft) * viewWidth; + } + + if (typeof paddingRight !== 'number') { + paddingRight = doubleFromPercentString(paddingRight) * viewWidth; + } + + return { + paddingTop, + paddingBottom, + paddingLeft, + paddingRight, + viewStyle, + }; + }; + _getInset = key => { const { isLandscape } = this.props; switch (key) { diff --git a/src/views/TabView/TabBarBottom.js b/src/views/TabView/TabBarBottom.js index cc2fd8fa..d1fd6431 100644 --- a/src/views/TabView/TabBarBottom.js +++ b/src/views/TabView/TabBarBottom.js @@ -40,7 +40,6 @@ type Props = { getTestIDProps: (scene: TabScene) => (scene: TabScene) => any, renderIcon: (scene: TabScene) => React.Node, style?: ViewStyleProp, - backgroundColor?: string, labelStyle?: TextStyleProp, tabStyle?: ViewStyleProp, showIcon?: boolean, @@ -165,7 +164,6 @@ class TabBarBottom extends React.PureComponent { inactiveBackgroundColor, style, tabStyle, - backgroundColor = '#F7F7F7', // Default background color in iOS 10 isLandscape, } = this.props; const { routes } = navigation.state; @@ -181,11 +179,11 @@ class TabBarBottom extends React.PureComponent { ]; return ( - - + + {routes.map((route: NavigationRoute, index: number) => { const focused = index === navigation.state.index; const scene = { route, index, focused }; @@ -228,8 +226,8 @@ class TabBarBottom extends React.PureComponent { ); })} - - + + ); } } @@ -237,11 +235,10 @@ class TabBarBottom extends React.PureComponent { const LABEL_LEFT_MARGIN = 20; const LABEL_TOP_MARGIN = 15; const styles = StyleSheet.create({ - tabBarContainer: { + tabBar: { + backgroundColor: '#F7F7F7', // Default background color in iOS 10 borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: 'rgba(0, 0, 0, .3)', - }, - tabBar: { flexDirection: 'row', }, tabBarLandscape: { diff --git a/src/views/__tests__/__snapshots__/TabView-test.js.snap b/src/views/__tests__/__snapshots__/TabView-test.js.snap index 24942da4..87de01e6 100644 --- a/src/views/__tests__/__snapshots__/TabView-test.js.snap +++ b/src/views/__tests__/__snapshots__/TabView-test.js.snap @@ -21,33 +21,21 @@ exports[`TabBarBottom renders successfully 1`] = ` } > + -