mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
18
Commits
v0.80.1
...
v0.62.0-rc.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bf7f1046d | ||
|
|
5b4816741b | ||
|
|
39e5a83062 | ||
|
|
fe348ab53d | ||
|
|
0fd83e4786 | ||
|
|
e97baa6066 | ||
|
|
76557f00d7 | ||
|
|
4693170d63 | ||
|
|
51dcb0195b | ||
|
|
203f3e3399 | ||
|
|
e7c289b56e | ||
|
|
3cfbae6540 | ||
|
|
3fd98d95ef | ||
|
|
c194ed2dbb | ||
|
|
93bbab3878 | ||
|
|
1a305fd79b | ||
|
|
45a43241cd | ||
|
|
041c392ec9 |
@@ -83,7 +83,7 @@ function reportException(e: ExtendedError, isFatal: boolean) {
|
||||
e.jsEngine == null ? message : `${message}, js engine: ${e.jsEngine}`;
|
||||
|
||||
const isHandledByLogBox =
|
||||
e.forceRedbox !== true && global.__reactExperimentalLogBox;
|
||||
e.forceRedbox !== true && global.__unstable_isLogBoxEnabled === true;
|
||||
|
||||
const data = preprocessException({
|
||||
message,
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* 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
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
* @flow
|
||||
*/
|
||||
|
||||
exports.version = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
minor: 62,
|
||||
patch: 0,
|
||||
prerelease: null,
|
||||
prerelease: 'rc.1',
|
||||
};
|
||||
|
||||
@@ -1671,6 +1671,33 @@ namespace facebook {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
|
||||
static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_show(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
||||
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "show", @selector(show), args, count);
|
||||
}
|
||||
|
||||
static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_hide(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
||||
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "hide", @selector(hide), args, count);
|
||||
}
|
||||
|
||||
|
||||
NativeLogBoxSpecJSI::NativeLogBoxSpecJSI(id<RCTTurboModule> instance, std::shared_ptr<CallInvoker> jsInvoker)
|
||||
: ObjCTurboModule("LogBox", instance, jsInvoker) {
|
||||
|
||||
methodMap_["show"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_show};
|
||||
|
||||
|
||||
methodMap_["hide"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_hide};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
|
||||
@@ -1771,6 +1771,25 @@ namespace facebook {
|
||||
};
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@protocol NativeLogBoxSpec <RCTBridgeModule, RCTTurboModule>
|
||||
|
||||
- (void)show;
|
||||
- (void)hide;
|
||||
|
||||
@end
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
/**
|
||||
* ObjC++ class for module 'LogBox'
|
||||
*/
|
||||
|
||||
class JSI_EXPORT NativeLogBoxSpecJSI : public ObjCTurboModule {
|
||||
public:
|
||||
NativeLogBoxSpecJSI(id<RCTTurboModule> instance, std::shared_ptr<CallInvoker> jsInvoker);
|
||||
|
||||
};
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@protocol NativeModalManagerSpec <RCTBridgeModule, RCTTurboModule>
|
||||
|
||||
- (void)addListener:(NSString *)eventName;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
('use strict');
|
||||
|
||||
import * as React from 'react';
|
||||
import LogBoxLog from './LogBoxLog';
|
||||
import {parseLogBoxException} from './parseLogBoxLog';
|
||||
import type {LogLevel} from './LogBoxLog';
|
||||
@@ -21,7 +22,7 @@ import type {
|
||||
} from './parseLogBoxLog';
|
||||
import parseErrorStack from '../../Core/Devtools/parseErrorStack';
|
||||
import type {ExtendedError} from '../../Core/Devtools/parseErrorStack';
|
||||
|
||||
import NativeLogBox from '../../NativeModules/specs/NativeLogBox';
|
||||
export type LogBoxLogs = Set<LogBoxLog>;
|
||||
export type LogData = $ReadOnly<{|
|
||||
level: LogLevel,
|
||||
@@ -73,7 +74,7 @@ let warningFilter: WarningFilter = function(format) {
|
||||
return {
|
||||
finalFormat: format,
|
||||
forceDialogImmediately: false,
|
||||
suppressDialog_LEGACY: false,
|
||||
suppressDialog_LEGACY: true,
|
||||
suppressCompletely: false,
|
||||
monitorEvent: 'unknown',
|
||||
monitorListVersion: 0,
|
||||
@@ -85,20 +86,6 @@ const LOGBOX_ERROR_MESSAGE =
|
||||
'An error was thrown when attempting to render log messages via LogBox.';
|
||||
|
||||
function getNextState() {
|
||||
const logArray = Array.from(logs);
|
||||
let index = logArray.length - 1;
|
||||
while (index >= 0) {
|
||||
// The latest syntax error is selected and displayed before all other logs.
|
||||
if (logArray[index].level === 'syntax') {
|
||||
return {
|
||||
logs,
|
||||
isDisabled: _isDisabled,
|
||||
selectedLogIndex: index,
|
||||
};
|
||||
}
|
||||
index -= 1;
|
||||
}
|
||||
|
||||
return {
|
||||
logs,
|
||||
isDisabled: _isDisabled,
|
||||
@@ -174,9 +161,10 @@ function appendNewLog(newLog) {
|
||||
let addPendingLog = () => {
|
||||
logs.add(newLog);
|
||||
if (_selectedIndex <= 0) {
|
||||
_selectedIndex = logs.size - 1;
|
||||
setSelectedLog(logs.size - 1);
|
||||
} else {
|
||||
handleUpdate();
|
||||
}
|
||||
handleUpdate();
|
||||
addPendingLog = null;
|
||||
};
|
||||
|
||||
@@ -190,8 +178,14 @@ function appendNewLog(newLog) {
|
||||
if (addPendingLog && status !== 'PENDING') {
|
||||
addPendingLog();
|
||||
clearTimeout(optimisticTimeout);
|
||||
} else if (status !== 'PENDING') {
|
||||
// The log has already been added but we need to trigger a render.
|
||||
handleUpdate();
|
||||
}
|
||||
});
|
||||
} else if (newLog.level === 'syntax') {
|
||||
logs.add(newLog);
|
||||
setSelectedLog(logs.size - 1);
|
||||
} else {
|
||||
logs.add(newLog);
|
||||
handleUpdate();
|
||||
@@ -255,21 +249,42 @@ export function symbolicateLogLazy(log: LogBoxLog) {
|
||||
export function clear(): void {
|
||||
if (logs.size > 0) {
|
||||
logs = new Set();
|
||||
_selectedIndex = -1;
|
||||
handleUpdate();
|
||||
setSelectedLog(-1);
|
||||
}
|
||||
}
|
||||
|
||||
export function setSelectedLog(index: number): void {
|
||||
_selectedIndex = index;
|
||||
export function setSelectedLog(proposedNewIndex: number): void {
|
||||
const oldIndex = _selectedIndex;
|
||||
let newIndex = proposedNewIndex;
|
||||
|
||||
const logArray = Array.from(logs);
|
||||
let index = logArray.length - 1;
|
||||
while (index >= 0) {
|
||||
// The latest syntax error is selected and displayed before all other logs.
|
||||
if (logArray[index].level === 'syntax') {
|
||||
newIndex = index;
|
||||
break;
|
||||
}
|
||||
index -= 1;
|
||||
}
|
||||
_selectedIndex = newIndex;
|
||||
handleUpdate();
|
||||
if (NativeLogBox) {
|
||||
setTimeout(() => {
|
||||
if (oldIndex < 0 && newIndex >= 0) {
|
||||
NativeLogBox.show();
|
||||
} else if (oldIndex >= 0 && newIndex < 0) {
|
||||
NativeLogBox.hide();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
export function clearWarnings(): void {
|
||||
const newLogs = Array.from(logs).filter(log => log.level !== 'warn');
|
||||
if (newLogs.length !== logs.size) {
|
||||
logs = new Set(newLogs);
|
||||
_selectedIndex = -1;
|
||||
setSelectedLog(-1);
|
||||
handleUpdate();
|
||||
}
|
||||
}
|
||||
@@ -280,8 +295,7 @@ export function clearErrors(): void {
|
||||
);
|
||||
if (newLogs.length !== logs.size) {
|
||||
logs = new Set(newLogs);
|
||||
_selectedIndex = -1;
|
||||
handleUpdate();
|
||||
setSelectedLog(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,3 +383,97 @@ export function observe(observer: Observer): Subscription {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
type State = $ReadOnly<{|
|
||||
logs: LogBoxLogs,
|
||||
isDisabled: boolean,
|
||||
hasError: boolean,
|
||||
selectedLogIndex: number,
|
||||
|}>;
|
||||
|
||||
type SubscribedComponent = React.AbstractComponent<
|
||||
$ReadOnly<{|
|
||||
logs: $ReadOnlyArray<LogBoxLog>,
|
||||
isDisabled: boolean,
|
||||
selectedLogIndex: number,
|
||||
|}>,
|
||||
>;
|
||||
|
||||
export function withSubscription(
|
||||
WrappedComponent: SubscribedComponent,
|
||||
): React.AbstractComponent<{||}> {
|
||||
class LogBoxStateSubscription extends React.Component<Props, State> {
|
||||
static getDerivedStateFromError() {
|
||||
return {hasError: true};
|
||||
}
|
||||
|
||||
componentDidCatch(err: Error, errorInfo: {componentStack: string, ...}) {
|
||||
reportLogBoxError(err, errorInfo.componentStack);
|
||||
}
|
||||
|
||||
_subscription: ?Subscription;
|
||||
|
||||
state = {
|
||||
logs: new Set(),
|
||||
isDisabled: false,
|
||||
hasError: false,
|
||||
selectedLogIndex: -1,
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
if (this.state.hasError) {
|
||||
// This happens when the component failed to render, in which case we delegate to the native redbox.
|
||||
// We can't show anyback fallback UI here, because the error may be with <View> or <Text>.
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
logs={Array.from(this.state.logs)}
|
||||
isDisabled={this.state.isDisabled}
|
||||
selectedLogIndex={this.state.selectedLogIndex}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this._subscription = observe(data => {
|
||||
this.setState(data);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
if (this._subscription != null) {
|
||||
this._subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDismiss = (): void => {
|
||||
// Here we handle the cases when the log is dismissed and it
|
||||
// was either the last log, or when the current index
|
||||
// is now outside the bounds of the log array.
|
||||
const {selectedLogIndex, logs: stateLogs} = this.state;
|
||||
const logsArray = Array.from(stateLogs);
|
||||
if (selectedLogIndex != null) {
|
||||
if (logsArray.length - 1 <= 0) {
|
||||
setSelectedLog(-1);
|
||||
} else if (selectedLogIndex >= logsArray.length - 1) {
|
||||
setSelectedLog(selectedLogIndex - 1);
|
||||
}
|
||||
|
||||
dismiss(logsArray[selectedLogIndex]);
|
||||
}
|
||||
};
|
||||
|
||||
_handleMinimize = (): void => {
|
||||
setSelectedLog(-1);
|
||||
};
|
||||
|
||||
_handleSetSelectedLog = (index: number): void => {
|
||||
setSelectedLog(index);
|
||||
};
|
||||
}
|
||||
|
||||
return LogBoxStateSubscription;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,13 @@ function getLogBoxLog() {
|
||||
message: {content: '...', substitutions: []},
|
||||
stack: createStack(['A', 'B', 'C']),
|
||||
category: 'Message category...',
|
||||
componentStack: [{component: 'LogBoxLog', location: 'LogBoxLog.js:1'}],
|
||||
componentStack: [
|
||||
{
|
||||
content: 'LogBoxLog',
|
||||
fileName: 'LogBoxLog.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
],
|
||||
codeFrame: {
|
||||
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
|
||||
location: {row: 199, column: 0},
|
||||
@@ -69,7 +75,11 @@ describe('LogBoxLog', () => {
|
||||
expect(log.stack).toEqual(createStack(['A', 'B', 'C']));
|
||||
expect(log.category).toEqual('Message category...');
|
||||
expect(log.componentStack).toEqual([
|
||||
{component: 'LogBoxLog', location: 'LogBoxLog.js:1'},
|
||||
{
|
||||
content: 'LogBoxLog',
|
||||
fileName: 'LogBoxLog.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
]);
|
||||
expect(log.codeFrame).toEqual({
|
||||
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
|
||||
|
||||
@@ -117,8 +117,16 @@ describe('parseLogBoxLog', () => {
|
||||
]),
|
||||
).toEqual({
|
||||
componentStack: [
|
||||
{component: 'MyComponent', location: 'filename.js:1'},
|
||||
{component: 'MyOtherComponent', location: 'filename2.js:1'},
|
||||
{
|
||||
content: 'MyComponent',
|
||||
fileName: 'filename.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
{
|
||||
content: 'MyOtherComponent',
|
||||
fileName: 'filename2.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
],
|
||||
category:
|
||||
'Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?%s',
|
||||
@@ -143,8 +151,16 @@ describe('parseLogBoxLog', () => {
|
||||
]),
|
||||
).toEqual({
|
||||
componentStack: [
|
||||
{component: 'MyComponent', location: 'filename.js:1'},
|
||||
{component: 'MyOtherComponent', location: 'filename2.js:1'},
|
||||
{
|
||||
content: 'MyComponent',
|
||||
fileName: 'filename.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
{
|
||||
content: 'MyOtherComponent',
|
||||
fileName: 'filename2.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
],
|
||||
category: 'Some kind of message',
|
||||
message: {
|
||||
@@ -164,8 +180,16 @@ describe('parseLogBoxLog', () => {
|
||||
]),
|
||||
).toEqual({
|
||||
componentStack: [
|
||||
{component: 'MyComponent', location: 'filename.js:1'},
|
||||
{component: 'MyOtherComponent', location: 'filename2.js:1'},
|
||||
{
|
||||
content: 'MyComponent',
|
||||
fileName: 'filename.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
{
|
||||
content: 'MyOtherComponent',
|
||||
fileName: 'filename2.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
],
|
||||
category:
|
||||
'Some kind of message Some other kind of message Some third kind of message',
|
||||
@@ -418,12 +442,14 @@ Please follow the instructions at: fburl.com/rn-remote-assets`,
|
||||
},
|
||||
componentStack: [
|
||||
{
|
||||
component: 'MyComponent',
|
||||
location: 'filename.js:1',
|
||||
content: 'MyComponent',
|
||||
fileName: 'filename.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
{
|
||||
component: 'MyOtherComponent',
|
||||
location: 'filename2.js:1',
|
||||
content: 'MyOtherComponent',
|
||||
fileName: 'filename2.js',
|
||||
location: {column: -1, row: 1},
|
||||
},
|
||||
],
|
||||
stack: [
|
||||
|
||||
@@ -42,12 +42,7 @@ export type Message = $ReadOnly<{|
|
||||
>,
|
||||
|}>;
|
||||
|
||||
export type ComponentStack = $ReadOnlyArray<
|
||||
$ReadOnly<{|
|
||||
component: string,
|
||||
location: string,
|
||||
|}>,
|
||||
>;
|
||||
export type ComponentStack = $ReadOnlyArray<CodeFrame>;
|
||||
|
||||
const SUBSTITUTION = UTFSequence.BOM + '%s';
|
||||
|
||||
@@ -127,6 +122,7 @@ export function parseCategory(
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function parseComponentStack(message: string): ComponentStack {
|
||||
return message
|
||||
.split(/\n {4}in /g)
|
||||
@@ -134,11 +130,17 @@ export function parseComponentStack(message: string): ComponentStack {
|
||||
if (!s) {
|
||||
return null;
|
||||
}
|
||||
let [component, location] = s.split(/ \(at /);
|
||||
if (!location) {
|
||||
[component, location] = s.split(/ \(/);
|
||||
const match = s.match(/(.*) \(at (.*\.js):([\d]+)\)/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
return {component, location: location && location.replace(')', '')};
|
||||
|
||||
let [content, fileName, row] = match.slice(1);
|
||||
return {
|
||||
content,
|
||||
fileName,
|
||||
location: {column: -1, row: parseInt(row, 10)},
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
+28
-98
@@ -10,26 +10,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as React from 'react';
|
||||
import Platform from '../Utilities/Platform';
|
||||
import RCTLog from '../Utilities/RCTLog';
|
||||
import LogBoxContainer from './UI/LogBoxContainer';
|
||||
import * as LogBoxData from './Data/LogBoxData';
|
||||
import {parseLogBoxLog} from './Data/parseLogBoxLog';
|
||||
|
||||
import type {LogBoxLogs, Subscription, IgnorePattern} from './Data/LogBoxData';
|
||||
import type {IgnorePattern} from './Data/LogBoxData';
|
||||
|
||||
import LogBoxLog from './Data/LogBoxLog';
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
type State = {|
|
||||
logs: LogBoxLogs,
|
||||
isDisabled: boolean,
|
||||
hasError: boolean,
|
||||
selectedLogIndex: number,
|
||||
|};
|
||||
|
||||
let LogBoxComponent;
|
||||
let LogBox;
|
||||
|
||||
/**
|
||||
* LogBox displays logs in the app.
|
||||
@@ -48,25 +36,26 @@ if (__DEV__) {
|
||||
warnImpl(...args);
|
||||
};
|
||||
|
||||
LogBoxComponent = class LogBox extends React.Component<Props, State> {
|
||||
static getDerivedStateFromError() {
|
||||
return {hasError: true};
|
||||
}
|
||||
|
||||
componentDidCatch(err, errorInfo) {
|
||||
LogBoxData.reportLogBoxError(err, errorInfo.componentStack);
|
||||
}
|
||||
|
||||
LogBox = {
|
||||
// TODO: deprecated, replace with ignoreLogs
|
||||
static ignoreWarnings(patterns: $ReadOnlyArray<IgnorePattern>): void {
|
||||
ignoreWarnings: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
|
||||
LogBox.ignoreLogs(patterns);
|
||||
}
|
||||
},
|
||||
|
||||
static ignoreLogs(patterns: $ReadOnlyArray<IgnorePattern>): void {
|
||||
ignoreLogs: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
|
||||
LogBoxData.addIgnorePatterns(patterns);
|
||||
}
|
||||
},
|
||||
|
||||
uninstall: (): void => {
|
||||
errorImpl = error;
|
||||
warnImpl = warn;
|
||||
delete (console: any).disableLogBox;
|
||||
},
|
||||
|
||||
install: (): void => {
|
||||
// Trigger lazy initialization of module.
|
||||
require('../NativeModules/specs/NativeLogBox');
|
||||
|
||||
static install(): void {
|
||||
errorImpl = function(...args) {
|
||||
registerError(...args);
|
||||
};
|
||||
@@ -92,62 +81,7 @@ if (__DEV__) {
|
||||
RCTLog.setWarningHandler((...args) => {
|
||||
registerWarning(...args);
|
||||
});
|
||||
}
|
||||
|
||||
static uninstall(): void {
|
||||
errorImpl = error;
|
||||
warnImpl = warn;
|
||||
delete (console: any).disableLogBox;
|
||||
}
|
||||
|
||||
_subscription: ?Subscription;
|
||||
|
||||
state = {
|
||||
logs: new Set(),
|
||||
isDisabled: false,
|
||||
hasError: false,
|
||||
selectedLogIndex: -1,
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
if (this.state.hasError) {
|
||||
// This happens when the component failed to render, in which case we delegate to the native redbox.
|
||||
// We can't show anyback fallback UI here, because the error may be with <View> or <Text>.
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.state.logs == null ? null : (
|
||||
<LogBoxContainer
|
||||
onDismiss={this._handleDismiss}
|
||||
onDismissWarns={LogBoxData.clearWarnings}
|
||||
onDismissErrors={LogBoxData.clearErrors}
|
||||
logs={this.state.logs}
|
||||
isDisabled={this.state.isDisabled}
|
||||
selectedLogIndex={this.state.selectedLogIndex}
|
||||
setSelectedLog={this._handleSetSelectedLog}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this._subscription = LogBoxData.observe(data => {
|
||||
this.setState(data);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
if (this._subscription != null) {
|
||||
this._subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDismiss(log: LogBoxLog): void {
|
||||
LogBoxData.dismiss(log);
|
||||
}
|
||||
|
||||
_handleSetSelectedLog(index: number): void {
|
||||
LogBoxData.setSelectedLog(index);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const isRCTLogAdviceWarning = (...args) => {
|
||||
@@ -227,31 +161,27 @@ if (__DEV__) {
|
||||
}
|
||||
};
|
||||
} else {
|
||||
LogBoxComponent = class extends React.Component<Props, State> {
|
||||
LogBox = {
|
||||
// TODO: deprecated, replace with ignoreLogs
|
||||
static ignoreWarnings(patterns: $ReadOnlyArray<IgnorePattern>): void {
|
||||
ignoreWarnings: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
|
||||
// Do nothing.
|
||||
}
|
||||
},
|
||||
|
||||
static ignoreLogs(patterns: $ReadOnlyArray<IgnorePattern>): void {
|
||||
ignoreLogs: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
|
||||
// Do nothing.
|
||||
}
|
||||
},
|
||||
|
||||
static install(): void {
|
||||
install: (): void => {
|
||||
// Do nothing.
|
||||
}
|
||||
},
|
||||
|
||||
static uninstall(): void {
|
||||
uninstall: (): void => {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = (LogBoxComponent: Class<React.Component<Props, State>> & {
|
||||
module.exports = (LogBox: {
|
||||
// TODO: deprecated, replace with ignoreLogs
|
||||
ignoreWarnings($ReadOnlyArray<IgnorePattern>): void,
|
||||
ignoreLogs($ReadOnlyArray<IgnorePattern>): void,
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as React from 'react';
|
||||
import {View, StyleSheet} from 'react-native';
|
||||
import * as LogBoxData from './Data/LogBoxData';
|
||||
import LogBoxInspector from './UI/LogBoxInspector';
|
||||
import type LogBoxLog from './Data/LogBoxLog';
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
logs: $ReadOnlyArray<LogBoxLog>,
|
||||
selectedLogIndex: number,
|
||||
isDisabled?: ?boolean,
|
||||
|}>;
|
||||
|
||||
export class _LogBoxInspectorContainer extends React.Component<Props> {
|
||||
render(): React.Node {
|
||||
return (
|
||||
<View style={StyleSheet.absoluteFill}>
|
||||
<LogBoxInspector
|
||||
onDismiss={this._handleDismiss}
|
||||
onMinimize={this._handleMinimize}
|
||||
onChangeSelectedIndex={this._handleSetSelectedLog}
|
||||
logs={this.props.logs}
|
||||
selectedIndex={this.props.selectedLogIndex}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleDismiss = (): void => {
|
||||
// Here we handle the cases when the log is dismissed and it
|
||||
// was either the last log, or when the current index
|
||||
// is now outside the bounds of the log array.
|
||||
const {selectedLogIndex, logs} = this.props;
|
||||
const logsArray = Array.from(logs);
|
||||
if (selectedLogIndex != null) {
|
||||
if (logsArray.length - 1 <= 0) {
|
||||
LogBoxData.setSelectedLog(-1);
|
||||
} else if (selectedLogIndex >= logsArray.length - 1) {
|
||||
LogBoxData.setSelectedLog(selectedLogIndex - 1);
|
||||
}
|
||||
|
||||
LogBoxData.dismiss(logsArray[selectedLogIndex]);
|
||||
}
|
||||
};
|
||||
|
||||
_handleMinimize = (): void => {
|
||||
LogBoxData.setSelectedLog(-1);
|
||||
};
|
||||
|
||||
_handleSetSelectedLog = (index: number): void => {
|
||||
LogBoxData.setSelectedLog(index);
|
||||
};
|
||||
}
|
||||
|
||||
export default (LogBoxData.withSubscription(
|
||||
_LogBoxInspectorContainer,
|
||||
): React.AbstractComponent<{||}>);
|
||||
+22
-49
@@ -11,46 +11,31 @@
|
||||
'use strict';
|
||||
|
||||
import * as React from 'react';
|
||||
import SafeAreaView from '../../Components/SafeAreaView/SafeAreaView';
|
||||
import StyleSheet from '../../StyleSheet/StyleSheet';
|
||||
import View from '../../Components/View/View';
|
||||
import LogBoxInspector from './LogBoxInspector';
|
||||
import LogBoxLog from '../Data/LogBoxLog';
|
||||
import LogBoxLogNotification from './LogBoxLogNotification';
|
||||
import type {LogBoxLogs} from '../Data/LogBoxData';
|
||||
import StyleSheet from '../StyleSheet/StyleSheet';
|
||||
import View from '../Components/View/View';
|
||||
import * as LogBoxData from './Data/LogBoxData';
|
||||
import LogBoxLog from './Data/LogBoxLog';
|
||||
import LogBoxLogNotification from './UI/LogBoxNotification';
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
onDismiss: (log: LogBoxLog) => void,
|
||||
onDismissWarns: () => void,
|
||||
onDismissErrors: () => void,
|
||||
setSelectedLog: number => void,
|
||||
logs: LogBoxLogs,
|
||||
logs: $ReadOnlyArray<LogBoxLog>,
|
||||
selectedLogIndex: number,
|
||||
isDisabled?: ?boolean,
|
||||
|}>;
|
||||
|
||||
function LogBoxContainer(props: Props): React.Node {
|
||||
const {selectedLogIndex, setSelectedLog} = props;
|
||||
export function _LogBoxNotificationContainer(props: Props): React.Node {
|
||||
const {logs} = props;
|
||||
|
||||
const logs = Array.from(props.logs);
|
||||
const onDismissWarns = () => {
|
||||
LogBoxData.clearWarnings();
|
||||
};
|
||||
const onDismissErrors = () => {
|
||||
LogBoxData.clearErrors();
|
||||
};
|
||||
|
||||
function handleInspectorDismiss() {
|
||||
// Here we handle the cases when the log is dismissed and it
|
||||
// was either the last log, or when the current index
|
||||
// is now outside the bounds of the log array.
|
||||
if (selectedLogIndex != null) {
|
||||
if (logs.length - 1 <= 0) {
|
||||
setSelectedLog(-1);
|
||||
} else if (selectedLogIndex >= logs.length - 1) {
|
||||
setSelectedLog(selectedLogIndex - 1);
|
||||
}
|
||||
props.onDismiss(logs[selectedLogIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
function handleInspectorMinimize() {
|
||||
setSelectedLog(-1);
|
||||
}
|
||||
const setSelectedLog = (index: number): void => {
|
||||
LogBoxData.setSelectedLog(index);
|
||||
};
|
||||
|
||||
function openLog(log: LogBoxLog) {
|
||||
let index = logs.length - 1;
|
||||
@@ -62,20 +47,6 @@ function LogBoxContainer(props: Props): React.Node {
|
||||
setSelectedLog(index);
|
||||
}
|
||||
|
||||
if (selectedLogIndex > -1) {
|
||||
return (
|
||||
<View style={StyleSheet.absoluteFill}>
|
||||
<LogBoxInspector
|
||||
onDismiss={handleInspectorDismiss}
|
||||
onMinimize={handleInspectorMinimize}
|
||||
onChangeSelectedIndex={setSelectedLog}
|
||||
logs={logs}
|
||||
selectedIndex={selectedLogIndex}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (logs.length === 0 || props.isDisabled === true) {
|
||||
return null;
|
||||
}
|
||||
@@ -93,7 +64,7 @@ function LogBoxContainer(props: Props): React.Node {
|
||||
level="warn"
|
||||
totalLogCount={warnings.length}
|
||||
onPressOpen={() => openLog(warnings[warnings.length - 1])}
|
||||
onPressDismiss={props.onDismissWarns}
|
||||
onPressDismiss={onDismissWarns}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
@@ -104,7 +75,7 @@ function LogBoxContainer(props: Props): React.Node {
|
||||
level="error"
|
||||
totalLogCount={errors.length}
|
||||
onPressOpen={() => openLog(errors[errors.length - 1])}
|
||||
onPressDismiss={props.onDismissErrors}
|
||||
onPressDismiss={onDismissErrors}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
@@ -126,4 +97,6 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
export default LogBoxContainer;
|
||||
export default (LogBoxData.withSubscription(
|
||||
_LogBoxNotificationContainer,
|
||||
): React.AbstractComponent<{||}>);
|
||||
@@ -14,7 +14,7 @@ import LogBoxInspectorCodeFrame from './LogBoxInspectorCodeFrame';
|
||||
import * as React from 'react';
|
||||
import ScrollView from '../../Components/ScrollView/ScrollView';
|
||||
import StyleSheet from '../../StyleSheet/StyleSheet';
|
||||
import Modal from '../../Modal/Modal';
|
||||
import View from '../../Components/View/View';
|
||||
import * as LogBoxData from '../Data/LogBoxData';
|
||||
import Keyboard from '../../Components/Keyboard/Keyboard';
|
||||
import LogBoxInspectorFooter from './LogBoxInspectorFooter';
|
||||
@@ -23,8 +23,7 @@ import LogBoxInspectorReactFrames from './LogBoxInspectorReactFrames';
|
||||
import LogBoxInspectorStackFrames from './LogBoxInspectorStackFrames';
|
||||
import LogBoxInspectorHeader from './LogBoxInspectorHeader';
|
||||
import * as LogBoxStyle from './LogBoxStyle';
|
||||
|
||||
import type LogBoxLog, {LogLevel} from '../Data/LogBoxLog';
|
||||
import LogBoxLog, {type LogLevel} from '../Data/LogBoxLog';
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
onDismiss: () => void,
|
||||
@@ -37,10 +36,12 @@ type Props = $ReadOnly<{|
|
||||
|
||||
function LogBoxInspector(props: Props): React.Node {
|
||||
const {logs, selectedIndex} = props;
|
||||
let log = logs[selectedIndex];
|
||||
|
||||
const log = logs[selectedIndex];
|
||||
React.useEffect(() => {
|
||||
LogBoxData.symbolicateLogNow(log);
|
||||
if (log) {
|
||||
LogBoxData.symbolicateLogNow(log);
|
||||
}
|
||||
}, [log]);
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -68,12 +69,7 @@ function LogBoxInspector(props: Props): React.Node {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
animationType="none"
|
||||
visible
|
||||
statusBarTranslucent
|
||||
supportedOrientations={['portrait']}
|
||||
presentationStyle="overFullScreen">
|
||||
<View style={styles.root}>
|
||||
<LogBoxInspectorHeader
|
||||
onSelectIndex={props.onChangeSelectedIndex}
|
||||
selectedIndex={selectedIndex}
|
||||
@@ -86,7 +82,7 @@ function LogBoxInspector(props: Props): React.Node {
|
||||
onMinimize={props.onMinimize}
|
||||
level={log.level}
|
||||
/>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,6 +139,10 @@ function LogBoxInspectorBody(props) {
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
flex: 1,
|
||||
backgroundColor: LogBoxStyle.getTextColor(),
|
||||
},
|
||||
scrollBody: {
|
||||
backgroundColor: LogBoxStyle.getBackgroundColor(0.9),
|
||||
flex: 1,
|
||||
|
||||
@@ -101,9 +101,11 @@ const styles = StyleSheet.create({
|
||||
syntaxErrorText: {
|
||||
textAlign: 'center',
|
||||
width: '100%',
|
||||
height: 48,
|
||||
fontSize: 14,
|
||||
paddingTop: 15,
|
||||
paddingBottom: 15,
|
||||
lineHeight: 20,
|
||||
paddingTop: 20,
|
||||
paddingBottom: 50,
|
||||
fontStyle: 'italic',
|
||||
color: LogBoxStyle.getTextColor(0.6),
|
||||
},
|
||||
|
||||
@@ -126,7 +126,7 @@ const headerStyles = StyleSheet.create({
|
||||
borderRadius: 3,
|
||||
},
|
||||
buttonImage: {
|
||||
tintColor: LogBoxStyle.getBackgroundColor(1),
|
||||
tintColor: LogBoxStyle.getTextColor(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -156,7 +156,7 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
},
|
||||
titleText: {
|
||||
color: LogBoxStyle.getBackgroundColor(1),
|
||||
color: LogBoxStyle.getTextColor(),
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
includeFontPadding: false,
|
||||
|
||||
@@ -18,12 +18,37 @@ import View from '../../Components/View/View';
|
||||
import LogBoxButton from './LogBoxButton';
|
||||
import * as LogBoxStyle from './LogBoxStyle';
|
||||
import LogBoxInspectorSection from './LogBoxInspectorSection';
|
||||
import openFileInEditor from '../../Core/Devtools/openFileInEditor';
|
||||
import type LogBoxLog from '../Data/LogBoxLog';
|
||||
|
||||
type Props = $ReadOnly<{|
|
||||
log: LogBoxLog,
|
||||
|}>;
|
||||
|
||||
const BEFORE_SLASH_RE = /^(.*)[\\/]/;
|
||||
|
||||
// Taken from React https://github.com/facebook/react/blob/206d61f72214e8ae5b935f0bf8628491cb7f0797/packages/react-devtools-shared/src/backend/describeComponentFrame.js#L27-L41
|
||||
function getPrettyFileName(path) {
|
||||
let fileName = path.replace(BEFORE_SLASH_RE, '');
|
||||
|
||||
// In DEV, include code for a common special case:
|
||||
// prefer "folder/index.js" instead of just "index.js".
|
||||
if (/^index\./.test(fileName)) {
|
||||
const match = path.match(BEFORE_SLASH_RE);
|
||||
if (match) {
|
||||
const pathBeforeSlash = match[1];
|
||||
if (pathBeforeSlash) {
|
||||
const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, '');
|
||||
// Note the below string contains a zero width space after the "/" character.
|
||||
// This is to prevent browsers like Chrome from formatting the file name as a link.
|
||||
// (Since this is a source link, it would not work to open the source file anyway.)
|
||||
fileName = folderName + '/' + fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
function LogBoxInspectorReactFrames(props: Props): React.Node {
|
||||
const [collapsed, setCollapsed] = React.useState(true);
|
||||
if (props.log.componentStack == null || props.log.componentStack.length < 1) {
|
||||
@@ -39,6 +64,10 @@ function LogBoxInspectorReactFrames(props: Props): React.Node {
|
||||
}
|
||||
|
||||
function getCollapseMessage() {
|
||||
if (props.log.componentStack.length <= 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
const count = props.log.componentStack.length - 3;
|
||||
if (collapsed) {
|
||||
return `See ${count} more components`;
|
||||
@@ -53,15 +82,34 @@ function LogBoxInspectorReactFrames(props: Props): React.Node {
|
||||
<View
|
||||
// Unfortunately we don't have a unique identifier for stack traces.
|
||||
key={index}
|
||||
style={componentStyles.frame}>
|
||||
<View style={componentStyles.component}>
|
||||
<Text style={componentStyles.frameName}>
|
||||
<Text style={componentStyles.bracket}>{'<'}</Text>
|
||||
{frame.component}
|
||||
<Text style={componentStyles.bracket}>{' />'}</Text>
|
||||
style={componentStyles.frameContainer}>
|
||||
<LogBoxButton
|
||||
backgroundColor={{
|
||||
default: 'transparent',
|
||||
pressed: LogBoxStyle.getBackgroundColor(1),
|
||||
}}
|
||||
onPress={
|
||||
// Older versions of DevTools do not provide full path.
|
||||
// This will not work on Windows, remove check once the
|
||||
// DevTools return the full file path.
|
||||
frame.fileName.startsWith('/')
|
||||
? () =>
|
||||
openFileInEditor(frame.fileName, frame.location?.row ?? 1)
|
||||
: null
|
||||
}
|
||||
style={componentStyles.frame}>
|
||||
<View style={componentStyles.component}>
|
||||
<Text style={componentStyles.frameName}>
|
||||
<Text style={componentStyles.bracket}>{'<'}</Text>
|
||||
{frame.content}
|
||||
<Text style={componentStyles.bracket}>{' />'}</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={componentStyles.frameLocation}>
|
||||
{getPrettyFileName(frame.fileName)}
|
||||
{frame.location ? `:${frame.location.row}` : ''}
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={componentStyles.frameLocation}>{frame.location}</Text>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
))}
|
||||
<View style={componentStyles.collapseContainer}>
|
||||
@@ -96,9 +144,15 @@ const componentStyles = StyleSheet.create({
|
||||
paddingVertical: 5,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
frameContainer: {
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: 15,
|
||||
},
|
||||
frame: {
|
||||
paddingHorizontal: 25,
|
||||
flex: 1,
|
||||
paddingVertical: 4,
|
||||
paddingHorizontal: 10,
|
||||
borderRadius: 5,
|
||||
},
|
||||
component: {
|
||||
flexDirection: 'row',
|
||||
|
||||
@@ -1,254 +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
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const LogBoxContainer = require('../LogBoxContainer').default;
|
||||
const LogBoxLog = require('../../Data/LogBoxLog').default;
|
||||
const render = require('../../../../jest/renderer');
|
||||
|
||||
describe('LogBoxContainer', () => {
|
||||
it('should render null with no logs', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxContainer
|
||||
onDismiss={() => {}}
|
||||
onDismissWarns={() => {}}
|
||||
onDismissErrors={() => {}}
|
||||
setSelectedLog={() => {}}
|
||||
selectedLogIndex={-1}
|
||||
logs={new Set()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render null with no selected log and disabled', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxContainer
|
||||
isDisabled
|
||||
onDismiss={() => {}}
|
||||
onDismissWarns={() => {}}
|
||||
onDismissErrors={() => {}}
|
||||
setSelectedLog={() => {}}
|
||||
selectedLogIndex={-1}
|
||||
logs={
|
||||
new Set([
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
])
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the latest warning notification', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxContainer
|
||||
onDismiss={() => {}}
|
||||
onDismissWarns={() => {}}
|
||||
onDismissErrors={() => {}}
|
||||
setSelectedLog={() => {}}
|
||||
selectedLogIndex={-1}
|
||||
logs={
|
||||
new Set([
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message (latest)',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message (latest)',
|
||||
componentStack: [],
|
||||
}),
|
||||
])
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the latest error notification', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxContainer
|
||||
onDismiss={() => {}}
|
||||
onDismissWarns={() => {}}
|
||||
onDismissErrors={() => {}}
|
||||
setSelectedLog={() => {}}
|
||||
selectedLogIndex={-1}
|
||||
logs={
|
||||
new Set([
|
||||
new LogBoxLog({
|
||||
level: 'error',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
new LogBoxLog({
|
||||
level: 'error',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message (latest)',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message (latest)',
|
||||
componentStack: [],
|
||||
}),
|
||||
])
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render both an error and warning notification', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxContainer
|
||||
onDismiss={() => {}}
|
||||
onDismissWarns={() => {}}
|
||||
onDismissErrors={() => {}}
|
||||
setSelectedLog={() => {}}
|
||||
selectedLogIndex={-1}
|
||||
logs={
|
||||
new Set([
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
new LogBoxLog({
|
||||
level: 'error',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message (latest)',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message (latest)',
|
||||
componentStack: [],
|
||||
}),
|
||||
])
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render selected fatal error even when disabled', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxContainer
|
||||
isDisabled
|
||||
onDismiss={() => {}}
|
||||
onDismissWarns={() => {}}
|
||||
onDismissErrors={() => {}}
|
||||
setSelectedLog={() => {}}
|
||||
selectedLogIndex={0}
|
||||
logs={
|
||||
new Set([
|
||||
new LogBoxLog({
|
||||
level: 'fatal',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Should be selected',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
])
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render selected syntax error even when disabled', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxContainer
|
||||
isDisabled
|
||||
onDismiss={() => {}}
|
||||
onDismissWarns={() => {}}
|
||||
onDismissErrors={() => {}}
|
||||
setSelectedLog={() => {}}
|
||||
selectedLogIndex={0}
|
||||
logs={
|
||||
new Set([
|
||||
new LogBoxLog({
|
||||
level: 'syntax',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Should be selected',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of syntax error message',
|
||||
componentStack: [],
|
||||
codeFrame: {
|
||||
fileName:
|
||||
'/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
|
||||
location: {row: 199, column: 0},
|
||||
content: ` 197 | });
|
||||
198 |
|
||||
> 199 | export default CrashReactApp;
|
||||
| ^
|
||||
200 |`,
|
||||
},
|
||||
}),
|
||||
])
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -40,7 +40,7 @@ describe('LogBoxInspectorReactFrames', () => {
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render componentStack frames', () => {
|
||||
it('should render componentStack frames without full path pressable', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxInspectorReactFrames
|
||||
log={
|
||||
@@ -55,8 +55,129 @@ describe('LogBoxInspectorReactFrames', () => {
|
||||
category: 'Some kind of message',
|
||||
componentStack: [
|
||||
{
|
||||
component: 'MyComponent',
|
||||
location: 'MyComponentFile.js:1',
|
||||
content: 'MyComponent',
|
||||
fileName: 'MyComponentFile.js',
|
||||
location: {
|
||||
row: 1,
|
||||
column: -1,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render componentStack frames with full path pressable', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxInspectorReactFrames
|
||||
log={
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [
|
||||
{
|
||||
content: 'MyComponent',
|
||||
fileName: '/path/to/MyComponentFile.js',
|
||||
location: {
|
||||
row: 1,
|
||||
column: -1,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render componentStack frames with parent folder of index.js', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxInspectorReactFrames
|
||||
log={
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [
|
||||
{
|
||||
content: 'MyComponent',
|
||||
fileName: '/path/to/index.js',
|
||||
location: {
|
||||
row: 1,
|
||||
column: -1,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render componentStack frames with more than 3 stacks', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxInspectorReactFrames
|
||||
log={
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [
|
||||
{
|
||||
content: 'MyComponent',
|
||||
fileName: '/path/to/index.js',
|
||||
location: {
|
||||
row: 1,
|
||||
column: -1,
|
||||
},
|
||||
},
|
||||
{
|
||||
content: 'MyComponent2',
|
||||
fileName: '/path/to/index2.js',
|
||||
location: {
|
||||
row: 1,
|
||||
column: -1,
|
||||
},
|
||||
},
|
||||
{
|
||||
content: 'MyComponent3',
|
||||
fileName: '/path/to/index3.js',
|
||||
location: {
|
||||
row: 1,
|
||||
column: -1,
|
||||
},
|
||||
},
|
||||
{
|
||||
content: 'MyComponent4',
|
||||
fileName: '/path/to/index4.js',
|
||||
location: {
|
||||
row: 1,
|
||||
column: -1,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const LogBoxLogNotification = require('../LogBoxLogNotification').default;
|
||||
const LogBoxNotification = require('../LogBoxNotification').default;
|
||||
const LogBoxLog = require('../../Data/LogBoxLog').default;
|
||||
const render = require('../../../../jest/renderer');
|
||||
|
||||
@@ -28,10 +28,10 @@ const log = new LogBoxLog({
|
||||
componentStack: [],
|
||||
});
|
||||
|
||||
describe('LogBoxLogNotification', () => {
|
||||
describe('LogBoxNotification', () => {
|
||||
it('should render log', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxLogNotification
|
||||
<LogBoxNotification
|
||||
log={log}
|
||||
totalLogCount={1}
|
||||
level="warn"
|
||||
@@ -1,17 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LogBoxContainer should render fatal with selectedIndex 2 1`] = `
|
||||
<Component
|
||||
animationType="none"
|
||||
hardwareAccelerated={false}
|
||||
presentationStyle="overFullScreen"
|
||||
statusBarTranslucent={true}
|
||||
supportedOrientations={
|
||||
Array [
|
||||
"portrait",
|
||||
]
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "rgba(255, 255, 255, 1)",
|
||||
"flex": 1,
|
||||
}
|
||||
}
|
||||
visible={true}
|
||||
>
|
||||
<LogBoxInspectorHeader
|
||||
level="fatal"
|
||||
@@ -47,23 +43,19 @@ exports[`LogBoxContainer should render fatal with selectedIndex 2 1`] = `
|
||||
onDismiss={[Function]}
|
||||
onMinimize={[Function]}
|
||||
/>
|
||||
</Component>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`LogBoxContainer should render null with no logs 1`] = `null`;
|
||||
|
||||
exports[`LogBoxContainer should render warning with selectedIndex 0 1`] = `
|
||||
<Component
|
||||
animationType="none"
|
||||
hardwareAccelerated={false}
|
||||
presentationStyle="overFullScreen"
|
||||
statusBarTranslucent={true}
|
||||
supportedOrientations={
|
||||
Array [
|
||||
"portrait",
|
||||
]
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "rgba(255, 255, 255, 1)",
|
||||
"flex": 1,
|
||||
}
|
||||
}
|
||||
visible={true}
|
||||
>
|
||||
<LogBoxInspectorHeader
|
||||
level="warn"
|
||||
@@ -99,5 +91,5 @@ exports[`LogBoxContainer should render warning with selectedIndex 0 1`] = `
|
||||
onDismiss={[Function]}
|
||||
onMinimize={[Function]}
|
||||
/>
|
||||
</Component>
|
||||
</View>
|
||||
`;
|
||||
|
||||
@@ -29,8 +29,10 @@ exports[`LogBoxInspectorFooter should render no buttons and a message for syntax
|
||||
"color": "rgba(255, 255, 255, 0.6)",
|
||||
"fontSize": 14,
|
||||
"fontStyle": "italic",
|
||||
"paddingBottom": 15,
|
||||
"paddingTop": 15,
|
||||
"height": 48,
|
||||
"lineHeight": 20,
|
||||
"paddingBottom": 50,
|
||||
"paddingTop": 20,
|
||||
"textAlign": "center",
|
||||
"width": "100%",
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ exports[`LogBoxInspectorHeader should render both buttons for two total 1`] = `
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(51, 51, 51, 1)",
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "600",
|
||||
"includeFontPadding": false,
|
||||
@@ -99,7 +99,7 @@ exports[`LogBoxInspectorHeader should render no buttons for one total 1`] = `
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(51, 51, 51, 1)",
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "600",
|
||||
"includeFontPadding": false,
|
||||
@@ -153,7 +153,7 @@ exports[`LogBoxInspectorHeader should render syntax error header 1`] = `
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(51, 51, 51, 1)",
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "600",
|
||||
"includeFontPadding": false,
|
||||
@@ -207,7 +207,7 @@ exports[`LogBoxInspectorHeader should render two buttons for three or more total
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(51, 51, 51, 1)",
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "600",
|
||||
"includeFontPadding": false,
|
||||
|
||||
+651
-40
@@ -1,81 +1,420 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LogBoxInspectorReactFrames should render componentStack frames 1`] = `
|
||||
exports[`LogBoxInspectorReactFrames should render componentStack frames with full path pressable 1`] = `
|
||||
<LogBoxInspectorSection
|
||||
heading="Component Stack"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"paddingHorizontal": 25,
|
||||
"paddingVertical": 4,
|
||||
"flexDirection": "row",
|
||||
"paddingHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingRight": 10,
|
||||
"borderRadius": 5,
|
||||
"flex": 1,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
"flexDirection": "row",
|
||||
"paddingRight": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
MyComponent
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
/>
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
MyComponent
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
/>
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 16,
|
||||
"paddingLeft": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
MyComponentFile.js
|
||||
:1
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"marginLeft": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 16,
|
||||
"paddingLeft": 10,
|
||||
"borderRadius": 5,
|
||||
}
|
||||
}
|
||||
>
|
||||
MyComponentFile.js:1
|
||||
</Text>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"lineHeight": 20,
|
||||
"marginTop": 0,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 5,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
</LogBoxInspectorSection>
|
||||
`;
|
||||
|
||||
exports[`LogBoxInspectorReactFrames should render componentStack frames with more than 3 stacks 1`] = `
|
||||
<LogBoxInspectorSection
|
||||
heading="Component Stack"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": 5,
|
||||
"flex": 1,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingRight": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
MyComponent
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
/>
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 16,
|
||||
"paddingLeft": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
to/index.js
|
||||
:1
|
||||
</Text>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": 5,
|
||||
"flex": 1,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingRight": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
MyComponent2
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
/>
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 16,
|
||||
"paddingLeft": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
index2.js
|
||||
:1
|
||||
</Text>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": 5,
|
||||
"flex": 1,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingRight": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
MyComponent3
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
/>
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 16,
|
||||
"paddingLeft": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
index3.js
|
||||
:1
|
||||
</Text>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
@@ -112,11 +451,283 @@ exports[`LogBoxInspectorReactFrames should render componentStack frames 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
See -2 more components
|
||||
See 1 more components
|
||||
</Text>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
</LogBoxInspectorSection>
|
||||
`;
|
||||
|
||||
exports[`LogBoxInspectorReactFrames should render componentStack frames with parent folder of index.js 1`] = `
|
||||
<LogBoxInspectorSection
|
||||
heading="Component Stack"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": 5,
|
||||
"flex": 1,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingRight": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
MyComponent
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
/>
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 16,
|
||||
"paddingLeft": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
to/index.js
|
||||
:1
|
||||
</Text>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"marginLeft": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": 5,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"lineHeight": 20,
|
||||
"marginTop": 0,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 5,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
</LogBoxInspectorSection>
|
||||
`;
|
||||
|
||||
exports[`LogBoxInspectorReactFrames should render componentStack frames without full path pressable 1`] = `
|
||||
<LogBoxInspectorSection
|
||||
heading="Component Stack"
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingHorizontal": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={null}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": 5,
|
||||
"flex": 1,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 4,
|
||||
}
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"paddingRight": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 1)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
MyComponent
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.4)",
|
||||
"fontFamily": "Menlo",
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
/>
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"includeFontPadding": false,
|
||||
"lineHeight": 16,
|
||||
"paddingLeft": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
MyComponentFile.js
|
||||
:1
|
||||
</Text>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"flexDirection": "row",
|
||||
"marginLeft": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxButton
|
||||
backgroundColor={
|
||||
Object {
|
||||
"default": "transparent",
|
||||
"pressed": "rgba(51, 51, 51, 1)",
|
||||
}
|
||||
}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": 5,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "rgba(255, 255, 255, 0.7)",
|
||||
"fontSize": 12,
|
||||
"fontWeight": "300",
|
||||
"lineHeight": 20,
|
||||
"marginTop": 0,
|
||||
"paddingHorizontal": 10,
|
||||
"paddingVertical": 5,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</LogBoxButton>
|
||||
</View>
|
||||
</LogBoxInspectorSection>
|
||||
`;
|
||||
|
||||
exports[`LogBoxInspectorReactFrames should render null for no componentStack frames 1`] = `null`;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LogBoxLogNotification should render log 1`] = `
|
||||
exports[`LogBoxNotification should render log 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* 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
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const {
|
||||
_LogBoxNotificationContainer: LogBoxNotificationContainer,
|
||||
} = require('../LogBoxNotificationContainer');
|
||||
const LogBoxLog = require('../Data/LogBoxLog').default;
|
||||
const render = require('../../../jest/renderer');
|
||||
|
||||
describe('LogBoxNotificationContainer', () => {
|
||||
it('should render null with no logs', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxNotificationContainer selectedLogIndex={-1} logs={[]} />,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render null with no selected log and disabled', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxNotificationContainer
|
||||
isDisabled
|
||||
selectedLogIndex={-1}
|
||||
logs={[
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the latest warning notification', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxNotificationContainer
|
||||
selectedLogIndex={-1}
|
||||
logs={[
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message (latest)',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message (latest)',
|
||||
componentStack: [],
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the latest error notification', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxNotificationContainer
|
||||
selectedLogIndex={-1}
|
||||
logs={[
|
||||
new LogBoxLog({
|
||||
level: 'error',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
new LogBoxLog({
|
||||
level: 'error',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message (latest)',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message (latest)',
|
||||
componentStack: [],
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render both an error and warning notification', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxNotificationContainer
|
||||
selectedLogIndex={-1}
|
||||
logs={[
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
new LogBoxLog({
|
||||
level: 'error',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message (latest)',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message (latest)',
|
||||
componentStack: [],
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render selected fatal error even when disabled', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxNotificationContainer
|
||||
isDisabled
|
||||
selectedLogIndex={0}
|
||||
logs={[
|
||||
new LogBoxLog({
|
||||
level: 'fatal',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Should be selected',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render selected syntax error even when disabled', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxNotificationContainer
|
||||
isDisabled
|
||||
selectedLogIndex={0}
|
||||
logs={[
|
||||
new LogBoxLog({
|
||||
level: 'syntax',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Should be selected',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of syntax error message',
|
||||
componentStack: [],
|
||||
codeFrame: {
|
||||
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
|
||||
location: {row: 199, column: 0},
|
||||
content: ` 197 | });
|
||||
198 |
|
||||
> 199 | export default CrashReactApp;
|
||||
| ^
|
||||
200 |`,
|
||||
},
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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
|
||||
* @flow strict-local
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const {
|
||||
_LogBoxInspectorContainer: LogBoxInspectorContainer,
|
||||
} = require('../LogBoxInspectorContainer');
|
||||
const LogBoxLog = require('../Data/LogBoxLog').default;
|
||||
const render = require('../../../jest/renderer');
|
||||
|
||||
describe('LogBoxNotificationContainer', () => {
|
||||
it('should render inspector with logs, even when disabled', () => {
|
||||
const output = render.shallowRender(
|
||||
<LogBoxInspectorContainer
|
||||
isDisabled
|
||||
selectedLogIndex={-1}
|
||||
logs={[
|
||||
new LogBoxLog({
|
||||
level: 'warn',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message',
|
||||
componentStack: [],
|
||||
}),
|
||||
new LogBoxLog({
|
||||
level: 'error',
|
||||
isComponentError: false,
|
||||
message: {
|
||||
content: 'Some kind of message (latest)',
|
||||
substitutions: [],
|
||||
},
|
||||
stack: [],
|
||||
category: 'Some kind of message (latest)',
|
||||
componentStack: [],
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
+7
-100
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LogBoxContainer should render both an error and warning notification 1`] = `
|
||||
exports[`LogBoxNotificationContainer should render both an error and warning notification 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
@@ -86,108 +86,15 @@ exports[`LogBoxContainer should render both an error and warning notification 1`
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`LogBoxContainer should render null with no logs 1`] = `null`;
|
||||
exports[`LogBoxNotificationContainer should render null with no logs 1`] = `null`;
|
||||
|
||||
exports[`LogBoxContainer should render null with no selected log and disabled 1`] = `null`;
|
||||
exports[`LogBoxNotificationContainer should render null with no selected log and disabled 1`] = `null`;
|
||||
|
||||
exports[`LogBoxContainer should render selected fatal error even when disabled 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxInspector
|
||||
logs={
|
||||
Array [
|
||||
LogBoxLog {
|
||||
"category": "Some kind of message",
|
||||
"codeFrame": undefined,
|
||||
"componentStack": Array [],
|
||||
"count": 1,
|
||||
"isComponentError": false,
|
||||
"level": "fatal",
|
||||
"message": Object {
|
||||
"content": "Should be selected",
|
||||
"substitutions": Array [],
|
||||
},
|
||||
"stack": Array [],
|
||||
"symbolicated": Object {
|
||||
"error": null,
|
||||
"stack": null,
|
||||
"status": "NONE",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
onChangeSelectedIndex={[Function]}
|
||||
onDismiss={[Function]}
|
||||
onMinimize={[Function]}
|
||||
selectedIndex={0}
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
exports[`LogBoxNotificationContainer should render selected fatal error even when disabled 1`] = `null`;
|
||||
|
||||
exports[`LogBoxContainer should render selected syntax error even when disabled 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxInspector
|
||||
logs={
|
||||
Array [
|
||||
LogBoxLog {
|
||||
"category": "Some kind of syntax error message",
|
||||
"codeFrame": Object {
|
||||
"content": " 197 | });
|
||||
198 |
|
||||
> 199 | export default CrashReactApp;
|
||||
| ^
|
||||
200 |",
|
||||
"fileName": "/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js",
|
||||
"location": Object {
|
||||
"column": 0,
|
||||
"row": 199,
|
||||
},
|
||||
},
|
||||
"componentStack": Array [],
|
||||
"count": 1,
|
||||
"isComponentError": false,
|
||||
"level": "syntax",
|
||||
"message": Object {
|
||||
"content": "Should be selected",
|
||||
"substitutions": Array [],
|
||||
},
|
||||
"stack": Array [],
|
||||
"symbolicated": Object {
|
||||
"error": null,
|
||||
"stack": null,
|
||||
"status": "NONE",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
onChangeSelectedIndex={[Function]}
|
||||
onDismiss={[Function]}
|
||||
onMinimize={[Function]}
|
||||
selectedIndex={0}
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
exports[`LogBoxNotificationContainer should render selected syntax error even when disabled 1`] = `null`;
|
||||
|
||||
exports[`LogBoxContainer should render the latest error notification 1`] = `
|
||||
exports[`LogBoxNotificationContainer should render the latest error notification 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
@@ -237,7 +144,7 @@ exports[`LogBoxContainer should render the latest error notification 1`] = `
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`LogBoxContainer should render the latest warning notification 1`] = `
|
||||
exports[`LogBoxNotificationContainer should render the latest warning notification 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
@@ -0,0 +1,62 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LogBoxNotificationContainer should render inspector with logs, even when disabled 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"left": 0,
|
||||
"position": "absolute",
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<LogBoxInspector
|
||||
logs={
|
||||
Array [
|
||||
LogBoxLog {
|
||||
"category": "Some kind of message",
|
||||
"codeFrame": undefined,
|
||||
"componentStack": Array [],
|
||||
"count": 1,
|
||||
"isComponentError": false,
|
||||
"level": "warn",
|
||||
"message": Object {
|
||||
"content": "Some kind of message",
|
||||
"substitutions": Array [],
|
||||
},
|
||||
"stack": Array [],
|
||||
"symbolicated": Object {
|
||||
"error": null,
|
||||
"stack": null,
|
||||
"status": "NONE",
|
||||
},
|
||||
},
|
||||
LogBoxLog {
|
||||
"category": "Some kind of message (latest)",
|
||||
"codeFrame": undefined,
|
||||
"componentStack": Array [],
|
||||
"count": 1,
|
||||
"isComponentError": false,
|
||||
"level": "error",
|
||||
"message": Object {
|
||||
"content": "Some kind of message (latest)",
|
||||
"substitutions": Array [],
|
||||
},
|
||||
"stack": Array [],
|
||||
"symbolicated": Object {
|
||||
"error": null,
|
||||
"stack": null,
|
||||
"status": "NONE",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
onChangeSelectedIndex={[Function]}
|
||||
onDismiss={[Function]}
|
||||
onMinimize={[Function]}
|
||||
selectedIndex={-1}
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
@@ -229,7 +229,7 @@ class Modal extends React.Component<Props> {
|
||||
}
|
||||
|
||||
const innerChildren = __DEV__ ? (
|
||||
<AppContainer rootTag={this.context.rootTag} internal_excludeLogBox>
|
||||
<AppContainer rootTag={this.context.rootTag}>
|
||||
{this.props.children}
|
||||
</AppContainer>
|
||||
) : (
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+show: () => void;
|
||||
+hide: () => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('LogBox'): ?Spec);
|
||||
@@ -94,16 +94,14 @@ class AppContainer extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
let logBox = null;
|
||||
if (__DEV__ && !this.props.internal_excludeLogBox) {
|
||||
if (!global.__RCTProfileIsProfiling) {
|
||||
if (global.__reactExperimentalLogBox) {
|
||||
const LogBox = require('../LogBox/LogBox');
|
||||
logBox = <LogBox />;
|
||||
} else {
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
logBox = <YellowBox />;
|
||||
}
|
||||
let yellowBox = null;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
!global.__RCTProfileIsProfiling &&
|
||||
!this.props.internal_excludeLogBox
|
||||
) {
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
yellowBox = <YellowBox />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +135,7 @@ class AppContainer extends React.Component<Props, State> {
|
||||
<View style={styles.appContainer} pointerEvents="box-none">
|
||||
{!this.state.hasError && innerView}
|
||||
{this.state.inspector}
|
||||
{logBox}
|
||||
{yellowBox}
|
||||
</View>
|
||||
</RootTagContext.Provider>
|
||||
);
|
||||
@@ -152,22 +150,8 @@ const styles = StyleSheet.create({
|
||||
|
||||
if (__DEV__) {
|
||||
if (!global.__RCTProfileIsProfiling) {
|
||||
if (global.__reactExperimentalLogBox) {
|
||||
const LogBox = require('../LogBox/LogBox');
|
||||
LogBox.install();
|
||||
|
||||
// TODO: (rickhanlonii) T57484314 Temporary hack to fix LogBox experiment but we need to
|
||||
// either decide to provide an error boundary by default or move this to a separate root.
|
||||
AppContainer.getDerivedStateFromError = function getDerivedStateFromError(
|
||||
error,
|
||||
state,
|
||||
) {
|
||||
return {...state, hasError: true};
|
||||
};
|
||||
} else {
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
YellowBox.install();
|
||||
}
|
||||
const YellowBox = require('../YellowBox/YellowBox');
|
||||
YellowBox.install();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@ const AppRegistry = {
|
||||
appParameters.fabric,
|
||||
showArchitectureIndicator,
|
||||
scopedPerformanceLogger,
|
||||
appKey === 'LogBox',
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -180,13 +181,15 @@ const AppRegistry = {
|
||||
* See http://facebook.github.io/react-native/docs/appregistry.html#runapplication
|
||||
*/
|
||||
runApplication(appKey: string, appParameters: any): void {
|
||||
const msg =
|
||||
'Running "' + appKey + '" with ' + JSON.stringify(appParameters);
|
||||
infoLog(msg);
|
||||
BugReporting.addSource(
|
||||
'AppRegistry.runApplication' + runCount++,
|
||||
() => msg,
|
||||
);
|
||||
if (appKey !== 'LogBox') {
|
||||
const msg =
|
||||
'Running "' + appKey + '" with ' + JSON.stringify(appParameters);
|
||||
infoLog(msg);
|
||||
BugReporting.addSource(
|
||||
'AppRegistry.runApplication' + runCount++,
|
||||
() => msg,
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
runnables[appKey] && runnables[appKey].run,
|
||||
`"${appKey}" has not been registered. This can happen if:\n` +
|
||||
@@ -292,4 +295,17 @@ const AppRegistry = {
|
||||
|
||||
BatchedBridge.registerCallableModule('AppRegistry', AppRegistry);
|
||||
|
||||
if (__DEV__) {
|
||||
const LogBoxInspector = require('../LogBox/LogBoxInspectorContainer').default;
|
||||
AppRegistry.registerComponent('LogBox', () => LogBoxInspector);
|
||||
} else {
|
||||
AppRegistry.registerComponent(
|
||||
'LogBox',
|
||||
() =>
|
||||
function NoOp() {
|
||||
return null;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = AppRegistry;
|
||||
|
||||
@@ -29,6 +29,7 @@ function renderApplication<Props: Object>(
|
||||
fabric?: boolean,
|
||||
showArchitectureIndicator?: boolean,
|
||||
scopedPerformanceLogger?: IPerformanceLogger,
|
||||
isLogBox?: boolean,
|
||||
) {
|
||||
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
|
||||
|
||||
@@ -39,7 +40,8 @@ function renderApplication<Props: Object>(
|
||||
rootTag={rootTag}
|
||||
fabric={fabric}
|
||||
showArchitectureIndicator={showArchitectureIndicator}
|
||||
WrapperComponent={WrapperComponent}>
|
||||
WrapperComponent={WrapperComponent}
|
||||
internal_excludeLogBox={isLogBox}>
|
||||
<RootComponent {...initialProps} rootTag={rootTag} />
|
||||
</AppContainer>
|
||||
</PerformanceLoggerContext.Provider>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
const YellowBoxWarning = require('./YellowBoxWarning');
|
||||
|
||||
import type {Category} from './YellowBoxCategory';
|
||||
|
||||
import type {Category, Message} from './YellowBoxCategory';
|
||||
import type {Stack} from './YellowBoxSymbolication';
|
||||
export type Registry = Map<Category, $ReadOnlyArray<YellowBoxWarning>>;
|
||||
|
||||
export type Observer = (registry: Registry) => void;
|
||||
@@ -32,25 +32,13 @@ let disabled = false;
|
||||
let projection = new Map();
|
||||
let updateTimeout = null;
|
||||
|
||||
function isWarningIgnored(warning: YellowBoxWarning): boolean {
|
||||
for (const pattern of ignorePatterns) {
|
||||
if (pattern instanceof RegExp && pattern.test(warning.message.content)) {
|
||||
return true;
|
||||
} else if (
|
||||
typeof pattern === 'string' &&
|
||||
warning.message.content.includes(pattern)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleUpdate(): void {
|
||||
projection = new Map();
|
||||
if (!disabled) {
|
||||
for (const [category, warnings] of registry) {
|
||||
const filtered = warnings.filter(warning => !isWarningIgnored(warning));
|
||||
const filtered = warnings.filter(
|
||||
warning => !YellowBoxRegistry.isWarningIgnored(warning.message),
|
||||
);
|
||||
if (filtered.length > 0) {
|
||||
projection.set(category, filtered);
|
||||
}
|
||||
@@ -67,18 +55,28 @@ function handleUpdate(): void {
|
||||
}
|
||||
|
||||
const YellowBoxRegistry = {
|
||||
add({
|
||||
args,
|
||||
}: $ReadOnly<{|
|
||||
args: $ReadOnlyArray<mixed>,
|
||||
|}>): void {
|
||||
if (typeof args[0] === 'string' && args[0].startsWith('(ADVICE)')) {
|
||||
return;
|
||||
isWarningIgnored(message: Message): boolean {
|
||||
for (const pattern of ignorePatterns) {
|
||||
if (pattern instanceof RegExp && pattern.test(message.content)) {
|
||||
return true;
|
||||
} else if (
|
||||
typeof pattern === 'string' &&
|
||||
message.content.includes(pattern)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const {category, message, stack} = YellowBoxWarning.parse({
|
||||
args,
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
add({
|
||||
category,
|
||||
message,
|
||||
stack,
|
||||
}: $ReadOnly<{|
|
||||
category: Category,
|
||||
message: Message,
|
||||
stack: Stack,
|
||||
|}>): void {
|
||||
let warnings = registry.get(category);
|
||||
if (warnings == null) {
|
||||
warnings = [];
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const YellowBoxWarning = require('../YellowBoxWarning');
|
||||
const YellowBoxCategory = require('../YellowBoxCategory');
|
||||
const YellowBoxRegistry = require('../YellowBoxRegistry');
|
||||
|
||||
@@ -34,7 +35,7 @@ describe('YellowBoxRegistry', () => {
|
||||
});
|
||||
|
||||
it('adds and deletes warnings', () => {
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
const {category: categoryA} = YellowBoxCategory.parse(['A']);
|
||||
|
||||
expect(registry().size).toBe(1);
|
||||
@@ -46,9 +47,9 @@ describe('YellowBoxRegistry', () => {
|
||||
});
|
||||
|
||||
it('clears all warnings', () => {
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add({args: ['B']});
|
||||
YellowBoxRegistry.add({args: ['C']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C']}));
|
||||
|
||||
expect(registry().size).toBe(3);
|
||||
|
||||
@@ -57,9 +58,9 @@ describe('YellowBoxRegistry', () => {
|
||||
});
|
||||
|
||||
it('sorts warnings in chronological order', () => {
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add({args: ['B']});
|
||||
YellowBoxRegistry.add({args: ['C']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C']}));
|
||||
|
||||
const {category: categoryA} = YellowBoxCategory.parse(['A']);
|
||||
const {category: categoryB} = YellowBoxCategory.parse(['B']);
|
||||
@@ -71,7 +72,7 @@ describe('YellowBoxRegistry', () => {
|
||||
categoryC,
|
||||
]);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
|
||||
// Expect `A` to be hoisted to the end of the registry.
|
||||
expect(Array.from(registry().keys())).toEqual([
|
||||
@@ -82,9 +83,9 @@ describe('YellowBoxRegistry', () => {
|
||||
});
|
||||
|
||||
it('ignores warnings matching patterns', () => {
|
||||
YellowBoxRegistry.add({args: ['A!']});
|
||||
YellowBoxRegistry.add({args: ['B?']});
|
||||
YellowBoxRegistry.add({args: ['C!']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A!']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B?']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C!']}));
|
||||
expect(registry().size).toBe(3);
|
||||
|
||||
YellowBoxRegistry.addIgnorePatterns(['!']);
|
||||
@@ -95,9 +96,9 @@ describe('YellowBoxRegistry', () => {
|
||||
});
|
||||
|
||||
it('ignores warnings matching regexs or pattern', () => {
|
||||
YellowBoxRegistry.add({args: ['There are 4 dogs']});
|
||||
YellowBoxRegistry.add({args: ['There are 3 cats']});
|
||||
YellowBoxRegistry.add({args: ['There are H cats']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['There are 4 dogs']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['There are 3 cats']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['There are H cats']}));
|
||||
expect(registry().size).toBe(3);
|
||||
|
||||
YellowBoxRegistry.addIgnorePatterns(['dogs']);
|
||||
@@ -111,9 +112,9 @@ describe('YellowBoxRegistry', () => {
|
||||
});
|
||||
|
||||
it('ignores all warnings when disabled', () => {
|
||||
YellowBoxRegistry.add({args: ['A!']});
|
||||
YellowBoxRegistry.add({args: ['B?']});
|
||||
YellowBoxRegistry.add({args: ['C!']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A!']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B?']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C!']}));
|
||||
expect(registry().size).toBe(3);
|
||||
|
||||
YellowBoxRegistry.setDisabled(true);
|
||||
@@ -124,57 +125,54 @@ describe('YellowBoxRegistry', () => {
|
||||
});
|
||||
|
||||
it('groups warnings by simple categories', () => {
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
expect(registry().size).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
expect(registry().size).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['B']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
|
||||
expect(registry().size).toBe(2);
|
||||
});
|
||||
|
||||
it('groups warnings by format string categories', () => {
|
||||
YellowBoxRegistry.add({args: ['%s', 'A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'A']}));
|
||||
expect(registry().size).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['%s', 'B']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'B']}));
|
||||
expect(registry().size).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
expect(registry().size).toBe(2);
|
||||
|
||||
YellowBoxRegistry.add({args: ['B']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
|
||||
expect(registry().size).toBe(3);
|
||||
});
|
||||
|
||||
it('groups warnings with consideration for arguments', () => {
|
||||
YellowBoxRegistry.add({args: ['A', 'B']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A', 'B']}));
|
||||
expect(registry().size).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A', 'B']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A', 'B']}));
|
||||
expect(registry().size).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A', 'C']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A', 'C']}));
|
||||
expect(registry().size).toBe(2);
|
||||
|
||||
YellowBoxRegistry.add({args: ['%s', 'A', 'A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'A', 'A']}));
|
||||
expect(registry().size).toBe(3);
|
||||
|
||||
YellowBoxRegistry.add({args: ['%s', 'B', 'A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'B', 'A']}));
|
||||
expect(registry().size).toBe(3);
|
||||
|
||||
YellowBoxRegistry.add({args: ['%s', 'B', 'B']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'B', 'B']}));
|
||||
expect(registry().size).toBe(4);
|
||||
});
|
||||
|
||||
it('ignores warnings starting with "(ADVICE)"', () => {
|
||||
YellowBoxRegistry.add({args: ['(ADVICE) ...']});
|
||||
expect(registry().size).toBe(0);
|
||||
});
|
||||
|
||||
it('does not ignore warnings formatted to start with "(ADVICE)"', () => {
|
||||
YellowBoxRegistry.add({args: ['%s ...', '(ADVICE)']});
|
||||
YellowBoxRegistry.add(
|
||||
YellowBoxWarning.parse({args: ['%s ...', '(ADVICE)']}),
|
||||
);
|
||||
expect(registry().size).toBe(1);
|
||||
});
|
||||
|
||||
@@ -189,8 +187,8 @@ describe('YellowBoxRegistry', () => {
|
||||
const {observer} = observe();
|
||||
expect(observer.mock.calls.length).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add({args: ['B']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
|
||||
jest.runAllImmediates();
|
||||
expect(observer.mock.calls.length).toBe(2);
|
||||
});
|
||||
@@ -207,7 +205,7 @@ describe('YellowBoxRegistry', () => {
|
||||
const {observer} = observe();
|
||||
expect(observer.mock.calls.length).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
jest.runAllImmediates();
|
||||
expect(observer.mock.calls.length).toBe(2);
|
||||
|
||||
@@ -226,7 +224,7 @@ describe('YellowBoxRegistry', () => {
|
||||
const {observer} = observe();
|
||||
expect(observer.mock.calls.length).toBe(1);
|
||||
|
||||
YellowBoxRegistry.add({args: ['A']});
|
||||
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
|
||||
jest.runAllImmediates();
|
||||
expect(observer.mock.calls.length).toBe(2);
|
||||
|
||||
|
||||
@@ -12,13 +12,12 @@
|
||||
|
||||
const React = require('react');
|
||||
|
||||
import type {Category} from './Data/YellowBoxCategory';
|
||||
import type {
|
||||
Registry,
|
||||
Subscription,
|
||||
IgnorePattern,
|
||||
} from './Data/YellowBoxRegistry';
|
||||
import type {Registry, IgnorePattern} from './Data/YellowBoxRegistry';
|
||||
import YellowBoxWarning from './Data/YellowBoxWarning';
|
||||
|
||||
import * as LogBoxData from '../LogBox/Data/LogBoxData';
|
||||
import NativeLogBox from '../NativeModules/specs/NativeLogBox';
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
type State = {|
|
||||
registry: ?Registry,
|
||||
@@ -47,14 +46,19 @@ let YellowBox;
|
||||
if (__DEV__) {
|
||||
const Platform = require('../Utilities/Platform');
|
||||
const RCTLog = require('../Utilities/RCTLog');
|
||||
const YellowBoxList = require('./UI/YellowBoxList');
|
||||
const YellowBoxContainer = require('./YellowBoxContainer').default;
|
||||
const LogBox = require('../LogBox/LogBox');
|
||||
const YellowBoxRegistry = require('./Data/YellowBoxRegistry');
|
||||
const LogBoxNotificationContainer = require('../LogBox/LogBoxNotificationContainer')
|
||||
.default;
|
||||
|
||||
// YellowBox needs to insert itself early,
|
||||
// in order to access the component stacks appended by React DevTools.
|
||||
const {error, warn} = console;
|
||||
let errorImpl = error;
|
||||
let warnImpl = warn;
|
||||
let _isLogBoxEnabled = false;
|
||||
let _isInstalled = false;
|
||||
(console: any).error = function(...args) {
|
||||
errorImpl(...args);
|
||||
};
|
||||
@@ -70,16 +74,17 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
static install(): void {
|
||||
if (_isLogBoxEnabled) {
|
||||
LogBox.install();
|
||||
return;
|
||||
}
|
||||
_isInstalled = true;
|
||||
|
||||
errorImpl = function(...args) {
|
||||
error.call(console, ...args);
|
||||
// Show YellowBox for the `warning` module.
|
||||
if (typeof args[0] === 'string' && args[0].startsWith('Warning: ')) {
|
||||
registerWarning(...args);
|
||||
}
|
||||
registerError(...args);
|
||||
};
|
||||
|
||||
warnImpl = function(...args) {
|
||||
warn.call(console, ...args);
|
||||
registerWarning(...args);
|
||||
};
|
||||
|
||||
@@ -102,51 +107,95 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
static uninstall(): void {
|
||||
if (_isLogBoxEnabled) {
|
||||
LogBox.uninstall();
|
||||
return;
|
||||
}
|
||||
_isInstalled = false;
|
||||
errorImpl = error;
|
||||
warnImpl = warn;
|
||||
delete (console: any).disableYellowBox;
|
||||
}
|
||||
|
||||
_subscription: ?Subscription;
|
||||
static __unstable_enableLogBox(): void {
|
||||
if (NativeLogBox == null) {
|
||||
// The native module is required to enable LogBox.
|
||||
return;
|
||||
}
|
||||
|
||||
state = {
|
||||
registry: null,
|
||||
};
|
||||
if (_isInstalled) {
|
||||
throw new Error(
|
||||
'LogBox must be enabled before AppContainer is required so that it can properly wrap the console methods.\n\nPlease enable LogBox earlier in your app.\n\n',
|
||||
);
|
||||
}
|
||||
_isLogBoxEnabled = true;
|
||||
|
||||
// TODO: Temporary hack to prevent cycles with the ExceptionManager.
|
||||
global.__unstable_isLogBoxEnabled = true;
|
||||
}
|
||||
|
||||
static __unstable_isLogBoxEnabled(): boolean {
|
||||
return !!_isLogBoxEnabled;
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
|
||||
return this.state.registry == null ? null : (
|
||||
<YellowBoxList
|
||||
onDismiss={this._handleDismiss}
|
||||
onDismissAll={this._handleDismissAll}
|
||||
registry={this.state.registry}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this._subscription = YellowBoxRegistry.observe(registry => {
|
||||
this.setState({registry});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
if (this._subscription != null) {
|
||||
this._subscription.unsubscribe();
|
||||
if (_isLogBoxEnabled) {
|
||||
return <LogBoxNotificationContainer />;
|
||||
}
|
||||
}
|
||||
|
||||
_handleDismiss = (category: Category): void => {
|
||||
YellowBoxRegistry.delete(category);
|
||||
};
|
||||
|
||||
_handleDismissAll(): void {
|
||||
YellowBoxRegistry.clear();
|
||||
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
|
||||
return <YellowBoxContainer />;
|
||||
}
|
||||
};
|
||||
|
||||
const registerWarning = (...args): void => {
|
||||
YellowBoxRegistry.add({args});
|
||||
if (typeof args[0] === 'string' && args[0].startsWith('(ADVICE)')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {category, message, stack} = YellowBoxWarning.parse({
|
||||
args,
|
||||
});
|
||||
|
||||
if (!YellowBoxRegistry.isWarningIgnored(message)) {
|
||||
YellowBoxRegistry.add({category, message, stack});
|
||||
warn.call(console, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
const registerError = (...args): void => {
|
||||
// Only show YellowBox for the `warning` module, otherwise pass through and skip.
|
||||
if (typeof args[0] !== 'string' || !args[0].startsWith('Warning: ')) {
|
||||
error.call(console, ...args);
|
||||
return;
|
||||
}
|
||||
|
||||
const format = args[0].replace('Warning: ', '');
|
||||
const filterResult = LogBoxData.checkWarningFilter(format);
|
||||
if (filterResult.suppressCompletely) {
|
||||
return;
|
||||
}
|
||||
|
||||
args[0] = filterResult.finalFormat;
|
||||
const {category, message, stack} = YellowBoxWarning.parse({
|
||||
args,
|
||||
});
|
||||
|
||||
if (YellowBoxRegistry.isWarningIgnored(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filterResult.forceDialogImmediately === true) {
|
||||
// This will pop a redbox. Do not downgrade. These are real bugs with same severity as throws.
|
||||
error.call(console, message.content);
|
||||
} else {
|
||||
// Unfortunately, we need to add the Warning: prefix back so we don't show a redbox later.
|
||||
args[0] = `Warning: ${filterResult.finalFormat}`;
|
||||
|
||||
// Note: YellowBox has no concept of "soft errors" so we're showing YellowBox for those.
|
||||
YellowBoxRegistry.add({category, message, stack});
|
||||
error.call(console, ...args);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
YellowBox = class extends React.Component<Props, State> {
|
||||
@@ -162,6 +211,13 @@ if (__DEV__) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
static __unstable_enableLogBox(): void {
|
||||
// Do nothing.
|
||||
}
|
||||
static __unstable_isLogBoxEnabled(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
return null;
|
||||
}
|
||||
@@ -172,5 +228,7 @@ module.exports = (YellowBox: Class<React.Component<Props, State>> & {
|
||||
ignoreWarnings($ReadOnlyArray<IgnorePattern>): void,
|
||||
install(): void,
|
||||
uninstall(): void,
|
||||
__unstable_enableLogBox(): void,
|
||||
__unstable_isLogBoxEnabled(): boolean,
|
||||
...
|
||||
});
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
import type {Category} from './Data/YellowBoxCategory';
|
||||
import type {Registry, Subscription} from './Data/YellowBoxRegistry';
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
type State = $ReadOnly<{|
|
||||
registry: ?Registry,
|
||||
|}>;
|
||||
|
||||
const YellowBoxList = require('./UI/YellowBoxList');
|
||||
const YellowBoxRegistry = require('./Data/YellowBoxRegistry');
|
||||
|
||||
class YellowBoxContainer extends React.Component<Props, State> {
|
||||
_subscription: ?Subscription;
|
||||
|
||||
state: State = {
|
||||
registry: null,
|
||||
};
|
||||
|
||||
render(): React.Node {
|
||||
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
|
||||
return this.state.registry == null ? null : (
|
||||
<YellowBoxList
|
||||
onDismiss={this._handleDismiss}
|
||||
onDismissAll={this._handleDismissAll}
|
||||
registry={this.state.registry}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this._subscription = YellowBoxRegistry.observe(registry => {
|
||||
this.setState({registry});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
if (this._subscription != null) {
|
||||
this._subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
_handleDismiss = (category: Category): void => {
|
||||
YellowBoxRegistry.delete(category);
|
||||
};
|
||||
|
||||
_handleDismissAll(): void {
|
||||
YellowBoxRegistry.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export default YellowBoxContainer;
|
||||
@@ -11,20 +11,62 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const YellowBox = require('../YellowBox');
|
||||
import * as React from 'react';
|
||||
const YellowBoxRegistry = require('../Data/YellowBoxRegistry');
|
||||
const LogBoxData = require('../../LogBox/Data/LogBoxData');
|
||||
const render = require('../../../jest/renderer');
|
||||
jest.mock('../../NativeModules/specs/NativeLogBox', () => true);
|
||||
jest.mock('../../LogBox/LogBoxNotificationContainer', () => ({
|
||||
__esModule: true,
|
||||
default: 'LogBoxNotificationContainer',
|
||||
}));
|
||||
|
||||
type Overrides = {|
|
||||
forceDialogImmediately?: boolean,
|
||||
suppressDialog_LEGACY?: boolean,
|
||||
suppressCompletely?: boolean,
|
||||
|};
|
||||
|
||||
const setFilter = (options?: Overrides) => {
|
||||
LogBoxData.setWarningFilter(format => ({
|
||||
finalFormat: format,
|
||||
forceDialogImmediately: false,
|
||||
suppressDialog_LEGACY: false,
|
||||
suppressCompletely: false,
|
||||
monitorEvent: null,
|
||||
monitorListVersion: 0,
|
||||
monitorSampleRate: 0,
|
||||
...options,
|
||||
}));
|
||||
};
|
||||
|
||||
const install = () => {
|
||||
const YellowBox = require('../YellowBox');
|
||||
YellowBox.install();
|
||||
};
|
||||
|
||||
const uninstall = () => {
|
||||
const YellowBox = require('../YellowBox');
|
||||
YellowBox.uninstall();
|
||||
};
|
||||
|
||||
describe('YellowBox', () => {
|
||||
const {error, warn} = console;
|
||||
const mockError = jest.fn();
|
||||
const mockWarn = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
(console: any).error = jest.fn();
|
||||
(console: any).warn = jest.fn();
|
||||
|
||||
mockError.mockClear();
|
||||
mockWarn.mockClear();
|
||||
|
||||
(console: any).error = mockError;
|
||||
(console: any).warn = mockWarn;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
YellowBox.uninstall();
|
||||
uninstall();
|
||||
(console: any).error = error;
|
||||
(console: any).warn = warn;
|
||||
});
|
||||
@@ -32,7 +74,7 @@ describe('YellowBox', () => {
|
||||
it('can set `disableYellowBox` after installing', () => {
|
||||
expect((console: any).disableYellowBox).toBe(undefined);
|
||||
|
||||
YellowBox.install();
|
||||
install();
|
||||
|
||||
expect((console: any).disableYellowBox).toBe(false);
|
||||
expect(YellowBoxRegistry.isDisabled()).toBe(false);
|
||||
@@ -47,7 +89,7 @@ describe('YellowBox', () => {
|
||||
expect((console: any).disableYellowBox).toBe(undefined);
|
||||
|
||||
(console: any).disableYellowBox = true;
|
||||
YellowBox.install();
|
||||
install();
|
||||
|
||||
expect((console: any).disableYellowBox).toBe(true);
|
||||
expect(YellowBoxRegistry.isDisabled()).toBe(true);
|
||||
@@ -56,22 +98,173 @@ describe('YellowBox', () => {
|
||||
it('registers warnings', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
YellowBox.install();
|
||||
install();
|
||||
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
(console: any).warn('...');
|
||||
expect(YellowBoxRegistry.add).toBeCalled();
|
||||
expect(mockWarn).toBeCalledTimes(1);
|
||||
expect(mockWarn).toBeCalledWith('...');
|
||||
});
|
||||
|
||||
it('registers errors beginning with "Warning: "', () => {
|
||||
it('registers errors', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
YellowBox.install();
|
||||
install();
|
||||
|
||||
(console: any).error('...');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(mockError).toBeCalledTimes(1);
|
||||
expect(mockError).toBeCalledWith('...');
|
||||
});
|
||||
|
||||
it('skips ADVICE warnings', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
install();
|
||||
|
||||
(console: any).warn('(ADVICE) Ignore me');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('skips ignored warnings', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
install();
|
||||
|
||||
(YellowBoxRegistry: any).isWarningIgnored.mockReturnValue(true);
|
||||
(console: any).warn('Ignore me');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('registers Warning module errors with default options to YellowBox', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
setFilter();
|
||||
install();
|
||||
|
||||
(console: any).error('Warning: ...');
|
||||
expect(YellowBoxRegistry.add).toBeCalled();
|
||||
expect(mockError).toBeCalled();
|
||||
expect(mockError).toBeCalledTimes(1);
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('skips Warning module errors with forceDialogImmediately', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
setFilter({
|
||||
suppressCompletely: true,
|
||||
});
|
||||
install();
|
||||
|
||||
(console: any).error('Warning: ...');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(mockError).not.toBeCalled();
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('registers Warning errors with forceDialogImmediately as console.error (with interpolation)', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
setFilter({
|
||||
forceDialogImmediately: true,
|
||||
});
|
||||
|
||||
install();
|
||||
|
||||
(console: any).error('Warning: %s', 'Something');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
expect(mockError).toBeCalledTimes(1);
|
||||
|
||||
// We expect this to be the interpolated value because we don't do interpolation downstream.
|
||||
// We also strip the "Warning" prefix, otherwise the redbox would be skipped downstream.
|
||||
expect(mockError).toBeCalledWith('Something');
|
||||
});
|
||||
|
||||
it('registers Warning errors with suppressDialog_LEGACY to YellowBox', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
setFilter({
|
||||
suppressDialog_LEGACY: true,
|
||||
});
|
||||
|
||||
install();
|
||||
|
||||
(console: any).error('Warning: Something');
|
||||
expect(YellowBoxRegistry.add).toBeCalledTimes(1);
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
expect(mockError).toBeCalledTimes(1);
|
||||
|
||||
// We cannot strip the "Warning" prefix or it would pop a redbox.
|
||||
expect(mockError).toBeCalledWith('Warning: Something');
|
||||
});
|
||||
|
||||
it('skips Warning errors sent to YellowBox but ignored by patterns', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
|
||||
setFilter({
|
||||
suppressDialog_LEGACY: true,
|
||||
});
|
||||
|
||||
install();
|
||||
(YellowBoxRegistry: any).isWarningIgnored.mockReturnValue(true);
|
||||
|
||||
(console: any).error('Warning: ...');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(mockWarn).not.toBeCalled();
|
||||
expect(mockError).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('if LogBox is enabled, installs and uninstalls LogBox', () => {
|
||||
jest.mock('../../LogBox/Data/LogBoxData');
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
const YellowBox = require('../YellowBox');
|
||||
YellowBox.__unstable_enableLogBox();
|
||||
install();
|
||||
|
||||
(console: any).warn('Some warning');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(LogBoxData.addLog).toBeCalled();
|
||||
expect(require('../YellowBox').__unstable_isLogBoxEnabled()).toBe(true);
|
||||
|
||||
uninstall();
|
||||
(LogBoxData.addLog: any).mockClear();
|
||||
|
||||
(console: any).warn('Some warning');
|
||||
expect(YellowBoxRegistry.add).not.toBeCalled();
|
||||
expect(LogBoxData.addLog).not.toBeCalled();
|
||||
expect(YellowBox.__unstable_isLogBoxEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
it('throws if LogBox is enabled after YellowBox is installed', () => {
|
||||
jest.mock('../Data/YellowBoxRegistry');
|
||||
const YellowBox = require('../YellowBox');
|
||||
install();
|
||||
|
||||
expect(() => YellowBox.__unstable_enableLogBox()).toThrow(
|
||||
'LogBox must be enabled before AppContainer is required so that it can properly wrap the console methods.\n\nPlease enable LogBox earlier in your app.\n\n',
|
||||
);
|
||||
});
|
||||
|
||||
it('should render YellowBoxContainer by default', () => {
|
||||
const YellowBox = require('../YellowBox');
|
||||
|
||||
const output = render.shallowRender(<YellowBox />);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render LogBoxNotificationContainer when LogBox is enabled', () => {
|
||||
const YellowBox = require('../YellowBox');
|
||||
|
||||
YellowBox.__unstable_enableLogBox();
|
||||
|
||||
const output = render.shallowRender(<YellowBox />);
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`YellowBox should render LogBoxNotificationContainer when LogBox is enabled 1`] = `<LogBoxNotificationContainer />`;
|
||||
|
||||
exports[`YellowBox should render YellowBoxContainer by default 1`] = `<YellowBoxContainer />`;
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
|
||||
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotification;
|
||||
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey;
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "RCTConstants.h"
|
||||
|
||||
NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
|
||||
NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey = @"traitCollection";
|
||||
@@ -14,6 +14,7 @@
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTBridge+Private.h"
|
||||
#import "RCTConstants.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTKeyCommands.h"
|
||||
#import "RCTLog.h"
|
||||
@@ -33,7 +34,6 @@
|
||||
#endif
|
||||
|
||||
NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";
|
||||
static NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
|
||||
|
||||
@interface RCTUIManager (RCTRootView)
|
||||
|
||||
@@ -367,21 +367,16 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
[self showLoadingView];
|
||||
}
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
|
||||
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
|
||||
{
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if ([previousTraitCollection hasDifferentColorAppearanceComparedToTraitCollection:self.traitCollection]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
|
||||
object:self
|
||||
userInfo:@{@"traitCollection": self.traitCollection}];
|
||||
}
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
|
||||
object:self
|
||||
userInfo:@{
|
||||
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey: self.traitCollection,
|
||||
}];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
|
||||
@@ -21,11 +21,11 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^(void){
|
||||
__rnVersion = @{
|
||||
RCTVersionMajor: @(0),
|
||||
RCTVersionMinor: @(0),
|
||||
RCTVersionPatch: @(0),
|
||||
RCTVersionPrerelease: [NSNull null],
|
||||
};
|
||||
RCTVersionMajor: @(0),
|
||||
RCTVersionMinor: @(62),
|
||||
RCTVersionPatch: @(0),
|
||||
RCTVersionPrerelease: @"rc.1",
|
||||
};
|
||||
});
|
||||
return __rnVersion;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
|
||||
#import "RCTSurfaceHostingView.h"
|
||||
|
||||
#import "RCTConstants.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTSurface.h"
|
||||
#import "RCTSurfaceDelegate.h"
|
||||
#import "RCTSurfaceView.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
static NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
|
||||
|
||||
@interface RCTSurfaceHostingView ()
|
||||
|
||||
@property (nonatomic, assign) BOOL isActivityIndicatorViewVisible;
|
||||
@@ -208,21 +207,15 @@ RCT_NOT_IMPLEMENTED(- (nullable instancetype)initWithCoder:(NSCoder *)coder)
|
||||
|
||||
#pragma mark - UITraitCollection updates
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
|
||||
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
|
||||
{
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if ([previousTraitCollection hasDifferentColorAppearanceComparedToTraitCollection:self.traitCollection]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
|
||||
object:self
|
||||
userInfo:@{@"traitCollection": self.traitCollection}];
|
||||
}
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
|
||||
object:self
|
||||
userInfo:@{
|
||||
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey: self.traitCollection,
|
||||
}];
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark - Private stuff
|
||||
|
||||
|
||||
@@ -96,6 +96,9 @@ rn_apple_library(
|
||||
) + react_module_plugin_providers(
|
||||
name = "RedBox",
|
||||
native_class_func = "RCTRedBoxCls",
|
||||
) + react_module_plugin_providers(
|
||||
name = "LogBox",
|
||||
native_class_func = "RCTLogBoxCls",
|
||||
) + react_module_plugin_providers(
|
||||
name = "TVNavigationEventEmitter",
|
||||
native_class_func = "RCTTVNavigationEventEmitterCls",
|
||||
|
||||
@@ -48,6 +48,7 @@ Class RCTPerfMonitorCls(void) __attribute__((used));
|
||||
Class RCTDevMenuCls(void) __attribute__((used));
|
||||
Class RCTDevSettingsCls(void) __attribute__((used));
|
||||
Class RCTRedBoxCls(void) __attribute__((used));
|
||||
Class RCTLogBoxCls(void) __attribute__((used));
|
||||
Class RCTTVNavigationEventEmitterCls(void) __attribute__((used));
|
||||
Class RCTWebSocketExecutorCls(void) __attribute__((used));
|
||||
Class RCTWebSocketModuleCls(void) __attribute__((used));
|
||||
|
||||
@@ -37,6 +37,7 @@ Class RCTCoreModulesClassProvider(const char *name) {
|
||||
{"DevMenu", RCTDevMenuCls},
|
||||
{"DevSettings", RCTDevSettingsCls},
|
||||
{"RedBox", RCTRedBoxCls},
|
||||
{"LogBox", RCTLogBoxCls},
|
||||
{"TVNavigationEventEmitter", RCTTVNavigationEventEmitterCls},
|
||||
{"WebSocketExecutor", RCTWebSocketExecutorCls},
|
||||
{"WebSocketModule", RCTWebSocketModuleCls},
|
||||
|
||||
@@ -12,7 +12,5 @@
|
||||
|
||||
RCT_EXTERN void RCTEnableAppearancePreference(BOOL enabled);
|
||||
|
||||
NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
|
||||
|
||||
@interface RCTAppearance : RCTEventEmitter <RCTBridgeModule>
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#import "RCTAppearance.h"
|
||||
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTConstants.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
#import "CoreModulesPlugins.h"
|
||||
@@ -86,7 +87,7 @@ RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme)
|
||||
NSDictionary *userInfo = [notification userInfo];
|
||||
UITraitCollection *traitCollection = nil;
|
||||
if (userInfo) {
|
||||
traitCollection = userInfo[@"traitCollection"];
|
||||
traitCollection = userInfo[RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey];
|
||||
}
|
||||
NSString *newColorScheme = RCTColorSchemePreference(traitCollection);
|
||||
if (![_currentColorScheme isEqualToString:newColorScheme]) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTAccessibilityManager.h>
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTConstants.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTUIUtils.h>
|
||||
#import <React/RCTUtils.h>
|
||||
@@ -61,9 +62,15 @@ RCT_EXPORT_MODULE()
|
||||
_currentInterfaceDimensions = RCTExportedDimensions(_bridge);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(interfaceFrameDidChange)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
selector:@selector(interfaceFrameDidChange)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(interfaceFrameDidChange)
|
||||
name:RCTUserInterfaceStyleDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTErrorCustomizer.h>
|
||||
|
||||
@class RCTJSStackFrame;
|
||||
|
||||
@interface RCTLogBox : NSObject <RCTBridgeModule>
|
||||
|
||||
- (void)show;
|
||||
- (void)hide;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "RCTLogBox.h"
|
||||
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTErrorInfo.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTJSStackFrame.h>
|
||||
#import <React/RCTRedBoxSetEnabled.h>
|
||||
#import <React/RCTReloadCommand.h>
|
||||
#import <React/RCTRedBoxSetEnabled.h>
|
||||
#import <React/RCTSurface.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "CoreModulesPlugins.h"
|
||||
|
||||
#if RCT_DEV_MENU
|
||||
|
||||
@class RCTLogBoxView;
|
||||
|
||||
@interface RCTLogBoxView : UIView
|
||||
@end
|
||||
|
||||
@implementation RCTLogBoxView
|
||||
{
|
||||
UIViewController *_rootViewController;
|
||||
RCTSurface *_surface;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame bridge:(RCTBridge *)bridge
|
||||
{
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
_surface = [[RCTSurface alloc] initWithBridge:bridge moduleName:@"LogBox" initialProperties:@{}];
|
||||
|
||||
[_surface start];
|
||||
[_surface setSize:frame.size];
|
||||
|
||||
if (![_surface synchronouslyWaitForStage:RCTSurfaceStageSurfaceDidInitialMounting timeout:1]) {
|
||||
RCTLogInfo(@"Failed to mount LogBox within 1s");
|
||||
}
|
||||
|
||||
_rootViewController = [UIViewController new];
|
||||
_rootViewController.view = (UIView *)_surface.view;
|
||||
_rootViewController.view.backgroundColor = [UIColor clearColor];
|
||||
_rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// Dismiss by deallocating the window.
|
||||
// This will also handle JS reload, otherwise the LogBox view would be stuck on top.
|
||||
[_rootViewController.view resignFirstResponder];
|
||||
[_rootViewController dismissViewControllerAnimated:NO completion:NULL];
|
||||
}
|
||||
|
||||
- (void)show
|
||||
{
|
||||
[RCTSharedApplication().delegate.window.rootViewController presentViewController:_rootViewController animated:NO completion:^{
|
||||
[self->_rootViewController.view becomeFirstResponder];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTLogBox () <NativeLogBoxSpec>
|
||||
@end
|
||||
|
||||
@implementation RCTLogBox
|
||||
{
|
||||
RCTLogBoxView *_view;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(show)
|
||||
{
|
||||
if (RCTRedBoxGetEnabled()) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!self->_view) {
|
||||
self->_view = [[RCTLogBoxView alloc] initWithFrame:[UIScreen mainScreen].bounds bridge: self->_bridge];
|
||||
}
|
||||
[self->_view show];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(hide)
|
||||
{
|
||||
if (RCTRedBoxGetEnabled()) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self->_view = nil;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
{
|
||||
if (RCTRedBoxGetEnabled()) {
|
||||
return std::make_shared<facebook::react::NativeLogBoxSpecJSI>(self, jsInvoker);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#else // Disabled
|
||||
|
||||
@interface RCTLogBox() <NativeLogBoxSpec>
|
||||
@end
|
||||
|
||||
@implementation RCTLogBox
|
||||
|
||||
+ (NSString *)moduleName
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)show {
|
||||
// noop
|
||||
}
|
||||
|
||||
- (void)hide {
|
||||
// noop
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
{
|
||||
return std::make_shared<facebook::react::NativeLogBoxSpecJSI>(self, jsInvoker);
|
||||
}
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
Class RCTLogBoxCls(void) {
|
||||
return RCTLogBox.class;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-master
|
||||
VERSION_NAME=0.62.0-rc.1
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
*
|
||||
* <p>Generated by an internal genrule from Flow types.
|
||||
*
|
||||
* @generated
|
||||
* @nolint
|
||||
*/
|
||||
|
||||
package com.facebook.fbreact.specs;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReactModuleWithSpec;
|
||||
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
|
||||
|
||||
public abstract class NativeLogBoxSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule {
|
||||
public NativeLogBoxSpec(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public abstract void hide();
|
||||
|
||||
@ReactMethod
|
||||
public abstract void show();
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactMarker;
|
||||
import com.facebook.react.devsupport.LogBoxModule;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.module.annotations.ReactModuleList;
|
||||
import com.facebook.react.module.model.ReactModuleInfo;
|
||||
@@ -49,6 +50,7 @@ import java.util.Map;
|
||||
DeviceInfoModule.class,
|
||||
DevSettingsModule.class,
|
||||
ExceptionsManagerModule.class,
|
||||
LogBoxModule.class,
|
||||
HeadlessJsTaskSupportModule.class,
|
||||
SourceCodeModule.class,
|
||||
TimingModule.class,
|
||||
@@ -94,6 +96,7 @@ import java.util.Map;
|
||||
DeviceInfoModule.class,
|
||||
DevSettingsModule.class,
|
||||
ExceptionsManagerModule.class,
|
||||
LogBoxModule.class,
|
||||
HeadlessJsTaskSupportModule.class,
|
||||
SourceCodeModule.class,
|
||||
TimingModule.class,
|
||||
@@ -142,6 +145,8 @@ import java.util.Map;
|
||||
return new DevSettingsModule(reactContext, mReactInstanceManager.getDevSupportManager());
|
||||
case ExceptionsManagerModule.NAME:
|
||||
return new ExceptionsManagerModule(mReactInstanceManager.getDevSupportManager());
|
||||
case LogBoxModule.NAME:
|
||||
return new LogBoxModule(reactContext, mReactInstanceManager.getDevSupportManager());
|
||||
case HeadlessJsTaskSupportModule.NAME:
|
||||
return new HeadlessJsTaskSupportModule(reactContext);
|
||||
case SourceCodeModule.NAME:
|
||||
|
||||
@@ -304,6 +304,27 @@ public class ReactInstanceManager {
|
||||
public JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
|
||||
return ReactInstanceManager.this.getJSExecutorFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable View createRootView(String appKey) {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity != null) {
|
||||
ReactRootView rootView = new ReactRootView(currentActivity);
|
||||
|
||||
rootView.startReactApplication(ReactInstanceManager.this, appKey, null);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyRootView(View rootView) {
|
||||
if (rootView instanceof ReactRootView) {
|
||||
((ReactRootView) rootView).unmountReactApplication();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.SensorManager;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -377,6 +378,14 @@ public class DevSupportManagerImpl
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable View createRootView(String appKey) {
|
||||
return mReactInstanceManagerHelper.createRootView(appKey);
|
||||
}
|
||||
|
||||
public void destroyRootView(View rootView) {
|
||||
mReactInstanceManagerHelper.destroyRootView(rootView);
|
||||
}
|
||||
|
||||
private void hideDevOptionsDialog() {
|
||||
if (mDevOptionsDialog != null) {
|
||||
mDevOptionsDialog.dismiss();
|
||||
|
||||
+9
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
@@ -40,6 +41,14 @@ public class DisabledDevSupportManager implements DevSupportManager {
|
||||
@Override
|
||||
public void showNewJSError(String message, ReadableArray details, int errorCookie) {}
|
||||
|
||||
@Override
|
||||
public @Nullable View createRootView(String appKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyRootView(View rootView) {}
|
||||
|
||||
@Override
|
||||
public void updateJSError(String message, ReadableArray details, int errorCookie) {}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import com.facebook.react.R;
|
||||
|
||||
/** Dialog for displaying JS errors in LogBox. */
|
||||
public class LogBoxDialog extends Dialog {
|
||||
public LogBoxDialog(Activity context, View reactRootView) {
|
||||
super(context, R.style.Theme_Catalyst_LogBox);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(reactRootView);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
|
||||
@ReactModule(name = LogBoxModule.NAME)
|
||||
public class LogBoxModule extends ReactContextBaseJavaModule {
|
||||
|
||||
public static final String NAME = "LogBox";
|
||||
|
||||
private final DevSupportManager mDevSupportManager;
|
||||
private @Nullable View mReactRootView;
|
||||
private @Nullable LogBoxDialog mLogBoxDialog;
|
||||
|
||||
public LogBoxModule(ReactApplicationContext reactContext, DevSupportManager devSupportManager) {
|
||||
super(reactContext);
|
||||
|
||||
mDevSupportManager = devSupportManager;
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mReactRootView == null) {
|
||||
mReactRootView = mDevSupportManager.createRootView("LogBox");
|
||||
if (mReactRootView == null) {
|
||||
FLog.e(
|
||||
ReactConstants.TAG,
|
||||
"Unable to launch logbox because react was unable to create the root view");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void show() {
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mLogBoxDialog == null) {
|
||||
Activity context = getCurrentActivity();
|
||||
if (context == null || context.isFinishing()) {
|
||||
FLog.e(
|
||||
ReactConstants.TAG,
|
||||
"Unable to launch logbox because react activity "
|
||||
+ "is not available, here is the error that logbox would've displayed: ");
|
||||
return;
|
||||
}
|
||||
mLogBoxDialog = new LogBoxDialog(context, mReactRootView);
|
||||
mLogBoxDialog.setCancelable(false);
|
||||
mLogBoxDialog.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void hide() {
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mLogBoxDialog != null) {
|
||||
if (mReactRootView.getParent() != null) {
|
||||
((ViewGroup) mReactRootView.getParent()).removeView(mReactRootView);
|
||||
}
|
||||
mLogBoxDialog.dismiss();
|
||||
mLogBoxDialog = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCatalystInstanceDestroy() {
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mReactRootView != null) {
|
||||
mDevSupportManager.destroyRootView(mReactRootView);
|
||||
mReactRootView = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+6
@@ -8,6 +8,7 @@
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.JavaJSExecutor;
|
||||
import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||
@@ -32,4 +33,9 @@ public interface ReactInstanceManagerDevHelper {
|
||||
Activity getCurrentActivity();
|
||||
|
||||
JavaScriptExecutorFactory getJavaScriptExecutorFactory();
|
||||
|
||||
@Nullable
|
||||
View createRootView(String appKey);
|
||||
|
||||
void destroyRootView(View rootView);
|
||||
}
|
||||
|
||||
+6
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.facebook.react.devsupport.interfaces;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
@@ -25,6 +26,11 @@ public interface DevSupportManager extends NativeModuleCallExceptionHandler {
|
||||
|
||||
void addCustomDevOption(String optionName, DevOptionHandler optionHandler);
|
||||
|
||||
@Nullable
|
||||
View createRootView(String appKey);
|
||||
|
||||
void destroyRootView(View rootView);
|
||||
|
||||
void showNewJSError(String message, ReadableArray details, int errorCookie);
|
||||
|
||||
void updateJSError(final String message, final ReadableArray details, final int errorCookie);
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ import java.util.Map;
|
||||
public class ReactNativeVersion {
|
||||
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
|
||||
"major", 0,
|
||||
"minor", 0,
|
||||
"minor", 62,
|
||||
"patch", 0,
|
||||
"prerelease", null);
|
||||
"prerelease", "rc.1");
|
||||
}
|
||||
|
||||
@@ -96,6 +96,12 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe
|
||||
// Do nothing as we are laid out by UIManager
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child, int index) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="catalyst_redbox_background">#eecc0000</color>
|
||||
<color name="catalyst_logbox_background">#ffffffff</color>
|
||||
</resources>
|
||||
|
||||
@@ -9,10 +9,22 @@
|
||||
<item name="android:outAnimation">@android:anim/fade_out</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
<style name="Theme.Catalyst.LogBox">
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowAnimationStyle">@style/Animation.Catalyst.LogBox</item>
|
||||
<item name="android:inAnimation">@android:anim/fade_in</item>
|
||||
<item name="android:outAnimation">@android:anim/fade_out</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
<style name="Animation.Catalyst.RedBox" parent="@android:style/Animation">
|
||||
<item name="android:windowEnterAnimation">@anim/catalyst_push_up_in</item>
|
||||
<item name="android:windowExitAnimation">@anim/catalyst_push_up_out</item>
|
||||
</style>
|
||||
<style name="Animation.Catalyst.LogBox" parent="@android:style/Animation">
|
||||
<item name="android:windowEnterAnimation">@anim/catalyst_push_up_in</item>
|
||||
<item name="android:windowExitAnimation">@anim/catalyst_push_up_out</item>
|
||||
</style>
|
||||
<style name="redboxButton">
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
|
||||
@@ -438,6 +438,9 @@ module.exports = {
|
||||
get unstable_RootTagContext(): RootTagContext {
|
||||
return require('./Libraries/ReactNative/RootTagContext');
|
||||
},
|
||||
get unstable_enableLogBox(): () => void {
|
||||
return require('./Libraries/YellowBox/YellowBox').__unstable_enableLogBox;
|
||||
},
|
||||
|
||||
// Prop Types
|
||||
get ColorPropType(): DeprecatedColorPropType {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"version": "1000.0.0",
|
||||
"version": "0.62.0-rc.1",
|
||||
"bin": "./cli.js",
|
||||
"description": "A framework for building native apps using React",
|
||||
"license": "MIT",
|
||||
@@ -174,4 +174,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "16.11.0",
|
||||
"react-native": "1000.0.0"
|
||||
"react-native": "0.62.0-rc.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.2",
|
||||
|
||||
Reference in New Issue
Block a user