main
js 102 lines 2.67 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import type {ReactContext} from 'shared/ReactTypes';
11
12 import * as React from 'react';
13 import {
14 createContext,
15 useContext,
16 useCallback,
17 useState,
18 startTransition,
19 } from 'react';
20
21 import {BridgeContext, StoreContext} from '../context';
22
23 import type {FrontendBridge} from '../../../bridge';
24 import type {DevToolsHookSettings} from '../../../backend/types';
25 import type Store from '../../store';
26
27 export type Theme = 'auto' | 'light' | 'dark';
28
29 type Context = {
30 isModalShowing: boolean,
31 setIsModalShowing: (value: boolean) => void,
32 environmentNames: null | Promise<Array<string>>,
33 hookSettings: null | Promise<$ReadOnly<DevToolsHookSettings>>,
34 };
35
36 const SettingsModalContext: ReactContext<Context> = createContext<Context>(
37 null as any as Context,
38 );
39 SettingsModalContext.displayName = 'SettingsModalContext';
40
41 function fetchEnvironmentNames(bridge: FrontendBridge): Promise<Array<string>> {
42 return new Promise(resolve => {
43 function onEnvironmentNames(names: Array<string>) {
44 bridge.removeListener('environmentNames', onEnvironmentNames);
45 resolve(names);
46 }
47 bridge.addListener('environmentNames', onEnvironmentNames);
48 bridge.send('getEnvironmentNames');
49 });
50 }
51
52 function fetchHookSettings(
53 store: Store,
54 ): Promise<$ReadOnly<DevToolsHookSettings>> {
55 return new Promise(resolve => {
56 function onHookSettings(settings: $ReadOnly<DevToolsHookSettings>) {
57 store.removeListener('hookSettings', onHookSettings);
58 resolve(settings);
59 }
60
61 store.addListener('hookSettings', onHookSettings);
62 store.getHookSettings();
63 });
64 }
65
66 function SettingsModalContextController({
67 children,
68 }: {
69 children: React$Node,
70 }): React.Node {
71 const bridge = useContext(BridgeContext);
72 const store = useContext(StoreContext);
73
74 const setIsModalShowing: boolean => void = useCallback(
75 (value: boolean) => {
76 startTransition(() => {
77 setContext({
78 isModalShowing: value,
79 setIsModalShowing,
80 environmentNames: value ? fetchEnvironmentNames(bridge) : null,
81 hookSettings: value ? fetchHookSettings(store) : null,
82 });
83 });
84 },
85 [bridge, store],
86 );
87
88 const [currentContext, setContext] = useState<Context>({
89 isModalShowing: false,
90 setIsModalShowing,
91 environmentNames: null,
92 hookSettings: null,
93 });
94
95 return (
96 <SettingsModalContext.Provider value={currentContext}>
97 {children}
98 </SettingsModalContext.Provider>
99 );
100 }
101
102 export {SettingsModalContext, SettingsModalContextController};