123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- /**
- * 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 strict-local
- * @format
- */
- 'use strict';
- import * as React from 'react';
- import StyleSheet from '../../StyleSheet/StyleSheet';
- import Platform from '../../Utilities/Platform';
- import Text from '../../Text/Text';
- 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) {
- return null;
- }
- function getStackList() {
- if (collapsed) {
- return props.log.componentStack.slice(0, 3);
- } else {
- return props.log.componentStack;
- }
- }
- function getCollapseMessage() {
- if (props.log.componentStack.length <= 3) {
- return;
- }
- const count = props.log.componentStack.length - 3;
- if (collapsed) {
- return `See ${count} more components`;
- } else {
- return `Collapse ${count} components`;
- }
- }
- return (
- <LogBoxInspectorSection heading="Component Stack">
- {getStackList().map((frame, index) => (
- <View
- // Unfortunately we don't have a unique identifier for stack traces.
- key={index}
- 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>
- </LogBoxButton>
- </View>
- ))}
- <View style={componentStyles.collapseContainer}>
- <LogBoxButton
- backgroundColor={{
- default: 'transparent',
- pressed: LogBoxStyle.getBackgroundColor(1),
- }}
- onPress={() => setCollapsed(!collapsed)}
- style={componentStyles.collapseButton}>
- <Text style={componentStyles.collapse}>{getCollapseMessage()}</Text>
- </LogBoxButton>
- </View>
- </LogBoxInspectorSection>
- );
- }
- const componentStyles = StyleSheet.create({
- collapseContainer: {
- marginLeft: 15,
- flexDirection: 'row',
- },
- collapseButton: {
- borderRadius: 5,
- },
- collapse: {
- color: LogBoxStyle.getTextColor(0.7),
- fontSize: 12,
- fontWeight: '300',
- lineHeight: 20,
- marginTop: 0,
- paddingVertical: 5,
- paddingHorizontal: 10,
- },
- frameContainer: {
- flexDirection: 'row',
- paddingHorizontal: 15,
- },
- frame: {
- flex: 1,
- paddingVertical: 4,
- paddingHorizontal: 10,
- borderRadius: 5,
- },
- component: {
- flexDirection: 'row',
- paddingRight: 10,
- },
- frameName: {
- fontFamily: Platform.select({android: 'monospace', ios: 'Menlo'}),
- color: LogBoxStyle.getTextColor(1),
- fontSize: 14,
- includeFontPadding: false,
- lineHeight: 18,
- },
- bracket: {
- fontFamily: Platform.select({android: 'monospace', ios: 'Menlo'}),
- color: LogBoxStyle.getTextColor(0.4),
- fontSize: 14,
- fontWeight: '500',
- includeFontPadding: false,
- lineHeight: 18,
- },
- frameLocation: {
- color: LogBoxStyle.getTextColor(0.7),
- fontSize: 12,
- fontWeight: '300',
- includeFontPadding: false,
- lineHeight: 16,
- paddingLeft: 10,
- },
- });
- export default LogBoxInspectorReactFrames;
|