@khanacademy/wonder-blocks-form 2.4.8 → 3.1.0

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 (32) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/es/index.js +15 -13
  3. package/dist/index.js +75 -77
  4. package/docs.md +5 -1
  5. package/package.json +2 -2
  6. package/src/__docs__/_overview_.stories.mdx +15 -0
  7. package/src/components/__docs__/checkbox-group.stories.js +35 -1
  8. package/src/components/__docs__/labeled-text-field.argtypes.js +2 -2
  9. package/src/components/__docs__/labeled-text-field.stories.js +25 -0
  10. package/src/components/__docs__/radio-group.stories.js +35 -0
  11. package/src/components/__docs__/radio.stories.js +3 -2
  12. package/src/components/__tests__/checkbox-group.test.js +144 -67
  13. package/src/components/__tests__/field-heading.test.js +40 -0
  14. package/src/components/__tests__/radio-group.test.js +155 -58
  15. package/src/components/checkbox-group.js +9 -15
  16. package/src/components/checkbox.js +2 -2
  17. package/src/components/choice-internal.js +5 -3
  18. package/src/components/choice.js +2 -2
  19. package/src/components/field-heading.js +27 -43
  20. package/src/components/labeled-text-field.js +2 -3
  21. package/src/components/radio-group.js +6 -4
  22. package/src/components/radio.js +2 -2
  23. package/src/index.js +0 -2
  24. package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +0 -6126
  25. package/src/__tests__/generated-snapshot.test.js +0 -654
  26. package/src/components/checkbox-group.md +0 -200
  27. package/src/components/checkbox.md +0 -134
  28. package/src/components/field-heading.md +0 -43
  29. package/src/components/labeled-text-field.md +0 -535
  30. package/src/components/radio-group.md +0 -129
  31. package/src/components/radio.md +0 -26
  32. package/src/components/text-field.md +0 -770
@@ -1,770 +0,0 @@
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
- ```