@@ -13,7 +13,7 @@ import '@reach/menu-button/styles.css';
1313import '@reach/tooltip/styles.css' ;
1414
1515import * as React from 'react' ;
16- import { useEffect , useMemo , useState } from 'react' ;
16+ import { useEffect , useMemo , useRef } from 'react' ;
1717import Store from '../store' ;
1818import { BridgeContext , ContextMenuContext , StoreContext } from './context' ;
1919import Components from './Components/Components' ;
@@ -27,6 +27,7 @@ import {ModalDialogContextController} from './ModalDialog';
2727import ReactLogo from './ReactLogo' ;
2828import UnsupportedVersionDialog from './UnsupportedVersionDialog' ;
2929import WarnIfLegacyBackendDetected from './WarnIfLegacyBackendDetected' ;
30+ import { useLocalStorage } from './hooks' ;
3031
3132import styles from './DevTools.css' ;
3233
@@ -106,9 +107,13 @@ export default function DevTools({
106107 viewAttributeSourceFunction,
107108 viewElementSourceFunction,
108109} : Props ) {
109- const [ tab , setTab ] = useState ( defaultTab ) ;
110- if ( overrideTab != null && overrideTab !== tab ) {
111- setTab ( overrideTab ) ;
110+ let [ tab , setTab ] = useLocalStorage < TabID > (
111+ 'React::DevTools::defaultTab' ,
112+ defaultTab ,
113+ ) ;
114+
115+ if ( overrideTab != null ) {
116+ tab = overrideTab ;
112117 }
113118
114119 const viewElementSource = useMemo (
@@ -127,6 +132,41 @@ export default function DevTools({
127132 [ enabledInspectedElementContextMenu , viewAttributeSourceFunction ] ,
128133 ) ;
129134
135+ const devToolsRef = useRef < HTMLElement | null > ( null ) ;
136+
137+ useEffect ( ( ) => {
138+ if ( ! showTabBar ) {
139+ return ;
140+ }
141+
142+ const div = devToolsRef . current ;
143+ if ( div === null ) {
144+ return ;
145+ }
146+
147+ const ownerWindow = div . ownerDocument . defaultView ;
148+ const handleKeyDown = ( event : KeyboardEvent ) => {
149+ if ( event . ctrlKey || event . metaKey ) {
150+ switch ( event . key ) {
151+ case '1' :
152+ setTab ( tabs [ 0 ] . id ) ;
153+ event . preventDefault ( ) ;
154+ event . stopPropagation ( ) ;
155+ break ;
156+ case '2' :
157+ setTab ( tabs [ 1 ] . id ) ;
158+ event . preventDefault ( ) ;
159+ event . stopPropagation ( ) ;
160+ break ;
161+ }
162+ }
163+ } ;
164+ ownerWindow . addEventListener ( 'keydown' , handleKeyDown ) ;
165+ return ( ) => {
166+ ownerWindow . removeEventListener ( 'keydown' , handleKeyDown ) ;
167+ } ;
168+ } , [ showTabBar ] ) ;
169+
130170 useEffect ( ( ) => {
131171 return ( ) => {
132172 try {
@@ -149,7 +189,7 @@ export default function DevTools({
149189 < ViewElementSourceContext . Provider value = { viewElementSource } >
150190 < TreeContextController >
151191 < ProfilerContextController >
152- < div className = { styles . DevTools } >
192+ < div className = { styles . DevTools } ref = { devToolsRef } >
153193 { showTabBar && (
154194 < div className = { styles . TabBar } >
155195 < ReactLogo />
0 commit comments