@khanacademy/wonder-blocks-form 4.0.8 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,7 +6,6 @@ var React = require('react');
6
6
  var aphrodite = require('aphrodite');
7
7
  var Color = require('@khanacademy/wonder-blocks-color');
8
8
  var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
9
- var wonderBlocksClickable = require('@khanacademy/wonder-blocks-clickable');
10
9
  var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
11
10
  var Spacing = require('@khanacademy/wonder-blocks-spacing');
12
11
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
@@ -65,7 +64,17 @@ function _objectWithoutPropertiesLoose(source, excluded) {
65
64
  return target;
66
65
  }
67
66
 
68
- const _excluded$4 = ["checked", "disabled", "error", "groupName", "id", "testId", "hovered", "focused", "pressed", "waiting"];
67
+ const _excluded$4 = ["checked", "disabled", "error", "groupName", "id", "testId"];
68
+ function mapCheckedToAriaChecked(value) {
69
+ switch (value) {
70
+ case true:
71
+ return "true";
72
+ case false:
73
+ return "false";
74
+ default:
75
+ return "mixed";
76
+ }
77
+ }
69
78
  const {
70
79
  blue: blue$1,
71
80
  red: red$1,
@@ -75,17 +84,31 @@ const {
75
84
  offBlack32: offBlack32$1,
76
85
  offBlack50: offBlack50$1
77
86
  } = Color__default["default"];
78
- const StyledInput$1 = wonderBlocksCore.addStyle("input");
79
- const checkboxCheck = {
87
+ const StyledInput$2 = wonderBlocksCore.addStyle("input");
88
+ const checkPath = {
80
89
  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"
81
90
  };
91
+ const indeterminatePath = {
92
+ small: "M3 8C3 7.44772 3.44772 7 4 7H12C12.5523 7 13 7.44772 13 8C13 8.55228 12.5523 9 12 9H4C3.44772 9 3 8.55228 3 8Z"
93
+ };
82
94
  class CheckboxCore extends React__namespace.Component {
83
95
  constructor(...args) {
84
96
  super(...args);
97
+ this.inputRef = React__namespace.createRef();
85
98
  this.handleChange = () => {
86
99
  return;
87
100
  };
88
101
  }
102
+ componentDidMount() {
103
+ if (this.props.checked == null && this.inputRef.current != null) {
104
+ this.inputRef.current.indeterminate = true;
105
+ }
106
+ }
107
+ componentDidUpdate(prevProps) {
108
+ if (this.inputRef.current != null) {
109
+ this.inputRef.current.indeterminate = this.props.checked == null;
110
+ }
111
+ }
89
112
  render() {
90
113
  const _this$props = this.props,
91
114
  {
@@ -94,32 +117,33 @@ class CheckboxCore extends React__namespace.Component {
94
117
  error,
95
118
  groupName,
96
119
  id,
97
- testId,
98
- hovered,
99
- focused,
100
- pressed
120
+ testId
101
121
  } = _this$props,
102
122
  sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$4);
103
123
  const stateStyles = _generateStyles$1(checked, error);
104
- const defaultStyle = [sharedStyles$1.inputReset, sharedStyles$1.default, stateStyles.default, !disabled && (pressed ? stateStyles.active : (hovered || focused) && stateStyles.focus), disabled && sharedStyles$1.disabled];
124
+ const defaultStyle = [sharedStyles$1.inputReset, sharedStyles$1.default, !disabled && stateStyles.default, disabled && sharedStyles$1.disabled];
105
125
  const props = {
106
126
  "data-test-id": testId
107
127
  };
108
- return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(StyledInput$1, _extends({}, sharedProps, {
128
+ const checkboxIcon = React__namespace.createElement(Icon__default["default"], {
129
+ color: disabled ? offBlack32$1 : white$1,
130
+ icon: checked ? checkPath : indeterminatePath,
131
+ size: "small",
132
+ style: sharedStyles$1.checkboxIcon
133
+ });
134
+ const ariaChecked = mapCheckedToAriaChecked(checked);
135
+ return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(StyledInput$2, _extends({}, sharedProps, {
136
+ ref: this.inputRef,
109
137
  type: "checkbox",
138
+ "aria-checked": ariaChecked,
110
139
  "aria-invalid": error,
111
- checked: checked,
140
+ checked: checked != null ? checked : undefined,
112
141
  disabled: disabled,
113
142
  id: id,
114
143
  name: groupName,
115
144
  onChange: this.handleChange,
116
145
  style: defaultStyle
117
- }, props)), checked && React__namespace.createElement(Icon__default["default"], {
118
- color: disabled ? offBlack32$1 : white$1,
119
- icon: checkboxCheck,
120
- size: "small",
121
- style: sharedStyles$1.checkIcon
122
- }));
146
+ }, props)), checked || checked == null ? checkboxIcon : React__namespace.createElement(React__namespace.Fragment, null));
123
147
  }
124
148
  }
125
149
  const size$1 = 16;
@@ -147,7 +171,7 @@ const sharedStyles$1 = aphrodite.StyleSheet.create({
147
171
  borderColor: offBlack16$1,
148
172
  borderWidth: 1
149
173
  },
150
- checkIcon: {
174
+ checkboxIcon: {
151
175
  position: "absolute",
152
176
  pointerEvents: "none"
153
177
  }
@@ -176,35 +200,43 @@ const _generateStyles$1 = (checked, error) => {
176
200
  }
177
201
  const palette = error ? colors$1.error : colors$1.default;
178
202
  let newStyles = {};
179
- if (checked) {
203
+ if (checked || checked == null) {
180
204
  newStyles = {
181
205
  default: {
182
206
  backgroundColor: palette.base,
183
- borderWidth: 0
184
- },
185
- focus: {
186
- boxShadow: `0 0 0 1px ${white$1}, 0 0 0 3px ${palette.base}`
187
- },
188
- active: {
189
- boxShadow: `0 0 0 1px ${white$1}, 0 0 0 3px ${palette.active}`,
190
- background: palette.active
207
+ borderWidth: 0,
208
+ ":focus-visible": {
209
+ boxShadow: `0 0 0 1px ${white$1}, 0 0 0 3px ${palette.base}`
210
+ },
211
+ ":hover": {
212
+ boxShadow: `0 0 0 1px ${white$1}, 0 0 0 3px ${palette.base}`
213
+ },
214
+ ":active": {
215
+ boxShadow: `0 0 0 1px ${white$1}, 0 0 0 3px ${palette.active}`,
216
+ background: palette.active
217
+ }
191
218
  }
192
219
  };
193
220
  } else {
194
221
  newStyles = {
195
222
  default: {
196
223
  backgroundColor: error ? fadedRed$1 : white$1,
197
- borderColor: error ? red$1 : offBlack50$1
198
- },
199
- focus: {
200
- backgroundColor: error ? fadedRed$1 : white$1,
201
- borderColor: palette.base,
202
- borderWidth: 2
203
- },
204
- active: {
205
- backgroundColor: palette.faded,
206
- borderColor: error ? activeRed$1 : blue$1,
207
- borderWidth: 2
224
+ borderColor: error ? red$1 : offBlack50$1,
225
+ ":focus-visible": {
226
+ backgroundColor: error ? fadedRed$1 : white$1,
227
+ borderColor: palette.base,
228
+ borderWidth: 2
229
+ },
230
+ ":hover": {
231
+ backgroundColor: error ? fadedRed$1 : white$1,
232
+ borderColor: palette.base,
233
+ borderWidth: 2
234
+ },
235
+ ":active": {
236
+ backgroundColor: palette.faded,
237
+ borderColor: error ? activeRed$1 : blue$1,
238
+ borderWidth: 2
239
+ }
208
240
  }
209
241
  };
210
242
  }
@@ -212,7 +244,7 @@ const _generateStyles$1 = (checked, error) => {
212
244
  return styles$5[styleKey];
213
245
  };
214
246
 
215
- const _excluded$3 = ["checked", "disabled", "error", "groupName", "id", "testId", "hovered", "focused", "pressed", "waiting"];
247
+ const _excluded$3 = ["checked", "disabled", "error", "groupName", "id", "testId"];
216
248
  const {
217
249
  blue,
218
250
  red,
@@ -222,7 +254,7 @@ const {
222
254
  offBlack32,
223
255
  offBlack50
224
256
  } = Color__default["default"];
225
- const StyledInput = wonderBlocksCore.addStyle("input");
257
+ const StyledInput$1 = wonderBlocksCore.addStyle("input");
226
258
  class RadioCore extends React__namespace.Component {
227
259
  constructor(...args) {
228
260
  super(...args);
@@ -238,21 +270,18 @@ class RadioCore extends React__namespace.Component {
238
270
  error,
239
271
  groupName,
240
272
  id,
241
- testId,
242
- hovered,
243
- focused,
244
- pressed
273
+ testId
245
274
  } = _this$props,
246
275
  sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$3);
247
276
  const stateStyles = _generateStyles(checked, error);
248
- const defaultStyle = [sharedStyles.inputReset, sharedStyles.default, stateStyles.default, !disabled && (pressed ? stateStyles.active : (hovered || focused) && stateStyles.focus), disabled && sharedStyles.disabled];
277
+ const defaultStyle = [sharedStyles.inputReset, sharedStyles.default, !disabled && stateStyles.default, disabled && sharedStyles.disabled];
249
278
  const props = {
250
279
  "data-test-id": testId
251
280
  };
252
- return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(StyledInput, _extends({}, sharedProps, {
281
+ return React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement(StyledInput$1, _extends({}, sharedProps, {
253
282
  type: "radio",
254
283
  "aria-invalid": error,
255
- checked: checked,
284
+ checked: checked != null ? checked : undefined,
256
285
  disabled: disabled,
257
286
  id: id,
258
287
  name: groupName,
@@ -327,31 +356,39 @@ const _generateStyles = (checked, error) => {
327
356
  default: {
328
357
  backgroundColor: white,
329
358
  borderColor: palette.base,
330
- borderWidth: size / 4
331
- },
332
- focus: {
333
- boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.base}`
334
- },
335
- active: {
336
- boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.active}`,
337
- borderColor: palette.active
359
+ borderWidth: size / 4,
360
+ ":focus-visible": {
361
+ boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.base}`
362
+ },
363
+ ":hover": {
364
+ boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.base}`
365
+ },
366
+ ":active": {
367
+ boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.active}`,
368
+ borderColor: palette.active
369
+ }
338
370
  }
339
371
  };
340
372
  } else {
341
373
  newStyles = {
342
374
  default: {
343
375
  backgroundColor: error ? fadedRed : white,
344
- borderColor: error ? red : offBlack50
345
- },
346
- focus: {
347
- backgroundColor: error ? fadedRed : white,
348
- borderColor: palette.base,
349
- borderWidth: 2
350
- },
351
- active: {
352
- backgroundColor: palette.faded,
353
- borderColor: error ? activeRed : blue,
354
- borderWidth: 2
376
+ borderColor: error ? red : offBlack50,
377
+ ":focus-visible": {
378
+ backgroundColor: error ? fadedRed : white,
379
+ borderColor: palette.base,
380
+ borderWidth: 2
381
+ },
382
+ ":hover": {
383
+ backgroundColor: error ? fadedRed : white,
384
+ borderColor: palette.base,
385
+ borderWidth: 2
386
+ },
387
+ ":active": {
388
+ backgroundColor: palette.faded,
389
+ borderColor: error ? activeRed : blue,
390
+ borderWidth: 2
391
+ }
355
392
  }
356
393
  };
357
394
  }
@@ -359,13 +396,10 @@ const _generateStyles = (checked, error) => {
359
396
  return styles$4[styleKey];
360
397
  };
361
398
 
362
- const _excluded$2 = ["label", "description", "onChange", "style", "className", "variant"];
399
+ const _excluded$2 = ["label", "description", "id", "onChange", "style", "className", "variant"];
363
400
  class ChoiceInternal extends React__namespace.Component {
364
401
  constructor(...args) {
365
402
  super(...args);
366
- this.handleLabelClick = event => {
367
- event.preventDefault();
368
- };
369
403
  this.handleClick = () => {
370
404
  const {
371
405
  checked,
@@ -385,17 +419,15 @@ class ChoiceInternal extends React__namespace.Component {
385
419
  return CheckboxCore;
386
420
  }
387
421
  }
388
- getLabel() {
422
+ getLabel(id) {
389
423
  const {
390
424
  disabled,
391
- id,
392
425
  label
393
426
  } = this.props;
394
427
  return React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
395
428
  style: [styles$3.label, disabled && styles$3.disabledLabel]
396
429
  }, React__namespace.createElement("label", {
397
- htmlFor: id,
398
- onClick: this.handleLabelClick
430
+ htmlFor: id
399
431
  }, label));
400
432
  }
401
433
  getDescription(id) {
@@ -412,41 +444,35 @@ class ChoiceInternal extends React__namespace.Component {
412
444
  {
413
445
  label,
414
446
  description,
447
+ id,
415
448
  style,
416
- className,
417
- variant
449
+ className
418
450
  } = _this$props,
419
451
  coreProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
420
452
  const ChoiceCore = this.getChoiceCoreComponent();
421
- const ClickableBehavior = wonderBlocksClickable.getClickableBehavior();
422
453
  return React__namespace.createElement(wonderBlocksCore.UniqueIDProvider, {
423
454
  mockOnFirstRender: true,
424
455
  scope: "choice"
425
456
  }, ids => {
457
+ const uniqueId = id || ids.get("main");
426
458
  const descriptionId = description ? ids.get("description") : undefined;
427
459
  return React__namespace.createElement(wonderBlocksCore.View, {
428
460
  style: style,
429
461
  className: className
430
- }, React__namespace.createElement(ClickableBehavior, {
431
- disabled: coreProps.disabled,
432
- onClick: this.handleClick,
433
- role: variant
434
- }, (state, childrenProps) => {
435
- return React__namespace.createElement(wonderBlocksCore.View, _extends({
436
- style: styles$3.wrapper
437
- }, childrenProps, {
438
- tabIndex: -1
439
- }), React__namespace.createElement(ChoiceCore, _extends({}, coreProps, state, {
440
- "aria-describedby": descriptionId
441
- })), React__namespace.createElement(wonderBlocksLayout.Strut, {
442
- size: Spacing__default["default"].xSmall_8
443
- }), label && this.getLabel());
444
- }), description && this.getDescription(descriptionId));
462
+ }, React__namespace.createElement(wonderBlocksCore.View, {
463
+ style: styles$3.wrapper,
464
+ tabIndex: -1
465
+ }, React__namespace.createElement(ChoiceCore, _extends({}, coreProps, {
466
+ id: uniqueId,
467
+ "aria-describedby": descriptionId,
468
+ onClick: this.handleClick
469
+ })), React__namespace.createElement(wonderBlocksLayout.Strut, {
470
+ size: Spacing__default["default"].xSmall_8
471
+ }), label && this.getLabel(uniqueId)), description && this.getDescription(descriptionId));
445
472
  });
446
473
  }
447
474
  }
448
475
  ChoiceInternal.defaultProps = {
449
- checked: false,
450
476
  disabled: false,
451
477
  error: false
452
478
  };
@@ -457,7 +483,6 @@ const styles$3 = aphrodite.StyleSheet.create({
457
483
  outline: "none"
458
484
  },
459
485
  label: {
460
- userSelect: "none",
461
486
  marginTop: -2
462
487
  },
463
488
  disabledLabel: {
@@ -655,6 +680,7 @@ class RadioGroup extends React__namespace.Component {
655
680
 
656
681
  const _excluded = ["id", "type", "value", "disabled", "onKeyDown", "placeholder", "light", "style", "testId", "readOnly", "autoComplete", "forwardedRef", "onFocus", "onBlur", "onValidate", "validate", "onChange", "required"];
657
682
  const defaultErrorMessage = "This field is required.";
683
+ const StyledInput = wonderBlocksCore.addStyle("input");
658
684
  class TextField extends React__namespace.Component {
659
685
  constructor(props) {
660
686
  super(props);
@@ -747,8 +773,8 @@ class TextField extends React__namespace.Component {
747
773
  forwardedRef
748
774
  } = _this$props,
749
775
  otherProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
750
- return React__namespace.createElement("input", _extends({
751
- 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]),
776
+ return React__namespace.createElement(StyledInput, _extends({
777
+ style: [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], !!this.state.error && styles$1.error, style && style],
752
778
  id: id,
753
779
  type: type,
754
780
  placeholder: placeholder,
@@ -1,8 +1,9 @@
1
1
  import type { AriaProps, StyleType } from "@khanacademy/wonder-blocks-core";
2
2
  import Choice from "../components/choice";
3
+ export type Checked = boolean | null | undefined;
3
4
  export type ChoiceCoreProps = AriaProps & {
4
5
  /** Whether this component is checked */
5
- checked: boolean;
6
+ checked: Checked;
6
7
  /** Whether this component is disabled */
7
8
  disabled: boolean;
8
9
  /** Whether this component should show an error state */
@@ -15,6 +16,8 @@ export type ChoiceCoreProps = AriaProps & {
15
16
  id?: string;
16
17
  /** Optional test ID for e2e testing */
17
18
  testId?: string;
19
+ /** Function that executes when the choice is clicked. */
20
+ onClick: () => void;
18
21
  };
19
22
  export type ChoiceComponentProps = ChoiceCoreProps & {
20
23
  /** Callback when this component is selected. The newCheckedState is the
@@ -6,13 +6,14 @@
6
6
  */
7
7
  import type { AriaProps, StyleType } from "@khanacademy/wonder-blocks-core";
8
8
  import Choice from "../components/choice";
9
+ export type Checked = boolean | null | void;
9
10
  export type ChoiceCoreProps = {|
10
11
  ...AriaProps,
11
12
  ...{|
12
13
  /**
13
14
  * Whether this component is checked
14
15
  */
15
- checked: boolean,
16
+ checked: Checked,
16
17
 
17
18
  /**
18
19
  * Whether this component is disabled
@@ -40,6 +41,11 @@ export type ChoiceCoreProps = {|
40
41
  * Optional test ID for e2e testing
41
42
  */
42
43
  testId?: string,
44
+
45
+ /**
46
+ * Function that executes when the choice is clicked.
47
+ */
48
+ onClick: () => void,
43
49
  |},
44
50
  |};
45
51
  export type ChoiceComponentProps = {|
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-form",
3
- "version": "4.0.8",
3
+ "version": "4.1.0",
4
4
  "design": "v1",
5
5
  "description": "Form components for Wonder Blocks.",
6
6
  "main": "dist/index.js",
@@ -16,13 +16,13 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@babel/runtime": "^7.18.6",
19
- "@khanacademy/wonder-blocks-clickable": "^3.0.8",
19
+ "@khanacademy/wonder-blocks-clickable": "^3.0.9",
20
20
  "@khanacademy/wonder-blocks-color": "^2.0.1",
21
- "@khanacademy/wonder-blocks-core": "^5.0.4",
22
- "@khanacademy/wonder-blocks-icon": "^2.0.8",
23
- "@khanacademy/wonder-blocks-layout": "^2.0.8",
21
+ "@khanacademy/wonder-blocks-core": "^5.1.0",
22
+ "@khanacademy/wonder-blocks-icon": "^2.0.9",
23
+ "@khanacademy/wonder-blocks-layout": "^2.0.9",
24
24
  "@khanacademy/wonder-blocks-spacing": "^4.0.1",
25
- "@khanacademy/wonder-blocks-typography": "^2.0.8"
25
+ "@khanacademy/wonder-blocks-typography": "^2.0.9"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "aphrodite": "^1.2.5",