main
html 384 lines 9.38 KB
Raw
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/immutable@4.0.0-rc.12/dist/immutable.js"></script>
13
14 <!-- Don't use this in production: -->
15 <script src="https://unpkg.com/babel-standalone@6.15.0/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
141 </span>
142 </button>
143 <ul className="List">
144 {items.map(item => (
145 <ListItem
146 key={item.id}
147 item={item}
148 removeItem={removeItem}
149 toggleItem={toggleItem}
150 />
151 ))}
152 </ul>
153 </Fragment>
154 );
155 }
156
157 function ListItem({ item, removeItem, toggleItem }) {
158 const handleDelete = useCallback(() => {
159 removeItem(item);
160 }, [item, removeItem]);
161
162 const handleToggle = useCallback(() => {
163 toggleItem(item);
164 }, [item, toggleItem]);
165
166 return (
167 <li className="ListItem">
168 <button className="IconButton" onClick={handleDelete}>
169 🗑
170 </button>
171 <label className="Label">
172 <input
173 className="Input"
174 checked={item.isComplete}
175 onChange={handleToggle}
176 type="checkbox"
177 />{" "}
178 {item.text}
179 </label>
180 </li>
181 );
182 }
183
184 function SimpleValues() {
185 return (
186 <ChildComponent
187 string="abc"
188 emptyString=""
189 number={123}
190 undefined={undefined}
191 null={null}
192 nan={NaN}
193 infinity={Infinity}
194 true={true}
195 false={false}
196 />
197 );
198 }
199
200 class Custom {
201 _number = 42;
202 get number() {
203 return this._number;
204 }
205 }
206
207 function CustomObject() {
208 return <ChildComponent customObject={new Custom()} />;
209 }
210
211 const baseInheritedKeys = Object.create(Object.prototype, {
212 enumerableStringBase: {
213 value: 1,
214 writable: true,
215 enumerable: true,
216 configurable: true,
217 },
218 [Symbol('enumerableSymbolBase')]: {
219 value: 1,
220 writable: true,
221 enumerable: true,
222 configurable: true,
223 },
224 nonEnumerableStringBase: {
225 value: 1,
226 writable: true,
227 enumerable: false,
228 configurable: true,
229 },
230 [Symbol('nonEnumerableSymbolBase')]: {
231 value: 1,
232 writable: true,
233 enumerable: false,
234 configurable: true,
235 },
236 });
237
238 const inheritedKeys = Object.create(baseInheritedKeys, {
239 enumerableString: {
240 value: 2,
241 writable: true,
242 enumerable: true,
243 configurable: true,
244 },
245 nonEnumerableString: {
246 value: 3,
247 writable: true,
248 enumerable: false,
249 configurable: true,
250 },
251 123: {
252 value: 3,
253 writable: true,
254 enumerable: true,
255 configurable: true,
256 },
257 [Symbol('nonEnumerableSymbol')]: {
258 value: 2,
259 writable: true,
260 enumerable: false,
261 configurable: true,
262 },
263 [Symbol('enumerableSymbol')]: {
264 value: 3,
265 writable: true,
266 enumerable: true,
267 configurable: true,
268 },
269 });
270
271 function InheritedKeys() {
272 return <ChildComponent data={inheritedKeys} />;
273 }
274
275 const object = {
276 string: "abc",
277 longString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKJLMNOPQRSTUVWXYZ1234567890",
278 emptyString: "",
279 number: 123,
280 boolean: true,
281 undefined: undefined,
282 null: null
283 };
284
285 function ObjectProps() {
286 return (
287 <ChildComponent
288 object={{
289 outer: {
290 inner: object
291 }
292 }}
293 array={["first", "second", "third"]}
294 objectInArray={[object]}
295 arrayInObject={{ array: ["first", "second", "third"] }}
296 deepObject={{
297 // Known limitation: we won't go deeper than several levels.
298 // In the future, we might offer a way to request deeper access on demand.
299 a: {
300 b: {
301 c: {
302 d: {
303 e: {
304 f: {
305 g: {
306 h: {
307 i: {
308 j: 10
309 }
310 }
311 }
312 }
313 }
314 }
315 }
316 }
317 }
318 }}
319 />
320 );
321 }
322
323 const set = new Set(['abc', 123]);
324 const map = new Map([['name', 'Brian'], ['food', 'sushi']]);
325 const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
326 const mapOfMaps = new Map([['first', map], ['second', map]]);
327 const typedArray = Int8Array.from([100, -100, 0]);
328 const immutable = Immutable.fromJS({
329 a: [{ hello: 'there' }, 'fixed', true],
330 b: 123,
331 c: {
332 '1': 'xyz',
333 xyz: 1,
334 },
335 });
336
337 class Foo {
338 flag = false;
339 object = {a: {b: {c: {d: 1}}}}
340 }
341
342 function UnserializableProps() {
343 return (
344 <ChildComponent
345 map={map}
346 set={set}
347 mapOfMaps={mapOfMaps}
348 setOfSets={setOfSets}
349 typedArray={typedArray}
350 immutable={immutable}
351 classInstance={new Foo()}
352 />
353 );
354 }
355
356 function ChildComponent(props: any) {
357 return null;
358 }
359
360 function InspectableElements() {
361 return (
362 <Fragment>
363 <SimpleValues />
364 <ObjectProps />
365 <UnserializableProps />
366 <CustomObject />
367 <InheritedKeys />
368 </Fragment>
369 );
370 }
371
372 function App() {
373 return (
374 <Fragment>
375 <List />
376 <InspectableElements />
377 </Fragment>
378 );
379 }
380
381 ReactDOM.render(<App />, document.getElementById("root"));
382 </script>
383 </body>
384 </html>