From 9e916c21b530122efe2a4b00c53a70854b5e650f Mon Sep 17 00:00:00 2001 From: Emily Brown Date: Thu, 13 Nov 2025 16:44:39 +0000 Subject: [PATCH 01/19] [DevTools] hotkey to start/stop profiling --- .../src/devtools/views/Profiler/Profiler.js | 36 +++++++++++++++++-- .../devtools/views/Profiler/RecordToggle.js | 6 +++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js b/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js index 4ac55b46f0e..11875c5335a 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js @@ -8,7 +8,7 @@ */ import * as React from 'react'; -import {Fragment, useContext} from 'react'; +import {Fragment, useContext, useEffect, useRef} from 'react'; import {ModalDialog} from '../ModalDialog'; import {ProfilerContext} from './ProfilerContext'; import TabBar from '../TabBar'; @@ -38,6 +38,8 @@ import {TimelineContext} from 'react-devtools-timeline/src/TimelineContext'; import styles from './Profiler.css'; function Profiler(_: {}) { + const profilerRef = useRef(null); + const { didRecordCommits, isProcessingData, @@ -47,6 +49,8 @@ function Profiler(_: {}) { selectedTabID, selectTab, supportsProfiling, + startProfiling, + stopProfiling, } = useContext(ProfilerContext); const {file: timelineTraceEventData, searchInputContainerRef} = @@ -56,6 +60,34 @@ function Profiler(_: {}) { const isLegacyProfilerSelected = selectedTabID !== 'timeline'; + // Cmd+E to start/stop profiler recording + useEffect(() => { + const div = profilerRef.current; + if (div === null) { + return; + } + + const ownerWindow = div.ownerDocument.defaultView; + const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; + const handleKeyDown = (event: KeyboardEvent) => { + const correctModifier = isMac ? event.metaKey : event.ctrlKey; + if (correctModifier && event.key === 'e') { + if (isProfiling) { + stopProfiling(); + } else { + startProfiling(); + } + event.preventDefault(); + event.stopPropagation(); + } + }; + + ownerWindow.addEventListener('keydown', handleKeyDown); + return () => { + ownerWindow.removeEventListener('keydown', handleKeyDown); + }; + }, [isProfiling, startProfiling, stopProfiling]); + let view = null; if (didRecordCommits || selectedTabID === 'timeline') { switch (selectedTabID) { @@ -112,7 +144,7 @@ function Profiler(_: {}) { return ( -
+
diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js b/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js index 7e79df9e081..48bd2b0d7ae 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js @@ -30,13 +30,17 @@ export default function RecordToggle({disabled}: Props): React.Node { className = styles.ActiveRecordToggle; } + const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; + const shortcut = isMac ? '⌘E' : 'Ctrl+E'; + const title = isProfiling ? `Stop profiling - ${shortcut}` : `Start profiling - ${shortcut}`; + return ( ); From 138fb2c1623bb89c4f7e63d457dc0e35796302d7 Mon Sep 17 00:00:00 2001 From: Emily Brown Date: Mon, 17 Nov 2025 15:09:40 +0000 Subject: [PATCH 02/19] Fixed linting issue --- .../src/devtools/views/Profiler/RecordToggle.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js b/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js index 48bd2b0d7ae..f9a63ff301b 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/RecordToggle.js @@ -32,7 +32,9 @@ export default function RecordToggle({disabled}: Props): React.Node { const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const shortcut = isMac ? '⌘E' : 'Ctrl+E'; - const title = isProfiling ? `Stop profiling - ${shortcut}` : `Start profiling - ${shortcut}`; + const title = isProfiling + ? `Stop profiling - ${shortcut}` + : `Start profiling - ${shortcut}`; return (