@khanacademy/wonder-blocks-form 3.1.7 → 3.1.9

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,26 @@
1
1
  # @khanacademy/wonder-blocks-form
2
2
 
3
+ ## 3.1.9
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [496119f2]
8
+ - @khanacademy/wonder-blocks-clickable@2.4.4
9
+ - @khanacademy/wonder-blocks-core@4.6.2
10
+ - @khanacademy/wonder-blocks-icon@1.2.35
11
+ - @khanacademy/wonder-blocks-layout@1.4.15
12
+ - @khanacademy/wonder-blocks-typography@1.1.37
13
+
14
+ ## 3.1.8
15
+
16
+ ### Patch Changes
17
+
18
+ - @khanacademy/wonder-blocks-clickable@2.4.3
19
+ - @khanacademy/wonder-blocks-core@4.6.1
20
+ - @khanacademy/wonder-blocks-icon@1.2.34
21
+ - @khanacademy/wonder-blocks-layout@1.4.14
22
+ - @khanacademy/wonder-blocks-typography@1.1.36
23
+
3
24
  ## 3.1.7
4
25
 
5
26
  ### Patch Changes
package/dist/index.js ADDED
@@ -0,0 +1,1067 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _extends = require('@babel/runtime/helpers/extends');
6
+ var React = require('react');
7
+ var _objectWithoutPropertiesLoose = require('@babel/runtime/helpers/objectWithoutPropertiesLoose');
8
+ var aphrodite = require('aphrodite');
9
+ var Color = require('@khanacademy/wonder-blocks-color');
10
+ var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
11
+ var wonderBlocksClickable = require('@khanacademy/wonder-blocks-clickable');
12
+ var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
13
+ var Spacing = require('@khanacademy/wonder-blocks-spacing');
14
+ var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
15
+ var Icon = require('@khanacademy/wonder-blocks-icon');
16
+
17
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
+
19
+ function _interopNamespace(e) {
20
+ if (e && e.__esModule) return e;
21
+ var n = Object.create(null);
22
+ if (e) {
23
+ Object.keys(e).forEach(function (k) {
24
+ if (k !== 'default') {
25
+ var d = Object.getOwnPropertyDescriptor(e, k);
26
+ Object.defineProperty(n, k, d.get ? d : {
27
+ enumerable: true,
28
+ get: function () { return e[k]; }
29
+ });
30
+ }
31
+ });
32
+ }
33
+ n["default"] = e;
34
+ return Object.freeze(n);
35
+ }
36
+
37
+ var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
38
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
39
+ var _objectWithoutPropertiesLoose__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutPropertiesLoose);
40
+ var Color__default = /*#__PURE__*/_interopDefaultLegacy(Color);
41
+ var Spacing__default = /*#__PURE__*/_interopDefaultLegacy(Spacing);
42
+ var Icon__default = /*#__PURE__*/_interopDefaultLegacy(Icon);
43
+
44
+ const _excluded$4 = ["checked", "disabled", "error", "groupName", "id", "testId", "hovered", "focused", "pressed", "waiting"];
45
+ const {
46
+ blue: blue$1,
47
+ red: red$1,
48
+ white: white$1,
49
+ offWhite: offWhite$1,
50
+ offBlack16: offBlack16$1,
51
+ offBlack32: offBlack32$1,
52
+ offBlack50: offBlack50$1
53
+ } = Color__default["default"];
54
+ const StyledInput$1 = wonderBlocksCore.addStyle("input");
55
+ const checkboxCheck = {
56
+ 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"
57
+ };
58
+ class CheckboxCore extends React__namespace.Component {
59
+ constructor(...args) {
60
+ super(...args);
61
+
62
+ this.handleChange = () => {
63
+ return;
64
+ };
65
+ }
66
+
67
+ render() {
68
+ const _this$props = this.props,
69
+ {
70
+ checked,
71
+ disabled,
72
+ error,
73
+ groupName,
74
+ id,
75
+ testId,
76
+ hovered,
77
+ focused,
78
+ pressed
79
+ } = _this$props,
80
+ sharedProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$4);
81
+
82
+ const stateStyles = _generateStyles$1(checked, error);
83
+
84
+ const defaultStyle = [sharedStyles$1.inputReset, sharedStyles$1.default, stateStyles.default, !disabled && (pressed ? stateStyles.active : (hovered || focused) && stateStyles.focus), disabled && sharedStyles$1.disabled];
85
+ const props = {
86
+ "data-test-id": testId
87
+ };
88
+ return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(StyledInput$1, _extends__default["default"]({}, sharedProps, {
89
+ type: "checkbox",
90
+ "aria-invalid": error,
91
+ checked: checked,
92
+ disabled: disabled,
93
+ id: id,
94
+ name: groupName,
95
+ onChange: this.handleChange,
96
+ style: defaultStyle
97
+ }, props)), checked && React__namespace.createElement(Icon__default["default"], {
98
+ color: disabled ? offBlack32$1 : white$1,
99
+ icon: checkboxCheck,
100
+ size: "small",
101
+ style: sharedStyles$1.checkIcon
102
+ }));
103
+ }
104
+
105
+ }
106
+ const size$1 = 16;
107
+ const sharedStyles$1 = aphrodite.StyleSheet.create({
108
+ inputReset: {
109
+ appearance: "none",
110
+ WebkitAppearance: "none",
111
+ MozAppearance: "none"
112
+ },
113
+ default: {
114
+ height: size$1,
115
+ width: size$1,
116
+ minHeight: size$1,
117
+ minWidth: size$1,
118
+ margin: 0,
119
+ outline: "none",
120
+ boxSizing: "border-box",
121
+ borderStyle: "solid",
122
+ borderWidth: 1,
123
+ borderRadius: 3
124
+ },
125
+ disabled: {
126
+ cursor: "auto",
127
+ backgroundColor: offWhite$1,
128
+ borderColor: offBlack16$1,
129
+ borderWidth: 1
130
+ },
131
+ checkIcon: {
132
+ position: "absolute",
133
+ pointerEvents: "none"
134
+ }
135
+ });
136
+ const fadedBlue$1 = Color.mix(Color.fade(blue$1, 0.16), white$1);
137
+ const activeBlue$1 = Color.mix(offBlack32$1, blue$1);
138
+ const fadedRed$1 = Color.mix(Color.fade(red$1, 0.08), white$1);
139
+ const activeRed$1 = Color.mix(offBlack32$1, red$1);
140
+ const colors$1 = {
141
+ default: {
142
+ faded: fadedBlue$1,
143
+ base: blue$1,
144
+ active: activeBlue$1
145
+ },
146
+ error: {
147
+ faded: fadedRed$1,
148
+ base: red$1,
149
+ active: activeRed$1
150
+ }
151
+ };
152
+ const styles$5 = {};
153
+
154
+ const _generateStyles$1 = (checked, error) => {
155
+ const styleKey = `${String(checked)}-${String(error)}`;
156
+
157
+ if (styles$5[styleKey]) {
158
+ return styles$5[styleKey];
159
+ }
160
+
161
+ const palette = error ? colors$1.error : colors$1.default;
162
+ let newStyles = {};
163
+
164
+ if (checked) {
165
+ newStyles = {
166
+ default: {
167
+ backgroundColor: palette.base,
168
+ borderWidth: 0
169
+ },
170
+ focus: {
171
+ boxShadow: `0 0 0 1px ${white$1}, 0 0 0 3px ${palette.base}`
172
+ },
173
+ active: {
174
+ boxShadow: `0 0 0 1px ${white$1}, 0 0 0 3px ${palette.active}`,
175
+ background: palette.active
176
+ }
177
+ };
178
+ } else {
179
+ newStyles = {
180
+ default: {
181
+ backgroundColor: error ? fadedRed$1 : white$1,
182
+ borderColor: error ? red$1 : offBlack50$1
183
+ },
184
+ focus: {
185
+ backgroundColor: error ? fadedRed$1 : white$1,
186
+ borderColor: palette.base,
187
+ borderWidth: 2
188
+ },
189
+ active: {
190
+ backgroundColor: palette.faded,
191
+ borderColor: error ? activeRed$1 : blue$1,
192
+ borderWidth: 2
193
+ }
194
+ };
195
+ }
196
+
197
+ styles$5[styleKey] = aphrodite.StyleSheet.create(newStyles);
198
+ return styles$5[styleKey];
199
+ };
200
+
201
+ const _excluded$3 = ["checked", "disabled", "error", "groupName", "id", "testId", "hovered", "focused", "pressed", "waiting"];
202
+ const {
203
+ blue,
204
+ red,
205
+ white,
206
+ offWhite,
207
+ offBlack16,
208
+ offBlack32,
209
+ offBlack50
210
+ } = Color__default["default"];
211
+ const StyledInput = wonderBlocksCore.addStyle("input");
212
+ class RadioCore extends React__namespace.Component {
213
+ constructor(...args) {
214
+ super(...args);
215
+
216
+ this.handleChange = () => {
217
+ return;
218
+ };
219
+ }
220
+
221
+ render() {
222
+ const _this$props = this.props,
223
+ {
224
+ checked,
225
+ disabled,
226
+ error,
227
+ groupName,
228
+ id,
229
+ testId,
230
+ hovered,
231
+ focused,
232
+ pressed
233
+ } = _this$props,
234
+ sharedProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$3);
235
+
236
+ const stateStyles = _generateStyles(checked, error);
237
+
238
+ const defaultStyle = [sharedStyles.inputReset, sharedStyles.default, stateStyles.default, !disabled && (pressed ? stateStyles.active : (hovered || focused) && stateStyles.focus), disabled && sharedStyles.disabled];
239
+ const props = {
240
+ "data-test-id": testId
241
+ };
242
+ return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(StyledInput, _extends__default["default"]({}, sharedProps, {
243
+ type: "radio",
244
+ "aria-invalid": error,
245
+ checked: checked,
246
+ disabled: disabled,
247
+ id: id,
248
+ name: groupName,
249
+ onChange: this.handleChange,
250
+ style: defaultStyle
251
+ }, props)), disabled && checked && React__namespace.createElement("span", {
252
+ style: disabledChecked
253
+ }));
254
+ }
255
+
256
+ }
257
+ const size = 16;
258
+ const disabledChecked = {
259
+ position: "absolute",
260
+ top: size / 4,
261
+ left: size / 4,
262
+ height: size / 2,
263
+ width: size / 2,
264
+ borderRadius: "50%",
265
+ backgroundColor: offBlack32
266
+ };
267
+ const sharedStyles = aphrodite.StyleSheet.create({
268
+ inputReset: {
269
+ appearance: "none",
270
+ WebkitAppearance: "none",
271
+ MozAppearance: "none"
272
+ },
273
+ default: {
274
+ height: size,
275
+ width: size,
276
+ minHeight: size,
277
+ minWidth: size,
278
+ margin: 0,
279
+ outline: "none",
280
+ boxSizing: "border-box",
281
+ borderStyle: "solid",
282
+ borderWidth: 1,
283
+ borderRadius: "50%"
284
+ },
285
+ disabled: {
286
+ cursor: "auto",
287
+ backgroundColor: offWhite,
288
+ borderColor: offBlack16,
289
+ borderWidth: 1
290
+ }
291
+ });
292
+ const fadedBlue = Color.mix(Color.fade(blue, 0.16), white);
293
+ const activeBlue = Color.mix(offBlack32, blue);
294
+ const fadedRed = Color.mix(Color.fade(red, 0.08), white);
295
+ const activeRed = Color.mix(offBlack32, red);
296
+ const colors = {
297
+ default: {
298
+ faded: fadedBlue,
299
+ base: blue,
300
+ active: activeBlue
301
+ },
302
+ error: {
303
+ faded: fadedRed,
304
+ base: red,
305
+ active: activeRed
306
+ }
307
+ };
308
+ const styles$4 = {};
309
+
310
+ const _generateStyles = (checked, error) => {
311
+ const styleKey = `${String(checked)}-${String(error)}`;
312
+
313
+ if (styles$4[styleKey]) {
314
+ return styles$4[styleKey];
315
+ }
316
+
317
+ const palette = error ? colors.error : colors.default;
318
+ let newStyles = {};
319
+
320
+ if (checked) {
321
+ newStyles = {
322
+ default: {
323
+ backgroundColor: white,
324
+ borderColor: palette.base,
325
+ borderWidth: size / 4
326
+ },
327
+ focus: {
328
+ boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.base}`
329
+ },
330
+ active: {
331
+ boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.active}`,
332
+ borderColor: palette.active
333
+ }
334
+ };
335
+ } else {
336
+ newStyles = {
337
+ default: {
338
+ backgroundColor: error ? fadedRed : white,
339
+ borderColor: error ? red : offBlack50
340
+ },
341
+ focus: {
342
+ backgroundColor: error ? fadedRed : white,
343
+ borderColor: palette.base,
344
+ borderWidth: 2
345
+ },
346
+ active: {
347
+ backgroundColor: palette.faded,
348
+ borderColor: error ? activeRed : blue,
349
+ borderWidth: 2
350
+ }
351
+ };
352
+ }
353
+
354
+ styles$4[styleKey] = aphrodite.StyleSheet.create(newStyles);
355
+ return styles$4[styleKey];
356
+ };
357
+
358
+ const _excluded$2 = ["label", "description", "onChange", "style", "className", "variant"];
359
+ class ChoiceInternal extends React__namespace.Component {
360
+ constructor(...args) {
361
+ super(...args);
362
+
363
+ this.handleLabelClick = event => {
364
+ event.preventDefault();
365
+ };
366
+
367
+ this.handleClick = () => {
368
+ const {
369
+ checked,
370
+ onChange,
371
+ variant
372
+ } = this.props;
373
+
374
+ if (variant === "radio" && checked) {
375
+ return;
376
+ }
377
+
378
+ onChange(!checked);
379
+ };
380
+ }
381
+
382
+ getChoiceCoreComponent() {
383
+ if (this.props.variant === "radio") {
384
+ return RadioCore;
385
+ } else {
386
+ return CheckboxCore;
387
+ }
388
+ }
389
+
390
+ getLabel() {
391
+ const {
392
+ disabled,
393
+ id,
394
+ label
395
+ } = this.props;
396
+ return React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
397
+ style: [styles$3.label, disabled && styles$3.disabledLabel]
398
+ }, React__namespace.createElement("label", {
399
+ htmlFor: id,
400
+ onClick: this.handleLabelClick
401
+ }, label));
402
+ }
403
+
404
+ getDescription(id) {
405
+ const {
406
+ description
407
+ } = this.props;
408
+ return React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
409
+ style: styles$3.description,
410
+ id: id
411
+ }, description);
412
+ }
413
+
414
+ render() {
415
+ const _this$props = this.props,
416
+ {
417
+ label,
418
+ description,
419
+ style,
420
+ className,
421
+ variant
422
+ } = _this$props,
423
+ coreProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$2);
424
+
425
+ const ChoiceCore = this.getChoiceCoreComponent();
426
+ const ClickableBehavior = wonderBlocksClickable.getClickableBehavior();
427
+ return React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, {
428
+ mockOnFirstRender: true,
429
+ scope: "choice"
430
+ }, ids => {
431
+ const descriptionId = description ? ids.get("description") : undefined;
432
+ return React__namespace.createElement(wonderBlocksCore.View, {
433
+ style: style,
434
+ className: className
435
+ }, React__namespace.createElement(ClickableBehavior, {
436
+ disabled: coreProps.disabled,
437
+ onClick: this.handleClick,
438
+ role: variant
439
+ }, (state, childrenProps) => {
440
+ return React__namespace.createElement(wonderBlocksCore.View, _extends__default["default"]({
441
+ style: styles$3.wrapper
442
+ }, childrenProps, {
443
+ tabIndex: -1
444
+ }), React__namespace.createElement(ChoiceCore, _extends__default["default"]({}, coreProps, state, {
445
+ "aria-describedby": descriptionId
446
+ })), React__namespace.createElement(wonderBlocksLayout.Strut, {
447
+ size: Spacing__default["default"].xSmall_8
448
+ }), label && this.getLabel());
449
+ }), description && this.getDescription(descriptionId));
450
+ });
451
+ }
452
+
453
+ }
454
+ ChoiceInternal.defaultProps = {
455
+ checked: false,
456
+ disabled: false,
457
+ error: false
458
+ };
459
+ const styles$3 = aphrodite.StyleSheet.create({
460
+ wrapper: {
461
+ flexDirection: "row",
462
+ alignItems: "flex-start",
463
+ outline: "none"
464
+ },
465
+ label: {
466
+ userSelect: "none",
467
+ marginTop: -2
468
+ },
469
+ disabledLabel: {
470
+ color: Color__default["default"].offBlack32
471
+ },
472
+ description: {
473
+ marginLeft: Spacing__default["default"].medium_16 + Spacing__default["default"].xSmall_8,
474
+ marginTop: Spacing__default["default"].xxxSmall_4,
475
+ color: Color__default["default"].offBlack64
476
+ }
477
+ });
478
+
479
+ class Checkbox extends React__namespace.Component {
480
+ render() {
481
+ return React__namespace.createElement(ChoiceInternal, _extends__default["default"]({
482
+ variant: "checkbox"
483
+ }, this.props));
484
+ }
485
+
486
+ }
487
+ Checkbox.defaultProps = {
488
+ disabled: false,
489
+ error: false
490
+ };
491
+
492
+ class Radio extends React__namespace.Component {
493
+ render() {
494
+ return React__namespace.createElement(ChoiceInternal, _extends__default["default"]({
495
+ variant: "radio"
496
+ }, this.props));
497
+ }
498
+
499
+ }
500
+ Radio.defaultProps = {
501
+ disabled: false,
502
+ error: false
503
+ };
504
+
505
+ const _excluded$1 = ["value", "variant"];
506
+ class Choice extends React__namespace.Component {
507
+ getChoiceComponent(variant) {
508
+ if (variant === "checkbox") {
509
+ return Checkbox;
510
+ } else {
511
+ return Radio;
512
+ }
513
+ }
514
+
515
+ render() {
516
+ const _this$props = this.props,
517
+ {
518
+ variant
519
+ } = _this$props,
520
+ remainingProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$1);
521
+
522
+ const ChoiceComponent = this.getChoiceComponent(variant);
523
+ return React__namespace.createElement(ChoiceComponent, remainingProps);
524
+ }
525
+
526
+ }
527
+ Choice.defaultProps = {
528
+ checked: false,
529
+ disabled: false,
530
+ onChange: () => {}
531
+ };
532
+
533
+ const styles$2 = aphrodite.StyleSheet.create({
534
+ fieldset: {
535
+ border: "none",
536
+ padding: 0,
537
+ margin: 0
538
+ },
539
+ legend: {
540
+ padding: 0
541
+ },
542
+ description: {
543
+ marginTop: Spacing__default["default"].xxxSmall_4,
544
+ color: Color__default["default"].offBlack64
545
+ },
546
+ error: {
547
+ marginTop: Spacing__default["default"].xxxSmall_4,
548
+ color: Color__default["default"].red
549
+ },
550
+ defaultLineGap: {
551
+ marginTop: Spacing__default["default"].xSmall_8
552
+ }
553
+ });
554
+
555
+ const StyledFieldset$1 = wonderBlocksCore.addStyle("fieldset");
556
+ const StyledLegend$1 = wonderBlocksCore.addStyle("legend");
557
+ class CheckboxGroup extends React__namespace.Component {
558
+ handleChange(changedValue, originalCheckedState) {
559
+ const {
560
+ onChange,
561
+ selectedValues
562
+ } = this.props;
563
+
564
+ if (originalCheckedState) {
565
+ const index = selectedValues.indexOf(changedValue);
566
+ const updatedSelection = [].concat(selectedValues.slice(0, index), selectedValues.slice(index + 1));
567
+ onChange(updatedSelection);
568
+ } else {
569
+ onChange([].concat(selectedValues, [changedValue]));
570
+ }
571
+ }
572
+
573
+ render() {
574
+ const {
575
+ children,
576
+ label,
577
+ description,
578
+ errorMessage,
579
+ groupName,
580
+ selectedValues,
581
+ style,
582
+ testId
583
+ } = this.props;
584
+ const allChildren = React__namespace.Children.toArray(children).filter(Boolean);
585
+ return React__namespace.createElement(StyledFieldset$1, {
586
+ "data-test-id": testId,
587
+ style: styles$2.fieldset
588
+ }, React__namespace.createElement(wonderBlocksCore.View, {
589
+ style: style
590
+ }, label && React__namespace.createElement(StyledLegend$1, {
591
+ style: styles$2.legend
592
+ }, React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, label)), description && React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
593
+ style: styles$2.description
594
+ }, description), errorMessage && React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
595
+ style: styles$2.error
596
+ }, errorMessage), (label || description || errorMessage) && React__namespace.createElement(wonderBlocksLayout.Strut, {
597
+ size: Spacing__default["default"].small_12
598
+ }), allChildren.map((child, index) => {
599
+ const {
600
+ style,
601
+ value
602
+ } = child.props;
603
+ const checked = selectedValues.includes(value);
604
+ return React__namespace.cloneElement(child, {
605
+ checked: checked,
606
+ error: !!errorMessage,
607
+ groupName: groupName,
608
+ id: `${groupName}-${value}`,
609
+ key: value,
610
+ onChange: () => this.handleChange(value, checked),
611
+ style: [index > 0 && styles$2.defaultLineGap, style],
612
+ variant: "checkbox"
613
+ });
614
+ })));
615
+ }
616
+
617
+ }
618
+
619
+ const StyledFieldset = wonderBlocksCore.addStyle("fieldset");
620
+ const StyledLegend = wonderBlocksCore.addStyle("legend");
621
+ class RadioGroup extends React__namespace.Component {
622
+ handleChange(changedValue) {
623
+ this.props.onChange(changedValue);
624
+ }
625
+
626
+ render() {
627
+ const {
628
+ children,
629
+ label,
630
+ description,
631
+ errorMessage,
632
+ groupName,
633
+ selectedValue,
634
+ style,
635
+ testId
636
+ } = this.props;
637
+ const allChildren = React__namespace.Children.toArray(children).filter(Boolean);
638
+ return React__namespace.createElement(StyledFieldset, {
639
+ "data-test-id": testId,
640
+ style: styles$2.fieldset
641
+ }, React__namespace.createElement(wonderBlocksCore.View, {
642
+ style: style
643
+ }, label && React__namespace.createElement(StyledLegend, {
644
+ style: styles$2.legend
645
+ }, React__namespace.createElement(wonderBlocksTypography.LabelMedium, null, label)), description && React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
646
+ style: styles$2.description
647
+ }, description), errorMessage && React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
648
+ style: styles$2.error
649
+ }, errorMessage), (label || description || errorMessage) && React__namespace.createElement(wonderBlocksLayout.Strut, {
650
+ size: Spacing__default["default"].small_12
651
+ }), allChildren.map((child, index) => {
652
+ const {
653
+ style,
654
+ value
655
+ } = child.props;
656
+ const checked = selectedValue === value;
657
+ return React__namespace.cloneElement(child, {
658
+ checked: checked,
659
+ error: !!errorMessage,
660
+ groupName: groupName,
661
+ id: `${groupName}-${value}`,
662
+ key: value,
663
+ onChange: () => this.handleChange(value),
664
+ style: [index > 0 && styles$2.defaultLineGap, style],
665
+ variant: "radio"
666
+ });
667
+ })));
668
+ }
669
+
670
+ }
671
+
672
+ const _excluded = ["id", "type", "value", "disabled", "onKeyDown", "placeholder", "light", "style", "testId", "readOnly", "autoComplete", "forwardedRef", "onFocus", "onBlur", "onValidate", "validate", "onChange", "required"];
673
+ const defaultErrorMessage = "This field is required.";
674
+
675
+ class TextField extends React__namespace.Component {
676
+ constructor(props) {
677
+ super(props);
678
+ this.state = {
679
+ error: null,
680
+ focused: false
681
+ };
682
+
683
+ this.maybeValidate = newValue => {
684
+ const {
685
+ validate,
686
+ onValidate,
687
+ required
688
+ } = this.props;
689
+
690
+ if (validate) {
691
+ const maybeError = validate(newValue) || null;
692
+ this.setState({
693
+ error: maybeError
694
+ }, () => {
695
+ if (onValidate) {
696
+ onValidate(maybeError);
697
+ }
698
+ });
699
+ } else if (required) {
700
+ const requiredString = typeof required === "string" ? required : defaultErrorMessage;
701
+ const maybeError = newValue ? null : requiredString;
702
+ this.setState({
703
+ error: maybeError
704
+ }, () => {
705
+ if (onValidate) {
706
+ onValidate(maybeError);
707
+ }
708
+ });
709
+ }
710
+ };
711
+
712
+ this.handleChange = event => {
713
+ const {
714
+ onChange
715
+ } = this.props;
716
+ const newValue = event.target.value;
717
+ this.maybeValidate(newValue);
718
+ onChange(newValue);
719
+ };
720
+
721
+ this.handleFocus = event => {
722
+ const {
723
+ onFocus
724
+ } = this.props;
725
+ this.setState({
726
+ focused: true
727
+ }, () => {
728
+ if (onFocus) {
729
+ onFocus(event);
730
+ }
731
+ });
732
+ };
733
+
734
+ this.handleBlur = event => {
735
+ const {
736
+ onBlur
737
+ } = this.props;
738
+ this.setState({
739
+ focused: false
740
+ }, () => {
741
+ if (onBlur) {
742
+ onBlur(event);
743
+ }
744
+ });
745
+ };
746
+
747
+ if (props.validate && props.value !== "") {
748
+ this.state.error = props.validate(props.value) || null;
749
+ }
750
+ }
751
+
752
+ componentDidMount() {
753
+ if (this.props.value !== "") {
754
+ this.maybeValidate(this.props.value);
755
+ }
756
+ }
757
+
758
+ render() {
759
+ const _this$props = this.props,
760
+ {
761
+ id,
762
+ type,
763
+ value,
764
+ disabled,
765
+ onKeyDown,
766
+ placeholder,
767
+ light,
768
+ style,
769
+ testId,
770
+ readOnly,
771
+ autoComplete,
772
+ forwardedRef
773
+ } = _this$props,
774
+ otherProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded);
775
+
776
+ return React__namespace.createElement("input", _extends__default["default"]({
777
+ className: aphrodite.css([styles$1.input, wonderBlocksTypography.styles.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]),
778
+ id: id,
779
+ type: type,
780
+ placeholder: placeholder,
781
+ value: value,
782
+ disabled: disabled,
783
+ onChange: this.handleChange,
784
+ onKeyDown: onKeyDown,
785
+ onFocus: this.handleFocus,
786
+ onBlur: this.handleBlur,
787
+ "data-test-id": testId,
788
+ readOnly: readOnly,
789
+ autoComplete: autoComplete,
790
+ ref: forwardedRef
791
+ }, otherProps));
792
+ }
793
+
794
+ }
795
+
796
+ TextField.defaultProps = {
797
+ type: "text",
798
+ disabled: false,
799
+ light: false
800
+ };
801
+ const styles$1 = aphrodite.StyleSheet.create({
802
+ input: {
803
+ width: "100%",
804
+ height: 40,
805
+ borderRadius: 4,
806
+ boxSizing: "border-box",
807
+ paddingLeft: Spacing__default["default"].medium_16,
808
+ margin: 0,
809
+ outline: "none",
810
+ boxShadow: "none"
811
+ },
812
+ default: {
813
+ background: Color__default["default"].white,
814
+ border: `1px solid ${Color__default["default"].offBlack16}`,
815
+ color: Color__default["default"].offBlack,
816
+ "::placeholder": {
817
+ color: Color__default["default"].offBlack64
818
+ }
819
+ },
820
+ error: {
821
+ background: `${Color.mix(Color.fade(Color__default["default"].red, 0.06), Color__default["default"].white)}`,
822
+ border: `1px solid ${Color__default["default"].red}`,
823
+ color: Color__default["default"].offBlack,
824
+ "::placeholder": {
825
+ color: Color__default["default"].offBlack64
826
+ }
827
+ },
828
+ disabled: {
829
+ background: Color__default["default"].offWhite,
830
+ border: `1px solid ${Color__default["default"].offBlack16}`,
831
+ color: Color__default["default"].offBlack64,
832
+ "::placeholder": {
833
+ color: Color__default["default"].offBlack32
834
+ }
835
+ },
836
+ focused: {
837
+ background: Color__default["default"].white,
838
+ border: `1px solid ${Color__default["default"].blue}`,
839
+ color: Color__default["default"].offBlack,
840
+ "::placeholder": {
841
+ color: Color__default["default"].offBlack64
842
+ }
843
+ },
844
+ defaultLight: {
845
+ boxShadow: `0px 0px 0px 1px ${Color__default["default"].blue}, 0px 0px 0px 2px ${Color__default["default"].white}`
846
+ },
847
+ errorLight: {
848
+ boxShadow: `0px 0px 0px 1px ${Color__default["default"].red}, 0px 0px 0px 2px ${Color__default["default"].white}`
849
+ }
850
+ });
851
+ var TextField$1 = React__namespace.forwardRef((props, ref) => React__namespace.createElement(TextField, _extends__default["default"]({}, props, {
852
+ forwardedRef: ref
853
+ })));
854
+
855
+ const StyledSpan = wonderBlocksCore.addStyle("span");
856
+ class FieldHeading extends React__namespace.Component {
857
+ renderLabel() {
858
+ const {
859
+ label,
860
+ id,
861
+ required,
862
+ testId
863
+ } = this.props;
864
+ const requiredIcon = React__namespace.createElement(StyledSpan, {
865
+ style: styles.required,
866
+ "aria-hidden": true
867
+ }, " ", "*");
868
+ return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
869
+ style: styles.label,
870
+ tag: "label",
871
+ htmlFor: id && `${id}-field`,
872
+ testId: testId && `${testId}-label`
873
+ }, label, required && requiredIcon), React__namespace.createElement(wonderBlocksLayout.Strut, {
874
+ size: Spacing__default["default"].xxxSmall_4
875
+ }));
876
+ }
877
+
878
+ maybeRenderDescription() {
879
+ const {
880
+ description,
881
+ testId
882
+ } = this.props;
883
+
884
+ if (!description) {
885
+ return null;
886
+ }
887
+
888
+ return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
889
+ style: styles.description,
890
+ testId: testId && `${testId}-description`
891
+ }, description), React__namespace.createElement(wonderBlocksLayout.Strut, {
892
+ size: Spacing__default["default"].xxxSmall_4
893
+ }));
894
+ }
895
+
896
+ maybeRenderError() {
897
+ const {
898
+ error,
899
+ id,
900
+ testId
901
+ } = this.props;
902
+
903
+ if (!error) {
904
+ return null;
905
+ }
906
+
907
+ return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(wonderBlocksLayout.Strut, {
908
+ size: Spacing__default["default"].small_12
909
+ }), React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
910
+ style: styles.error,
911
+ role: "alert",
912
+ id: id && `${id}-error`,
913
+ testId: testId && `${testId}-error`
914
+ }, error));
915
+ }
916
+
917
+ render() {
918
+ const {
919
+ field,
920
+ style
921
+ } = this.props;
922
+ return React__namespace.createElement(wonderBlocksCore.View, {
923
+ style: style
924
+ }, this.renderLabel(), this.maybeRenderDescription(), React__namespace.createElement(wonderBlocksLayout.Strut, {
925
+ size: Spacing__default["default"].xSmall_8
926
+ }), field, this.maybeRenderError());
927
+ }
928
+
929
+ }
930
+ const styles = aphrodite.StyleSheet.create({
931
+ label: {
932
+ color: Color__default["default"].offBlack
933
+ },
934
+ description: {
935
+ color: Color__default["default"].offBlack64
936
+ },
937
+ error: {
938
+ color: Color__default["default"].red
939
+ },
940
+ required: {
941
+ color: Color__default["default"].red
942
+ }
943
+ });
944
+
945
+ class LabeledTextField extends React__namespace.Component {
946
+ constructor(props) {
947
+ super(props);
948
+
949
+ this.handleValidate = errorMessage => {
950
+ const {
951
+ onValidate
952
+ } = this.props;
953
+ this.setState({
954
+ error: errorMessage
955
+ }, () => {
956
+ if (onValidate) {
957
+ onValidate(errorMessage);
958
+ }
959
+ });
960
+ };
961
+
962
+ this.handleFocus = event => {
963
+ const {
964
+ onFocus
965
+ } = this.props;
966
+ this.setState({
967
+ focused: true
968
+ }, () => {
969
+ if (onFocus) {
970
+ onFocus(event);
971
+ }
972
+ });
973
+ };
974
+
975
+ this.handleBlur = event => {
976
+ const {
977
+ onBlur
978
+ } = this.props;
979
+ this.setState({
980
+ focused: false
981
+ }, () => {
982
+ if (onBlur) {
983
+ onBlur(event);
984
+ }
985
+ });
986
+ };
987
+
988
+ this.state = {
989
+ error: null,
990
+ focused: false
991
+ };
992
+ }
993
+
994
+ render() {
995
+ const {
996
+ id,
997
+ type,
998
+ label,
999
+ description,
1000
+ value,
1001
+ disabled,
1002
+ required,
1003
+ validate,
1004
+ onChange,
1005
+ onKeyDown,
1006
+ placeholder,
1007
+ light,
1008
+ style,
1009
+ testId,
1010
+ readOnly,
1011
+ autoComplete,
1012
+ forwardedRef,
1013
+ ariaDescribedby
1014
+ } = this.props;
1015
+ return React__namespace.createElement(wonderBlocksCore.IDProvider, {
1016
+ id: id,
1017
+ scope: "labeled-text-field"
1018
+ }, uniqueId => React__namespace.createElement(FieldHeading, {
1019
+ id: uniqueId,
1020
+ testId: testId,
1021
+ style: style,
1022
+ field: React__namespace.createElement(TextField$1, {
1023
+ id: `${uniqueId}-field`,
1024
+ "aria-describedby": ariaDescribedby ? ariaDescribedby : `${uniqueId}-error`,
1025
+ "aria-invalid": this.state.error ? "true" : "false",
1026
+ "aria-required": required ? "true" : "false",
1027
+ required: required,
1028
+ testId: testId && `${testId}-field`,
1029
+ type: type,
1030
+ value: value,
1031
+ placeholder: placeholder,
1032
+ disabled: disabled,
1033
+ validate: validate,
1034
+ onValidate: this.handleValidate,
1035
+ onChange: onChange,
1036
+ onKeyDown: onKeyDown,
1037
+ onFocus: this.handleFocus,
1038
+ onBlur: this.handleBlur,
1039
+ light: light,
1040
+ readOnly: readOnly,
1041
+ autoComplete: autoComplete,
1042
+ ref: forwardedRef
1043
+ }),
1044
+ label: label,
1045
+ description: description,
1046
+ required: !!required,
1047
+ error: !this.state.focused && this.state.error || ""
1048
+ }));
1049
+ }
1050
+
1051
+ }
1052
+
1053
+ LabeledTextField.defaultProps = {
1054
+ type: "text",
1055
+ disabled: false,
1056
+ light: false
1057
+ };
1058
+ var labeledTextField = React__namespace.forwardRef((props, ref) => React__namespace.createElement(LabeledTextField, _extends__default["default"]({}, props, {
1059
+ forwardedRef: ref
1060
+ })));
1061
+
1062
+ exports.Checkbox = Checkbox;
1063
+ exports.CheckboxGroup = CheckboxGroup;
1064
+ exports.Choice = Choice;
1065
+ exports.LabeledTextField = labeledTextField;
1066
+ exports.RadioGroup = RadioGroup;
1067
+ exports.TextField = TextField$1;
@@ -0,0 +1,2 @@
1
+ // @flow
2
+ export * from "../src/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-form",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
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.18.6",
19
- "@khanacademy/wonder-blocks-clickable": "^2.4.2",
19
+ "@khanacademy/wonder-blocks-clickable": "^2.4.4",
20
20
  "@khanacademy/wonder-blocks-color": "^1.2.0",
21
- "@khanacademy/wonder-blocks-core": "^4.6.0",
22
- "@khanacademy/wonder-blocks-icon": "^1.2.33",
23
- "@khanacademy/wonder-blocks-layout": "^1.4.13",
21
+ "@khanacademy/wonder-blocks-core": "^4.6.2",
22
+ "@khanacademy/wonder-blocks-icon": "^1.2.35",
23
+ "@khanacademy/wonder-blocks-layout": "^1.4.15",
24
24
  "@khanacademy/wonder-blocks-spacing": "^3.0.5",
25
- "@khanacademy/wonder-blocks-typography": "^1.1.35"
25
+ "@khanacademy/wonder-blocks-typography": "^1.1.37"
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.5.0"
32
+ "wb-dev-build-settings": "^0.7.0"
33
33
  }
34
34
  }