1. <!DOCTYPE html>
    
  2. <html>
    
  3.   <head>
    
  4.     <meta charset="UTF-8" />
    
  5.     <title>TODO List</title>
    
  6. 
    
  7.     <!-- DevTools -->
    
  8.     <script src="http://localhost:8097"></script>
    
  9. 
    
  10.     <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    
  11.     <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
  12.     <script src="https://unpkg.com/[email protected]/dist/immutable.js"></script>
    
  13. 
    
  14.     <!-- Don't use this in production: -->
    
  15.     <script src="https://unpkg.com/[email protected]/babel.min.js"></script>
    
  16. 
    
  17.     <style type="text/css">
    
  18.       .Input {
    
  19.         font-size: 1rem;
    
  20.         padding: 0.25rem;
    
  21.       }
    
  22. 
    
  23.       .IconButton {
    
  24.         padding: 0.25rem;
    
  25.         border: none;
    
  26.         background: none;
    
  27.         cursor: pointer;
    
  28.       }
    
  29. 
    
  30.       .List {
    
  31.         margin: 0.5rem 0 0;
    
  32.         padding: 0;
    
  33.       }
    
  34. 
    
  35.       .ListItem {
    
  36.         list-style-type: none;
    
  37.       }
    
  38. 
    
  39.       .Label {
    
  40.         cursor: pointer;
    
  41.         padding: 0.25rem;
    
  42.         color: #555;
    
  43.       }
    
  44.       .Label:hover {
    
  45.         color: #000;
    
  46.       }
    
  47. 
    
  48.       .IconButton {
    
  49.         padding: 0.25rem;
    
  50.         border: none;
    
  51.         background: none;
    
  52.         cursor: pointer;
    
  53.       }
    
  54.     </style>
    
  55.   </head>
    
  56.   <body>
    
  57.     <div id="root"></div>
    
  58.     <script type="text/babel">
    
  59.       const { Fragment, useCallback, useState } = React;
    
  60. 
    
  61.       function List(props) {
    
  62.         const [newItemText, setNewItemText] = useState("");
    
  63.         const [items, setItems] = useState([
    
  64.           { id: 1, isComplete: true, text: "First" },
    
  65.           { id: 2, isComplete: true, text: "Second" },
    
  66.           { id: 3, isComplete: false, text: "Third" }
    
  67.         ]);
    
  68.         const [uid, setUID] = useState(4);
    
  69. 
    
  70.         const handleClick = useCallback(() => {
    
  71.           if (newItemText !== "") {
    
  72.             setItems([
    
  73.               ...items,
    
  74.               {
    
  75.                 id: uid,
    
  76.                 isComplete: false,
    
  77.                 text: newItemText
    
  78.               }
    
  79.             ]);
    
  80.             setUID(uid + 1);
    
  81.             setNewItemText("");
    
  82.           }
    
  83.         }, [newItemText, items, uid]);
    
  84. 
    
  85.         const handleKeyPress = useCallback(
    
  86.           event => {
    
  87.             if (event.key === "Enter") {
    
  88.               handleClick();
    
  89.             }
    
  90.           },
    
  91.           [handleClick]
    
  92.         );
    
  93. 
    
  94.         const handleChange = useCallback(
    
  95.           event => {
    
  96.             setNewItemText(event.currentTarget.value);
    
  97.           },
    
  98.           [setNewItemText]
    
  99.         );
    
  100. 
    
  101.         const removeItem = useCallback(
    
  102.           itemToRemove => setItems(items.filter(item => item !== itemToRemove)),
    
  103.           [items]
    
  104.         );
    
  105. 
    
  106.         const toggleItem = useCallback(
    
  107.           itemToToggle => {
    
  108.             const index = items.indexOf(itemToToggle);
    
  109. 
    
  110.             setItems(
    
  111.               items
    
  112.                 .slice(0, index)
    
  113.                 .concat({
    
  114.                   ...itemToToggle,
    
  115.                   isComplete: !itemToToggle.isComplete
    
  116.                 })
    
  117.                 .concat(items.slice(index + 1))
    
  118.             );
    
  119.           },
    
  120.           [items]
    
  121.         );
    
  122. 
    
  123.         return (
    
  124.           <Fragment>
    
  125.             <h1>List</h1>
    
  126.             <input
    
  127.               type="text"
    
  128.               placeholder="New list item..."
    
  129.               className="Input"
    
  130.               value={newItemText}
    
  131.               onChange={handleChange}
    
  132.               onKeyPress={handleKeyPress}
    
  133.             />
    
  134.             <button
    
  135.               className="IconButton"
    
  136.               disabled={newItemText === ""}
    
  137.               onClick={handleClick}
    
  138.             >
    
  139.               <span role="img" aria-label="Add item">
    
  140.               </span>
    
  141.             </button>
    
  142.             <ul className="List">
    
  143.               {items.map(item => (
    
  144.                 <ListItem
    
  145.                   key={item.id}
    
  146.                   item={item}
    
  147.                   removeItem={removeItem}
    
  148.                   toggleItem={toggleItem}
    
  149.                 />
    
  150.               ))}
    
  151.             </ul>
    
  152.           </Fragment>
    
  153.         );
    
  154.       }
    
  155. 
    
  156.       function ListItem({ item, removeItem, toggleItem }) {
    
  157.         const handleDelete = useCallback(() => {
    
  158.           removeItem(item);
    
  159.         }, [item, removeItem]);
    
  160. 
    
  161.         const handleToggle = useCallback(() => {
    
  162.           toggleItem(item);
    
  163.         }, [item, toggleItem]);
    
  164. 
    
  165.         return (
    
  166.           <li className="ListItem">
    
  167.             <button className="IconButton" onClick={handleDelete}>
    
  168.               🗑
    
  169.             </button>
    
  170.             <label className="Label">
    
  171.               <input
    
  172.                 className="Input"
    
  173.                 checked={item.isComplete}
    
  174.                 onChange={handleToggle}
    
  175.                 type="checkbox"
    
  176.               />{" "}
    
  177.               {item.text}
    
  178.             </label>
    
  179.           </li>
    
  180.         );
    
  181.       }
    
  182. 
    
  183.       function SimpleValues() {
    
  184.         return (
    
  185.           <ChildComponent
    
  186.             string="abc"
    
  187.             emptyString=""
    
  188.             number={123}
    
  189.             undefined={undefined}
    
  190.             null={null}
    
  191.             nan={NaN}
    
  192.             infinity={Infinity}
    
  193.             true={true}
    
  194.             false={false}
    
  195.           />
    
  196.         );
    
  197.       }
    
  198. 
    
  199.       class Custom {
    
  200.         _number = 42;
    
  201.         get number() {
    
  202.           return this._number;
    
  203.         }
    
  204.       }
    
  205. 
    
  206.       function CustomObject() {
    
  207.         return <ChildComponent customObject={new Custom()} />;
    
  208.       }
    
  209. 
    
  210.       const baseInheritedKeys = Object.create(Object.prototype, {
    
  211.       enumerableStringBase: {
    
  212.         value: 1,
    
  213.         writable: true,
    
  214.         enumerable: true,
    
  215.         configurable: true,
    
  216.       },
    
  217.       [Symbol('enumerableSymbolBase')]: {
    
  218.         value: 1,
    
  219.         writable: true,
    
  220.         enumerable: true,
    
  221.         configurable: true,
    
  222.       },
    
  223.       nonEnumerableStringBase: {
    
  224.         value: 1,
    
  225.         writable: true,
    
  226.         enumerable: false,
    
  227.         configurable: true,
    
  228.       },
    
  229.       [Symbol('nonEnumerableSymbolBase')]: {
    
  230.         value: 1,
    
  231.         writable: true,
    
  232.         enumerable: false,
    
  233.         configurable: true,
    
  234.       },
    
  235.     });
    
  236. 
    
  237.     const inheritedKeys = Object.create(baseInheritedKeys, {
    
  238.       enumerableString: {
    
  239.         value: 2,
    
  240.         writable: true,
    
  241.         enumerable: true,
    
  242.         configurable: true,
    
  243.       },
    
  244.       nonEnumerableString: {
    
  245.         value: 3,
    
  246.         writable: true,
    
  247.         enumerable: false,
    
  248.         configurable: true,
    
  249.       },
    
  250.       123: {
    
  251.         value: 3,
    
  252.         writable: true,
    
  253.         enumerable: true,
    
  254.         configurable: true,
    
  255.       },
    
  256.       [Symbol('nonEnumerableSymbol')]: {
    
  257.         value: 2,
    
  258.         writable: true,
    
  259.         enumerable: false,
    
  260.         configurable: true,
    
  261.       },
    
  262.       [Symbol('enumerableSymbol')]: {
    
  263.         value: 3,
    
  264.         writable: true,
    
  265.         enumerable: true,
    
  266.         configurable: true,
    
  267.       },
    
  268.       });
    
  269. 
    
  270.       function InheritedKeys() {
    
  271.         return <ChildComponent data={inheritedKeys} />;
    
  272.       }
    
  273. 
    
  274.       const object = {
    
  275.         string: "abc",
    
  276.         longString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKJLMNOPQRSTUVWXYZ1234567890",
    
  277.         emptyString: "",
    
  278.         number: 123,
    
  279.         boolean: true,
    
  280.         undefined: undefined,
    
  281.         null: null
    
  282.       };
    
  283. 
    
  284.       function ObjectProps() {
    
  285.         return (
    
  286.           <ChildComponent
    
  287.             object={{
    
  288.               outer: {
    
  289.                 inner: object
    
  290.               }
    
  291.             }}
    
  292.             array={["first", "second", "third"]}
    
  293.             objectInArray={[object]}
    
  294.             arrayInObject={{ array: ["first", "second", "third"] }}
    
  295.             deepObject={{
    
  296.               // Known limitation: we won't go deeper than several levels.
    
  297.               // In the future, we might offer a way to request deeper access on demand.
    
  298.               a: {
    
  299.                 b: {
    
  300.                   c: {
    
  301.                     d: {
    
  302.                       e: {
    
  303.                         f: {
    
  304.                           g: {
    
  305.                             h: {
    
  306.                               i: {
    
  307.                                 j: 10
    
  308.                               }
    
  309.                             }
    
  310.                           }
    
  311.                         }
    
  312.                       }
    
  313.                     }
    
  314.                   }
    
  315.                 }
    
  316.               }
    
  317.             }}
    
  318.           />
    
  319.         );
    
  320.       }
    
  321. 
    
  322.       const set = new Set(['abc', 123]);
    
  323.       const map = new Map([['name', 'Brian'], ['food', 'sushi']]);
    
  324.       const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
    
  325.       const mapOfMaps = new Map([['first', map], ['second', map]]);
    
  326.       const typedArray = Int8Array.from([100, -100, 0]);
    
  327.       const immutable = Immutable.fromJS({
    
  328.         a: [{ hello: 'there' }, 'fixed', true],
    
  329.         b: 123,
    
  330.         c: {
    
  331.           '1': 'xyz',
    
  332.           xyz: 1,
    
  333.         },
    
  334.       });
    
  335. 
    
  336.       class Foo {
    
  337.         flag = false;
    
  338.         object = {a: {b: {c: {d: 1}}}}
    
  339.       }
    
  340. 
    
  341.       function UnserializableProps() {
    
  342.         return (
    
  343.           <ChildComponent
    
  344.             map={map}
    
  345.             set={set}
    
  346.             mapOfMaps={mapOfMaps}
    
  347.             setOfSets={setOfSets}
    
  348.             typedArray={typedArray}
    
  349.             immutable={immutable}
    
  350.             classInstance={new Foo()}
    
  351.           />
    
  352.         );
    
  353.       }
    
  354. 
    
  355.       function ChildComponent(props: any) {
    
  356.         return null;
    
  357.       }
    
  358. 
    
  359.       function InspectableElements() {
    
  360.         return (
    
  361.           <Fragment>
    
  362.             <SimpleValues />
    
  363.             <ObjectProps />
    
  364.             <UnserializableProps />
    
  365.             <CustomObject />
    
  366.             <InheritedKeys />
    
  367.           </Fragment>
    
  368.         );
    
  369.       }
    
  370. 
    
  371.       function App() {
    
  372.         return (
    
  373.           <Fragment>
    
  374.             <List />
    
  375.             <InspectableElements />
    
  376.           </Fragment>
    
  377.         );
    
  378.       }
    
  379. 
    
  380.       ReactDOM.render(<App />, document.getElementById("root"));
    
  381.     </script>
    
  382.   </body>
    
  383. </html>