@khanacademy/wonder-blocks-form 2.2.2 → 2.3.2

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
@@ -935,7 +935,8 @@ class LabeledTextFieldInternal extends react__WEBPACK_IMPORTED_MODULE_0__["Compo
935
935
  testId,
936
936
  readOnly,
937
937
  autoComplete,
938
- forwardedRef
938
+ forwardedRef,
939
+ ariaDescribedby
939
940
  } = this.props;
940
941
  return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__["IDProvider"], {
941
942
  id: id,
@@ -946,7 +947,7 @@ class LabeledTextFieldInternal extends react__WEBPACK_IMPORTED_MODULE_0__["Compo
946
947
  style: style,
947
948
  field: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_text_field_js__WEBPACK_IMPORTED_MODULE_3__[/* default */ "a"], {
948
949
  id: `${uniqueId}-field`,
949
- "aria-describedby": `${uniqueId}-error`,
950
+ "aria-describedby": ariaDescribedby ? ariaDescribedby : `${uniqueId}-error`,
950
951
  "aria-invalid": this.state.error ? "true" : "false",
951
952
  testId: testId && `${testId}-field`,
952
953
  type: type,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-form",
3
- "version": "2.2.2",
3
+ "version": "2.3.2",
4
4
  "design": "v1",
5
5
  "description": "Form components for Wonder Blocks.",
6
6
  "main": "dist/index.js",
@@ -15,21 +15,20 @@
15
15
  "access": "public"
16
16
  },
17
17
  "dependencies": {
18
- "@babel/runtime": "^7.13.10",
19
- "@khanacademy/wonder-blocks-clickable": "^2.1.3",
20
- "@khanacademy/wonder-blocks-color": "^1.1.19",
21
- "@khanacademy/wonder-blocks-core": "^3.1.5",
22
- "@khanacademy/wonder-blocks-icon": "^1.2.22",
23
- "@khanacademy/wonder-blocks-layout": "^1.4.4",
24
- "@khanacademy/wonder-blocks-spacing": "^3.0.4",
25
- "@khanacademy/wonder-blocks-typography": "^1.1.26"
18
+ "@babel/runtime": "^7.16.3",
19
+ "@khanacademy/wonder-blocks-clickable": "^2.2.2",
20
+ "@khanacademy/wonder-blocks-color": "^1.1.20",
21
+ "@khanacademy/wonder-blocks-core": "^4.0.0",
22
+ "@khanacademy/wonder-blocks-icon": "^1.2.24",
23
+ "@khanacademy/wonder-blocks-layout": "^1.4.6",
24
+ "@khanacademy/wonder-blocks-spacing": "^3.0.5",
25
+ "@khanacademy/wonder-blocks-typography": "^1.1.28"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "aphrodite": "^1.2.5",
29
- "react": "^16.4.1"
29
+ "react": "16.14.0"
30
30
  },
31
31
  "devDependencies": {
32
- "wb-dev-build-settings": "^0.1.2"
33
- },
34
- "gitHead": "9a9cc04bf2bbfb425f991a347b4f8b0d0d56e120"
32
+ "wb-dev-build-settings": "^0.2.0"
33
+ }
35
34
  }
@@ -1,6 +1,7 @@
1
1
  //@flow
2
2
  import * as React from "react";
3
3
  import {mount} from "enzyme";
4
+ import "jest-enzyme";
4
5
 
5
6
  import CheckboxGroup from "../checkbox-group.js";
6
7
  import Choice from "../choice.js";
@@ -1,6 +1,7 @@
1
1
  // @flow
2
2
  import * as React from "react";
3
3
  import {mount} from "enzyme";
4
+ import "jest-enzyme";
4
5
  import {StyleSheet} from "aphrodite";
5
6
 
6
7
  import FieldHeading from "../field-heading.js";
@@ -1,6 +1,8 @@
1
1
  //@flow
2
2
  import * as React from "react";
3
3
  import {mount} from "enzyme";
4
+ import "jest-enzyme";
5
+ import {render, screen} from "@testing-library/react";
4
6
 
5
7
  import {StyleSheet} from "aphrodite";
6
8
  import LabeledTextField from "../labeled-text-field.js";
@@ -186,6 +188,49 @@ describe("LabeledTextField", () => {
186
188
  expect(input).toBeDisabled();
187
189
  });
188
190
 
191
+ it("ariaDescribedby prop sets aria-describedby", () => {
192
+ // Arrange
193
+ const ariaDescription = "aria description";
194
+
195
+ // Act
196
+ render(
197
+ <LabeledTextField
198
+ label="Label"
199
+ value=""
200
+ onChange={() => {}}
201
+ ariaDescribedby={ariaDescription}
202
+ />,
203
+ );
204
+
205
+ // Assert
206
+ const input = screen.getByRole("textbox");
207
+ expect(input.getAttribute("aria-describedby")).toEqual(ariaDescription);
208
+ });
209
+
210
+ it("auto-generates a unique error when ariaDescribedby is not passed in", () => {
211
+ // Arrange
212
+
213
+ // Act
214
+ render(
215
+ <LabeledTextField
216
+ label="Label"
217
+ value=""
218
+ onChange={() => {}}
219
+ // ariaDescribedby is not passed in
220
+ />,
221
+ );
222
+
223
+ // Assert
224
+ // Since the generated aria-describedby is unique,
225
+ // we cannot know what it will be.
226
+ // We only test if the aria-describedby attribute starts with
227
+ // "uid-" and ends with "-error".
228
+ const input = screen.getByRole("textbox");
229
+ expect(input.getAttribute("aria-describedby")).toMatch(
230
+ /^uid-.*-error$/,
231
+ );
232
+ });
233
+
189
234
  it("validate prop is called when input changes", () => {
190
235
  // Arrange
191
236
  const validate = jest.fn((value: string): ?string => {});
@@ -1,6 +1,7 @@
1
1
  //@flow
2
2
  import * as React from "react";
3
3
  import {mount} from "enzyme";
4
+ import "jest-enzyme";
4
5
 
5
6
  import RadioGroup from "../radio-group.js";
6
7
  import Choice from "../choice.js";
@@ -1,6 +1,7 @@
1
1
  // @flow
2
2
  import * as React from "react";
3
3
  import {mount} from "enzyme";
4
+ import "jest-enzyme";
4
5
 
5
6
  import TextField from "../text-field.js";
6
7
 
@@ -24,8 +24,7 @@ const {blue, red, white, offWhite, offBlack16, offBlack32, offBlack50} = Color;
24
24
  const StyledInput = addStyle("input");
25
25
 
26
26
  const checkboxCheck: IconAsset = {
27
- small:
28
- "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",
27
+ 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",
29
28
  };
30
29
 
31
30
  /**
@@ -41,6 +41,11 @@ type Props = {|
41
41
  */
42
42
  disabled: boolean,
43
43
 
44
+ /**
45
+ * Identifies the element or elements that describes this text field.
46
+ */
47
+ ariaDescribedby?: string | Array<string>,
48
+
44
49
  /**
45
50
  * Provide a validation for the input value.
46
51
  * Return a string error message or null | void for a valid input.
@@ -207,6 +212,7 @@ class LabeledTextFieldInternal extends React.Component<
207
212
  readOnly,
208
213
  autoComplete,
209
214
  forwardedRef,
215
+ ariaDescribedby,
210
216
  } = this.props;
211
217
 
212
218
  return (
@@ -219,7 +225,11 @@ class LabeledTextFieldInternal extends React.Component<
219
225
  field={
220
226
  <TextField
221
227
  id={`${uniqueId}-field`}
222
- aria-describedby={`${uniqueId}-error`}
228
+ aria-describedby={
229
+ ariaDescribedby
230
+ ? ariaDescribedby
231
+ : `${uniqueId}-error`
232
+ }
223
233
  aria-invalid={
224
234
  this.state.error ? "true" : "false"
225
235
  }
@@ -255,11 +265,9 @@ type ExportProps = $Diff<
255
265
  WithForwardRef,
256
266
  >;
257
267
 
258
- const LabeledTextField: React.AbstractComponent<
259
- ExportProps,
260
- HTMLInputElement,
261
- > = React.forwardRef<ExportProps, HTMLInputElement>((props, ref) => (
262
- <LabeledTextFieldInternal {...props} forwardedRef={ref} />
263
- ));
268
+ const LabeledTextField: React.AbstractComponent<ExportProps, HTMLInputElement> =
269
+ React.forwardRef<ExportProps, HTMLInputElement>((props, ref) => (
270
+ <LabeledTextFieldInternal {...props} forwardedRef={ref} />
271
+ ));
264
272
 
265
273
  export default LabeledTextField;
@@ -16,7 +16,7 @@ export default {
16
16
  title: "Form / LabeledTextField",
17
17
  };
18
18
 
19
- export const text: StoryComponentType = () => {
19
+ export const Text: StoryComponentType = () => {
20
20
  const [value, setValue] = React.useState("Khan");
21
21
 
22
22
  const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
@@ -37,7 +37,7 @@ export const text: StoryComponentType = () => {
37
37
  );
38
38
  };
39
39
 
40
- export const number: StoryComponentType = () => {
40
+ export const Number: StoryComponentType = () => {
41
41
  const [value, setValue] = React.useState("18");
42
42
 
43
43
  const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
@@ -59,7 +59,7 @@ export const number: StoryComponentType = () => {
59
59
  );
60
60
  };
61
61
 
62
- export const password: StoryComponentType = () => {
62
+ export const Password: StoryComponentType = () => {
63
63
  const [value, setValue] = React.useState("Password123");
64
64
 
65
65
  const validate = (value: string) => {
@@ -91,7 +91,7 @@ export const password: StoryComponentType = () => {
91
91
  );
92
92
  };
93
93
 
94
- export const email: StoryComponentType = () => {
94
+ export const Email: StoryComponentType = () => {
95
95
  const [value, setValue] = React.useState("khan@khan.org");
96
96
 
97
97
  const validate = (value: string) => {
@@ -121,7 +121,7 @@ export const email: StoryComponentType = () => {
121
121
  );
122
122
  };
123
123
 
124
- export const telephone: StoryComponentType = () => {
124
+ export const Telephone: StoryComponentType = () => {
125
125
  const [value, setValue] = React.useState("123-456-7890");
126
126
 
127
127
  const validate = (value: string) => {
@@ -151,7 +151,7 @@ export const telephone: StoryComponentType = () => {
151
151
  );
152
152
  };
153
153
 
154
- export const error: StoryComponentType = () => {
154
+ export const Error: StoryComponentType = () => {
155
155
  const [value, setValue] = React.useState("khan");
156
156
 
157
157
  const validate = (value: string) => {
@@ -181,7 +181,7 @@ export const error: StoryComponentType = () => {
181
181
  );
182
182
  };
183
183
 
184
- export const disabled: StoryComponentType = () => (
184
+ export const Disabled: StoryComponentType = () => (
185
185
  <LabeledTextField
186
186
  label="Name"
187
187
  description="Please enter your name"
@@ -192,7 +192,7 @@ export const disabled: StoryComponentType = () => (
192
192
  />
193
193
  );
194
194
 
195
- export const light: StoryComponentType = () => {
195
+ export const Light: StoryComponentType = () => {
196
196
  const [value, setValue] = React.useState("");
197
197
 
198
198
  const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
@@ -222,7 +222,7 @@ export const light: StoryComponentType = () => {
222
222
  );
223
223
  };
224
224
 
225
- export const customStyle: StoryComponentType = () => {
225
+ export const CustomStyle: StoryComponentType = () => {
226
226
  const [firstName, setFirstName] = React.useState("");
227
227
  const [lastName, setLastName] = React.useState("");
228
228
 
@@ -257,9 +257,9 @@ export const customStyle: StoryComponentType = () => {
257
257
  );
258
258
  };
259
259
 
260
- export const ref: StoryComponentType = () => {
260
+ export const Ref: StoryComponentType = () => {
261
261
  const [value, setValue] = React.useState("Khan");
262
- const inputRef = React.createRef<HTMLInputElement>();
262
+ const inputRef = React.createRef();
263
263
 
264
264
  const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
265
265
  if (event.key === "Enter") {
@@ -292,7 +292,7 @@ export const ref: StoryComponentType = () => {
292
292
  );
293
293
  };
294
294
 
295
- export const readOnly: StoryComponentType = () => {
295
+ export const ReadOnly: StoryComponentType = () => {
296
296
  const [value, setValue] = React.useState("Khan");
297
297
 
298
298
  const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
@@ -314,7 +314,7 @@ export const readOnly: StoryComponentType = () => {
314
314
  );
315
315
  };
316
316
 
317
- export const autoComplete: StoryComponentType = () => {
317
+ export const AutoComplete: StoryComponentType = () => {
318
318
  const [value, setValue] = React.useState("");
319
319
 
320
320
  const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
@@ -316,11 +316,9 @@ type ExportProps = $Diff<
316
316
  WithForwardRef,
317
317
  >;
318
318
 
319
- const TextField: React.AbstractComponent<
320
- ExportProps,
321
- HTMLInputElement,
322
- > = React.forwardRef<ExportProps, HTMLInputElement>((props, ref) => (
323
- <TextFieldInternal {...props} forwardedRef={ref} />
324
- ));
319
+ const TextField: React.AbstractComponent<ExportProps, HTMLInputElement> =
320
+ React.forwardRef<ExportProps, HTMLInputElement>((props, ref) => (
321
+ <TextFieldInternal {...props} forwardedRef={ref} />
322
+ ));
325
323
 
326
324
  export default TextField;
@@ -2,7 +2,7 @@
2
2
  import * as React from "react";
3
3
  import {StyleSheet} from "aphrodite";
4
4
 
5
- import {View, Text} from "@khanacademy/wonder-blocks-core";
5
+ import {View, Text as _Text} from "@khanacademy/wonder-blocks-core";
6
6
  import Color from "@khanacademy/wonder-blocks-color";
7
7
  import {Strut} from "@khanacademy/wonder-blocks-layout";
8
8
  import Spacing from "@khanacademy/wonder-blocks-spacing";
@@ -15,7 +15,7 @@ export default {
15
15
  title: "Form / TextField",
16
16
  };
17
17
 
18
- export const text: StoryComponentType = () => {
18
+ export const Text: StoryComponentType = () => {
19
19
  const [value, setValue] = React.useState("");
20
20
 
21
21
  const handleChange = (newValue: string) => {
@@ -40,7 +40,7 @@ export const text: StoryComponentType = () => {
40
40
  );
41
41
  };
42
42
 
43
- export const number: StoryComponentType = () => {
43
+ export const Number: StoryComponentType = () => {
44
44
  const [value, setValue] = React.useState("12345");
45
45
 
46
46
  const handleChange = (newValue: string) => {
@@ -65,7 +65,7 @@ export const number: StoryComponentType = () => {
65
65
  );
66
66
  };
67
67
 
68
- export const password: StoryComponentType = () => {
68
+ export const Password: StoryComponentType = () => {
69
69
  const [value, setValue] = React.useState("Password123");
70
70
  const [errorMessage, setErrorMessage] = React.useState();
71
71
  const [focused, setFocused] = React.useState(false);
@@ -118,14 +118,14 @@ export const password: StoryComponentType = () => {
118
118
  {!focused && errorMessage && (
119
119
  <View>
120
120
  <Strut size={Spacing.xSmall_8} />
121
- <Text style={styles.errorMessage}>{errorMessage}</Text>
121
+ <_Text style={styles.errorMessage}>{errorMessage}</_Text>
122
122
  </View>
123
123
  )}
124
124
  </View>
125
125
  );
126
126
  };
127
127
 
128
- export const email: StoryComponentType = () => {
128
+ export const Email: StoryComponentType = () => {
129
129
  const [value, setValue] = React.useState("khan@khanacademy.org");
130
130
  const [errorMessage, setErrorMessage] = React.useState();
131
131
  const [focused, setFocused] = React.useState(false);
@@ -176,14 +176,14 @@ export const email: StoryComponentType = () => {
176
176
  {!focused && errorMessage && (
177
177
  <View>
178
178
  <Strut size={Spacing.xSmall_8} />
179
- <Text style={styles.errorMessage}>{errorMessage}</Text>
179
+ <_Text style={styles.errorMessage}>{errorMessage}</_Text>
180
180
  </View>
181
181
  )}
182
182
  </View>
183
183
  );
184
184
  };
185
185
 
186
- export const telephone: StoryComponentType = () => {
186
+ export const Telephone: StoryComponentType = () => {
187
187
  const [value, setValue] = React.useState("123-456-7890");
188
188
  const [errorMessage, setErrorMessage] = React.useState();
189
189
  const [focused, setFocused] = React.useState(false);
@@ -234,14 +234,14 @@ export const telephone: StoryComponentType = () => {
234
234
  {!focused && errorMessage && (
235
235
  <View>
236
236
  <Strut size={Spacing.xSmall_8} />
237
- <Text style={styles.errorMessage}>{errorMessage}</Text>
237
+ <_Text style={styles.errorMessage}>{errorMessage}</_Text>
238
238
  </View>
239
239
  )}
240
240
  </View>
241
241
  );
242
242
  };
243
243
 
244
- export const error: StoryComponentType = () => {
244
+ export const Error: StoryComponentType = () => {
245
245
  const [value, setValue] = React.useState("khan");
246
246
  const [errorMessage, setErrorMessage] = React.useState();
247
247
  const [focused, setFocused] = React.useState(false);
@@ -292,14 +292,14 @@ export const error: StoryComponentType = () => {
292
292
  {!focused && errorMessage && (
293
293
  <View>
294
294
  <Strut size={Spacing.xSmall_8} />
295
- <Text style={styles.errorMessage}>{errorMessage}</Text>
295
+ <_Text style={styles.errorMessage}>{errorMessage}</_Text>
296
296
  </View>
297
297
  )}
298
298
  </View>
299
299
  );
300
300
  };
301
301
 
302
- export const disabled: StoryComponentType = () => (
302
+ export const Disabled: StoryComponentType = () => (
303
303
  <TextField
304
304
  id="tf-1"
305
305
  value=""
@@ -309,7 +309,7 @@ export const disabled: StoryComponentType = () => (
309
309
  />
310
310
  );
311
311
 
312
- export const light: StoryComponentType = () => {
312
+ export const Light: StoryComponentType = () => {
313
313
  const [value, setValue] = React.useState("khan@khanacademy.org");
314
314
  const [errorMessage, setErrorMessage] = React.useState();
315
315
  const [focused, setFocused] = React.useState(false);
@@ -361,14 +361,16 @@ export const light: StoryComponentType = () => {
361
361
  {!focused && errorMessage && (
362
362
  <View>
363
363
  <Strut size={Spacing.xSmall_8} />
364
- <Text style={styles.errorMessageLight}>{errorMessage}</Text>
364
+ <_Text style={styles.errorMessageLight}>
365
+ {errorMessage}
366
+ </_Text>
365
367
  </View>
366
368
  )}
367
369
  </View>
368
370
  );
369
371
  };
370
372
 
371
- export const customStyle: StoryComponentType = () => {
373
+ export const CustomStyle: StoryComponentType = () => {
372
374
  const [value, setValue] = React.useState("");
373
375
 
374
376
  const handleChange = (newValue: string) => {
@@ -394,7 +396,7 @@ export const customStyle: StoryComponentType = () => {
394
396
  );
395
397
  };
396
398
 
397
- export const ref: StoryComponentType = () => {
399
+ export const Ref: StoryComponentType = () => {
398
400
  const [value, setValue] = React.useState("");
399
401
  const inputRef: RefObject<typeof HTMLInputElement> = React.createRef();
400
402
 
@@ -433,7 +435,7 @@ export const ref: StoryComponentType = () => {
433
435
  );
434
436
  };
435
437
 
436
- export const readOnly: StoryComponentType = () => {
438
+ export const ReadOnly: StoryComponentType = () => {
437
439
  const [value, setValue] = React.useState("Khan");
438
440
 
439
441
  const handleChange = (newValue: string) => {
@@ -459,7 +461,7 @@ export const readOnly: StoryComponentType = () => {
459
461
  );
460
462
  };
461
463
 
462
- export const autoComplete: StoryComponentType = () => {
464
+ export const AutoComplete: StoryComponentType = () => {
463
465
  const [value, setValue] = React.useState("");
464
466
 
465
467
  const handleChange = (newValue: string) => {
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2018 Khan Academy
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.