main
js 96 lines 2.85 KB
Raw
1 /** @flow */
2
3 import * as React from 'react';
4 import {forwardRef} from 'react';
5 import Bridge from 'react-devtools-shared/src/bridge';
6 import Store from 'react-devtools-shared/src/devtools/store';
7 import {subscribeToStoreErrors} from 'react-devtools-shared/src/devtools/storeErrorLogger';
8 import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
9 import {getSavedComponentFilters} from 'react-devtools-shared/src/utils';
10
11 import type {Wall} from 'react-devtools-shared/src/frontend/types';
12 import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
13 import type {Props} from 'react-devtools-shared/src/devtools/views/DevTools';
14 import type {Config} from 'react-devtools-shared/src/devtools/store';
15
16 export function createStore(bridge: FrontendBridge, config?: Config): Store {
17 const store = new Store(bridge, {
18 checkBridgeProtocolCompatibility: true,
19 supportsTraceUpdates: true,
20 ...config,
21 });
22 subscribeToStoreErrors(store, bridge);
23 return store;
24 }
25
26 export function createBridge(contentWindow: any, wall?: Wall): FrontendBridge {
27 if (wall == null) {
28 wall = {
29 listen(fn) {
30 // $FlowFixMe[missing-local-annot]
31 const onMessage = ({data}) => {
32 fn(data);
33 };
34 window.addEventListener('message', onMessage);
35 return () => {
36 window.removeEventListener('message', onMessage);
37 };
38 },
39 send(
40 event: string,
41 payload: mixed,
42 transferable?: $ReadOnlyArray<mixed>,
43 ) {
44 contentWindow.postMessage({event, payload}, '*', transferable);
45 },
46 };
47 }
48
49 return new Bridge(wall) as FrontendBridge;
50 }
51
52 export function initialize(
53 contentWindow: any,
54 {
55 bridge,
56 store,
57 }: {
58 bridge?: FrontendBridge,
59 store?: Store,
60 } = {},
61 ): component(...props: Props) {
62 if (bridge == null) {
63 bridge = createBridge(contentWindow);
64 }
65
66 // Type refinement.
67 const frontendBridge = bridge as any as FrontendBridge;
68
69 if (store == null) {
70 store = createStore(frontendBridge);
71 }
72
73 const onGetSavedPreferences = () => {
74 // This is the only message we're listening for,
75 // so it's safe to cleanup after we've received it.
76 frontendBridge.removeListener('getSavedPreferences', onGetSavedPreferences);
77
78 const data = {
79 componentFilters: getSavedComponentFilters(),
80 };
81
82 // The renderer interface can't read saved preferences directly,
83 // because they are stored in localStorage within the context of the extension.
84 // Instead it relies on the extension to pass them through.
85 frontendBridge.send('savedPreferences', data);
86 };
87
88 frontendBridge.addListener('getSavedPreferences', onGetSavedPreferences);
89
90 const ForwardRef = forwardRef<Props, mixed>((props, ref) => (
91 <DevTools ref={ref} bridge={frontendBridge} store={store} {...props} />
92 ));
93 ForwardRef.displayName = 'DevTools';
94
95 return ForwardRef;
96 }