- /**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
- import * as React from 'react'; 
- import {useCallback, useContext, useEffect, useMemo, useRef} from 'react'; 
- import {SettingsModalContext} from './SettingsModalContext'; 
- import Button from '../Button'; 
- import ButtonIcon from '../ButtonIcon'; 
- import TabBar from '../TabBar'; 
- import {StoreContext} from '../context'; 
- import { 
- useLocalStorage, 
- useModalDismissSignal, 
- useSubscription, 
- } from '../hooks'; 
- import ComponentsSettings from './ComponentsSettings'; 
- import DebuggingSettings from './DebuggingSettings'; 
- import GeneralSettings from './GeneralSettings'; 
- import ProfilerSettings from './ProfilerSettings'; 
- import styles from './SettingsModal.css'; 
- type TabID = 'general' | 'components' | 'profiler'; 
- export default function SettingsModal(_: {}): React.Node { 
- const {isModalShowing, setIsModalShowing} = useContext(SettingsModalContext); 
- const store = useContext(StoreContext); 
- const {profilerStore} = store; 
- // Updating preferences while profiling is in progress could break things (e.g. filtering) 
- // Explicitly disallow it for now. 
- const isProfilingSubscription = useMemo( 
- () => ({ 
- getCurrentValue: () => profilerStore.isProfiling, 
- subscribe: (callback: Function) => { 
- profilerStore.addListener('isProfiling', callback); 
- return () => profilerStore.removeListener('isProfiling', callback); 
- },
- }),
- [profilerStore], 
- );
- const isProfiling = useSubscription<boolean>(isProfilingSubscription); 
- if (isProfiling && isModalShowing) { 
- setIsModalShowing(false); 
- }
- if (!isModalShowing) { 
- return null; 
- }
- return <SettingsModalImpl />; 
- }
- function SettingsModalImpl(_: {}) { 
- const {setIsModalShowing} = useContext(SettingsModalContext); 
- const dismissModal = useCallback( 
- () => setIsModalShowing(false), 
- [setIsModalShowing], 
- );
- const [selectedTabID, selectTab] = useLocalStorage<TabID>( 
- 'React::DevTools::selectedSettingsTabID', 
- 'general', 
- ); 
- const modalRef = useRef<HTMLDivElement | null>(null); 
- useModalDismissSignal(modalRef, dismissModal); 
- useEffect(() => { 
- if (modalRef.current !== null) { 
- modalRef.current.focus(); 
- }
- }, [modalRef]); 
- let view = null; 
- switch (selectedTabID) { 
- case 'components': 
- view = <ComponentsSettings />; 
- break;
- // $FlowFixMe[incompatible-type] is this missing in TabID? 
- case 'debugging': 
- view = <DebuggingSettings />; 
- break;
- case 'general': 
- view = <GeneralSettings />; 
- break;
- case 'profiler': 
- view = <ProfilerSettings />; 
- break;
- default:
- break; 
- }
- return ( 
- <div className={styles.Background}> 
- <div className={styles.Modal} ref={modalRef}> 
- <div className={styles.Tabs}> 
- <TabBar 
- currentTab={selectedTabID} 
- id="Settings" 
- selectTab={selectTab} 
- tabs={tabs} 
- type="settings" 
- />
- <div className={styles.Spacer} /> 
- <Button onClick={dismissModal} title="Close settings dialog"> 
- <ButtonIcon type="close" /> 
- </Button> 
- </div> 
- <div className={styles.Content}>{view}</div> 
- </div> 
- </div> 
- );
- }
- const tabs = [ 
- {
- id: 'general',
- icon: 'settings',
- label: 'General',
- },
- {
- id: 'debugging',
- icon: 'bug',
- label: 'Debugging',
- },
- {
- id: 'components',
- icon: 'components',
- label: 'Components',
- },
- {
- id: 'profiler',
- icon: 'profiler',
- label: 'Profiler',
- },
- ];