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