@@ -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,37 @@ 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 =
67+ React . unstable_Activity ||
68+ function AlwaysVisibleActivity ( {
69+ children,
70+ } : {
71+ children : React . Node ,
72+ mode : string ,
73+ } ) {
74+ return children ;
75+ } ;
76+
77+ function TabContent ( {
78+ children,
79+ activeTab,
80+ name,
81+ } : {
82+ children : React . Node ,
83+ activeTab : string ,
84+ name : string ,
85+ } ) {
86+ const hidden = activeTab !== name ;
87+ const mode = hidden ? 'hidden' : 'visible' ;
88+ return (
89+ < MaybeActivity mode = { mode } name = { name + '-tab' } >
90+ < div className = { styles . TabContent } hidden = { hidden } >
91+ { children }
92+ </ div >
93+ </ MaybeActivity >
94+ ) ;
95+ }
96+
5997export type TabID = 'components' | 'profiler' | 'suspense' ;
6098
6199export type ViewElementSource = (
@@ -289,6 +327,7 @@ export default function DevTools({
289327 useLayoutEffect ( ( ) => {
290328 return ( ) => {
291329 try {
330+ // TODO: <DevTools> can't be put int <Activity> without being able to resume listening
292331 // Shut the Bridge down synchronously (during unmount).
293332 bridge . shutdown ( ) ;
294333 } catch ( error ) {
@@ -302,98 +341,102 @@ export default function DevTools({
302341 } , [ ] ) ;
303342
304343 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 >
344+ < StrictMode >
345+ < BridgeContext . Provider value = { bridge } >
346+ < StoreContext . Provider value = { store } >
347+ < OptionsContext . Provider value = { options } >
348+ < ContextMenuContext . Provider value = { contextMenu } >
349+ < ModalDialogContextController >
350+ < SettingsContextController
351+ browserTheme = { browserTheme }
352+ componentsPortalContainer = { componentsPortalContainer }
353+ profilerPortalContainer = { profilerPortalContainer } >
354+ < ViewElementSourceContext . Provider value = { viewElementSource } >
355+ < HookNamesModuleLoaderContext . Provider
356+ value = { hookNamesModuleLoaderFunction || null } >
357+ < FetchFileWithCachingContext . Provider
358+ value = { fetchFileWithCaching || null } >
359+ < TreeContextController >
360+ < ProfilerContextController >
361+ < TimelineContextController >
362+ < InspectedElementContextController >
363+ < SuspenseTreeContextController >
364+ < ThemeProvider >
355365 < div
356- className = { styles . TabContent }
357- hidden = { tab !== 'profiler' } >
358- < Profiler
359- portalContainer = {
360- profilerPortalContainer
361- }
362- />
366+ className = { styles . DevTools }
367+ ref = { devToolsRef }
368+ data-react-devtools-portal-root = { true } >
369+ { showTabBar && (
370+ < div className = { styles . TabBar } >
371+ < ReactLogo />
372+ < span
373+ className = { styles . DevToolsVersion } >
374+ { process . env . DEVTOOLS_VERSION }
375+ </ span >
376+ < div className = { styles . Spacer } />
377+ < TabBar
378+ currentTab = { tab }
379+ id = "DevTools"
380+ selectTab = { selectTab }
381+ tabs = { tabs }
382+ type = "navigation"
383+ />
384+ </ div >
385+ ) }
386+ < TabContent
387+ name = "components"
388+ activeTab = { tab } >
389+ < Components
390+ portalContainer = {
391+ componentsPortalContainer
392+ }
393+ />
394+ </ TabContent >
395+ < TabContent
396+ name = "profiler"
397+ activeTab = { tab } >
398+ < Profiler
399+ portalContainer = {
400+ profilerPortalContainer
401+ }
402+ />
403+ </ TabContent >
404+ < TabContent
405+ name = "suspense"
406+ activeTab = { tab } >
407+ < SuspenseTab
408+ portalContainer = {
409+ suspensePortalContainer
410+ }
411+ />
412+ </ TabContent >
363413 </ div >
364- < div
365- className = { styles . TabContent }
366- hidden = { tab !== 'suspense' } >
367- < SuspenseTab
368- portalContainer = {
369- suspensePortalContainer
370- }
414+ { editorPortalContainer ? (
415+ < EditorPane
416+ selectedSource = { currentSelectedSource }
417+ portalContainer = { editorPortalContainer }
371418 />
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 >
419+ ) : null }
420+ </ ThemeProvider >
421+ </ SuspenseTreeContextController >
422+ </ InspectedElementContextController >
423+ </ TimelineContextController >
424+ </ ProfilerContextController >
425+ </ TreeContextController >
426+ </ FetchFileWithCachingContext . Provider >
427+ </ HookNamesModuleLoaderContext . Provider >
428+ </ ViewElementSourceContext . Provider >
429+ </ SettingsContextController >
430+ < UnsupportedBridgeProtocolDialog />
431+ { warnIfLegacyBackendDetected && < WarnIfLegacyBackendDetected /> }
432+ { warnIfUnsupportedVersionDetected && (
433+ < UnsupportedVersionDialog />
434+ ) }
435+ </ ModalDialogContextController >
436+ </ ContextMenuContext . Provider >
437+ </ OptionsContext . Provider >
438+ </ StoreContext . Provider >
439+ </ BridgeContext . Provider >
440+ </ StrictMode >
398441 ) ;
399442}
0 commit comments