RN: Revamp YellowBox for Warnings
Reviewed By: vjeux Differential Revision: D2667624 fb-gh-sync-id: f3c6ed63f3138edd13e7fe283cf877d598018813
This commit is contained in:
parent
b641d3de37
commit
8ab51828ff
|
@ -15,19 +15,20 @@
|
|||
*/
|
||||
|
||||
'use strict';
|
||||
var React = require('react-native');
|
||||
var {
|
||||
|
||||
const React = require('react-native');
|
||||
const {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
var UpdatePropertiesExampleView = requireNativeComponent('UpdatePropertiesExampleView');
|
||||
var FlexibleSizeExampleView = requireNativeComponent('FlexibleSizeExampleView');
|
||||
const requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
class AppPropertiesUpdateExample extends React.Component {
|
||||
render() {
|
||||
// Do not require this unless we are actually rendering.
|
||||
const UpdatePropertiesExampleView = requireNativeComponent('UpdatePropertiesExampleView');
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>
|
||||
|
@ -45,6 +46,8 @@ class AppPropertiesUpdateExample extends React.Component {
|
|||
|
||||
class RootViewSizeFlexibilityExample extends React.Component {
|
||||
render() {
|
||||
// Do not require this unless we are actually rendering.
|
||||
const FlexibleSizeExampleView = requireNativeComponent('FlexibleSizeExampleView');
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>
|
||||
|
@ -60,7 +63,7 @@ class RootViewSizeFlexibilityExample extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#F5FCFF',
|
||||
|
|
|
@ -1,393 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule WarningBox
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var AsyncStorage = require('AsyncStorage');
|
||||
var EventEmitter = require('EventEmitter');
|
||||
var Map = require('Map');
|
||||
var PanResponder = require('PanResponder');
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var Text = require('Text');
|
||||
var TouchableOpacity = require('TouchableOpacity');
|
||||
var View = require('View');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var rebound = require('rebound');
|
||||
var stringifySafe = require('stringifySafe');
|
||||
|
||||
var SCREEN_WIDTH = require('Dimensions').get('window').width;
|
||||
var IGNORED_WARNINGS_KEY = '__DEV_WARNINGS_IGNORED';
|
||||
|
||||
var consoleWarn = console.warn.bind(console);
|
||||
|
||||
var warningCounts = new Map();
|
||||
var ignoredWarnings: Array<string> = [];
|
||||
var totalWarningCount = 0;
|
||||
var warningCountEvents = new EventEmitter();
|
||||
|
||||
/**
|
||||
* WarningBox renders warnings on top of the app being developed. Warnings help
|
||||
* guard against subtle yet significant issues that can impact the quality of
|
||||
* your application, such as accessibility and memory leaks. This "in your
|
||||
* face" style of warning allows developers to notice and correct these issues
|
||||
* as quickly as possible.
|
||||
*
|
||||
* The warning box is currently opt-in. Set the following flag to enable it:
|
||||
*
|
||||
* `console.yellowBoxEnabled = true;`
|
||||
*
|
||||
* If "ignore" is tapped on a warning, the WarningBox will record that warning
|
||||
* and will not display it again. This is useful for hiding errors that already
|
||||
* exist or have been introduced elsewhere. To re-enable all of the errors, set
|
||||
* the following:
|
||||
*
|
||||
* `console.yellowBoxResetIgnored = true;`
|
||||
*
|
||||
* This can also be set permanently, and ignore will only silence the warnings
|
||||
* until the next refresh.
|
||||
*/
|
||||
|
||||
if (__DEV__) {
|
||||
console.warn = function() {
|
||||
consoleWarn.apply(null, arguments);
|
||||
if (!console.yellowBoxEnabled) {
|
||||
return;
|
||||
}
|
||||
var warning = Array.prototype.map.call(arguments, stringifySafe).join(' ');
|
||||
if (!console.yellowBoxResetIgnored &&
|
||||
ignoredWarnings.indexOf(warning) !== -1) {
|
||||
return;
|
||||
}
|
||||
var count = warningCounts.has(warning) ? warningCounts.get(warning) + 1 : 1;
|
||||
warningCounts.set(warning, count);
|
||||
totalWarningCount += 1;
|
||||
warningCountEvents.emit('count', totalWarningCount);
|
||||
};
|
||||
}
|
||||
|
||||
function saveIgnoredWarnings() {
|
||||
AsyncStorage.setItem(
|
||||
IGNORED_WARNINGS_KEY,
|
||||
JSON.stringify(ignoredWarnings),
|
||||
function(err) {
|
||||
if (err) {
|
||||
console.warn('Could not save ignored warnings.', err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
AsyncStorage.getItem(IGNORED_WARNINGS_KEY, function(err, data) {
|
||||
if (!err && data && !console.yellowBoxResetIgnored) {
|
||||
ignoredWarnings = JSON.parse(data);
|
||||
}
|
||||
});
|
||||
|
||||
var WarningRow = React.createClass({
|
||||
componentWillMount: function() {
|
||||
this.springSystem = new rebound.SpringSystem();
|
||||
this.dismissalSpring = this.springSystem.createSpring();
|
||||
this.dismissalSpring.setRestSpeedThreshold(0.05);
|
||||
this.dismissalSpring.setCurrentValue(0);
|
||||
this.dismissalSpring.addListener({
|
||||
onSpringUpdate: () => {
|
||||
var val = this.dismissalSpring.getCurrentValue();
|
||||
this.text && this.text.setNativeProps({
|
||||
left: SCREEN_WIDTH * val,
|
||||
});
|
||||
this.container && this.container.setNativeProps({
|
||||
opacity: 1 - val,
|
||||
});
|
||||
this.closeButton && this.closeButton.setNativeProps({
|
||||
opacity: 1 - (val * 5),
|
||||
});
|
||||
},
|
||||
onSpringAtRest: () => {
|
||||
if (this.dismissalSpring.getCurrentValue()) {
|
||||
this.collapseSpring.setEndValue(1);
|
||||
}
|
||||
},
|
||||
});
|
||||
this.collapseSpring = this.springSystem.createSpring();
|
||||
this.collapseSpring.setRestSpeedThreshold(0.05);
|
||||
this.collapseSpring.setCurrentValue(0);
|
||||
this.collapseSpring.getSpringConfig().friction = 20;
|
||||
this.collapseSpring.getSpringConfig().tension = 200;
|
||||
this.collapseSpring.addListener({
|
||||
onSpringUpdate: () => {
|
||||
var val = this.collapseSpring.getCurrentValue();
|
||||
this.container && this.container.setNativeProps({
|
||||
height: Math.abs(46 - (val * 46)),
|
||||
});
|
||||
},
|
||||
onSpringAtRest: () => {
|
||||
this.props.onDismissed();
|
||||
},
|
||||
});
|
||||
this.panGesture = PanResponder.create({
|
||||
onStartShouldSetPanResponder: () => {
|
||||
return !!this.dismissalSpring.getCurrentValue();
|
||||
},
|
||||
onMoveShouldSetPanResponder: () => true,
|
||||
onPanResponderGrant: () => {
|
||||
this.isResponderOnlyToBlockTouches =
|
||||
!!this.dismissalSpring.getCurrentValue();
|
||||
},
|
||||
onPanResponderMove: (e, gestureState) => {
|
||||
if (this.isResponderOnlyToBlockTouches) {
|
||||
return;
|
||||
}
|
||||
this.dismissalSpring.setCurrentValue(gestureState.dx / SCREEN_WIDTH);
|
||||
},
|
||||
onPanResponderRelease: (e, gestureState) => {
|
||||
if (this.isResponderOnlyToBlockTouches) {
|
||||
return;
|
||||
}
|
||||
var gestureCompletion = gestureState.dx / SCREEN_WIDTH;
|
||||
var doesGestureRelease = (gestureState.vx + gestureCompletion) > 0.5;
|
||||
this.dismissalSpring.setEndValue(doesGestureRelease ? 1 : 0);
|
||||
}
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
var countText;
|
||||
if (warningCounts.get(this.props.warning) > 1) {
|
||||
countText = (
|
||||
<Text style={styles.bold}>
|
||||
({warningCounts.get(this.props.warning)}){" "}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<View
|
||||
style={styles.warningBox}
|
||||
ref={container => { this.container = container; }}
|
||||
{...this.panGesture.panHandlers}>
|
||||
<TouchableOpacity
|
||||
onPress={this.props.onOpened}>
|
||||
<Text
|
||||
style={styles.warningText}
|
||||
numberOfLines={2}
|
||||
ref={text => { this.text = text; }}>
|
||||
{countText}
|
||||
{this.props.warning}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<View
|
||||
ref={closeButton => { this.closeButton = closeButton; }}
|
||||
style={styles.closeButton}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.dismissalSpring.setEndValue(1);
|
||||
}}>
|
||||
<Text style={styles.closeButtonText}>✕</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var WarningBoxOpened = React.createClass({
|
||||
render: function() {
|
||||
var countText;
|
||||
if (warningCounts.get(this.props.warning) > 1) {
|
||||
countText = (
|
||||
<Text style={styles.bold}>
|
||||
({warningCounts.get(this.props.warning)}){" "}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.9}
|
||||
onPress={this.props.onClose}
|
||||
style={styles.yellowBox}>
|
||||
<Text style={styles.yellowBoxText}>
|
||||
{countText}
|
||||
{this.props.warning}
|
||||
</Text>
|
||||
<View style={styles.yellowBoxButtons}>
|
||||
<TouchableOpacity
|
||||
onPress={this.props.onDismissed}
|
||||
style={styles.yellowBoxButton}>
|
||||
<Text style={styles.yellowBoxButtonText}>
|
||||
Dismiss
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={this.props.onIgnored}
|
||||
style={styles.yellowBoxButton}>
|
||||
<Text style={styles.yellowBoxButtonText}>
|
||||
Ignore
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var canMountWarningBox = true;
|
||||
|
||||
var WarningBox = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
totalWarningCount,
|
||||
openWarning: null,
|
||||
};
|
||||
},
|
||||
componentWillMount: function() {
|
||||
if (console.yellowBoxResetIgnored) {
|
||||
AsyncStorage.setItem(IGNORED_WARNINGS_KEY, '[]', function(err) {
|
||||
if (err) {
|
||||
console.warn('Could not reset ignored warnings.', err);
|
||||
}
|
||||
});
|
||||
ignoredWarnings = [];
|
||||
}
|
||||
},
|
||||
componentDidMount: function() {
|
||||
invariant(
|
||||
canMountWarningBox,
|
||||
'There can only be one WarningBox'
|
||||
);
|
||||
canMountWarningBox = false;
|
||||
warningCountEvents.addListener(
|
||||
'count',
|
||||
this._onWarningCount
|
||||
);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
warningCountEvents.removeAllListeners();
|
||||
canMountWarningBox = true;
|
||||
},
|
||||
_onWarningCount: function(totalWarningCount) {
|
||||
// Must use setImmediate because warnings often happen during render and
|
||||
// state cannot be set while rendering
|
||||
setImmediate(() => {
|
||||
this.setState({ totalWarningCount, });
|
||||
});
|
||||
},
|
||||
_onDismiss: function(warning) {
|
||||
warningCounts.delete(warning);
|
||||
this.setState({
|
||||
openWarning: null,
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
if (warningCounts.size === 0) {
|
||||
return <View />;
|
||||
}
|
||||
if (this.state.openWarning) {
|
||||
return (
|
||||
<WarningBoxOpened
|
||||
warning={this.state.openWarning}
|
||||
onClose={() => {
|
||||
this.setState({ openWarning: null });
|
||||
}}
|
||||
onDismissed={this._onDismiss.bind(this, this.state.openWarning)}
|
||||
onIgnored={() => {
|
||||
ignoredWarnings.push(this.state.openWarning);
|
||||
saveIgnoredWarnings();
|
||||
this._onDismiss(this.state.openWarning);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
var warningRows = [];
|
||||
warningCounts.forEach((count, warning) => {
|
||||
warningRows.push(
|
||||
<WarningRow
|
||||
key={warning}
|
||||
onOpened={() => {
|
||||
this.setState({ openWarning: warning });
|
||||
}}
|
||||
onDismissed={this._onDismiss.bind(this, warning)}
|
||||
warning={warning}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<View style={styles.warningContainer}>
|
||||
{warningRows}
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
bold: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
closeButton: {
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
height: 46,
|
||||
width: 46,
|
||||
},
|
||||
closeButtonText: {
|
||||
color: 'white',
|
||||
fontSize: 32,
|
||||
position: 'relative',
|
||||
left: 8,
|
||||
},
|
||||
warningContainer: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0
|
||||
},
|
||||
warningBox: {
|
||||
position: 'relative',
|
||||
backgroundColor: 'rgba(171, 124, 36, 0.9)',
|
||||
flex: 1,
|
||||
height: 46,
|
||||
},
|
||||
warningText: {
|
||||
color: 'white',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
marginLeft: 15,
|
||||
marginRight: 46,
|
||||
top: 7,
|
||||
},
|
||||
yellowBox: {
|
||||
backgroundColor: 'rgba(171, 124, 36, 0.9)',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
padding: 15,
|
||||
paddingTop: 35,
|
||||
},
|
||||
yellowBoxText: {
|
||||
color: 'white',
|
||||
fontSize: 20,
|
||||
},
|
||||
yellowBoxButtons: {
|
||||
flexDirection: 'row',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
},
|
||||
yellowBoxButton: {
|
||||
flex: 1,
|
||||
padding: 25,
|
||||
},
|
||||
yellowBoxButtonText: {
|
||||
color: 'white',
|
||||
fontSize: 16,
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = WarningBox;
|
|
@ -0,0 +1,335 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule YellowBox
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('EventEmitter');
|
||||
import type EmitterSubscription from 'EmitterSubscription';
|
||||
const Map = require('Map');
|
||||
const Platform = require('Platform');
|
||||
const React = require('React');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
|
||||
const _warningEmitter = new EventEmitter();
|
||||
const _warningMap = new Map();
|
||||
|
||||
/**
|
||||
* YellowBox renders warnings at the bottom of the app being developed.
|
||||
*
|
||||
* Warnings help guard against subtle yet significant issues that can impact the
|
||||
* quality of the app. This "in your face" style of warning allows developers to
|
||||
* notice and correct these issues as quickly as possible.
|
||||
*
|
||||
* By default, the warning box is enabled in `__DEV__`. Set the following flag
|
||||
* to disable it (and call `console.warn` to update any rendered <YellowBox>):
|
||||
*
|
||||
* console.disableYellowBox = true;
|
||||
* console.warn('YellowBox is disabled.');
|
||||
*
|
||||
* Warnings can be ignored programmatically by setting the array:
|
||||
*
|
||||
* console.ignoredYellowBox = ['Warning: ...'];
|
||||
*
|
||||
* Strings in `console.ignoredYellowBox` can be a prefix of the warning that
|
||||
* should be ignored.
|
||||
*/
|
||||
|
||||
if (__DEV__) {
|
||||
const {error, warn} = console;
|
||||
console.error = function() {
|
||||
error.apply(console, arguments);
|
||||
// Show yellow box for the `warning` module.
|
||||
if (typeof arguments[0] === 'string' &&
|
||||
arguments[0].startsWith('Warning: ')) {
|
||||
updateWarningMap.apply(null, arguments);
|
||||
}
|
||||
};
|
||||
console.warn = function() {
|
||||
warn.apply(console, arguments);
|
||||
updateWarningMap.apply(null, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
function updateWarningMap(format, ...args): void {
|
||||
const sprintf = require('sprintf');
|
||||
const stringifySafe = require('stringifySafe');
|
||||
|
||||
format = String(format);
|
||||
const argCount = (format.match(/%s/g) || []).length;
|
||||
const warning = [
|
||||
sprintf(format, ...args.slice(0, argCount)),
|
||||
...args.slice(argCount).map(stringifySafe),
|
||||
].join(' ');
|
||||
|
||||
const count = _warningMap.has(warning) ? _warningMap.get(warning) : 0;
|
||||
_warningMap.set(warning, count + 2);
|
||||
_warningEmitter.emit('warning', _warningMap);
|
||||
}
|
||||
|
||||
function isWarningIgnored(warning: string): boolean {
|
||||
return (
|
||||
Array.isArray(console.ignoredYellowBox) &&
|
||||
console.ignoredYellowBox.some(
|
||||
ignorePrefix => warning.startsWith(ignorePrefix)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const WarningRow = ({count, warning, onPress}) => {
|
||||
const Text = require('Text');
|
||||
const TouchableHighlight = require('TouchableHighlight');
|
||||
const View = require('View');
|
||||
|
||||
const countText = count > 1 ?
|
||||
<Text style={styles.listRowCount}>{'(' + count + ') '}</Text> :
|
||||
null;
|
||||
|
||||
return (
|
||||
<View style={styles.listRow}>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.5}
|
||||
onPress={onPress}
|
||||
style={styles.listRowContent}
|
||||
underlayColor="transparent">
|
||||
<Text style={styles.listRowText} numberOfLines={2}>
|
||||
{countText}
|
||||
{warning}
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const WarningInspector = ({count, warning, onClose, onDismiss}) => {
|
||||
const ScrollView = require('ScrollView');
|
||||
const Text = require('Text');
|
||||
const TouchableHighlight = require('TouchableHighlight');
|
||||
const View = require('View');
|
||||
|
||||
const countSentence =
|
||||
'Warning encountered ' + count + ' time' + (count - 1 ? 's' : '') + '.';
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.95}
|
||||
underlayColor={backgroundColor(0.8)}
|
||||
onPress={onClose}
|
||||
style={styles.inspector}>
|
||||
<View style={styles.inspectorContent}>
|
||||
<View style={styles.inspectorCount}>
|
||||
<Text style={styles.inspectorCountText}>{countSentence}</Text>
|
||||
</View>
|
||||
<ScrollView style={styles.inspectorWarning}>
|
||||
<Text style={styles.inspectorWarningText}>{warning}</Text>
|
||||
</ScrollView>
|
||||
<View style={styles.inspectorButtons}>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.5}
|
||||
onPress={onDismiss}
|
||||
style={styles.inspectorButton}
|
||||
underlayColor="transparent">
|
||||
<Text style={styles.inspectorButtonText}>
|
||||
Dismiss Warning
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
};
|
||||
|
||||
class YellowBox extends React.Component {
|
||||
state: {
|
||||
inspecting: ?string;
|
||||
warningMap: Map;
|
||||
};
|
||||
_listener: ?EmitterSubscription;
|
||||
|
||||
constructor(props: mixed, context: mixed) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
inspecting: null,
|
||||
warningMap: _warningMap,
|
||||
};
|
||||
this.dismissWarning = warning => {
|
||||
const {inspecting, warningMap} = this.state;
|
||||
warningMap.delete(warning);
|
||||
this.setState({
|
||||
inspecting: inspecting === warning ? null : inspecting,
|
||||
warningMap,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let scheduled = null;
|
||||
this._listener = _warningEmitter.addListener('warning', warningMap => {
|
||||
// Use `setImmediate` because warnings often happen during render, but
|
||||
// state cannot be set while rendering.
|
||||
scheduled = scheduled || setImmediate(() => {
|
||||
scheduled = null;
|
||||
this.setState({
|
||||
warningMap,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._listener) {
|
||||
this._listener.remove();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (console.disableYellowBox || this.state.warningMap.size === 0) {
|
||||
return null;
|
||||
}
|
||||
const ScrollView = require('ScrollView');
|
||||
const View = require('View');
|
||||
|
||||
const inspecting = this.state.inspecting;
|
||||
const inspector = inspecting !== null ?
|
||||
<WarningInspector
|
||||
count={this.state.warningMap.get(inspecting)}
|
||||
warning={inspecting}
|
||||
onClose={() => this.setState({inspecting: null})}
|
||||
onDismiss={() => this.dismissWarning(inspecting)}
|
||||
/> :
|
||||
null;
|
||||
|
||||
const rows = [];
|
||||
this.state.warningMap.forEach((count, warning) => {
|
||||
if (!isWarningIgnored(warning)) {
|
||||
rows.push(
|
||||
<WarningRow
|
||||
key={warning}
|
||||
count={count}
|
||||
warning={warning}
|
||||
onPress={() => this.setState({inspecting: warning})}
|
||||
onDismiss={() => this.dismissWarning(warning)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const listStyle = [
|
||||
styles.list,
|
||||
// Additional `0.4` so the 5th row can peek into view.
|
||||
{height: Math.min(rows.length, 4.4) * (rowGutter + rowHeight)},
|
||||
];
|
||||
return (
|
||||
<View style={inspector ? styles.fullScreen : listStyle}>
|
||||
<ScrollView style={listStyle}>
|
||||
{rows}
|
||||
</ScrollView>
|
||||
{inspector}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const backgroundColor = opacity => 'rgba(250, 186, 48, ' + opacity + ')';
|
||||
const textColor = 'white';
|
||||
const rowGutter = 1;
|
||||
const rowHeight = 46;
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
fullScreen: {
|
||||
backgroundColor: 'transparent',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
inspector: {
|
||||
backgroundColor: backgroundColor(0.95),
|
||||
flex: 1,
|
||||
},
|
||||
inspectorContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
inspectorButtons: {
|
||||
flexDirection: 'row',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
inspectorButton: {
|
||||
padding: 22,
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
inspectorButtonText: {
|
||||
color: textColor,
|
||||
fontSize: 14,
|
||||
opacity: 0.8,
|
||||
textAlign: 'center',
|
||||
},
|
||||
inspectorContent: {
|
||||
flex: 1,
|
||||
paddingTop: 5,
|
||||
},
|
||||
inspectorCount: {
|
||||
padding: 15,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
inspectorCountText: {
|
||||
color: textColor,
|
||||
fontSize: 14,
|
||||
},
|
||||
inspectorWarning: {
|
||||
padding: 15,
|
||||
position: 'absolute',
|
||||
top: 39,
|
||||
bottom: 60,
|
||||
},
|
||||
inspectorWarningText: {
|
||||
color: textColor,
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
list: {
|
||||
backgroundColor: 'transparent',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
listRow: {
|
||||
position: 'relative',
|
||||
backgroundColor: backgroundColor(0.95),
|
||||
flex: 1,
|
||||
height: rowHeight,
|
||||
marginTop: rowGutter,
|
||||
},
|
||||
listRowContent: {
|
||||
flex: 1,
|
||||
},
|
||||
listRowCount: {
|
||||
color: 'rgba(255, 255, 255, 0.5)',
|
||||
},
|
||||
listRowText: {
|
||||
color: textColor,
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: Platform.OS === 'android' ? 5 : 7,
|
||||
marginLeft: 15,
|
||||
marginRight: 15,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = YellowBox;
|
|
@ -8,6 +8,7 @@
|
|||
*
|
||||
* @providesModule renderApplication
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Inspector = require('Inspector');
|
||||
|
@ -20,6 +21,8 @@ var View = require('View');
|
|||
|
||||
var invariant = require('invariant');
|
||||
|
||||
var YellowBox = __DEV__ ? require('YellowBox') : null;
|
||||
|
||||
// require BackAndroid so it sets the default handler that exits the app if no listeners respond
|
||||
require('BackAndroid');
|
||||
|
||||
|
@ -89,10 +92,14 @@ var AppContainer = React.createClass({
|
|||
<Portal
|
||||
onModalVisibilityChanged={this.setRootAccessibility}/>
|
||||
</View>;
|
||||
|
||||
let yellowBox = null;
|
||||
if (__DEV__) {
|
||||
yellowBox = <YellowBox />;
|
||||
}
|
||||
return this.state.enabled ?
|
||||
<View style={styles.appContainer}>
|
||||
{appView}
|
||||
{yellowBox}
|
||||
{this.renderInspector()}
|
||||
</View> :
|
||||
appView;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*
|
||||
* @providesModule renderApplication
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
|
@ -19,7 +20,7 @@ var View = require('View');
|
|||
var invariant = require('invariant');
|
||||
|
||||
var Inspector = __DEV__ ? require('Inspector') : null;
|
||||
var WarningBox = __DEV__ ? require('WarningBox') : null;
|
||||
var YellowBox = __DEV__ ? require('YellowBox') : null;
|
||||
|
||||
var AppContainer = React.createClass({
|
||||
mixins: [Subscribable.Mixin],
|
||||
|
@ -47,14 +48,16 @@ var AppContainer = React.createClass({
|
|||
},
|
||||
|
||||
render: function() {
|
||||
var shouldRenderWarningBox = __DEV__ && console.yellowBoxEnabled;
|
||||
var warningBox = shouldRenderWarningBox ? <WarningBox /> : null;
|
||||
let yellowBox = null;
|
||||
if (__DEV__) {
|
||||
yellowBox = <YellowBox />;
|
||||
}
|
||||
return (
|
||||
<View style={styles.appContainer}>
|
||||
<View collapsible={false} style={styles.appContainer} ref="main">
|
||||
{this.props.children}
|
||||
</View>
|
||||
{warningBox}
|
||||
{yellowBox}
|
||||
{this.state.inspector}
|
||||
</View>
|
||||
);
|
||||
|
@ -70,6 +73,7 @@ function renderApplication<D, P, S>(
|
|||
rootTag,
|
||||
'Expect to have a valid rootTag, instead got ', rootTag
|
||||
);
|
||||
/* eslint-disable jsx-no-undef-with-namespace */
|
||||
React.render(
|
||||
<AppContainer rootTag={rootTag}>
|
||||
<RootComponent
|
||||
|
@ -79,6 +83,7 @@ function renderApplication<D, P, S>(
|
|||
</AppContainer>,
|
||||
rootTag
|
||||
);
|
||||
/* eslint-enable jsx-no-undef-with-namespace */
|
||||
}
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
|
|
Loading…
Reference in New Issue