@khanacademy/wonder-blocks-form 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/dist/es/index.js +1100 -0
  3. package/dist/index.js +1419 -0
  4. package/dist/index.js.flow +2 -0
  5. package/docs.md +1 -0
  6. package/package.json +35 -0
  7. package/src/__tests__/__snapshots__/custom-snapshot.test.js.snap +1349 -0
  8. package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +6126 -0
  9. package/src/__tests__/custom-snapshot.test.js +66 -0
  10. package/src/__tests__/generated-snapshot.test.js +654 -0
  11. package/src/components/__tests__/checkbox-group.test.js +84 -0
  12. package/src/components/__tests__/field-heading.test.js +182 -0
  13. package/src/components/__tests__/labeled-text-field.test.js +442 -0
  14. package/src/components/__tests__/radio-group.test.js +84 -0
  15. package/src/components/__tests__/text-field.test.js +424 -0
  16. package/src/components/checkbox-core.js +201 -0
  17. package/src/components/checkbox-group.js +161 -0
  18. package/src/components/checkbox-group.md +200 -0
  19. package/src/components/checkbox.js +94 -0
  20. package/src/components/checkbox.md +134 -0
  21. package/src/components/choice-internal.js +206 -0
  22. package/src/components/choice.js +104 -0
  23. package/src/components/field-heading.js +157 -0
  24. package/src/components/field-heading.md +43 -0
  25. package/src/components/group-styles.js +35 -0
  26. package/src/components/labeled-text-field.js +265 -0
  27. package/src/components/labeled-text-field.md +535 -0
  28. package/src/components/labeled-text-field.stories.js +359 -0
  29. package/src/components/radio-core.js +176 -0
  30. package/src/components/radio-group.js +142 -0
  31. package/src/components/radio-group.md +129 -0
  32. package/src/components/radio.js +93 -0
  33. package/src/components/radio.md +26 -0
  34. package/src/components/text-field.js +326 -0
  35. package/src/components/text-field.md +770 -0
  36. package/src/components/text-field.stories.js +513 -0
  37. package/src/index.js +18 -0
  38. package/src/util/types.js +77 -0
@@ -0,0 +1,770 @@
1
+ Text
2
+
3
+ ```js
4
+ import {TextField} from "@khanacademy/wonder-blocks-form";
5
+
6
+ class TextFieldExample extends React.Component {
7
+ constructor(props) {
8
+ super(props);
9
+ this.state = {
10
+ value: "",
11
+ };
12
+ this.handleChange = this.handleChange.bind(this);
13
+ this.handleKeyDown = this.handleKeyDown.bind(this);
14
+ }
15
+
16
+ handleChange(newValue) {
17
+ this.setState({value: newValue});
18
+ }
19
+
20
+ handleKeyDown(event) {
21
+ if (event.key === "Enter") {
22
+ event.currentTarget.blur();
23
+ }
24
+ }
25
+
26
+ render() {
27
+ return (
28
+ <TextField
29
+ id="tf-1"
30
+ type="text"
31
+ value={this.state.value}
32
+ placeholder="Text"
33
+ onChange={this.handleChange}
34
+ onKeyDown={this.handleKeyDown}
35
+ />
36
+ );
37
+ }
38
+ }
39
+
40
+ <TextFieldExample />
41
+ ```
42
+
43
+ Number
44
+
45
+ ```js
46
+ import {TextField} from "@khanacademy/wonder-blocks-form";
47
+
48
+ class TextFieldExample extends React.Component {
49
+ constructor(props) {
50
+ super(props);
51
+ this.state = {
52
+ value: "12345",
53
+ };
54
+ this.handleChange = this.handleChange.bind(this);
55
+ this.handleKeyDown = this.handleKeyDown.bind(this);
56
+ }
57
+
58
+ handleChange(newValue) {
59
+ this.setState({value: newValue});
60
+ }
61
+
62
+ handleKeyDown(event) {
63
+ if (event.key === "Enter") {
64
+ event.currentTarget.blur();
65
+ }
66
+ }
67
+
68
+ render() {
69
+ return (
70
+ <TextField
71
+ id="tf-2"
72
+ type="number"
73
+ value={this.state.value}
74
+ placeholder="Number"
75
+ onChange={this.handleChange}
76
+ onKeyDown={this.handleKeyDown}
77
+ />
78
+ );
79
+ }
80
+ }
81
+
82
+ <TextFieldExample />
83
+ ```
84
+
85
+ Password (with Validation)
86
+
87
+ ```js
88
+ import {StyleSheet} from "aphrodite";
89
+ import {View, Text} from "@khanacademy/wonder-blocks-core";
90
+ import Color from "@khanacademy/wonder-blocks-color";
91
+ import {Strut} from "@khanacademy/wonder-blocks-layout";
92
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
93
+ import {TextField} from "@khanacademy/wonder-blocks-form";
94
+
95
+ class TextFieldExample extends React.Component {
96
+ constructor(props) {
97
+ super(props);
98
+ this.state = {
99
+ value: "Password123",
100
+ errorMessage: null,
101
+ focused: false,
102
+ };
103
+ this.validate = this.validate.bind(this);
104
+ this.handleValidate = this.handleValidate.bind(this);
105
+ this.handleChange = this.handleChange.bind(this);
106
+ this.handleKeyDown = this.handleKeyDown.bind(this);
107
+ this.handleFocus = this.handleFocus.bind(this);
108
+ this.handleBlur = this.handleBlur.bind(this);
109
+ }
110
+
111
+ validate(value) {
112
+ if (value.length < 8) {
113
+ return "Password must be at least 8 characters long";
114
+ }
115
+ if (!/\d/.test(value)) {
116
+ return "Password must contain a numeric value";
117
+ }
118
+ }
119
+
120
+ handleValidate(errorMessage) {
121
+ this.setState({errorMessage: errorMessage});
122
+ }
123
+
124
+ handleChange(newValue) {
125
+ this.setState({value: newValue});
126
+ }
127
+
128
+ handleKeyDown(event) {
129
+ if (event.key === "Enter") {
130
+ event.currentTarget.blur();
131
+ }
132
+ }
133
+
134
+ handleFocus() {
135
+ this.setState({focused: true});
136
+ }
137
+
138
+ handleBlur() {
139
+ this.setState({focused: false});
140
+ }
141
+
142
+ render() {
143
+ return (
144
+ <View>
145
+ <TextField
146
+ id="tf-3"
147
+ type="password"
148
+ value={this.state.value}
149
+ placeholder="Password"
150
+ validate={this.validate}
151
+ onValidate={this.handleValidate}
152
+ onChange={this.handleChange}
153
+ onKeyDown={this.handleKeyDown}
154
+ onFocus={this.handleFocus}
155
+ onBlur={this.handleBlur}
156
+ />
157
+ {!this.state.focused && this.state.errorMessage && (
158
+ <View>
159
+ <Strut size={Spacing.xSmall_8} />
160
+ <Text style={styles.errorMessage}>{this.state.errorMessage}</Text>
161
+ </View>
162
+ )}
163
+ </View>
164
+ );
165
+ }
166
+ }
167
+
168
+ const styles = StyleSheet.create({
169
+ errorMessage: {
170
+ color: Color.red,
171
+ paddingLeft: Spacing.xxxSmall_4,
172
+ },
173
+ });
174
+
175
+ <TextFieldExample />
176
+ ```
177
+
178
+ Email (with Validation)
179
+
180
+ ```js
181
+ import {StyleSheet} from "aphrodite";
182
+ import {View, Text} from "@khanacademy/wonder-blocks-core";
183
+ import Color from "@khanacademy/wonder-blocks-color";
184
+ import {Strut} from "@khanacademy/wonder-blocks-layout";
185
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
186
+ import {TextField} from "@khanacademy/wonder-blocks-form";
187
+
188
+ class TextFieldExample extends React.Component {
189
+ constructor(props) {
190
+ super(props);
191
+ this.state = {
192
+ value: "khan@khanacademy.org",
193
+ errorMessage: null,
194
+ focused: false,
195
+ };
196
+ this.validate = this.validate.bind(this);
197
+ this.handleValidate = this.handleValidate.bind(this);
198
+ this.handleChange = this.handleChange.bind(this);
199
+ this.handleKeyDown = this.handleKeyDown.bind(this);
200
+ this.handleFocus = this.handleFocus.bind(this);
201
+ this.handleBlur = this.handleBlur.bind(this);
202
+ }
203
+
204
+ validate(value) {
205
+ const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
206
+ if (!emailRegex.test(value)) {
207
+ return "Please enter a valid email";
208
+ }
209
+ }
210
+
211
+ handleValidate(errorMessage) {
212
+ this.setState({errorMessage: errorMessage});
213
+ }
214
+
215
+ handleChange(newValue) {
216
+ this.setState({value: newValue});
217
+ }
218
+
219
+ handleKeyDown(event) {
220
+ if (event.key === "Enter") {
221
+ event.currentTarget.blur();
222
+ }
223
+ }
224
+
225
+ handleFocus() {
226
+ this.setState({focused: true});
227
+ }
228
+
229
+ handleBlur() {
230
+ this.setState({focused: false});
231
+ }
232
+
233
+ render() {
234
+ return (
235
+ <View>
236
+ <TextField
237
+ id="tf-4"
238
+ type="email"
239
+ value={this.state.value}
240
+ placeholder="Email"
241
+ validate={this.validate}
242
+ onValidate={this.handleValidate}
243
+ onChange={this.handleChange}
244
+ onKeyDown={this.handleKeyDown}
245
+ onFocus={this.handleFocus}
246
+ onBlur={this.handleBlur}
247
+ />
248
+ {!this.state.focused && this.state.errorMessage && (
249
+ <View>
250
+ <Strut size={Spacing.xSmall_8} />
251
+ <Text style={styles.errorMessage}>{this.state.errorMessage}</Text>
252
+ </View>
253
+ )}
254
+ </View>
255
+ );
256
+ }
257
+ }
258
+
259
+ const styles = StyleSheet.create({
260
+ errorMessage: {
261
+ color: Color.red,
262
+ paddingLeft: Spacing.xxxSmall_4,
263
+ },
264
+ });
265
+
266
+ <TextFieldExample />
267
+ ```
268
+
269
+ Telephone (with Validation)
270
+
271
+ ```js
272
+ import {StyleSheet} from "aphrodite";
273
+ import {View, Text} from "@khanacademy/wonder-blocks-core";
274
+ import Color from "@khanacademy/wonder-blocks-color";
275
+ import {Strut} from "@khanacademy/wonder-blocks-layout";
276
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
277
+ import {TextField} from "@khanacademy/wonder-blocks-form";
278
+
279
+ class TextFieldExample extends React.Component {
280
+ constructor(props) {
281
+ super(props);
282
+ this.state = {
283
+ value: "123-456-7890",
284
+ errorMessage: null,
285
+ focused: false,
286
+ };
287
+ this.validate = this.validate.bind(this);
288
+ this.handleValidate = this.handleValidate.bind(this);
289
+ this.handleChange = this.handleChange.bind(this);
290
+ this.handleKeyDown = this.handleKeyDown.bind(this);
291
+ this.handleFocus = this.handleFocus.bind(this);
292
+ this.handleBlur = this.handleBlur.bind(this);
293
+ }
294
+
295
+ validate(value) {
296
+ const telRegex = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/;
297
+ if (!telRegex.test(value)) {
298
+ return "Invalid US telephone number";
299
+ }
300
+ }
301
+
302
+ handleValidate(errorMessage) {
303
+ this.setState({errorMessage: errorMessage});
304
+ }
305
+
306
+ handleChange(newValue) {
307
+ this.setState({value: newValue});
308
+ }
309
+
310
+ handleKeyDown(event) {
311
+ if (event.key === "Enter") {
312
+ event.currentTarget.blur();
313
+ }
314
+ }
315
+
316
+ handleFocus() {
317
+ this.setState({focused: true});
318
+ }
319
+
320
+ handleBlur() {
321
+ this.setState({focused: false});
322
+ }
323
+
324
+ render() {
325
+ return (
326
+ <View>
327
+ <TextField
328
+ id="tf-5"
329
+ type="email"
330
+ value={this.state.value}
331
+ placeholder="Telephone"
332
+ validate={this.validate}
333
+ onValidate={this.handleValidate}
334
+ onChange={this.handleChange}
335
+ onKeyDown={this.handleKeyDown}
336
+ onFocus={this.handleFocus}
337
+ onBlur={this.handleBlur}
338
+ />
339
+ {!this.state.focused && this.state.errorMessage && (
340
+ <View>
341
+ <Strut size={Spacing.xSmall_8} />
342
+ <Text style={styles.errorMessage}>{this.state.errorMessage}</Text>
343
+ </View>
344
+ )}
345
+ </View>
346
+ );
347
+ }
348
+ }
349
+
350
+ const styles = StyleSheet.create({
351
+ errorMessage: {
352
+ color: Color.red,
353
+ paddingLeft: Spacing.xxxSmall_4,
354
+ },
355
+ });
356
+
357
+ <TextFieldExample />
358
+ ```
359
+
360
+ Error
361
+
362
+ ```js
363
+ import {StyleSheet} from "aphrodite";
364
+ import {View, Text} from "@khanacademy/wonder-blocks-core";
365
+ import Color from "@khanacademy/wonder-blocks-color";
366
+ import {Strut} from "@khanacademy/wonder-blocks-layout";
367
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
368
+ import {TextField} from "@khanacademy/wonder-blocks-form";
369
+
370
+ class TextFieldExample extends React.Component {
371
+ constructor(props) {
372
+ super(props);
373
+ this.state = {
374
+ value: "khan",
375
+ errorMessage: null,
376
+ focused: false,
377
+ };
378
+ this.validate = this.validate.bind(this);
379
+ this.handleValidate = this.handleValidate.bind(this);
380
+ this.handleChange = this.handleChange.bind(this);
381
+ this.handleKeyDown = this.handleKeyDown.bind(this);
382
+ this.handleFocus = this.handleFocus.bind(this);
383
+ this.handleBlur = this.handleBlur.bind(this);
384
+ }
385
+
386
+ validate(value) {
387
+ const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
388
+ if (!emailRegex.test(value)) {
389
+ return "Please enter a valid email";
390
+ }
391
+ }
392
+
393
+ handleValidate(errorMessage) {
394
+ this.setState({errorMessage: errorMessage});
395
+ }
396
+
397
+ handleChange(newValue) {
398
+ this.setState({value: newValue});
399
+ }
400
+
401
+ handleKeyDown(event) {
402
+ if (event.key === "Enter") {
403
+ event.currentTarget.blur();
404
+ }
405
+ }
406
+
407
+ handleFocus() {
408
+ this.setState({focused: true});
409
+ }
410
+
411
+ handleBlur() {
412
+ this.setState({focused: false});
413
+ }
414
+
415
+ render() {
416
+ return (
417
+ <View>
418
+ <TextField
419
+ id="tf-6"
420
+ type="email"
421
+ value={this.state.value}
422
+ placeholder="Email"
423
+ validate={this.validate}
424
+ onValidate={this.handleValidate}
425
+ onChange={this.handleChange}
426
+ onKeyDown={this.handleKeyDown}
427
+ onFocus={this.handleFocus}
428
+ onBlur={this.handleBlur}
429
+ />
430
+ {!this.state.focused && this.state.errorMessage && (
431
+ <View>
432
+ <Strut size={Spacing.xSmall_8} />
433
+ <Text style={styles.errorMessage}>{this.state.errorMessage}</Text>
434
+ </View>
435
+ )}
436
+ </View>
437
+ );
438
+ }
439
+ }
440
+
441
+ const styles = StyleSheet.create({
442
+ errorMessage: {
443
+ color: Color.red,
444
+ paddingLeft: Spacing.xxxSmall_4,
445
+ },
446
+ });
447
+
448
+ <TextFieldExample />
449
+ ```
450
+
451
+ Disabled
452
+
453
+ ```js
454
+ import {TextField} from "@khanacademy/wonder-blocks-form";
455
+
456
+ <TextField
457
+ id="tf-7" value=""
458
+ placeholder="This field is disabled."
459
+ onChange={() => {}}
460
+ disabled={true}
461
+ />
462
+ ```
463
+
464
+ Light (default focus ring fits a dark background)
465
+
466
+ ```js
467
+ import {StyleSheet} from "aphrodite";
468
+ import {View, Text} from "@khanacademy/wonder-blocks-core";
469
+ import Color from "@khanacademy/wonder-blocks-color";
470
+ import {Strut} from "@khanacademy/wonder-blocks-layout";
471
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
472
+ import {TextField} from "@khanacademy/wonder-blocks-form";
473
+
474
+ class TextFieldExample extends React.Component {
475
+ constructor(props) {
476
+ super(props);
477
+ this.state = {
478
+ value: "khan@khanacademy.org",
479
+ errorMessage: null,
480
+ focused: false,
481
+ };
482
+ this.validate = this.validate.bind(this);
483
+ this.handleValidate = this.handleValidate.bind(this);
484
+ this.handleChange = this.handleChange.bind(this);
485
+ this.handleKeyDown = this.handleKeyDown.bind(this);
486
+ this.handleFocus = this.handleFocus.bind(this);
487
+ this.handleBlur = this.handleBlur.bind(this);
488
+ }
489
+
490
+ validate(value) {
491
+ const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
492
+ if (!emailRegex.test(value)) {
493
+ return "Please enter a valid email";
494
+ }
495
+ }
496
+
497
+ handleValidate(errorMessage) {
498
+ this.setState({errorMessage: errorMessage});
499
+ }
500
+
501
+ handleChange(newValue) {
502
+ this.setState({value: newValue});
503
+ }
504
+
505
+ handleKeyDown(event) {
506
+ if (event.key === "Enter") {
507
+ event.currentTarget.blur();
508
+ }
509
+ }
510
+
511
+ handleFocus() {
512
+ this.setState({focused: true});
513
+ }
514
+
515
+ handleBlur() {
516
+ this.setState({focused: false});
517
+ }
518
+
519
+ render() {
520
+ return (
521
+ <View style={styles.darkBackground}>
522
+ <TextField
523
+ id="tf-8"
524
+ type="email"
525
+ value={this.state.value}
526
+ light={true}
527
+ placeholder="Email"
528
+ validate={this.validate}
529
+ onValidate={this.handleValidate}
530
+ onChange={this.handleChange}
531
+ onKeyDown={this.handleKeyDown}
532
+ onFocus={this.handleFocus}
533
+ onBlur={this.handleBlur}
534
+ />
535
+ {!this.state.focused && this.state.errorMessage && (
536
+ <View>
537
+ <Strut size={Spacing.xSmall_8} />
538
+ <Text style={styles.errorMessage}>{this.state.errorMessage}</Text>
539
+ </View>
540
+ )}
541
+ </View>
542
+ );
543
+ }
544
+ }
545
+
546
+ const styles = StyleSheet.create({
547
+ errorMessage: {
548
+ color: Color.white,
549
+ paddingLeft: Spacing.xxxSmall_4,
550
+ },
551
+ darkBackground: {
552
+ backgroundColor: Color.darkBlue,
553
+ padding: Spacing.medium_16,
554
+ },
555
+ });
556
+
557
+ <TextFieldExample />
558
+ ```
559
+
560
+ Custom Style
561
+
562
+ ```js
563
+ import {StyleSheet} from "aphrodite";
564
+ import Color from "@khanacademy/wonder-blocks-color";
565
+ import {View} from "@khanacademy/wonder-blocks-core";
566
+ import {TextField} from "@khanacademy/wonder-blocks-form";
567
+
568
+ class TextFieldExample extends React.Component {
569
+ constructor(props) {
570
+ super(props);
571
+ this.state = {
572
+ value: "",
573
+ };
574
+ this.handleChange = this.handleChange.bind(this);
575
+ this.handleKeyDown = this.handleKeyDown.bind(this);
576
+ }
577
+
578
+ handleChange(newValue) {
579
+ this.setState({value: newValue});
580
+ }
581
+
582
+ handleKeyDown(event) {
583
+ if (event.key === "Enter") {
584
+ event.currentTarget.blur();
585
+ }
586
+ }
587
+
588
+ render() {
589
+ return (
590
+ <TextField
591
+ id="tf-9"
592
+ style={styles.customField}
593
+ type="text"
594
+ value={this.state.value}
595
+ placeholder="Text"
596
+ onChange={this.handleChange}
597
+ onKeyDown={this.handleKeyDown}
598
+ />
599
+ );
600
+ }
601
+ }
602
+
603
+ const styles = StyleSheet.create({
604
+ customField: {
605
+ backgroundColor: Color.darkBlue,
606
+ color: Color.white,
607
+ border: "none",
608
+ maxWidth: 250,
609
+ "::placeholder": {
610
+ color: Color.white64,
611
+ },
612
+ },
613
+ });
614
+
615
+ <TextFieldExample />
616
+ ```
617
+
618
+ Using Ref
619
+
620
+ ```js
621
+ import {View} from "@khanacademy/wonder-blocks-core";
622
+ import {TextField} from "@khanacademy/wonder-blocks-form";
623
+ import Button from "@khanacademy/wonder-blocks-button";
624
+ import {Strut} from "@khanacademy/wonder-blocks-layout";
625
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
626
+ import {StyleSheet} from "aphrodite";
627
+
628
+ class TextFieldExample extends React.Component {
629
+ constructor(props) {
630
+ super(props);
631
+ this.state = {
632
+ value: "",
633
+ };
634
+ this.inputRef = React.createRef();
635
+ this.handleChange = this.handleChange.bind(this);
636
+ this.handleKeyDown = this.handleKeyDown.bind(this);
637
+ this.handleSubmit = this.handleSubmit.bind(this);
638
+ }
639
+
640
+ handleChange(newValue) {
641
+ this.setState({value: newValue});
642
+ }
643
+
644
+ handleKeyDown(event) {
645
+ if (event.key === "Enter") {
646
+ event.currentTarget.blur();
647
+ }
648
+ }
649
+
650
+ handleSubmit() {
651
+ if (this.inputRef.current) {
652
+ this.inputRef.current.focus();
653
+ }
654
+ }
655
+
656
+ render() {
657
+ return (
658
+ <View>
659
+ <TextField
660
+ id="tf-10"
661
+ type="text"
662
+ value={this.state.value}
663
+ placeholder="Text"
664
+ onChange={this.handleChange}
665
+ onKeyDown={this.handleKeyDown}
666
+ ref={this.inputRef}
667
+ />
668
+ <Strut size={Spacing.medium_16} />
669
+ <Button style={styles.button} onClick={this.handleSubmit}>
670
+ Focus Input
671
+ </Button>
672
+ </View>
673
+ );
674
+ }
675
+ }
676
+
677
+ const styles = StyleSheet.create({
678
+ button: {
679
+ maxWidth: 150,
680
+ },
681
+ });
682
+
683
+ <TextFieldExample />
684
+ ```
685
+
686
+ Read Only
687
+
688
+ ```js
689
+ import {TextField} from "@khanacademy/wonder-blocks-form";
690
+
691
+ class TextFieldExample extends React.Component {
692
+ constructor(props) {
693
+ super(props);
694
+ this.state = {
695
+ value: "Khan",
696
+ };
697
+ this.handleChange = this.handleChange.bind(this);
698
+ this.handleKeyDown = this.handleKeyDown.bind(this);
699
+ }
700
+
701
+ handleChange(newValue) {
702
+ this.setState({value: newValue});
703
+ }
704
+
705
+ handleKeyDown(event) {
706
+ if (event.key === "Enter") {
707
+ event.currentTarget.blur();
708
+ }
709
+ }
710
+
711
+ render() {
712
+ return (
713
+ <TextField
714
+ id="tf-1"
715
+ type="text"
716
+ value={this.state.value}
717
+ placeholder="Text"
718
+ onChange={this.handleChange}
719
+ onKeyDown={this.handleKeyDown}
720
+ readOnly={true}
721
+ />
722
+ );
723
+ }
724
+ }
725
+
726
+ <TextFieldExample />
727
+ ```
728
+
729
+ Autocomplete
730
+
731
+ ```js
732
+ import {TextField} from "@khanacademy/wonder-blocks-form";
733
+
734
+ class TextFieldExample extends React.Component {
735
+ constructor(props) {
736
+ super(props);
737
+ this.state = {
738
+ value: "",
739
+ };
740
+ this.handleChange = this.handleChange.bind(this);
741
+ this.handleKeyDown = this.handleKeyDown.bind(this);
742
+ }
743
+
744
+ handleChange(newValue) {
745
+ this.setState({value: newValue});
746
+ }
747
+
748
+ handleKeyDown(event) {
749
+ if (event.key === "Enter") {
750
+ event.currentTarget.blur();
751
+ }
752
+ }
753
+
754
+ render() {
755
+ return (
756
+ <TextField
757
+ id="tf-1"
758
+ type="text"
759
+ value={this.state.value}
760
+ placeholder="Text"
761
+ onChange={this.handleChange}
762
+ onKeyDown={this.handleKeyDown}
763
+ autoComplete="name"
764
+ />
765
+ );
766
+ }
767
+ }
768
+
769
+ <TextFieldExample />
770
+ ```