diff --git a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css index c6fa68ddb782d..e73880f632012 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css +++ b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css @@ -31,6 +31,31 @@ font-family: var(--font-family-sans); } +.Source { + padding: 0.25rem; + border-top: 1px solid var(--color-border); +} + +.SourceHeaderRow { + display: flex; + align-items: center; +} + +.SourceHeader { + flex: 1 1; + font-family: var(--font-family-sans); +} + +.SourceOneLiner { + font-family: var(--font-family-monospace); + font-size: var(--font-size-monospace-normal); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + margin-left: 1rem; +} + .Component, .Owner { color: var(--color-component-name); diff --git a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js index 08d15104ec8e5..dcf3529a7140d 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js @@ -7,6 +7,7 @@ * @flow */ +import {copy} from 'clipboard-js'; import React, {useCallback, useContext} from 'react'; import {TreeDispatcherContext, TreeStateContext} from './TreeContext'; import {BridgeContext, StoreContext} from '../context'; @@ -272,6 +273,7 @@ function InspectedElementView({ hooks, owners, props, + source, state, } = inspectedElement; @@ -403,6 +405,54 @@ function InspectedElementView({ ))} )} + + {source !== null && ( + + )} + + ); +} + +// This function is based on packages/shared/describeComponentFrame.js +function formatSourceForDisplay(fileName: string, lineNumber: string) { + const BEFORE_SLASH_RE = /^(.*)[\\\/]/; + + let nameOnly = fileName.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(nameOnly)) { + const match = fileName.match(BEFORE_SLASH_RE); + if (match) { + const pathBeforeSlash = match[1]; + if (pathBeforeSlash) { + const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ''); + nameOnly = folderName + '/' + nameOnly; + } + } + } + + return `${nameOnly}:${lineNumber}`; +} + +type SourceProps = {| + fileName: string, + lineNumber: string, +|}; + +function Source({fileName, lineNumber}: SourceProps) { + const handleCopy = () => copy(`${fileName}:${lineNumber}`); + return ( +
+
+
source
+ +
+
+ {formatSourceForDisplay(fileName, lineNumber)} +
); }