Repository: facebook/react
Pull request: [DevTools] add support for HostSingleton & HostResource

## Summary

This is to support two new reconciler work tags `HostSingleton` and `HostResource` introduced in PRs #25243 #25426. The behavior is described below.
I also renamed an option in components settings from an internal concept "host" to more understood "dom nodes"

## How did you test this change?

Tested on the latest Vercel playground app https://github.com/vercel/app-playground/

Before the change, devtools cannot show correct display name for these new elements. Also, some unnecessary internal details are exposed to users.
<img width="1395" alt="image" src="https://user-images.githubusercontent.com/1001890/199578181-c4e4ea74-baa1-4507-83d0-91a62ad7de5f.png">

After the change, the display names are correctly shown and the "state" would always be hidden in the detail view.
<img width="1417" alt="image" src="https://user-images.githubusercontent.com/1001890/199578442-adc1951d-7d5b-4b84-ad64-85bcf7a8ebcc.png">

These elements will also be hidden just like other native dom elements (e.g. `<div>`)
<img width="836" alt="image" src="https://user-images.githubusercontent.com/1001890/199578598-2dfacf64-ddc9-42b5-a246-dd0b09f629af.png">





Changed files:
filename: packages/react-devtools-shared/src/backend/renderer.js
patch: @@ -237,6 +237,8 @@ export function getInternalReactConstants(
       HostComponent: 5,
       HostPortal: 4,
       HostRoot: 3,
+      HostResource: 26, // In reality, 18.2+. But doesn't hurt to include it here
+      HostSingleton: 27, // Same as above
       HostText: 6,
       IncompleteClassComponent: 17,
       IndeterminateComponent: 2,
@@ -269,6 +271,8 @@ export function getInternalReactConstants(
       HostComponent: 5,
       HostPortal: 4,
       HostRoot: 3,
+      HostResource: -1, // Doesn't exist yet
+      HostSingleton: -1, // Doesn't exist yet
       HostText: 6,
       IncompleteClassComponent: 17,
       IndeterminateComponent: 2,
@@ -300,6 +304,8 @@ export function getInternalReactConstants(
       HostComponent: 5,
       HostPortal: 4,
       HostRoot: 3,
+      HostResource: -1, // Doesn't exist yet
+      HostSingleton: -1, // Doesn't exist yet
       HostText: 6,
       IncompleteClassComponent: 17,
       IndeterminateComponent: 2,
@@ -331,6 +337,8 @@ export function getInternalReactConstants(
       HostComponent: 7,
       HostPortal: 6,
       HostRoot: 5,
+      HostResource: -1, // Doesn't exist yet
+      HostSingleton: -1, // Doesn't exist yet
       HostText: 8,
       IncompleteClassComponent: -1, // Doesn't exist yet
       IndeterminateComponent: 4,
@@ -362,6 +370,8 @@ export function getInternalReactConstants(
       HostComponent: 5,
       HostPortal: 4,
       HostRoot: 3,
+      HostResource: -1, // Doesn't exist yet
+      HostSingleton: -1, // Doesn't exist yet
       HostText: 6,
       IncompleteClassComponent: -1, // Doesn't exist yet
       IndeterminateComponent: 0,
@@ -401,6 +411,8 @@ export function getInternalReactConstants(
     IndeterminateComponent,
     ForwardRef,
     HostRoot,
+    HostResource,
+    HostSingleton,
     HostComponent,
     HostPortal,
     HostText,
@@ -466,6 +478,8 @@ export function getInternalReactConstants(
         }
         return null;
       case HostComponent:
+      case HostSingleton:
+      case HostResource:
         return type;
       case HostPortal:
       case HostText:
@@ -600,6 +614,8 @@ export function attach(
     Fragment,
     FunctionComponent,
     HostRoot,
+    HostResource,
+    HostSingleton,
     HostPortal,
     HostComponent,
     HostText,
@@ -1044,6 +1060,8 @@ export function attach(
       case HostRoot:
         return ElementTypeRoot;
       case HostComponent:
+      case HostResource:
+      case HostSingleton:
         return ElementTypeHostComponent;
       case HostPortal:
       case HostText:

filename: packages/react-devtools-shared/src/backend/types.js
patch: @@ -40,6 +40,8 @@ export type WorkTagMap = {
   HostComponent: WorkTag,
   HostPortal: WorkTag,
   HostRoot: WorkTag,
+  HostResource: WorkTag,
+  HostSingleton: WorkTag,
   HostText: WorkTag,
   IncompleteClassComponent: WorkTag,
   IndeterminateComponent: WorkTag,

filename: packages/react-devtools-shared/src/devtools/views/Components/InspectedElementStateTree.js
patch: @@ -9,6 +9,7 @@
 
 import {copy} from 'clipboard-js';
 import * as React from 'react';
+import {ElementTypeHostComponent} from 'react-devtools-shared/src/types';
 import Button from '../Button';
 import ButtonIcon from '../ButtonIcon';
 import KeyValue from './KeyValue';
@@ -33,52 +34,55 @@ export default function InspectedElementStateTree({
   inspectedElement,
   store,
 }: Props): React.Node {
-  const {state} = inspectedElement;
+  const {state, type} = inspectedElement;
+
+  // HostSingleton and HostResource may have state that we don't want to expose to users
+  const isHostComponent = type === ElementTypeHostComponent;
 
   const entries = state != null ? Object.entries(state) : null;
+  const isEmpty = entries === null || entries.length === 0;
+
+  if (isEmpty || isHostComponent) {
+    return null;
+  }
+
   if (entries !== null) {
     entries.sort(alphaSortEntries);
   }
 
-  const isEmpty = entries === null || entries.length === 0;
-
   const handleCopy = () => copy(serializeDataForCopy(((state: any): Object)));
 
-  if (isEmpty) {
-    return null;
-  } else {
-    return (
-      <div className={styles.InspectedElementTree}>
-        <div className={styles.HeaderRow}>
-          <div className={styles.Header}>state</div>
-          {!isEmpty && (
-            <Button onClick={handleCopy} title="Copy to clipboard">
-              <ButtonIcon type="copy" />
-            </Button>
-          )}
-        </div>
-        {isEmpty && <div className={styles.Empty}>None</div>}
-        {!isEmpty &&
-          (entries: any).map(([name, value]) => (
-            <KeyValue
-              key={name}
-              alphaSort={true}
-              bridge={bridge}
-              canDeletePaths={true}
-              canEditValues={true}
-              canRenamePaths={true}
-              depth={1}
-              element={element}
-              hidden={false}
-              inspectedElement={inspectedElement}
-              name={name}
-              path={[name]}
-              pathRoot="state"
-              store={store}
-              value={value}
-            />
-          ))}
+  return (
+    <div className={styles.InspectedElementTree}>
+      <div className={styles.HeaderRow}>
+        <div className={styles.Header}>state</div>
+        {!isEmpty && (
+          <Button onClick={handleCopy} title="Copy to clipboard">
+            <ButtonIcon type="copy" />
+          </Button>
+        )}
       </div>
-    );
-  }
+      {isEmpty && <div className={styles.Empty}>None</div>}
+      {!isEmpty &&
+        (entries: any).map(([name, value]) => (
+          <KeyValue
+            key={name}
+            alphaSort={true}
+            bridge={bridge}
+            canDeletePaths={true}
+            canEditValues={true}
+            canRenamePaths={true}
+            depth={1}
+            element={element}
+            hidden={false}
+            inspectedElement={inspectedElement}
+            name={name}
+            path={[name]}
+            pathRoot="state"
+            store={store}
+            value={value}
+          />
+        ))}
+    </div>
+  );
 }

filename: packages/react-devtools-shared/src/devtools/views/Settings/ComponentsSettings.js
patch: @@ -373,7 +373,7 @@ export default function ComponentsSettings(_: {}): React.Node {
                     <option value={ElementTypeFunction}>function</option>
                     <option value={ElementTypeForwardRef}>forward ref</option>
                     <option value={ElementTypeHostComponent}>
-                      host (e.g. &lt;div&gt;)
+                      dom nodes (e.g. &lt;div&gt;)
                     </option>
                     <option value={ElementTypeMemo}>memo</option>
                     <option value={ElementTypeOtherOrUnknown}>other</option>