@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,654 @@
1
+ // This file is auto-generated by gen-snapshot-tests.js
2
+ // Do not edit this file. To make changes to these snapshot tests:
3
+ // 1. edit the markdown documentation files in the package,
4
+ // packages/wonder-blocks-form
5
+ // 2. Run `yarn run gen-snapshot-tests`.
6
+ import React from "react";
7
+ import renderer from "react-test-renderer";
8
+
9
+ // Mock react-dom as jest doesn't like findDOMNode.
10
+ jest.mock("react-dom");
11
+ import {View} from "@khanacademy/wonder-blocks-core";
12
+ import {
13
+ Checkbox,
14
+ Radio,
15
+ CheckboxGroup,
16
+ Choice,
17
+ RadioGroup,
18
+ TextField,
19
+ } from "@khanacademy/wonder-blocks-form";
20
+ import {StyleSheet} from "aphrodite";
21
+ import {
22
+ LabelMedium,
23
+ LabelSmall,
24
+ LabelLarge,
25
+ LabelXSmall,
26
+ } from "@khanacademy/wonder-blocks-typography";
27
+ import Color from "@khanacademy/wonder-blocks-color";
28
+
29
+ import CheckboxCore from "./../components/checkbox-core.js";
30
+ import RadioCore from "./../components/radio-core.js";
31
+ import ChoiceInternal from "./../components/choice-internal.js";
32
+ import FieldHeading from "./../components/field-heading.js";
33
+
34
+ describe("wonder-blocks-form", () => {
35
+ it("example 1", () => {
36
+ const styles = StyleSheet.create({
37
+ row: {
38
+ flexDirection: "row",
39
+ },
40
+ marginRight: {
41
+ marginRight: 16,
42
+ },
43
+ });
44
+
45
+ const handleChange = (checked) =>
46
+ console.log(
47
+ `clicked on checkbox, will be checked=${checked.toString()}`,
48
+ );
49
+
50
+ const example = (
51
+ <View style={styles.row}>
52
+ <Checkbox
53
+ error={false}
54
+ checked={false}
55
+ style={styles.marginRight}
56
+ onChange={handleChange}
57
+ />
58
+ <Checkbox
59
+ error={false}
60
+ checked={true}
61
+ style={styles.marginRight}
62
+ onChange={handleChange}
63
+ />
64
+ <Checkbox
65
+ error={true}
66
+ checked={false}
67
+ style={styles.marginRight}
68
+ onChange={handleChange}
69
+ />
70
+ <Checkbox
71
+ error={true}
72
+ checked={true}
73
+ style={styles.marginRight}
74
+ onChange={handleChange}
75
+ />
76
+ <Checkbox
77
+ disabled={true}
78
+ checked={false}
79
+ style={styles.marginRight}
80
+ onChange={handleChange}
81
+ />
82
+ <Checkbox
83
+ disabled={true}
84
+ checked={true}
85
+ style={styles.marginRight}
86
+ onChange={handleChange}
87
+ />
88
+ </View>
89
+ );
90
+ const tree = renderer.create(example).toJSON();
91
+ expect(tree).toMatchSnapshot();
92
+ });
93
+
94
+ it("example 2", () => {
95
+ class Settings extends React.Component {
96
+ constructor() {
97
+ super();
98
+ this.state = {
99
+ assignment: false,
100
+ };
101
+ this.handleChange = this.handleChange.bind(this);
102
+ }
103
+
104
+ handleChange(checked) {
105
+ this.setState({
106
+ assignment: checked,
107
+ }); // Potentially do something here with this updated state information.
108
+ }
109
+
110
+ render() {
111
+ const handleChanged = (checked) =>
112
+ console.log(
113
+ `clicked on checkbox with checked=${checked.toString()}`,
114
+ );
115
+
116
+ const headingText = "Functions";
117
+ return (
118
+ <View>
119
+ <Checkbox
120
+ label="Receive assignment reminders for Algebra"
121
+ description="You will receive a reminder 24 hours before each deadline"
122
+ checked={this.state.assignment}
123
+ id="assignment"
124
+ onChange={this.handleChange}
125
+ testId="algebra-assignment-test"
126
+ variant="checkbox"
127
+ />
128
+ </View>
129
+ );
130
+ }
131
+ }
132
+
133
+ const example = <Settings />;
134
+ const tree = renderer.create(example).toJSON();
135
+ expect(tree).toMatchSnapshot();
136
+ });
137
+
138
+ it("example 3", () => {
139
+ const styles = StyleSheet.create({
140
+ wrapper: {
141
+ flexDirection: "row",
142
+ alignItems: "center",
143
+ justifyContent: "space-evenly",
144
+ },
145
+ topic: {
146
+ maxWidth: 600,
147
+ },
148
+ });
149
+
150
+ class ContentItem extends React.Component {
151
+ constructor() {
152
+ super();
153
+ this.state = {
154
+ checked: false,
155
+ };
156
+ }
157
+
158
+ handleChange(checked) {
159
+ this.setState({
160
+ checked: checked,
161
+ }); // Potentially do something here with this updated state information.
162
+ }
163
+
164
+ render() {
165
+ const handleChanged = (checked) =>
166
+ console.log(
167
+ `clicked on checkbox with checked=${checked.toString()}`,
168
+ );
169
+
170
+ const headingText = "Functions";
171
+ const descriptionText = `A great cook knows how to take basic ingredients and
172
+ prepare a delicious meal. In this topic, you will become function-chefs! You
173
+ will learn how to combine functions with arithmetic operations and how to
174
+ compose functions.`;
175
+ return (
176
+ <View style={styles.wrapper}>
177
+ <View style={styles.topic}>
178
+ <label htmlFor="topic-123">
179
+ <LabelMedium>{headingText}</LabelMedium>
180
+ </label>
181
+ <LabelSmall>{descriptionText}</LabelSmall>
182
+ </View>
183
+ <Checkbox
184
+ checked={this.state.checked}
185
+ id="topic-123"
186
+ onChange={(checked) => this.handleChange(checked)}
187
+ />
188
+ </View>
189
+ );
190
+ }
191
+ }
192
+
193
+ const example = <ContentItem />;
194
+ const tree = renderer.create(example).toJSON();
195
+ expect(tree).toMatchSnapshot();
196
+ });
197
+
198
+ it("example 4", () => {
199
+ const styles = StyleSheet.create({
200
+ row: {
201
+ flexDirection: "row",
202
+ },
203
+ marginRight: {
204
+ marginRight: 16,
205
+ },
206
+ });
207
+
208
+ const handleChange = (checked) =>
209
+ console.log(
210
+ `clicked on radio, will be checked=${checked.toString()}`,
211
+ );
212
+
213
+ const example = (
214
+ <View style={styles.row}>
215
+ <Radio
216
+ error={false}
217
+ checked={false}
218
+ style={styles.marginRight}
219
+ onChange={handleChange}
220
+ />
221
+ <Radio
222
+ error={false}
223
+ checked={true}
224
+ style={styles.marginRight}
225
+ onChange={handleChange}
226
+ />
227
+ <Radio
228
+ error={true}
229
+ checked={false}
230
+ style={styles.marginRight}
231
+ onChange={handleChange}
232
+ />
233
+ <Radio
234
+ error={true}
235
+ checked={true}
236
+ style={styles.marginRight}
237
+ onChange={handleChange}
238
+ />
239
+ <Radio
240
+ disabled={true}
241
+ checked={false}
242
+ style={styles.marginRight}
243
+ onChange={handleChange}
244
+ />
245
+ <Radio
246
+ disabled={true}
247
+ checked={true}
248
+ style={styles.marginRight}
249
+ onChange={handleChange}
250
+ />
251
+ </View>
252
+ );
253
+ const tree = renderer.create(example).toJSON();
254
+ expect(tree).toMatchSnapshot();
255
+ });
256
+
257
+ it("example 5", () => {
258
+ const styles = StyleSheet.create({
259
+ wrapper: {
260
+ width: 300,
261
+ },
262
+ });
263
+
264
+ class CheckboxGroupPizzaExample extends React.Component {
265
+ constructor() {
266
+ super();
267
+ this.state = {
268
+ selectedValues: ["pineapple"],
269
+ };
270
+ this.handleChange = this.handleChange.bind(this);
271
+ }
272
+
273
+ handleChange(change) {
274
+ console.log(`${change} was selected!`);
275
+ const error = this.checkForError(change);
276
+ this.setState({
277
+ selectedValues: change,
278
+ error: error,
279
+ });
280
+ }
281
+
282
+ checkForError(input) {
283
+ if (input.length > 3) {
284
+ return "You have selected too many toppings";
285
+ }
286
+ }
287
+
288
+ render() {
289
+ return (
290
+ <CheckboxGroup
291
+ label="Pizza order"
292
+ description="You may choose at most three toppings"
293
+ errorMessage={this.state.error}
294
+ groupName="Toppings"
295
+ onChange={this.handleChange}
296
+ selectedValues={this.state.selectedValues}
297
+ >
298
+ <Choice label="Pepperoni" value="pepperoni" />
299
+ <Choice
300
+ label="Sausage"
301
+ value="sausage"
302
+ description="Imported from Italy"
303
+ />
304
+ <Choice label="Extra cheese" value="cheese" />
305
+ <Choice label="Green pepper" value="pepper" />
306
+ <Choice label="Mushroom" value="mushroom" />
307
+ <Choice
308
+ label="Pineapple"
309
+ value="pineapple"
310
+ description="Does in fact belong on pizzas"
311
+ />
312
+ </CheckboxGroup>
313
+ );
314
+ }
315
+ }
316
+
317
+ const example = (
318
+ <View style={styles.wrapper}>
319
+ <CheckboxGroupPizzaExample />
320
+ </View>
321
+ );
322
+ const tree = renderer.create(example).toJSON();
323
+ expect(tree).toMatchSnapshot();
324
+ });
325
+
326
+ it("example 6", () => {
327
+ const styles = StyleSheet.create({
328
+ wrapper: {
329
+ width: 650,
330
+ },
331
+ group: {
332
+ flexDirection: "row",
333
+ flexWrap: "wrap",
334
+ },
335
+ choice: {
336
+ marginTop: 8,
337
+ width: 200,
338
+ },
339
+ title: {
340
+ paddingBottom: 8,
341
+ borderBottom: `1px solid ${Color.offBlack64}`,
342
+ },
343
+ });
344
+
345
+ class ClassSelectorExample extends React.Component {
346
+ constructor() {
347
+ super();
348
+ this.state = {
349
+ selectedValues: [],
350
+ };
351
+ this.handleChange = this.handleChange.bind(this);
352
+ }
353
+
354
+ handleChange(change) {
355
+ console.log(`${change} was selected!`);
356
+ this.setState({
357
+ selectedValues: change,
358
+ });
359
+ }
360
+
361
+ render() {
362
+ return (
363
+ <CheckboxGroup
364
+ groupName="science-classes"
365
+ onChange={this.handleChange}
366
+ selectedValues={this.state.selectedValues}
367
+ style={styles.group}
368
+ >
369
+ <Choice
370
+ label="Biology"
371
+ value="1"
372
+ style={styles.choice}
373
+ />
374
+ <Choice
375
+ label="AP®︎ Biology"
376
+ value="2"
377
+ style={styles.choice}
378
+ />
379
+ <Choice
380
+ label="High school biology"
381
+ value="3"
382
+ style={styles.choice}
383
+ />
384
+ <Choice
385
+ label="Cosmology and astronomy"
386
+ value="4"
387
+ style={styles.choice}
388
+ />
389
+ <Choice
390
+ label="Electrical engineering"
391
+ value="5"
392
+ style={styles.choice}
393
+ />
394
+ <Choice
395
+ label="Health and medicine"
396
+ value="6"
397
+ style={styles.choice}
398
+ />
399
+ </CheckboxGroup>
400
+ );
401
+ }
402
+ }
403
+
404
+ const example = (
405
+ <View style={styles.wrapper}>
406
+ <LabelLarge style={styles.title}>Science</LabelLarge>
407
+ <ClassSelectorExample />
408
+ </View>
409
+ );
410
+ const tree = renderer.create(example).toJSON();
411
+ expect(tree).toMatchSnapshot();
412
+ });
413
+
414
+ it("example 7", () => {
415
+ const styles = StyleSheet.create({
416
+ choice: {
417
+ margin: 0,
418
+ height: 48,
419
+ borderTop: "solid 1px #CCC",
420
+ justifyContent: "center",
421
+ ":last-child": {
422
+ borderBottom: "solid 1px #CCC",
423
+ },
424
+ },
425
+ description: {
426
+ marginTop: 5,
427
+ color: Color.offBlack64,
428
+ },
429
+ });
430
+
431
+ class ClassSelectorExample extends React.Component {
432
+ constructor() {
433
+ super();
434
+ this.state = {
435
+ selectedValues: [],
436
+ };
437
+ this.handleChange = this.handleChange.bind(this);
438
+ }
439
+
440
+ handleChange(change) {
441
+ console.log(`${change} was selected!`);
442
+ this.setState({
443
+ selectedValues: change,
444
+ });
445
+ }
446
+
447
+ render() {
448
+ return (
449
+ <CheckboxGroup
450
+ label={
451
+ <LabelLarge>Select all prime numbers</LabelLarge>
452
+ }
453
+ description={
454
+ <LabelXSmall style={styles.description}>
455
+ Hint: There is at least one prime number
456
+ </LabelXSmall>
457
+ }
458
+ groupName="science-classes"
459
+ onChange={this.handleChange}
460
+ selectedValues={this.state.selectedValues}
461
+ >
462
+ <Choice label="1" value="1" style={styles.choice} />
463
+ <Choice label="2" value="2" style={styles.choice} />
464
+ <Choice label="3" value="3" style={styles.choice} />
465
+ <Choice label="4" value="4" style={styles.choice} />
466
+ <Choice label="5" value="5" style={styles.choice} />
467
+ </CheckboxGroup>
468
+ );
469
+ }
470
+ }
471
+
472
+ const example = (
473
+ <View>
474
+ <ClassSelectorExample />
475
+ </View>
476
+ );
477
+ const tree = renderer.create(example).toJSON();
478
+ expect(tree).toMatchSnapshot();
479
+ });
480
+
481
+ it("example 8", () => {
482
+ const styles = StyleSheet.create({
483
+ wrapper: {
484
+ width: 300,
485
+ },
486
+ });
487
+
488
+ class RadioGroupPokemonExample extends React.Component {
489
+ constructor() {
490
+ super();
491
+ this.state = {
492
+ selectedValue: null,
493
+ };
494
+ this.handleChange = this.handleChange.bind(this);
495
+ }
496
+
497
+ handleChange(change) {
498
+ console.log(`${change} was selected!`);
499
+ const error = this.checkForError(change);
500
+ this.setState({
501
+ selectedValue: change,
502
+ error: error,
503
+ });
504
+ }
505
+
506
+ checkForError(input) {
507
+ if (input === "infiltrator") {
508
+ return "Superman isn't a Pokemon!";
509
+ }
510
+ }
511
+
512
+ render() {
513
+ return (
514
+ <RadioGroup
515
+ label="Choose a starter!"
516
+ description="Your first Pokemon"
517
+ errorMessage={this.state.error}
518
+ groupName="Pokemon"
519
+ onChange={this.handleChange}
520
+ selectedValue={this.state.selectedValue}
521
+ >
522
+ <Choice label="Bulbasaur" value="bulb" />
523
+ <Choice
524
+ label="Charmander"
525
+ value="char"
526
+ description="Oops, we ran out of Charmanders"
527
+ disabled
528
+ />
529
+ <Choice label="Squirtle" value="squirt" />
530
+ <Choice label="Pikachu" value="pika" />
531
+ <Choice label="Superman" value="infiltrator" />
532
+ </RadioGroup>
533
+ );
534
+ }
535
+ }
536
+
537
+ const example = (
538
+ <View style={styles.wrapper}>
539
+ <RadioGroupPokemonExample />
540
+ </View>
541
+ );
542
+ const tree = renderer.create(example).toJSON();
543
+ expect(tree).toMatchSnapshot();
544
+ });
545
+
546
+ it("example 9", () => {
547
+ const styles = StyleSheet.create({
548
+ wrapper: {
549
+ width: 650,
550
+ },
551
+ choice: {
552
+ margin: 0,
553
+ height: 48,
554
+ borderTop: "solid 1px #CCC",
555
+ justifyContent: "center",
556
+ ":last-child": {
557
+ borderBottom: "solid 1px #CCC",
558
+ },
559
+ },
560
+ prompt: {
561
+ marginBottom: 16,
562
+ },
563
+ });
564
+
565
+ class ClassSelectorExample extends React.Component {
566
+ constructor() {
567
+ super();
568
+ this.state = {
569
+ selectedValue: null,
570
+ };
571
+ this.handleChange = this.handleChange.bind(this);
572
+ }
573
+
574
+ handleChange(change) {
575
+ console.log(`${change} was selected!`);
576
+ this.setState({
577
+ selectedValue: change,
578
+ });
579
+ }
580
+
581
+ render() {
582
+ return (
583
+ <RadioGroup
584
+ groupName="science-classes"
585
+ onChange={this.handleChange}
586
+ selectedValue={this.state.selectedValue}
587
+ >
588
+ <Choice label="A" value="1" style={styles.choice} />
589
+ <Choice label="B" value="2" style={styles.choice} />
590
+ <Choice label="AB" value="3" style={styles.choice} />
591
+ <Choice label="O" value="4" style={styles.choice} />
592
+ </RadioGroup>
593
+ );
594
+ }
595
+ }
596
+
597
+ const example = (
598
+ <View>
599
+ <LabelLarge style={styles.prompt}>
600
+ Select your blood type
601
+ </LabelLarge>
602
+ <ClassSelectorExample />
603
+ </View>
604
+ );
605
+ const tree = renderer.create(example).toJSON();
606
+ expect(tree).toMatchSnapshot();
607
+ });
608
+
609
+ it("example 10", () => {
610
+ class FieldHeadingExample extends React.Component {
611
+ constructor(props) {
612
+ super(props);
613
+ this.state = {
614
+ value: "",
615
+ };
616
+ this.handleKeyDown = this.handleKeyDown.bind(this);
617
+ }
618
+
619
+ handleKeyDown(event) {
620
+ if (event.key === "Enter") {
621
+ event.currentTarget.blur();
622
+ }
623
+ }
624
+
625
+ render() {
626
+ return (
627
+ <FieldHeading
628
+ field={
629
+ <TextField
630
+ id="tf-1"
631
+ type="text"
632
+ value={this.state.value}
633
+ placeholder="Username"
634
+ onChange={(newValue) =>
635
+ this.setState({
636
+ value: newValue,
637
+ })
638
+ }
639
+ onKeyDown={this.handleKeyDown}
640
+ />
641
+ }
642
+ label="Username"
643
+ description="Please enter your username."
644
+ error="That username is already taken."
645
+ />
646
+ );
647
+ }
648
+ }
649
+
650
+ const example = <FieldHeadingExample />;
651
+ const tree = renderer.create(example).toJSON();
652
+ expect(tree).toMatchSnapshot();
653
+ });
654
+ });