diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js index 52e6a764d2ca74..9803929e6232ca 100644 --- a/Libraries/Components/StatusBar/StatusBar.js +++ b/Libraries/Components/StatusBar/StatusBar.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow + * @flow strict-local */ 'use strict'; @@ -103,13 +103,52 @@ type Props = $ReadOnly<{| barStyle?: ?('default' | 'light-content' | 'dark-content'), |}>; +type StackEntryProps = { + /** + * The background color of the status bar. + * + * @platform android + */ + backgroundColor: { + value: ?string, + animated: ?boolean, + }, + /** + * Sets the color of the status bar text. + */ + barStyle: { + value: ?string, + animated: ?boolean, + }, + /** + * If the status bar is translucent. + * When translucent is set to true, the app will draw under the status bar. + * This is useful when using a semi transparent status bar color. + */ + translucent: ?boolean, + /** + * + */ + hidden: { + value: ?boolean, + animated: boolean, + transition: ?('slide' | 'fade'), + }, + /** + * If the network activity indicator should be visible. + * + * @platform ios + */ + networkActivityIndicatorVisible: ?boolean, +}; + /** * Merges the prop stack with the default values. */ function mergePropsStack( - propsStack: Array, - defaultValues: Object, -): Object { + propsStack: $ReadOnlyArray, + defaultValues: StackEntryProps, +): StackEntryProps { return propsStack.reduce((prev, cur) => { for (const prop in cur) { if (cur[prop] != null) { @@ -124,32 +163,24 @@ function mergePropsStack( * Returns an object to insert in the props stack from the props * and the transition/animation info. */ -function createStackEntry(props: any): any { +function createStackEntry(props: Props): StackEntryProps { return { - backgroundColor: - props.backgroundColor != null - ? { - value: props.backgroundColor, - animated: props.animated, - } - : null, - barStyle: - props.barStyle != null - ? { - value: props.barStyle, - animated: props.animated, - } - : null, - translucent: props.translucent, - hidden: - props.hidden != null - ? { - value: props.hidden, - animated: props.animated, - transition: props.showHideTransition, - } - : null, - networkActivityIndicatorVisible: props.networkActivityIndicatorVisible, + backgroundColor: { + value: props.backgroundColor, + animated: props.animated, + }, + barStyle: { + value: props.barStyle, + animated: props.animated, + }, + translucent: props.translucent || false, + hidden: { + value: props.hidden, + animated: props.animated || false, + transition: props.showHideTransition, + }, + networkActivityIndicatorVisible: + props.networkActivityIndicatorVisible || false, }; } @@ -195,7 +226,7 @@ function createStackEntry(props: any): any { class StatusBar extends React.Component { static _propsStack = []; - static _defaultProps = createStackEntry({ + static _defaultProps: StackEntryProps = createStackEntry({ animated: false, showHideTransition: 'fade', backgroundColor: 'black', @@ -229,11 +260,10 @@ class StatusBar extends React.Component { * @param animation Optional animation when * changing the status bar hidden property. */ - static setHidden(hidden: boolean, animation?: StatusBarAnimation) { - animation = animation || 'none'; + static setHidden(hidden: boolean = true, animation?: StatusBarAnimation) { StatusBar._defaultProps.hidden.value = hidden; if (Platform.OS === 'ios') { - StatusBarManager.setHidden(hidden, animation); + StatusBarManager.setHidden(hidden, animation || 'none'); } else if (Platform.OS === 'android') { StatusBarManager.setHidden(hidden); } @@ -245,10 +275,9 @@ class StatusBar extends React.Component { * @param animated Animate the style change. */ static setBarStyle(style: StatusBarStyle, animated?: boolean) { - animated = animated || false; StatusBar._defaultProps.barStyle.value = style; if (Platform.OS === 'ios') { - StatusBarManager.setStyle(style, animated); + StatusBarManager.setStyle(style, animated || false); } else if (Platform.OS === 'android') { StatusBarManager.setStyle(style); } @@ -279,9 +308,8 @@ class StatusBar extends React.Component { console.warn('`setBackgroundColor` is only available on Android'); return; } - animated = animated || false; StatusBar._defaultProps.backgroundColor.value = color; - StatusBarManager.setColor(processColor(color), animated); + StatusBarManager.setColor(processColor(color), animated || false); } /** diff --git a/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js b/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js deleted file mode 100644 index f3f8c016026e32..00000000000000 --- a/Libraries/Utilities/__tests__/deepFreezeAndThrowOnMutationInDev-test.js +++ /dev/null @@ -1,143 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+react_native - */ - -const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev'); - -describe('deepFreezeAndThrowOnMutationInDev', function() { - it('should be a noop on non object values', () => { - __DEV__ = true; - expect(() => deepFreezeAndThrowOnMutationInDev('')).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev(null)).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev(false)).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev(5)).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev()).not.toThrow(); - __DEV__ = false; - expect(() => deepFreezeAndThrowOnMutationInDev('')).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev(null)).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev(false)).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev(5)).not.toThrow(); - expect(() => deepFreezeAndThrowOnMutationInDev()).not.toThrow(); - }); - - it('should not throw on object without prototype', () => { - __DEV__ = true; - const o = Object.create(null); - o.key = 'Value'; - expect(() => deepFreezeAndThrowOnMutationInDev(o)).not.toThrow(); - }); - - it('should throw on mutation in dev with strict', () => { - 'use strict'; - __DEV__ = true; - const o = {key: 'oldValue'}; - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.key = 'newValue'; - }).toThrowError( - 'You attempted to set the key `key` with the value `"newValue"` ' + - 'on an object that is meant to be immutable and has been frozen.', - ); - expect(o.key).toBe('oldValue'); - }); - - it('should throw on mutation in dev without strict', () => { - __DEV__ = true; - const o = {key: 'oldValue'}; - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.key = 'newValue'; - }).toThrowError( - 'You attempted to set the key `key` with the value `"newValue"` ' + - 'on an object that is meant to be immutable and has been frozen.', - ); - expect(o.key).toBe('oldValue'); - }); - - it('should throw on nested mutation in dev with strict', () => { - 'use strict'; - __DEV__ = true; - const o = {key1: {key2: {key3: 'oldValue'}}}; - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.key1.key2.key3 = 'newValue'; - }).toThrowError( - 'You attempted to set the key `key3` with the value `"newValue"` ' + - 'on an object that is meant to be immutable and has been frozen.', - ); - expect(o.key1.key2.key3).toBe('oldValue'); - }); - - it('should throw on nested mutation in dev without strict', () => { - __DEV__ = true; - const o = {key1: {key2: {key3: 'oldValue'}}}; - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.key1.key2.key3 = 'newValue'; - }).toThrowError( - 'You attempted to set the key `key3` with the value `"newValue"` ' + - 'on an object that is meant to be immutable and has been frozen.', - ); - expect(o.key1.key2.key3).toBe('oldValue'); - }); - - it('should throw on insertion in dev with strict', () => { - 'use strict'; - __DEV__ = true; - const o = {oldKey: 'value'}; - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.newKey = 'value'; - }).toThrowError( - /(Cannot|Can't) add property newKey, object is not extensible/, - ); - expect(o.newKey).toBe(undefined); - }); - - it('should not throw on insertion in dev without strict', () => { - __DEV__ = true; - const o = {oldKey: 'value'}; - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.newKey = 'value'; - }).not.toThrow(); - expect(o.newKey).toBe(undefined); - }); - - it('should mutate and not throw on mutation in prod', () => { - 'use strict'; - __DEV__ = false; - const o = {key: 'oldValue'}; - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.key = 'newValue'; - }).not.toThrow(); - expect(o.key).toBe('newValue'); - }); - - // This is a limitation of the technique unfortunately - it('should not deep freeze already frozen objects', () => { - 'use strict'; - __DEV__ = true; - const o = {key1: {key2: 'oldValue'}}; - Object.freeze(o); - deepFreezeAndThrowOnMutationInDev(o); - expect(() => { - o.key1.key2 = 'newValue'; - }).not.toThrow(); - expect(o.key1.key2).toBe('newValue'); - }); - - it("shouldn't recurse infinitely", () => { - __DEV__ = true; - const o = {}; - o.circular = o; - deepFreezeAndThrowOnMutationInDev(o); - }); -});