1. <!DOCTYPE html>
    
  2. <html>
    
  3.   <head>
    
  4.     <title>React Developer Tools</title>
    
  5.     <meta charset="utf8" />
    
  6.     <style>
    
  7.       html {
    
  8.         height: 100%;
    
  9.         font-family: sans-serif;
    
  10.       }
    
  11.       body {
    
  12.         height: 100%;
    
  13.         margin: 0;
    
  14.         padding: 0;
    
  15.         background-color: #fff;
    
  16.         color: #777d88;
    
  17.       }
    
  18. 
    
  19.       .container {
    
  20.         height: 100%;
    
  21.         display: flex;
    
  22.         flex-direction: column;
    
  23.         align-items: center;
    
  24.         justify-content: center;
    
  25.         overflow: auto;
    
  26.       }
    
  27. 
    
  28.       p {
    
  29.         padding: 0;
    
  30.         margin: 0;
    
  31.       }
    
  32. 
    
  33.       .input {
    
  34.         display: block;
    
  35.         font-weight: 100;
    
  36.         padding: 0 0.25rem;
    
  37.         border: 1px solid #aaa;
    
  38.         background-color: #fff;
    
  39.         color: #666;
    
  40.       }
    
  41. 
    
  42.       .link {
    
  43.         color: #1478fa;
    
  44.         text-decoration: none;
    
  45.       }
    
  46.       .link:hover {
    
  47.         text-decoration: underline;
    
  48.       }
    
  49. 
    
  50.       .waiting-header {
    
  51.         padding: 0.5rem;
    
  52.         display: inline-block;
    
  53.         position: absolute;
    
  54.         right: 0.5rem;
    
  55.         top: 0.5rem;
    
  56.         border-radius: 0.25rem;
    
  57.         background-color: rgba(0,1,2,.6);
    
  58.         color: white;
    
  59.         border: none;
    
  60.         font-weight: 100;
    
  61.         font-style: italic;
    
  62.       }
    
  63. 
    
  64.       .boxes {
    
  65.         display: flex;
    
  66.         flex-direction: column;
    
  67.         align-items: stretch;
    
  68.         justify-content: center;
    
  69.         padding: 1rem;
    
  70.       }
    
  71.       .box {
    
  72.         text-align: center;
    
  73.         border-radius: 0.5rem;
    
  74.         background-color: #f7f7f7;
    
  75.         border: 1px solid #eee;
    
  76.         color: #777d88;
    
  77.         padding: 1rem;
    
  78.         margin-top: 1rem;
    
  79.       }
    
  80.       .box:first-of-type {
    
  81.         margin-top: 0;
    
  82.       }
    
  83. 
    
  84.       .box-header {
    
  85.         text-align: center;
    
  86.         color: #5f6673;
    
  87.         font-size: 1.25rem;
    
  88.         margin-bottom: 0.5rem;
    
  89.       }
    
  90.       .box-content {
    
  91.         line-height: 1.5rem;
    
  92.       }
    
  93. 
    
  94.       #loading-status {
    
  95.         text-align: center;
    
  96.         margin-top: 1rem;
    
  97.       }
    
  98. 
    
  99.       .prompt,
    
  100.       .confirmation {
    
  101.         margin-bottom: 0.25rem;
    
  102.       }
    
  103. 
    
  104.       .confirmation {
    
  105.         font-style: italic;
    
  106.       }
    
  107. 
    
  108.       .hidden {
    
  109.         display: none;
    
  110.       }
    
  111.     </style>
    
  112.   </head>
    
  113.   <body>
    
  114.     <div id="container" class="container" style="-webkit-user-select: none; -webkit-app-region: drag;">
    
  115.       <div class="waiting-header">Waiting for React to connect…</div>
    
  116.       <div class="boxes" style="-webkit-app-region: none;">
    
  117.         <div class="box">
    
  118.           <div class="box-header">React Native</div>
    
  119.           <div class="box-content">
    
  120.             Open the <a
    
  121.               id="rn-help-link"
    
  122.               class="link"
    
  123.               target="_blank"
    
  124.               rel="noopener noreferrer"
    
  125.               href="https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu"
    
  126.             >in-app developer menu</a> to connect.
    
  127.           </div>
    
  128.         </div>
    
  129.         <div class="box">
    
  130.           <div class="box-header">React DOM</div>
    
  131.           <div class="box-content">
    
  132.             <div id="box-content-prompt" class="prompt">
    
  133.               Add one of the following (click to copy):
    
  134.             </div>
    
  135.             <div id="box-content-confirmation" class="confirmation hidden">
    
  136.               Copied to clipboard.
    
  137.             </div>
    
  138.             <span class="input" contenteditable="true" id="localhost"></span>
    
  139.             <span class="input" contenteditable="true" id="byip"></span>
    
  140.             to the top of the page you want to debug,
    
  141.             <br />
    
  142.             <strong>before</strong> importing React DOM.
    
  143.           </div>
    
  144.         </div>
    
  145.         <div class="box">
    
  146.           <div class="box-header">Profiler</div>
    
  147.           <div class="box-content">
    
  148.             Open the <a
    
  149.               id="profiler"
    
  150.               class="link"
    
  151.               href="#"
    
  152.             >Profiler tab</a> to inspect saved profiles.
    
  153.           </div>
    
  154.         </div>
    
  155.         <div id="loading-status">Starting the server…</div>
    
  156.       </div>
    
  157.     </div>
    
  158.     <script>
    
  159.       // window.api is defined in preload.js
    
  160.       const {electron, readEnv, ip, getDevTools} = window.api;
    
  161.       const {options, useHttps, host, protocol, port} = readEnv();
    
  162. 
    
  163.       const localIp = ip.address();
    
  164.       const defaultPort = (port === 443 && useHttps) || (port === 80 && !useHttps);
    
  165.       const server = defaultPort ? `${protocol}://${host}` : `${protocol}://${host}:${port}`;
    
  166.       const serverIp = defaultPort ? `${protocol}://${localIp}` : `${protocol}://${localIp}:${port}`;
    
  167.       const $ = document.querySelector.bind(document);
    
  168.       
    
  169.       let timeoutID;
    
  170.       
    
  171.       function selectAllAndCopy(event) {
    
  172.         const element = event.target;
    
  173.         if (window.getSelection) {
    
  174.           const selection = window.getSelection();
    
  175.           const range = document.createRange();
    
  176.           range.selectNodeContents(element);
    
  177.           selection.removeAllRanges();
    
  178.           selection.addRange(range);
    
  179.           electron.clipboard.writeText(event.target.textContent);
    
  180.           
    
  181.           const $promptDiv = $("#box-content-prompt");
    
  182.           const $confirmationDiv = $("#box-content-confirmation");
    
  183.           $promptDiv.classList.add('hidden');
    
  184.           $confirmationDiv.classList.remove('hidden');
    
  185. 
    
  186.           if (timeoutID) {
    
  187.             clearTimeout(timeoutID);
    
  188.           }
    
  189. 
    
  190.           timeoutID = setTimeout(() => {
    
  191.             $promptDiv.classList.remove('hidden');
    
  192.             $confirmationDiv.classList.add('hidden');
    
  193.           }, 1000);
    
  194.         }
    
  195.       }
    
  196. 
    
  197.       function openProfiler() {
    
  198.         window.devtools
    
  199.           .setContentDOMNode(document.getElementById("container"))
    
  200.           .openProfiler();
    
  201.       }
    
  202. 
    
  203.       function attachListeners() {
    
  204.         const link = $('#rn-help-link');
    
  205.         link.addEventListener('click', event => {
    
  206.           event.preventDefault();
    
  207.           electron.shell.openExternal(link.href);
    
  208.         });
    
  209.   
    
  210.         const $localhost = $("#localhost");
    
  211.         $localhost.innerText = `<script src="${server}"></` + 'script>';
    
  212.         $localhost.addEventListener('click', selectAllAndCopy);
    
  213.         $localhost.addEventListener('focus', selectAllAndCopy);
    
  214.   
    
  215.         const $byIp = $("#byip");
    
  216.         $byIp.innerText = `<script src="${serverIp}"></` + 'script>';
    
  217.         $byIp.addEventListener('click', selectAllAndCopy);
    
  218.         $byIp.addEventListener('focus', selectAllAndCopy);
    
  219.   
    
  220.         const $profiler = $("#profiler");
    
  221.         $profiler.addEventListener('click', openProfiler);
    
  222.       };
    
  223. 
    
  224.       // Initially attach the listeners
    
  225.       attachListeners();
    
  226. 
    
  227.       window.devtools = getDevTools();
    
  228.       window.server = window.devtools
    
  229.         .setContentDOMNode(document.getElementById("container"))
    
  230.         .setDisconnectedCallback(attachListeners)
    
  231.         .setStatusListener(function(status) {
    
  232.           const element = document.getElementById("loading-status");
    
  233.           if (element) {
    
  234.             element.innerText = status;
    
  235.           }
    
  236.         })
    
  237.         .startServer(port, host, options);
    
  238.     </script>
    
  239.   </body>
    
  240. </html>