@samitouri / QOS-React / commits / 031a5aaffb

Show component location for selected element in bottom/right of props panel (#17567)

* Show component location info for selected element in bottom/right of props panel * Moved RegExp declaration into function basedon PR feedback

Brian Vaughn committed Dec 10, 2019 at 09:24 UTC 031a5aaffbc06f0ac115f1d814e43e4d63ae15d2
2 files changed +75
packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.css
+25
@@ -31,6 +31,31 @@
31 font-family: var(--font-family-sans);
32 }
33
34 +.Source {
35 + padding: 0.25rem;
36 + border-top: 1px solid var(--color-border);
37 +}
38 +
39 +.SourceHeaderRow {
40 + display: flex;
41 + align-items: center;
42 +}
43 +
44 +.SourceHeader {
45 + flex: 1 1;
46 + font-family: var(--font-family-sans);
47 +}
48 +
49 +.SourceOneLiner {
50 + font-family: var(--font-family-monospace);
51 + font-size: var(--font-size-monospace-normal);
52 + white-space: nowrap;
53 + overflow: hidden;
54 + text-overflow: ellipsis;
55 + max-width: 100%;
56 + margin-left: 1rem;
57 +}
58 +
59 .Component,
60 .Owner {
61 color: var(--color-component-name);
packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js
+50
@@ -7,6 +7,7 @@
7 * @flow
8 */
9
10 +import {copy} from 'clipboard-js';
11 import React, {useCallback, useContext} from 'react';
12 import {TreeDispatcherContext, TreeStateContext} from './TreeContext';
13 import {BridgeContext, StoreContext} from '../context';
@@ -272,6 +273,7 @@ function InspectedElementView({
273 hooks,
274 owners,
275 props,
276 + source,
277 state,
278 } = inspectedElement;
279
@@ -403,6 +405,54 @@ function InspectedElementView({
405 ))}
406 </div>
407 )}
408 +
409 + {source !== null && (
410 + <Source fileName={source.fileName} lineNumber={source.lineNumber} />
411 + )}
412 + </div>
413 + );
414 +}
415 +
416 +// This function is based on packages/shared/describeComponentFrame.js
417 +function formatSourceForDisplay(fileName: string, lineNumber: string) {
418 + const BEFORE_SLASH_RE = /^(.*)[\\\/]/;
419 +
420 + let nameOnly = fileName.replace(BEFORE_SLASH_RE, '');
421 +
422 + // In DEV, include code for a common special case:
423 + // prefer "folder/index.js" instead of just "index.js".
424 + if (/^index\./.test(nameOnly)) {
425 + const match = fileName.match(BEFORE_SLASH_RE);
426 + if (match) {
427 + const pathBeforeSlash = match[1];
428 + if (pathBeforeSlash) {
429 + const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, '');
430 + nameOnly = folderName + '/' + nameOnly;
431 + }
432 + }
433 + }
434 +
435 + return `${nameOnly}:${lineNumber}`;
436 +}
437 +
438 +type SourceProps = {|
439 + fileName: string,
440 + lineNumber: string,
441 +|};
442 +
443 +function Source({fileName, lineNumber}: SourceProps) {
444 + const handleCopy = () => copy(`${fileName}:${lineNumber}`);
445 + return (
446 + <div className={styles.Source}>
447 + <div className={styles.SourceHeaderRow}>
448 + <div className={styles.SourceHeader}>source</div>
449 + <Button onClick={handleCopy} title="Copy to clipboard">
450 + <ButtonIcon type="copy" />
451 + </Button>
452 + </div>
453 + <div className={styles.SourceOneLiner}>
454 + {formatSourceForDisplay(fileName, lineNumber)}
455 + </div>
456 </div>
457 );
458 }