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';
import type Store from 'react-devtools-shared/src/devtools/store';
type TabID = 'general' | 'debugging' | 'components' | 'profiler';
export default function SettingsModal(): React.Node {
const {isModalShowing, setIsModalShowing} = useContext(SettingsModalContext);
const store = useContext(StoreContext);
const {profilerStore} = store;
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 store={store} />;
}
type ImplProps = {store: Store};
function SettingsModalImpl({store}: ImplProps) {
const {setIsModalShowing, environmentNames, hookSettings} =
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 environmentNames={environmentNames} />;
break;
case 'debugging':
view = <DebuggingSettings hookSettings={hookSettings} store={store} />;
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',
},
];