@khanacademy/wonder-blocks-form 2.4.2 → 2.4.5
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.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-form
|
|
2
2
|
|
|
3
|
+
## 2.4.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [83486dba]
|
|
8
|
+
- @khanacademy/wonder-blocks-icon@1.2.29
|
|
9
|
+
|
|
10
|
+
## 2.4.4
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [5f4a4297]
|
|
15
|
+
- Updated dependencies [2b96fd59]
|
|
16
|
+
- @khanacademy/wonder-blocks-core@4.3.2
|
|
17
|
+
- @khanacademy/wonder-blocks-clickable@2.2.7
|
|
18
|
+
- @khanacademy/wonder-blocks-icon@1.2.28
|
|
19
|
+
- @khanacademy/wonder-blocks-layout@1.4.10
|
|
20
|
+
- @khanacademy/wonder-blocks-typography@1.1.32
|
|
21
|
+
|
|
22
|
+
## 2.4.3
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- @khanacademy/wonder-blocks-clickable@2.2.6
|
|
27
|
+
- @khanacademy/wonder-blocks-core@4.3.1
|
|
28
|
+
- @khanacademy/wonder-blocks-icon@1.2.27
|
|
29
|
+
- @khanacademy/wonder-blocks-layout@1.4.9
|
|
30
|
+
- @khanacademy/wonder-blocks-typography@1.1.31
|
|
31
|
+
|
|
3
32
|
## 2.4.2
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/dist/es/index.js
CHANGED
|
@@ -24,16 +24,11 @@ const StyledInput$1 = addStyle("input");
|
|
|
24
24
|
const checkboxCheck = {
|
|
25
25
|
small: "M11.263 4.324a1 1 0 1 1 1.474 1.352l-5.5 6a1 1 0 0 1-1.505-.036l-2.5-3a1 1 0 1 1 1.536-1.28L6.536 9.48l4.727-5.157z"
|
|
26
26
|
};
|
|
27
|
-
/**
|
|
28
|
-
* The internal stateless ☑️ Checkbox
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
27
|
class CheckboxCore extends React.Component {
|
|
32
28
|
constructor(...args) {
|
|
33
29
|
super(...args);
|
|
34
30
|
|
|
35
31
|
this.handleChange = () => {
|
|
36
|
-
// Empty because change is handled by ClickableBehavior
|
|
37
32
|
return;
|
|
38
33
|
};
|
|
39
34
|
}
|
|
@@ -59,18 +54,16 @@ class CheckboxCore extends React.Component {
|
|
|
59
54
|
const props = {
|
|
60
55
|
"data-test-id": testId
|
|
61
56
|
};
|
|
62
|
-
return
|
|
57
|
+
return React.createElement(React.Fragment, null, React.createElement(StyledInput$1, _extends({}, sharedProps, {
|
|
63
58
|
type: "checkbox",
|
|
64
59
|
"aria-invalid": error,
|
|
65
60
|
checked: checked,
|
|
66
61
|
disabled: disabled,
|
|
67
62
|
id: id,
|
|
68
|
-
name: groupName
|
|
69
|
-
// component, but we handle the click via ClickableBehavior
|
|
70
|
-
,
|
|
63
|
+
name: groupName,
|
|
71
64
|
onChange: this.handleChange,
|
|
72
65
|
style: defaultStyle
|
|
73
|
-
}, props)), checked &&
|
|
66
|
+
}, props)), checked && React.createElement(Icon, {
|
|
74
67
|
color: disabled ? offBlack32$1 : white$1,
|
|
75
68
|
icon: checkboxCheck,
|
|
76
69
|
size: "small",
|
|
@@ -81,7 +74,6 @@ class CheckboxCore extends React.Component {
|
|
|
81
74
|
}
|
|
82
75
|
const size$1 = 16;
|
|
83
76
|
const sharedStyles$1 = StyleSheet.create({
|
|
84
|
-
// Reset the default styled input element
|
|
85
77
|
inputReset: {
|
|
86
78
|
appearance: "none",
|
|
87
79
|
WebkitAppearance: "none",
|
|
@@ -129,7 +121,6 @@ const colors$1 = {
|
|
|
129
121
|
const styles$5 = {};
|
|
130
122
|
|
|
131
123
|
const _generateStyles$1 = (checked, error) => {
|
|
132
|
-
// "hash" the parameters
|
|
133
124
|
const styleKey = `${String(checked)}-${String(error)}`;
|
|
134
125
|
|
|
135
126
|
if (styles$5[styleKey]) {
|
|
@@ -187,16 +178,11 @@ const {
|
|
|
187
178
|
offBlack50
|
|
188
179
|
} = Color;
|
|
189
180
|
const StyledInput = addStyle("input");
|
|
190
|
-
/**
|
|
191
|
-
* The internal stateless 🔘 Radio button
|
|
192
|
-
*/
|
|
193
|
-
|
|
194
181
|
class RadioCore extends React.Component {
|
|
195
182
|
constructor(...args) {
|
|
196
183
|
super(...args);
|
|
197
184
|
|
|
198
185
|
this.handleChange = () => {
|
|
199
|
-
// Empty because change is handled by ClickableBehavior
|
|
200
186
|
return;
|
|
201
187
|
};
|
|
202
188
|
}
|
|
@@ -222,25 +208,22 @@ class RadioCore extends React.Component {
|
|
|
222
208
|
const props = {
|
|
223
209
|
"data-test-id": testId
|
|
224
210
|
};
|
|
225
|
-
return
|
|
211
|
+
return React.createElement(React.Fragment, null, React.createElement(StyledInput, _extends({}, sharedProps, {
|
|
226
212
|
type: "radio",
|
|
227
213
|
"aria-invalid": error,
|
|
228
214
|
checked: checked,
|
|
229
215
|
disabled: disabled,
|
|
230
216
|
id: id,
|
|
231
|
-
name: groupName
|
|
232
|
-
// component, but we handle the click via ClickableBehavior
|
|
233
|
-
,
|
|
217
|
+
name: groupName,
|
|
234
218
|
onChange: this.handleChange,
|
|
235
219
|
style: defaultStyle
|
|
236
|
-
}, props)), disabled && checked &&
|
|
220
|
+
}, props)), disabled && checked && React.createElement("span", {
|
|
237
221
|
style: disabledChecked
|
|
238
222
|
}));
|
|
239
223
|
}
|
|
240
224
|
|
|
241
225
|
}
|
|
242
|
-
const size = 16;
|
|
243
|
-
|
|
226
|
+
const size = 16;
|
|
244
227
|
const disabledChecked = {
|
|
245
228
|
position: "absolute",
|
|
246
229
|
top: size / 4,
|
|
@@ -251,7 +234,6 @@ const disabledChecked = {
|
|
|
251
234
|
backgroundColor: offBlack32
|
|
252
235
|
};
|
|
253
236
|
const sharedStyles = StyleSheet.create({
|
|
254
|
-
// Reset the default styled input element
|
|
255
237
|
inputReset: {
|
|
256
238
|
appearance: "none",
|
|
257
239
|
WebkitAppearance: "none",
|
|
@@ -295,7 +277,6 @@ const colors = {
|
|
|
295
277
|
const styles$4 = {};
|
|
296
278
|
|
|
297
279
|
const _generateStyles = (checked, error) => {
|
|
298
|
-
// "hash" the parameters
|
|
299
280
|
const styleKey = `${String(checked)}-${String(error)}`;
|
|
300
281
|
|
|
301
282
|
if (styles$4[styleKey]) {
|
|
@@ -344,22 +325,11 @@ const _generateStyles = (checked, error) => {
|
|
|
344
325
|
};
|
|
345
326
|
|
|
346
327
|
const _excluded$2 = ["label", "description", "onChange", "style", "className", "variant"];
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* This is a potentially labeled 🔘 or ☑️ item. This is an internal component
|
|
350
|
-
* that's wrapped by Checkbox and Radio. Choice is a wrapper for Checkbox and
|
|
351
|
-
* Radio with many of its props auto-populated, to be used with CheckboxGroup
|
|
352
|
-
* and RadioGroup. This design allows for more explicit prop typing. For
|
|
353
|
-
* example, we can make onChange a required prop on Checkbox but not on Choice
|
|
354
|
-
* (because for Choice, that prop would be auto-populated by CheckboxGroup).
|
|
355
|
-
*/
|
|
356
328
|
class ChoiceInternal extends React.Component {
|
|
357
329
|
constructor(...args) {
|
|
358
330
|
super(...args);
|
|
359
331
|
|
|
360
332
|
this.handleLabelClick = event => {
|
|
361
|
-
// Browsers automatically use the for attribute to select the input,
|
|
362
|
-
// but we use ClickableBehavior to handle this.
|
|
363
333
|
event.preventDefault();
|
|
364
334
|
};
|
|
365
335
|
|
|
@@ -368,7 +338,7 @@ class ChoiceInternal extends React.Component {
|
|
|
368
338
|
checked,
|
|
369
339
|
onChange,
|
|
370
340
|
variant
|
|
371
|
-
} = this.props;
|
|
341
|
+
} = this.props;
|
|
372
342
|
|
|
373
343
|
if (variant === "radio" && checked) {
|
|
374
344
|
return;
|
|
@@ -392,9 +362,9 @@ class ChoiceInternal extends React.Component {
|
|
|
392
362
|
id,
|
|
393
363
|
label
|
|
394
364
|
} = this.props;
|
|
395
|
-
return
|
|
365
|
+
return React.createElement(LabelMedium, {
|
|
396
366
|
style: [styles$3.label, disabled && styles$3.disabledLabel]
|
|
397
|
-
},
|
|
367
|
+
}, React.createElement("label", {
|
|
398
368
|
htmlFor: id,
|
|
399
369
|
onClick: this.handleLabelClick
|
|
400
370
|
}, label));
|
|
@@ -404,7 +374,7 @@ class ChoiceInternal extends React.Component {
|
|
|
404
374
|
const {
|
|
405
375
|
description
|
|
406
376
|
} = this.props;
|
|
407
|
-
return
|
|
377
|
+
return React.createElement(LabelSmall, {
|
|
408
378
|
style: styles$3.description,
|
|
409
379
|
id: id
|
|
410
380
|
}, description);
|
|
@@ -423,29 +393,26 @@ class ChoiceInternal extends React.Component {
|
|
|
423
393
|
|
|
424
394
|
const ChoiceCore = this.getChoiceCoreComponent();
|
|
425
395
|
const ClickableBehavior = getClickableBehavior();
|
|
426
|
-
return
|
|
396
|
+
return React.createElement(UniqueIDProvider, {
|
|
427
397
|
mockOnFirstRender: true,
|
|
428
398
|
scope: "choice"
|
|
429
399
|
}, ids => {
|
|
430
400
|
const descriptionId = description && ids.get("description");
|
|
431
|
-
return
|
|
401
|
+
return React.createElement(View, {
|
|
432
402
|
style: style,
|
|
433
403
|
className: className
|
|
434
|
-
},
|
|
404
|
+
}, React.createElement(ClickableBehavior, {
|
|
435
405
|
disabled: coreProps.disabled,
|
|
436
406
|
onClick: this.handleClick,
|
|
437
407
|
role: variant
|
|
438
408
|
}, (state, childrenProps) => {
|
|
439
|
-
return
|
|
409
|
+
return React.createElement(View, _extends({
|
|
440
410
|
style: styles$3.wrapper
|
|
441
411
|
}, childrenProps, {
|
|
442
|
-
// We are resetting the tabIndex=0 from handlers
|
|
443
|
-
// because the ChoiceCore component will receive
|
|
444
|
-
// focus on basis of it being an input element.
|
|
445
412
|
tabIndex: -1
|
|
446
|
-
}),
|
|
413
|
+
}), React.createElement(ChoiceCore, _extends({}, coreProps, state, {
|
|
447
414
|
"aria-describedby": descriptionId
|
|
448
|
-
})),
|
|
415
|
+
})), React.createElement(Strut, {
|
|
449
416
|
size: Spacing.xSmall_8
|
|
450
417
|
}), label && this.getLabel());
|
|
451
418
|
}), description && this.getDescription(descriptionId));
|
|
@@ -466,33 +433,21 @@ const styles$3 = StyleSheet.create({
|
|
|
466
433
|
},
|
|
467
434
|
label: {
|
|
468
435
|
userSelect: "none",
|
|
469
|
-
// NOTE: The checkbox/radio button (height 16px) should be center
|
|
470
|
-
// aligned with the first line of the label. However, LabelMedium has a
|
|
471
|
-
// declared line height of 20px, so we need to adjust the top to get the
|
|
472
|
-
// desired alignment.
|
|
473
436
|
marginTop: -2
|
|
474
437
|
},
|
|
475
438
|
disabledLabel: {
|
|
476
439
|
color: Color.offBlack32
|
|
477
440
|
},
|
|
478
441
|
description: {
|
|
479
|
-
// 16 for icon + 8 for spacing strut
|
|
480
442
|
marginLeft: Spacing.medium_16 + Spacing.xSmall_8,
|
|
481
443
|
marginTop: Spacing.xxxSmall_4,
|
|
482
444
|
color: Color.offBlack64
|
|
483
445
|
}
|
|
484
446
|
});
|
|
485
447
|
|
|
486
|
-
/**
|
|
487
|
-
* ☑️ A nicely styled checkbox for all your checking needs. Can optionally take
|
|
488
|
-
* label and description props.
|
|
489
|
-
*
|
|
490
|
-
* If you want a whole group of Checkbox[es] that are related, see the Choice
|
|
491
|
-
* and CheckboxGroup components.
|
|
492
|
-
*/
|
|
493
448
|
class Checkbox extends React.Component {
|
|
494
449
|
render() {
|
|
495
|
-
return
|
|
450
|
+
return React.createElement(ChoiceInternal, _extends({
|
|
496
451
|
variant: "checkbox"
|
|
497
452
|
}, this.props));
|
|
498
453
|
}
|
|
@@ -503,16 +458,9 @@ Checkbox.defaultProps = {
|
|
|
503
458
|
error: false
|
|
504
459
|
};
|
|
505
460
|
|
|
506
|
-
/**
|
|
507
|
-
* 🔘 A nicely styled radio button for all your non-AMFM radio button needs. Can
|
|
508
|
-
* optionally take label and description props.
|
|
509
|
-
*
|
|
510
|
-
* This component should not really be used by itself because radio buttons are
|
|
511
|
-
* often grouped together. See RadioGroup.
|
|
512
|
-
*/
|
|
513
461
|
class Radio extends React.Component {
|
|
514
462
|
render() {
|
|
515
|
-
return
|
|
463
|
+
return React.createElement(ChoiceInternal, _extends({
|
|
516
464
|
variant: "radio"
|
|
517
465
|
}, this.props));
|
|
518
466
|
}
|
|
@@ -524,16 +472,6 @@ Radio.defaultProps = {
|
|
|
524
472
|
};
|
|
525
473
|
|
|
526
474
|
const _excluded$1 = ["value", "variant"];
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* This is a labeled 🔘 or ☑️ item. Choice is meant to be used as children of
|
|
530
|
-
* CheckboxGroup and RadioGroup because many of its props are auto-populated
|
|
531
|
-
* and not shown in the documentation here. See those components for usage
|
|
532
|
-
* examples.
|
|
533
|
-
*
|
|
534
|
-
* If you wish to use just a single field, use Checkbox or Radio with the
|
|
535
|
-
* optional label and description props.
|
|
536
|
-
*/
|
|
537
475
|
class Choice extends React.Component {
|
|
538
476
|
getChoiceComponent(variant) {
|
|
539
477
|
if (variant === "checkbox") {
|
|
@@ -544,8 +482,6 @@ class Choice extends React.Component {
|
|
|
544
482
|
}
|
|
545
483
|
|
|
546
484
|
render() {
|
|
547
|
-
// we don't need this going into the ChoiceComponent
|
|
548
|
-
// eslint-disable-next-line no-unused-vars
|
|
549
485
|
const _this$props = this.props,
|
|
550
486
|
{
|
|
551
487
|
variant
|
|
@@ -553,7 +489,7 @@ class Choice extends React.Component {
|
|
|
553
489
|
remainingProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
|
|
554
490
|
|
|
555
491
|
const ChoiceComponent = this.getChoiceComponent(variant);
|
|
556
|
-
return
|
|
492
|
+
return React.createElement(ChoiceComponent, remainingProps);
|
|
557
493
|
}
|
|
558
494
|
|
|
559
495
|
}
|
|
@@ -587,13 +523,6 @@ const styles$2 = StyleSheet.create({
|
|
|
587
523
|
|
|
588
524
|
const StyledFieldset$1 = addStyle("fieldset");
|
|
589
525
|
const StyledLegend$1 = addStyle("legend");
|
|
590
|
-
/**
|
|
591
|
-
* A checkbox group allows multiple selection. This component auto-populates
|
|
592
|
-
* many props for its children Choice components. The Choice component is
|
|
593
|
-
* exposed for the user to apply custom styles or to indicate which choices are
|
|
594
|
-
* disabled.
|
|
595
|
-
*/
|
|
596
|
-
|
|
597
526
|
class CheckboxGroup extends React.Component {
|
|
598
527
|
handleChange(changedValue, originalCheckedState) {
|
|
599
528
|
const {
|
|
@@ -621,18 +550,18 @@ class CheckboxGroup extends React.Component {
|
|
|
621
550
|
style,
|
|
622
551
|
testId
|
|
623
552
|
} = this.props;
|
|
624
|
-
return
|
|
553
|
+
return React.createElement(StyledFieldset$1, {
|
|
625
554
|
"data-test-id": testId,
|
|
626
555
|
style: styles$2.fieldset
|
|
627
|
-
},
|
|
556
|
+
}, React.createElement(View, {
|
|
628
557
|
style: style
|
|
629
|
-
}, typeof label === "string" ?
|
|
558
|
+
}, typeof label === "string" ? React.createElement(StyledLegend$1, {
|
|
630
559
|
style: styles$2.legend
|
|
631
|
-
},
|
|
560
|
+
}, React.createElement(LabelMedium, null, label)) : label && label, typeof description === "string" ? React.createElement(LabelSmall, {
|
|
632
561
|
style: styles$2.description
|
|
633
|
-
}, description) : description && description, errorMessage &&
|
|
562
|
+
}, description) : description && description, errorMessage && React.createElement(LabelSmall, {
|
|
634
563
|
style: styles$2.error
|
|
635
|
-
}, errorMessage), (label || description || errorMessage) &&
|
|
564
|
+
}, errorMessage), (label || description || errorMessage) && React.createElement(Strut, {
|
|
636
565
|
size: Spacing.small_12
|
|
637
566
|
}), React.Children.map(children, (child, index) => {
|
|
638
567
|
const {
|
|
@@ -640,7 +569,7 @@ class CheckboxGroup extends React.Component {
|
|
|
640
569
|
value
|
|
641
570
|
} = child.props;
|
|
642
571
|
const checked = selectedValues.includes(value);
|
|
643
|
-
return
|
|
572
|
+
return React.createElement(React.Fragment, null, React.cloneElement(child, {
|
|
644
573
|
checked: checked,
|
|
645
574
|
error: !!errorMessage,
|
|
646
575
|
groupName: groupName,
|
|
@@ -657,15 +586,6 @@ class CheckboxGroup extends React.Component {
|
|
|
657
586
|
|
|
658
587
|
const StyledFieldset = addStyle("fieldset");
|
|
659
588
|
const StyledLegend = addStyle("legend");
|
|
660
|
-
/**
|
|
661
|
-
* A radio group allows only single selection. Like CheckboxGroup, this
|
|
662
|
-
* component auto-populates many props for its children Choice components. The
|
|
663
|
-
* Choice component is exposed for the user to apply custom styles or to
|
|
664
|
-
* indicate which choices are disabled. The use of the groupName prop is
|
|
665
|
-
* important to maintain expected keyboard navigation behavior for
|
|
666
|
-
* accessibility.
|
|
667
|
-
*/
|
|
668
|
-
|
|
669
589
|
class RadioGroup extends React.Component {
|
|
670
590
|
handleChange(changedValue) {
|
|
671
591
|
this.props.onChange(changedValue);
|
|
@@ -682,18 +602,18 @@ class RadioGroup extends React.Component {
|
|
|
682
602
|
style,
|
|
683
603
|
testId
|
|
684
604
|
} = this.props;
|
|
685
|
-
return
|
|
605
|
+
return React.createElement(StyledFieldset, {
|
|
686
606
|
"data-test-id": testId,
|
|
687
607
|
style: styles$2.fieldset
|
|
688
|
-
},
|
|
608
|
+
}, React.createElement(View, {
|
|
689
609
|
style: style
|
|
690
|
-
}, label &&
|
|
610
|
+
}, label && React.createElement(StyledLegend, {
|
|
691
611
|
style: styles$2.legend
|
|
692
|
-
},
|
|
612
|
+
}, React.createElement(LabelMedium, null, label)), description && React.createElement(LabelSmall, {
|
|
693
613
|
style: styles$2.description
|
|
694
|
-
}, description), errorMessage &&
|
|
614
|
+
}, description), errorMessage && React.createElement(LabelSmall, {
|
|
695
615
|
style: styles$2.error
|
|
696
|
-
}, errorMessage), (label || description || errorMessage) &&
|
|
616
|
+
}, errorMessage), (label || description || errorMessage) && React.createElement(Strut, {
|
|
697
617
|
size: Spacing.small_12
|
|
698
618
|
}), React.Children.map(children, (child, index) => {
|
|
699
619
|
const {
|
|
@@ -701,7 +621,7 @@ class RadioGroup extends React.Component {
|
|
|
701
621
|
value
|
|
702
622
|
} = child.props;
|
|
703
623
|
const checked = selectedValue === value;
|
|
704
|
-
return
|
|
624
|
+
return React.createElement(React.Fragment, null, React.cloneElement(child, {
|
|
705
625
|
checked: checked,
|
|
706
626
|
error: !!errorMessage,
|
|
707
627
|
groupName: groupName,
|
|
@@ -719,11 +639,6 @@ class RadioGroup extends React.Component {
|
|
|
719
639
|
const _excluded = ["id", "type", "value", "disabled", "onKeyDown", "placeholder", "light", "style", "testId", "readOnly", "autoComplete", "forwardedRef", "onFocus", "onBlur", "onValidate", "validate", "onChange", "required"];
|
|
720
640
|
const defaultErrorMessage = "This field is required.";
|
|
721
641
|
|
|
722
|
-
// TODO(WB-1081): Change class name back to TextField after Styleguidist is gone.
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* A TextField is an element used to accept a single line of text from the user.
|
|
726
|
-
*/
|
|
727
642
|
class TextFieldInternal extends React.Component {
|
|
728
643
|
constructor(props) {
|
|
729
644
|
super(props);
|
|
@@ -797,7 +712,6 @@ class TextFieldInternal extends React.Component {
|
|
|
797
712
|
};
|
|
798
713
|
|
|
799
714
|
if (props.validate && props.value !== "") {
|
|
800
|
-
// Ensures error is updated on unmounted server-side renders
|
|
801
715
|
this.state.error = props.validate(props.value) || null;
|
|
802
716
|
}
|
|
803
717
|
}
|
|
@@ -826,9 +740,8 @@ class TextFieldInternal extends React.Component {
|
|
|
826
740
|
} = _this$props,
|
|
827
741
|
otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
|
828
742
|
|
|
829
|
-
return
|
|
830
|
-
className: css([styles$1.input, styles$6.LabelMedium, styles$1.default,
|
|
831
|
-
disabled ? styles$1.disabled : this.state.focused ? [styles$1.focused, light && styles$1.defaultLight] : this.state.error && [styles$1.error, light && styles$1.errorLight], style && style]),
|
|
743
|
+
return React.createElement("input", _extends({
|
|
744
|
+
className: css([styles$1.input, styles$6.LabelMedium, styles$1.default, disabled ? styles$1.disabled : this.state.focused ? [styles$1.focused, light && styles$1.defaultLight] : this.state.error && [styles$1.error, light && styles$1.errorLight], style && style]),
|
|
832
745
|
id: id,
|
|
833
746
|
type: type,
|
|
834
747
|
placeholder: placeholder,
|
|
@@ -902,16 +815,11 @@ const styles$1 = StyleSheet.create({
|
|
|
902
815
|
boxShadow: `0px 0px 0px 1px ${Color.red}, 0px 0px 0px 2px ${Color.white}`
|
|
903
816
|
}
|
|
904
817
|
});
|
|
905
|
-
const TextField =
|
|
818
|
+
const TextField = React.forwardRef((props, ref) => React.createElement(TextFieldInternal, _extends({}, props, {
|
|
906
819
|
forwardedRef: ref
|
|
907
820
|
})));
|
|
908
821
|
|
|
909
822
|
const StyledSpan = addStyle("span");
|
|
910
|
-
/**
|
|
911
|
-
* A FieldHeading is an element that provides a label, description, and error element
|
|
912
|
-
* to present better context and hints to any type of form field component.
|
|
913
|
-
*/
|
|
914
|
-
|
|
915
823
|
class FieldHeading extends React.Component {
|
|
916
824
|
renderLabel() {
|
|
917
825
|
const {
|
|
@@ -920,16 +828,16 @@ class FieldHeading extends React.Component {
|
|
|
920
828
|
required,
|
|
921
829
|
testId
|
|
922
830
|
} = this.props;
|
|
923
|
-
const requiredIcon =
|
|
831
|
+
const requiredIcon = React.createElement(StyledSpan, {
|
|
924
832
|
style: styles.required,
|
|
925
833
|
"aria-hidden": true
|
|
926
834
|
}, " ", "*");
|
|
927
|
-
return
|
|
835
|
+
return React.createElement(React.Fragment, null, typeof label === "string" ? React.createElement(LabelMedium, {
|
|
928
836
|
style: styles.label,
|
|
929
837
|
tag: "label",
|
|
930
838
|
htmlFor: id && `${id}-field`,
|
|
931
839
|
testId: testId && `${testId}-label`
|
|
932
|
-
}, label, required && requiredIcon) : label,
|
|
840
|
+
}, label, required && requiredIcon) : label, React.createElement(Strut, {
|
|
933
841
|
size: Spacing.xxxSmall_4
|
|
934
842
|
}));
|
|
935
843
|
}
|
|
@@ -944,10 +852,10 @@ class FieldHeading extends React.Component {
|
|
|
944
852
|
return null;
|
|
945
853
|
}
|
|
946
854
|
|
|
947
|
-
return
|
|
855
|
+
return React.createElement(React.Fragment, null, typeof description === "string" ? React.createElement(LabelSmall, {
|
|
948
856
|
style: styles.description,
|
|
949
857
|
testId: testId && `${testId}-description`
|
|
950
|
-
}, description) : description,
|
|
858
|
+
}, description) : description, React.createElement(Strut, {
|
|
951
859
|
size: Spacing.xxxSmall_4
|
|
952
860
|
}));
|
|
953
861
|
}
|
|
@@ -963,9 +871,9 @@ class FieldHeading extends React.Component {
|
|
|
963
871
|
return null;
|
|
964
872
|
}
|
|
965
873
|
|
|
966
|
-
return
|
|
874
|
+
return React.createElement(React.Fragment, null, React.createElement(Strut, {
|
|
967
875
|
size: Spacing.small_12
|
|
968
|
-
}), typeof error === "string" ?
|
|
876
|
+
}), typeof error === "string" ? React.createElement(LabelSmall, {
|
|
969
877
|
style: styles.error,
|
|
970
878
|
role: "alert",
|
|
971
879
|
id: id && `${id}-error`,
|
|
@@ -978,9 +886,9 @@ class FieldHeading extends React.Component {
|
|
|
978
886
|
field,
|
|
979
887
|
style
|
|
980
888
|
} = this.props;
|
|
981
|
-
return
|
|
889
|
+
return React.createElement(View, {
|
|
982
890
|
style: style
|
|
983
|
-
}, this.renderLabel(), this.maybeRenderDescription(),
|
|
891
|
+
}, this.renderLabel(), this.maybeRenderDescription(), React.createElement(Strut, {
|
|
984
892
|
size: Spacing.xSmall_8
|
|
985
893
|
}), field, this.maybeRenderError());
|
|
986
894
|
}
|
|
@@ -1001,12 +909,6 @@ const styles = StyleSheet.create({
|
|
|
1001
909
|
}
|
|
1002
910
|
});
|
|
1003
911
|
|
|
1004
|
-
// TODO(WB-1081): Change class name back to LabeledTextField after Styleguidist is gone.
|
|
1005
|
-
|
|
1006
|
-
/**
|
|
1007
|
-
* A LabeledTextField is an element used to accept a single line of text
|
|
1008
|
-
* from the user paired with a label, description, and error field elements.
|
|
1009
|
-
*/
|
|
1010
912
|
class LabeledTextFieldInternal extends React.Component {
|
|
1011
913
|
constructor(props) {
|
|
1012
914
|
super(props);
|
|
@@ -1077,14 +979,14 @@ class LabeledTextFieldInternal extends React.Component {
|
|
|
1077
979
|
forwardedRef,
|
|
1078
980
|
ariaDescribedby
|
|
1079
981
|
} = this.props;
|
|
1080
|
-
return
|
|
982
|
+
return React.createElement(IDProvider, {
|
|
1081
983
|
id: id,
|
|
1082
984
|
scope: "labeled-text-field"
|
|
1083
|
-
}, uniqueId =>
|
|
985
|
+
}, uniqueId => React.createElement(FieldHeading, {
|
|
1084
986
|
id: uniqueId,
|
|
1085
987
|
testId: testId,
|
|
1086
988
|
style: style,
|
|
1087
|
-
field:
|
|
989
|
+
field: React.createElement(TextField, {
|
|
1088
990
|
id: `${uniqueId}-field`,
|
|
1089
991
|
"aria-describedby": ariaDescribedby ? ariaDescribedby : `${uniqueId}-error`,
|
|
1090
992
|
"aria-invalid": this.state.error ? "true" : "false",
|
|
@@ -1120,7 +1022,7 @@ LabeledTextFieldInternal.defaultProps = {
|
|
|
1120
1022
|
disabled: false,
|
|
1121
1023
|
light: false
|
|
1122
1024
|
};
|
|
1123
|
-
const LabeledTextField =
|
|
1025
|
+
const LabeledTextField = React.forwardRef((props, ref) => React.createElement(LabeledTextFieldInternal, _extends({}, props, {
|
|
1124
1026
|
forwardedRef: ref
|
|
1125
1027
|
})));
|
|
1126
1028
|
|
package/dist/index.js
CHANGED
|
@@ -182,8 +182,22 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|
|
182
182
|
* ☑️ A nicely styled checkbox for all your checking needs. Can optionally take
|
|
183
183
|
* label and description props.
|
|
184
184
|
*
|
|
185
|
+
* If used by itself, a checkbox provides two options - checked and unchecked.
|
|
186
|
+
* A group of checkboxes can be used to allow a user to select multiple values
|
|
187
|
+
* from a list of options.
|
|
188
|
+
*
|
|
185
189
|
* If you want a whole group of Checkbox[es] that are related, see the Choice
|
|
186
190
|
* and CheckboxGroup components.
|
|
191
|
+
*
|
|
192
|
+
* ### Usage
|
|
193
|
+
*
|
|
194
|
+
* ```jsx
|
|
195
|
+
* import {Checkbox} from "@khanacademy/wonder-blocks-form";
|
|
196
|
+
*
|
|
197
|
+
* const [checked, setChecked] = React.useState(false);
|
|
198
|
+
*
|
|
199
|
+
* <Checkbox checked={checked} onChange={setChecked} />
|
|
200
|
+
* ```
|
|
187
201
|
*/
|
|
188
202
|
class Checkbox extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
189
203
|
render() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-form",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.5",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"description": "Form components for Wonder Blocks.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,19 +16,19 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@babel/runtime": "^7.16.3",
|
|
19
|
-
"@khanacademy/wonder-blocks-clickable": "^2.2.
|
|
19
|
+
"@khanacademy/wonder-blocks-clickable": "^2.2.7",
|
|
20
20
|
"@khanacademy/wonder-blocks-color": "^1.1.20",
|
|
21
|
-
"@khanacademy/wonder-blocks-core": "^4.3.
|
|
22
|
-
"@khanacademy/wonder-blocks-icon": "^1.2.
|
|
23
|
-
"@khanacademy/wonder-blocks-layout": "^1.4.
|
|
21
|
+
"@khanacademy/wonder-blocks-core": "^4.3.2",
|
|
22
|
+
"@khanacademy/wonder-blocks-icon": "^1.2.29",
|
|
23
|
+
"@khanacademy/wonder-blocks-layout": "^1.4.10",
|
|
24
24
|
"@khanacademy/wonder-blocks-spacing": "^3.0.5",
|
|
25
|
-
"@khanacademy/wonder-blocks-typography": "^1.1.
|
|
25
|
+
"@khanacademy/wonder-blocks-typography": "^1.1.32"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"aphrodite": "^1.2.5",
|
|
29
29
|
"react": "16.14.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"wb-dev-build-settings": "^0.
|
|
32
|
+
"wb-dev-build-settings": "^0.4.0"
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {Meta, Story, Canvas} from "@storybook/addon-docs";
|
|
2
|
+
import {StyleSheet} from "aphrodite";
|
|
3
|
+
|
|
4
|
+
import Color from "@khanacademy/wonder-blocks-color";
|
|
5
|
+
import {Checkbox} from "@khanacademy/wonder-blocks-form";
|
|
6
|
+
import {LabelSmall} from "@khanacademy/wonder-blocks-typography";
|
|
7
|
+
|
|
8
|
+
<Meta
|
|
9
|
+
title="Form/Checkbox/Accessibility"
|
|
10
|
+
component={Checkbox}
|
|
11
|
+
parameters={{
|
|
12
|
+
previewTabs: {
|
|
13
|
+
canvas: {hidden: true},
|
|
14
|
+
},
|
|
15
|
+
viewMode: "docs",
|
|
16
|
+
chromatic: {
|
|
17
|
+
// Disables chromatic testing for these stories.
|
|
18
|
+
disableSnapshot: true,
|
|
19
|
+
},
|
|
20
|
+
}}
|
|
21
|
+
/>
|
|
22
|
+
|
|
23
|
+
export const ErrorTemplate = (args) => {
|
|
24
|
+
const [checked, setChecked] = React.useState(false);
|
|
25
|
+
const errorState = !checked;
|
|
26
|
+
return (
|
|
27
|
+
<View>
|
|
28
|
+
<Checkbox
|
|
29
|
+
checked={checked}
|
|
30
|
+
onChange={setChecked}
|
|
31
|
+
error={errorState}
|
|
32
|
+
aria-describedby={errorState && "error-message"}
|
|
33
|
+
aria-required={true}
|
|
34
|
+
{...args}
|
|
35
|
+
/>
|
|
36
|
+
{errorState && (
|
|
37
|
+
<LabelSmall style={styles.error} id="error-message">
|
|
38
|
+
You must agree to the terms to continue
|
|
39
|
+
</LabelSmall>
|
|
40
|
+
)}
|
|
41
|
+
</View>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const DisabledTemplate = (args) => {
|
|
46
|
+
const [checked, setChecked] = React.useState(false);
|
|
47
|
+
const errorState = !checked;
|
|
48
|
+
return (
|
|
49
|
+
<Checkbox
|
|
50
|
+
checked={checked}
|
|
51
|
+
onChange={setChecked}
|
|
52
|
+
label="Some setting"
|
|
53
|
+
description="You do not have permission to change this setting"
|
|
54
|
+
disabled={true}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
## Accessibility
|
|
60
|
+
|
|
61
|
+
### ARIA
|
|
62
|
+
|
|
63
|
+
`Checkbox` can take in all ARIA props defined in Wonder Blocks Core types.
|
|
64
|
+
|
|
65
|
+
Elements with role `"checkbox"` can have an `aria-checked` property that
|
|
66
|
+
exposes the checked state to assistive technology. The dev does not have
|
|
67
|
+
to worry about this because the Wonder Blocks Checkbox component is an
|
|
68
|
+
`input` element with type `"checkbox"`, as this has built-in semantics and
|
|
69
|
+
does not require ARIA.
|
|
70
|
+
|
|
71
|
+
The current implementation of `Checkbox` uses `aria-describedby` with the
|
|
72
|
+
label and description that may be passed in as props.
|
|
73
|
+
|
|
74
|
+
See the Error section for information about `aria-invalid` and
|
|
75
|
+
`aria-required`.
|
|
76
|
+
|
|
77
|
+
### Error state
|
|
78
|
+
|
|
79
|
+
The Wonder Blocks `Checkbox` component takes an `error` boolean prop. Setting
|
|
80
|
+
this prop to true will set `aria-invalid` to true, and the color of the
|
|
81
|
+
checkbox to red.
|
|
82
|
+
|
|
83
|
+
When a form input is invalid, the user should provide a reason for why
|
|
84
|
+
this is.
|
|
85
|
+
|
|
86
|
+
Generally, it is also suggested this is the validation error message is
|
|
87
|
+
passed to the checkbox's `aria-describedby` prop so assistive tech can
|
|
88
|
+
read it. However, this is not possible with the current implementation of
|
|
89
|
+
the Wonder Blocks Form Checkbox component.
|
|
90
|
+
|
|
91
|
+
The error state can be used to signal that a required checkbox has not been
|
|
92
|
+
checked. In cases where a checkbox is required, the checkbox component should
|
|
93
|
+
set the `aria-required` prop to true for assistive tech.
|
|
94
|
+
There should also be some sort of visual indication that checking
|
|
95
|
+
the box is required, such as a "Required" label or an asterisk.
|
|
96
|
+
|
|
97
|
+
<Canvas>
|
|
98
|
+
<Story
|
|
99
|
+
name="Error state"
|
|
100
|
+
args={{
|
|
101
|
+
label: "I accept the terms and conditions",
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
{ErrorTemplate.bind({})}
|
|
105
|
+
</Story>
|
|
106
|
+
</Canvas>
|
|
107
|
+
|
|
108
|
+
### Disabled state
|
|
109
|
+
|
|
110
|
+
The Wonder Blocks `Checkbox` compoenent takes a `disabled` boolean prop.
|
|
111
|
+
This sets the underlying `input` element's `disabled` prop to `true`.
|
|
112
|
+
This makes is so that the checkbox is not interactable. Also, assistive
|
|
113
|
+
tech will indicated that the checkbox is dimmed.
|
|
114
|
+
|
|
115
|
+
A user will not be able to navigate to the checkbox with a keyboard.
|
|
116
|
+
Screen reader users will be able to navigate to the checkbox with
|
|
117
|
+
screen reader controls.
|
|
118
|
+
|
|
119
|
+
It is suggested that if an element is disabled, an explanation as to why
|
|
120
|
+
should to provided somewhere.
|
|
121
|
+
|
|
122
|
+
<Canvas>
|
|
123
|
+
<Story name="Disabled state">{DisabledTemplate.bind({})}</Story>
|
|
124
|
+
</Canvas>
|
|
125
|
+
|
|
126
|
+
### Keyboard Interaction
|
|
127
|
+
|
|
128
|
+
If a checkbox is not disabled, a user can tab to it using standard
|
|
129
|
+
keyboard navigation. The Space key toggles the checked state of the checkbox.
|
|
130
|
+
|
|
131
|
+
Note the the Space key triggers the `onChange` function of the
|
|
132
|
+
Wonder Blocks Checkbox component. If the user does not specify an `onChange`
|
|
133
|
+
funciton prop that in turn updates the value of `checked`, neither clicking
|
|
134
|
+
nor the Space key will toggle the Checkbox.
|
|
135
|
+
|
|
136
|
+
### References
|
|
137
|
+
|
|
138
|
+
- [Accessible validation of checkbox and radiobutton groups](https://blog.tenon.io/accessible-validation-of-checkbox-and-radiobutton-groups/)
|
|
139
|
+
- [HTML: Validating a checkbox with HTML5](https://www.the-art-of-web.com/html/html5-checkbox-required/#example1)
|
|
140
|
+
- [aria-checked MDN Docs](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked)
|
|
141
|
+
- [ARIA: checkbox role MDN Docs](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/checkbox_role)
|
|
142
|
+
|
|
143
|
+
export const styles = StyleSheet.create({
|
|
144
|
+
error: {
|
|
145
|
+
color: Color.red,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import {StyleSheet} from "aphrodite";
|
|
4
|
+
|
|
5
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
6
|
+
import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography";
|
|
7
|
+
import type {StoryComponentType} from "@storybook/react";
|
|
8
|
+
|
|
9
|
+
import Checkbox from "../checkbox.js";
|
|
10
|
+
|
|
11
|
+
import ComponentInfo from "../../../../../.storybook/components/component-info.js";
|
|
12
|
+
import {name, version} from "../../../package.json";
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
title: "Form / Checkbox",
|
|
16
|
+
component: Checkbox,
|
|
17
|
+
parameters: {
|
|
18
|
+
componentSubtitle: ((
|
|
19
|
+
<ComponentInfo name={name} version={version} />
|
|
20
|
+
): any),
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const Default: StoryComponentType = (args) => <Checkbox {...args} />;
|
|
25
|
+
|
|
26
|
+
Default.args = {
|
|
27
|
+
checked: false,
|
|
28
|
+
onChange: () => {},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
Default.parameters = {
|
|
32
|
+
chromatic: {
|
|
33
|
+
// We already have screenshots of another story that covers
|
|
34
|
+
// this and more cases.
|
|
35
|
+
disableSnapshot: true,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Controlled: StoryComponentType = () => {
|
|
40
|
+
const [checked, setChecked] = React.useState(false);
|
|
41
|
+
return <Checkbox checked={checked} onChange={setChecked} />;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
Controlled.parameters = {
|
|
45
|
+
chromatic: {
|
|
46
|
+
// Disabling because this doesn't test visuals, its for testing
|
|
47
|
+
// that `state` works as expected.
|
|
48
|
+
disableSnapshot: true,
|
|
49
|
+
},
|
|
50
|
+
docs: {
|
|
51
|
+
storyDescription:
|
|
52
|
+
"Use state to keep track of whether the checkbox is checked or not",
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const Variants: StoryComponentType = () => (
|
|
57
|
+
<View style={styles.row}>
|
|
58
|
+
<Checkbox
|
|
59
|
+
error={false}
|
|
60
|
+
checked={false}
|
|
61
|
+
style={styles.marginRight}
|
|
62
|
+
onChange={() => {}}
|
|
63
|
+
/>
|
|
64
|
+
<Checkbox
|
|
65
|
+
error={false}
|
|
66
|
+
checked={true}
|
|
67
|
+
style={styles.marginRight}
|
|
68
|
+
onChange={() => {}}
|
|
69
|
+
/>
|
|
70
|
+
<Checkbox
|
|
71
|
+
error={true}
|
|
72
|
+
checked={false}
|
|
73
|
+
style={styles.marginRight}
|
|
74
|
+
onChange={() => {}}
|
|
75
|
+
/>
|
|
76
|
+
<Checkbox
|
|
77
|
+
error={true}
|
|
78
|
+
checked={true}
|
|
79
|
+
style={styles.marginRight}
|
|
80
|
+
onChange={() => {}}
|
|
81
|
+
/>
|
|
82
|
+
<Checkbox
|
|
83
|
+
disabled={true}
|
|
84
|
+
checked={false}
|
|
85
|
+
style={styles.marginRight}
|
|
86
|
+
onChange={() => {}}
|
|
87
|
+
/>
|
|
88
|
+
<Checkbox
|
|
89
|
+
disabled={true}
|
|
90
|
+
checked={true}
|
|
91
|
+
style={styles.marginRight}
|
|
92
|
+
onChange={() => {}}
|
|
93
|
+
/>
|
|
94
|
+
</View>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
Variants.parameters = {
|
|
98
|
+
docs: {
|
|
99
|
+
storyDescription:
|
|
100
|
+
"The checkbox has various styles for clickable states. Here are sets of default checkboxes, checkboxes in an error state, and disabled checkboxes.",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const WithLabel: StoryComponentType = () => {
|
|
105
|
+
const [checked, setChecked] = React.useState(false);
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<Checkbox
|
|
109
|
+
label="Receive assignment reminders for Algebra"
|
|
110
|
+
description="You will receive a reminder 24 hours before each deadline"
|
|
111
|
+
checked={checked}
|
|
112
|
+
onChange={setChecked}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
WithLabel.parameters = {
|
|
118
|
+
docs: {
|
|
119
|
+
storyDescription:
|
|
120
|
+
"The checkbox can have a optional label and description. This allows it to be used as a settings-like item. The user of this component is responsible for keeping track of checked state and providing an onChange callback.",
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const AdditionalClickTarget: StoryComponentType = () => {
|
|
125
|
+
const [checked, setChecked] = React.useState(false);
|
|
126
|
+
const headingText = "Functions";
|
|
127
|
+
const descriptionText = `A great cook knows how to take basic
|
|
128
|
+
ingredients and prepare a delicious meal. In this topic, you will
|
|
129
|
+
become function-chefs! You will learn how to combine functions
|
|
130
|
+
with arithmetic operations and how to compose functions.`;
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<View style={styles.wrapper}>
|
|
134
|
+
<View style={styles.topic}>
|
|
135
|
+
<label htmlFor="topic-123">
|
|
136
|
+
<LabelMedium>{headingText}</LabelMedium>
|
|
137
|
+
</label>
|
|
138
|
+
<LabelSmall>{descriptionText}</LabelSmall>
|
|
139
|
+
</View>
|
|
140
|
+
<Checkbox checked={checked} id="topic-123" onChange={setChecked} />
|
|
141
|
+
</View>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
AdditionalClickTarget.parameters = {
|
|
146
|
+
docs: {
|
|
147
|
+
storyDescription:
|
|
148
|
+
"Sometimes one may wish to use a checkbox in a different context (label may not be right next to the checkbox), like in this example content item. Use a `<label htmlFor={id}>` element where the id matches the `id` prop of the Checkbox. This is for accessibility purposes, and doing this also automatically makes the label a click target for the checkbox.",
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const styles = StyleSheet.create({
|
|
153
|
+
row: {
|
|
154
|
+
flexDirection: "row",
|
|
155
|
+
},
|
|
156
|
+
marginRight: {
|
|
157
|
+
marginRight: 16,
|
|
158
|
+
},
|
|
159
|
+
wrapper: {
|
|
160
|
+
flexDirection: "row",
|
|
161
|
+
alignItems: "center",
|
|
162
|
+
justifyContent: "space-evenly",
|
|
163
|
+
},
|
|
164
|
+
topic: {
|
|
165
|
+
maxWidth: 600,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
@@ -79,8 +79,22 @@ type DefaultProps = {|
|
|
|
79
79
|
* ☑️ A nicely styled checkbox for all your checking needs. Can optionally take
|
|
80
80
|
* label and description props.
|
|
81
81
|
*
|
|
82
|
+
* If used by itself, a checkbox provides two options - checked and unchecked.
|
|
83
|
+
* A group of checkboxes can be used to allow a user to select multiple values
|
|
84
|
+
* from a list of options.
|
|
85
|
+
*
|
|
82
86
|
* If you want a whole group of Checkbox[es] that are related, see the Choice
|
|
83
87
|
* and CheckboxGroup components.
|
|
88
|
+
*
|
|
89
|
+
* ### Usage
|
|
90
|
+
*
|
|
91
|
+
* ```jsx
|
|
92
|
+
* import {Checkbox} from "@khanacademy/wonder-blocks-form";
|
|
93
|
+
*
|
|
94
|
+
* const [checked, setChecked] = React.useState(false);
|
|
95
|
+
*
|
|
96
|
+
* <Checkbox checked={checked} onChange={setChecked} />
|
|
97
|
+
* ```
|
|
84
98
|
*/
|
|
85
99
|
export default class Checkbox extends React.Component<ChoiceComponentProps> {
|
|
86
100
|
static defaultProps: DefaultProps = {
|