@@ -13,7 +13,14 @@ import '@reach/menu-button/styles.css';
1313import '@reach/tooltip/styles.css' ;
1414
1515import * as React from 'react' ;
16- import { useCallback , useEffect , useLayoutEffect , useMemo , useRef } from 'react' ;
16+ import {
17+ StrictMode ,
18+ useCallback ,
19+ useEffect ,
20+ useLayoutEffect ,
21+ useMemo ,
22+ useRef ,
23+ } from 'react' ;
1724import Store from '../store' ;
1825import {
1926 BridgeContext ,
@@ -56,6 +63,38 @@ import type {BrowserTheme} from 'react-devtools-shared/src/frontend/types';
5663import type { ReactFunctionLocation , ReactCallSite } from 'shared/ReactTypes' ;
5764import type { SourceSelection } from './Editor/EditorPane' ;
5865
66+ const MaybeActivity : any =
67+ React . Activity ||
68+ ( React as any ) . unstable_Activity ||
69+ function AlwaysVisibleActivity ( {
70+ children,
71+ } : {
72+ children : React . Node ,
73+ mode : string ,
74+ } ) {
75+ return children ;
76+ } ;
77+
78+ function TabContent ( {
79+ children,
80+ activeTab,
81+ name,
82+ } : {
83+ children : React . Node ,
84+ activeTab : string ,
85+ name : string ,
86+ } ) {
87+ const hidden = activeTab !== name ;
88+ const mode = hidden ? 'hidden' : 'visible' ;
89+ return (
90+ < MaybeActivity mode = { mode } name = { name + '-tab' } >
91+ < div className = { styles . TabContent } hidden = { hidden } >
92+ { children }
93+ </ div >
94+ </ MaybeActivity >
95+ ) ;
96+ }
97+
5998export type TabID = 'components' | 'profiler' | 'suspense' ;
6099
61100export type ViewElementSource = (
@@ -289,6 +328,7 @@ export default function DevTools({
289328 useLayoutEffect ( ( ) => {
290329 return ( ) => {
291330 try {
331+ // TODO: <DevTools> can't be put int <Activity> without being able to resume listening
292332 // Shut the Bridge down synchronously (during unmount).
293333 bridge . shutdown ( ) ;
294334 } catch ( error ) {
@@ -302,98 +342,102 @@ export default function DevTools({
302342 } , [ ] ) ;
303343
304344 return (
305- < BridgeContext . Provider value = { bridge } >
306- < StoreContext . Provider value = { store } >
307- < OptionsContext . Provider value = { options } >
308- < ContextMenuContext . Provider value = { contextMenu } >
309- < ModalDialogContextController >
310- < SettingsContextController
311- browserTheme = { browserTheme }
312- componentsPortalContainer = { componentsPortalContainer }
313- profilerPortalContainer = { profilerPortalContainer } >
314- < ViewElementSourceContext . Provider value = { viewElementSource } >
315- < HookNamesModuleLoaderContext . Provider
316- value = { hookNamesModuleLoaderFunction || null } >
317- < FetchFileWithCachingContext . Provider
318- value = { fetchFileWithCaching || null } >
319- < TreeContextController >
320- < ProfilerContextController >
321- < TimelineContextController >
322- < InspectedElementContextController >
323- < SuspenseTreeContextController >
324- < ThemeProvider >
325- < div
326- className = { styles . DevTools }
327- ref = { devToolsRef }
328- data-react-devtools-portal-root = { true } >
329- { showTabBar && (
330- < div className = { styles . TabBar } >
331- < ReactLogo />
332- < span
333- className = { styles . DevToolsVersion } >
334- { process . env . DEVTOOLS_VERSION }
335- </ span >
336- < div className = { styles . Spacer } />
337- < TabBar
338- currentTab = { tab }
339- id = "DevTools"
340- selectTab = { selectTab }
341- tabs = { tabs }
342- type = "navigation"
343- />
344- </ div >
345- ) }
346- < div
347- className = { styles . TabContent }
348- hidden = { tab !== 'components' } >
349- < Components
350- portalContainer = {
351- componentsPortalContainer
352- }
353- />
354- </ div >
345+ < StrictMode >
346+ < BridgeContext . Provider value = { bridge } >
347+ < StoreContext . Provider value = { store } >
348+ < OptionsContext . Provider value = { options } >
349+ < ContextMenuContext . Provider value = { contextMenu } >
350+ < ModalDialogContextController >
351+ < SettingsContextController
352+ browserTheme = { browserTheme }
353+ componentsPortalContainer = { componentsPortalContainer }
354+ profilerPortalContainer = { profilerPortalContainer } >
355+ < ViewElementSourceContext . Provider value = { viewElementSource } >
356+ < HookNamesModuleLoaderContext . Provider
357+ value = { hookNamesModuleLoaderFunction || null } >
358+ < FetchFileWithCachingContext . Provider
359+ value = { fetchFileWithCaching || null } >
360+ < TreeContextController >
361+ < ProfilerContextController >
362+ < TimelineContextController >
363+ < InspectedElementContextController >
364+ < SuspenseTreeContextController >
365+ < ThemeProvider >
355366 < div
356- className = { styles . TabContent }
357- hidden = { tab !== 'profiler' } >
358- < Profiler
359- portalContainer = {
360- profilerPortalContainer
361- }
362- />
367+ className = { styles . DevTools }
368+ ref = { devToolsRef }
369+ data-react-devtools-portal-root = { true } >
370+ { showTabBar && (
371+ < div className = { styles . TabBar } >
372+ < ReactLogo />
373+ < span
374+ className = { styles . DevToolsVersion } >
375+ { process . env . DEVTOOLS_VERSION }
376+ </ span >
377+ < div className = { styles . Spacer } />
378+ < TabBar
379+ currentTab = { tab }
380+ id = "DevTools"
381+ selectTab = { selectTab }
382+ tabs = { tabs }
383+ type = "navigation"
384+ />
385+ </ div >
386+ ) }
387+ < TabContent
388+ name = "components"
389+ activeTab = { tab } >
390+ < Components
391+ portalContainer = {
392+ componentsPortalContainer
393+ }
394+ />
395+ </ TabContent >
396+ < TabContent
397+ name = "profiler"
398+ activeTab = { tab } >
399+ < Profiler
400+ portalContainer = {
401+ profilerPortalContainer
402+ }
403+ />
404+ </ TabContent >
405+ < TabContent
406+ name = "suspense"
407+ activeTab = { tab } >
408+ < SuspenseTab
409+ portalContainer = {
410+ suspensePortalContainer
411+ }
412+ />
413+ </ TabContent >
363414 </ div >
364- < div
365- className = { styles . TabContent }
366- hidden = { tab !== 'suspense' } >
367- < SuspenseTab
368- portalContainer = {
369- suspensePortalContainer
370- }
415+ { editorPortalContainer ? (
416+ < EditorPane
417+ selectedSource = { currentSelectedSource }
418+ portalContainer = { editorPortalContainer }
371419 />
372- </ div >
373- </ div >
374- { editorPortalContainer ? (
375- < EditorPane
376- selectedSource = { currentSelectedSource }
377- portalContainer = { editorPortalContainer }
378- />
379- ) : null }
380- </ ThemeProvider >
381- </ SuspenseTreeContextController >
382- </ InspectedElementContextController >
383- </ TimelineContextController >
384- </ ProfilerContextController >
385- </ TreeContextController >
386- </ FetchFileWithCachingContext . Provider >
387- </ HookNamesModuleLoaderContext . Provider >
388- </ ViewElementSourceContext . Provider >
389- </ SettingsContextController >
390- < UnsupportedBridgeProtocolDialog />
391- { warnIfLegacyBackendDetected && < WarnIfLegacyBackendDetected /> }
392- { warnIfUnsupportedVersionDetected && < UnsupportedVersionDialog /> }
393- </ ModalDialogContextController >
394- </ ContextMenuContext . Provider >
395- </ OptionsContext . Provider >
396- </ StoreContext . Provider >
397- </ BridgeContext . Provider >
420+ ) : null }
421+ </ ThemeProvider >
422+ </ SuspenseTreeContextController >
423+ </ InspectedElementContextController >
424+ </ TimelineContextController >
425+ </ ProfilerContextController >
426+ </ TreeContextController >
427+ </ FetchFileWithCachingContext . Provider >
428+ </ HookNamesModuleLoaderContext . Provider >
429+ </ ViewElementSourceContext . Provider >
430+ </ SettingsContextController >
431+ < UnsupportedBridgeProtocolDialog />
432+ { warnIfLegacyBackendDetected && < WarnIfLegacyBackendDetected /> }
433+ { warnIfUnsupportedVersionDetected && (
434+ < UnsupportedVersionDialog />
435+ ) }
436+ </ ModalDialogContextController >
437+ </ ContextMenuContext . Provider >
438+ </ OptionsContext . Provider >
439+ </ StoreContext . Provider >
440+ </ BridgeContext . Provider >
441+ </ StrictMode >
398442 ) ;
399443}
0 commit comments