@khanacademy/wonder-blocks-form 2.4.4 → 2.4.7

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
+ ## 2.4.7
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [34c7aacb]
8
+ - @khanacademy/wonder-blocks-color@1.2.0
9
+
10
+ ## 2.4.6
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [ee6fc773]
15
+ - @khanacademy/wonder-blocks-clickable@2.3.0
16
+
17
+ ## 2.4.5
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies [83486dba]
22
+ - @khanacademy/wonder-blocks-icon@1.2.29
23
+
3
24
  ## 2.4.4
4
25
 
5
26
  ### Patch Changes
package/dist/index.js CHANGED
@@ -464,6 +464,24 @@ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
464
464
  boxShadow: `0px 0px 0px 1px ${_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.red}, 0px 0px 0px 2px ${_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.white}`
465
465
  }
466
466
  });
467
+
468
+ /**
469
+ * A TextField is an element used to accept a single line of text from the user.
470
+ *
471
+ * ### Usage
472
+ *
473
+ * ```jsx
474
+ * import {TextField} from "@khanacademy/wonder-blocks-form";
475
+ *
476
+ * const [value, setValue] = React.useState("");
477
+ *
478
+ * <TextField
479
+ * id="some-unique-text-field-id"
480
+ * value={value}
481
+ * onChange={setValue}
482
+ * />
483
+ * ```
484
+ */
467
485
  const TextField = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["forwardRef"]((props, ref) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](TextFieldInternal, _extends({}, props, {
468
486
  forwardedRef: ref
469
487
  })));
@@ -666,6 +684,63 @@ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
666
684
  *
667
685
  * If you wish to use just a single field, use Checkbox or Radio with the
668
686
  * optional label and description props.
687
+ *
688
+ * ### Checkbox Usage
689
+ *
690
+ * ```jsx
691
+ * import {Choice, CheckboxGroup} from "@khanacademy/wonder-blocks-form";
692
+ *
693
+ * const [selectedValues, setSelectedValues] = React.useState([]);
694
+ *
695
+ * // Checkbox usage
696
+ * <CheckboxGroup
697
+ * label="some-label"
698
+ * description="some-description"
699
+ * groupName="some-group-name"
700
+ * onChange={setSelectedValues}
701
+ * selectedValues={selectedValues}
702
+ * />
703
+ * // Add as many choices as necessary
704
+ * <Choice
705
+ * label="Choice 1"
706
+ * value="some-choice-value"
707
+ * description="Some choice description."
708
+ * />
709
+ * <Choice
710
+ * label="Choice 2"
711
+ * value="some-choice-value-2"
712
+ * description="Some choice description."
713
+ * />
714
+ * </CheckboxGroup>
715
+ * ```
716
+ *
717
+ * ### Radio Usage
718
+ *
719
+ * ```jsx
720
+ * import {Choice, RadioGroup} from "@khanacademy/wonder-blocks-form";
721
+ *
722
+ * const [selectedValue, setSelectedValue] = React.useState("");
723
+ *
724
+ * <RadioGroup
725
+ * label="some-label"
726
+ * description="some-description"
727
+ * groupName="some-group-name"
728
+ * onChange={setSelectedValue}>
729
+ * selectedValues={selectedValue}
730
+ * />
731
+ * // Add as many choices as necessary
732
+ * <Choice
733
+ * label="Choice 1"
734
+ * value="some-choice-value"
735
+ * description="Some choice description."
736
+ * />
737
+ * <Choice
738
+ * label="Choice 2"
739
+ * value="some-choice-value-2"
740
+ * description="Some choice description."
741
+ * />
742
+ * </RadioGroup>
743
+ * ```
669
744
  */
670
745
  class Choice extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
671
746
  getChoiceComponent(variant) {
@@ -725,6 +800,33 @@ const StyledLegend = Object(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MO
725
800
  * many props for its children Choice components. The Choice component is
726
801
  * exposed for the user to apply custom styles or to indicate which choices are
727
802
  * disabled.
803
+ *
804
+ * ### Usage
805
+ *
806
+ * ```jsx
807
+ * import {Choice, CheckboxGroup} from "@khanacademy/wonder-blocks-form";
808
+ *
809
+ * const [selectedValues, setSelectedValues] = React.useState([]);
810
+ *
811
+ * <CheckboxGroup
812
+ * label="some-label"
813
+ * description="some-description"
814
+ * groupName="some-group-name"
815
+ * onChange={setSelectedValues}
816
+ * selectedValues={selectedValues}
817
+ * />
818
+ * // Add as many choices as necessary
819
+ * <Choice
820
+ * label="Choice 1"
821
+ * value="some-choice-value"
822
+ * />
823
+ * <Choice
824
+ * label="Choice 2"
825
+ * value="some-choice-value-2"
826
+ * description="Some choice description."
827
+ * />
828
+ * </CheckboxGroup>
829
+ * ```
728
830
  */
729
831
 
730
832
  class CheckboxGroup extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
@@ -820,6 +922,33 @@ const StyledLegend = Object(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MO
820
922
  * indicate which choices are disabled. The use of the groupName prop is
821
923
  * important to maintain expected keyboard navigation behavior for
822
924
  * accessibility.
925
+ *
926
+ * ### Usage
927
+ *
928
+ * ```jsx
929
+ * import {Choice, RadioGroup} from "@khanacademy/wonder-blocks-form";
930
+ *
931
+ * const [selectedValue, setSelectedValue] = React.useState([]);
932
+ *
933
+ * <RadioGroup
934
+ * label="some-label"
935
+ * description="some-description"
936
+ * groupName="some-group-name"
937
+ * onChange={setSelectedValue}
938
+ * selectedValue={selectedValue}
939
+ * />
940
+ * // Add as many choices as necessary
941
+ * <Choice
942
+ * label="Choice 1"
943
+ * value="some-choice-value"
944
+ * />
945
+ * <Choice
946
+ * label="Choice 2"
947
+ * value="some-choice-value-2"
948
+ * description="Some choice description."
949
+ * />
950
+ * </RadioGroup>
951
+ * ```
823
952
  */
824
953
 
825
954
  class RadioGroup extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
@@ -1009,6 +1138,27 @@ LabeledTextFieldInternal.defaultProps = {
1009
1138
  disabled: false,
1010
1139
  light: false
1011
1140
  };
1141
+
1142
+ /**
1143
+ * A LabeledTextField is an element used to accept a single line of text
1144
+ * from the user paired with a label, description, and error field elements.
1145
+ *
1146
+ * ### Usage
1147
+ *
1148
+ * ```jsx
1149
+ * import {LabeledTextField} from "@khanacademy/wonder-blocks-form";
1150
+ *
1151
+ * const [value, setValue] = React.useState("");
1152
+ *
1153
+ * <LabeledTextField
1154
+ * label="Label"
1155
+ * description="Hello, this is the description for this field"
1156
+ * placeholder="Placeholder"
1157
+ * value={value}
1158
+ * onChange={setValue}
1159
+ * />
1160
+ * ```
1161
+ */
1012
1162
  const LabeledTextField = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["forwardRef"]((props, ref) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](LabeledTextFieldInternal, _extends({}, props, {
1013
1163
  forwardedRef: ref
1014
1164
  })));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-form",
3
- "version": "2.4.4",
3
+ "version": "2.4.7",
4
4
  "design": "v1",
5
5
  "description": "Form components for Wonder Blocks.",
6
6
  "main": "dist/index.js",
@@ -15,11 +15,11 @@
15
15
  "access": "public"
16
16
  },
17
17
  "dependencies": {
18
- "@babel/runtime": "^7.16.3",
19
- "@khanacademy/wonder-blocks-clickable": "^2.2.7",
20
- "@khanacademy/wonder-blocks-color": "^1.1.20",
18
+ "@babel/runtime": "^7.18.6",
19
+ "@khanacademy/wonder-blocks-clickable": "^2.3.0",
20
+ "@khanacademy/wonder-blocks-color": "^1.2.0",
21
21
  "@khanacademy/wonder-blocks-core": "^4.3.2",
22
- "@khanacademy/wonder-blocks-icon": "^1.2.28",
22
+ "@khanacademy/wonder-blocks-icon": "^1.2.29",
23
23
  "@khanacademy/wonder-blocks-layout": "^1.4.10",
24
24
  "@khanacademy/wonder-blocks-spacing": "^3.0.5",
25
25
  "@khanacademy/wonder-blocks-typography": "^1.1.32"
@@ -0,0 +1,266 @@
1
+ // @flow
2
+ import * as React from "react";
3
+ import {StyleSheet} from "aphrodite";
4
+
5
+ import {View} from "@khanacademy/wonder-blocks-core";
6
+ import Color from "@khanacademy/wonder-blocks-color";
7
+ import {Choice, CheckboxGroup} from "@khanacademy/wonder-blocks-form";
8
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
9
+ import {LabelLarge, LabelXSmall} from "@khanacademy/wonder-blocks-typography";
10
+
11
+ import type {StoryComponentType} from "@storybook/react";
12
+
13
+ import ComponentInfo from "../../../../../.storybook/components/component-info.js";
14
+ import {name, version} from "../../../package.json";
15
+
16
+ export default {
17
+ title: "Form / CheckboxGroup",
18
+ component: CheckboxGroup,
19
+ parameters: {
20
+ componentSubtitle: ((
21
+ <ComponentInfo name={name} version={version} />
22
+ ): any),
23
+ },
24
+ };
25
+
26
+ export const Default: StoryComponentType = (args) => {
27
+ return (
28
+ <CheckboxGroup {...args}>
29
+ <Choice label="Pepperoni" value="pepperoni" />
30
+ <Choice
31
+ label="Sausage"
32
+ value="sausage"
33
+ description="Imported from Italy"
34
+ />
35
+ <Choice label="Extra cheese" value="cheese" />
36
+ <Choice label="Green pepper" value="pepper" />
37
+ <Choice label="Mushroom" value="mushroom" />
38
+ </CheckboxGroup>
39
+ );
40
+ };
41
+
42
+ Default.args = {
43
+ // Required
44
+ groupName: "toppings",
45
+ selectedValues: ["pepperoni", "sausage"],
46
+ onChange: () => {},
47
+ // Optional
48
+ label: "Pizza toppings",
49
+ description: "Choose as many toppings as you would like.",
50
+ };
51
+
52
+ export const Basic: StoryComponentType = () => {
53
+ const [selectedValues, setSelectedValues] = React.useState([]);
54
+
55
+ return (
56
+ <CheckboxGroup
57
+ groupName="toppings"
58
+ onChange={setSelectedValues}
59
+ selectedValues={selectedValues}
60
+ >
61
+ <Choice label="Pepperoni" value="pepperoni" />
62
+ <Choice
63
+ label="Sausage"
64
+ value="sausage"
65
+ description="Imported from Italy"
66
+ />
67
+ <Choice label="Extra cheese" value="cheese" />
68
+ <Choice label="Green pepper" value="pepper" />
69
+ <Choice label="Mushroom" value="mushroom" />
70
+ </CheckboxGroup>
71
+ );
72
+ };
73
+
74
+ Basic.parameters = {
75
+ docs: {
76
+ storyDescription: `This is a basic example of a checkbox group.
77
+ The Wonder Blocks \`CheckboxGroup\` component takes \`Choice\`
78
+ components as children. One of the \`Choice\` components here
79
+ includes a description.`,
80
+ },
81
+ };
82
+
83
+ export const Error: StoryComponentType = () => {
84
+ const toppingsError = "You have selected too many toppings";
85
+ const [selectedValues, setSelectedValues] = React.useState([
86
+ "pepperoni",
87
+ "sausage",
88
+ "cheese",
89
+ "pepper",
90
+ ]);
91
+ const [error, setError] = React.useState(toppingsError);
92
+
93
+ // Returns an error message if more than 3 items are selected,
94
+ // and it returns undefined otherwise. We use undefined instead of
95
+ // null here because null would result in a flow error, whereas
96
+ // undefined would be the same as not passing in anything to the
97
+ // checkbox group's `errorMessage` prop.
98
+ const checkForError = (input) => {
99
+ if (input.length > 3) {
100
+ return toppingsError;
101
+ }
102
+ };
103
+
104
+ const handleChange = (input) => {
105
+ const errorMessage = checkForError(input);
106
+ setSelectedValues(input);
107
+ setError(errorMessage);
108
+ };
109
+
110
+ return (
111
+ <CheckboxGroup
112
+ label="Pizza order"
113
+ groupName="toppings"
114
+ description="You may choose at most three toppings"
115
+ onChange={handleChange}
116
+ errorMessage={error}
117
+ selectedValues={selectedValues}
118
+ >
119
+ <Choice label="Pepperoni" value="pepperoni" />
120
+ <Choice
121
+ label="Sausage"
122
+ value="sausage"
123
+ description="Imported from Italy"
124
+ />
125
+ <Choice label="Extra cheese" value="cheese" />
126
+ <Choice label="Green pepper" value="pepper" />
127
+ <Choice label="Mushroom" value="mushroom" />
128
+ </CheckboxGroup>
129
+ );
130
+ };
131
+
132
+ Error.parameters = {
133
+ docs: {
134
+ storyDescription: `This is what a checkbox group looks like
135
+ if it has an error. It displays the error that is passed into the
136
+ \`errorMessage\` prop, provided the error is not null. It also
137
+ uses the error styling for all the checkboxes. Here, the error
138
+ message is saved as a state, updated in the change handler, and then
139
+ passed in as the \`errorMessage\` prop.`,
140
+ },
141
+ };
142
+
143
+ export const RowStyling: StoryComponentType = () => {
144
+ const [selectedValues, setSelectedValues] = React.useState([]);
145
+
146
+ return (
147
+ <View style={styles.wrapper}>
148
+ <LabelLarge style={styles.title}>Science</LabelLarge>
149
+ <CheckboxGroup
150
+ groupName="science-classes"
151
+ onChange={setSelectedValues}
152
+ selectedValues={selectedValues}
153
+ style={styles.group}
154
+ >
155
+ <Choice label="Biology" value="1" style={styles.choice} />
156
+ <Choice label="AP®︎ Biology" value="2" style={styles.choice} />
157
+ <Choice
158
+ label="High school biology"
159
+ value="3"
160
+ style={styles.choice}
161
+ />
162
+ <Choice
163
+ label="Cosmology and astronomy"
164
+ value="4"
165
+ style={styles.choice}
166
+ />
167
+ <Choice
168
+ label="Electrical engineering"
169
+ value="5"
170
+ style={styles.choice}
171
+ />
172
+ <Choice
173
+ label="Health and medicine"
174
+ value="6"
175
+ style={styles.choice}
176
+ />
177
+ </CheckboxGroup>
178
+ </View>
179
+ );
180
+ };
181
+
182
+ RowStyling.parameters = {
183
+ docs: {
184
+ storyDescription: `This example shows how one can add custom styles
185
+ to the checkbox group and to each component to achieve desired custom
186
+ layouts. The context in this example is inspired by the class selector
187
+ modal. The label is created separately because we are reflowing all
188
+ the elements in the group to row. The checkboxes render
189
+ horizontally when the style on the \`CheckboxGroup\` is set to
190
+ \`{flexDirection: "row"}\`. Here, \`{flexWrap: "wrap"}\` is also
191
+ used so the options continue on the next line.`,
192
+ },
193
+ };
194
+
195
+ export const MultipleChoiceStyling: StoryComponentType = () => {
196
+ const [selectedValues, setSelectedValues] = React.useState([]);
197
+
198
+ return (
199
+ <CheckboxGroup
200
+ label={<LabelLarge>Select all prime numbers</LabelLarge>}
201
+ description={
202
+ <LabelXSmall style={styles.description}>
203
+ Hint: There is at least one prime number
204
+ </LabelXSmall>
205
+ }
206
+ groupName="science-classes"
207
+ onChange={setSelectedValues}
208
+ selectedValues={selectedValues}
209
+ >
210
+ <Choice label="1" value="1" style={styles.multipleChoice} />
211
+ <Choice label="2" value="2" style={styles.multipleChoice} />
212
+ <Choice label="3" value="3" style={styles.multipleChoice} />
213
+ <Choice label="4" value="4" style={styles.multipleChoice} />
214
+ <Choice
215
+ label="5"
216
+ value="5"
217
+ style={[styles.multipleChoice, styles.last]}
218
+ />
219
+ </CheckboxGroup>
220
+ );
221
+ };
222
+
223
+ MultipleChoiceStyling.parameters = {
224
+ docs: {
225
+ storyDescription: `This example shows how to use custom styling
226
+ to change the appearance of the checkbox group to look more like
227
+ a multiple choice question. You may also provide custom typography
228
+ to the label and description. Here, there is a line in
229
+ between each question, which is achieved using the
230
+ \`{borderTop: "solid 1px #CCC"}\` style on each \`Choice\`
231
+ component.`,
232
+ },
233
+ };
234
+
235
+ const styles = StyleSheet.create({
236
+ // Row styling
237
+ wrapper: {
238
+ width: 650,
239
+ },
240
+ group: {
241
+ flexDirection: "row",
242
+ flexWrap: "wrap",
243
+ },
244
+ choice: {
245
+ marginTop: Spacing.xSmall_8,
246
+ width: 200,
247
+ },
248
+ title: {
249
+ paddingBottom: Spacing.xSmall_8,
250
+ borderBottom: `1px solid ${Color.offBlack64}`,
251
+ },
252
+ // Multiple choice styling
253
+ multipleChoice: {
254
+ margin: 0,
255
+ height: 48,
256
+ borderTop: "solid 1px #CCC",
257
+ justifyContent: "center",
258
+ },
259
+ description: {
260
+ marginTop: 5,
261
+ color: Color.offBlack64,
262
+ },
263
+ last: {
264
+ borderBottom: "solid 1px #CCC",
265
+ },
266
+ });
@@ -117,7 +117,7 @@ export const WithLabel: StoryComponentType = () => {
117
117
  WithLabel.parameters = {
118
118
  docs: {
119
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.",
120
+ "The checkbox can have an 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
121
  },
122
122
  };
123
123
 
@@ -0,0 +1,86 @@
1
+ // @flow
2
+ import * as React from "react";
3
+ import {StyleSheet} from "aphrodite";
4
+
5
+ import {View} from "@khanacademy/wonder-blocks-core";
6
+ import {
7
+ Choice,
8
+ CheckboxGroup,
9
+ RadioGroup,
10
+ } from "@khanacademy/wonder-blocks-form";
11
+ import {Strut} from "@khanacademy/wonder-blocks-layout";
12
+ import Spacing from "@khanacademy/wonder-blocks-spacing";
13
+
14
+ import type {StoryComponentType} from "@storybook/react";
15
+
16
+ import ComponentInfo from "../../../../../.storybook/components/component-info.js";
17
+ import {name, version} from "../../../package.json";
18
+
19
+ export default {
20
+ title: "Form / Choice",
21
+ component: Choice,
22
+ parameters: {
23
+ componentSubtitle: ((
24
+ <ComponentInfo name={name} version={version} />
25
+ ): any),
26
+ },
27
+ };
28
+
29
+ export const Default: StoryComponentType = (args) => {
30
+ const [selectedValues, setSelectedValues] = React.useState([]);
31
+ const [selectedValue, setSelectedValue] = React.useState("");
32
+
33
+ return (
34
+ <View style={styles.row}>
35
+ <CheckboxGroup
36
+ label="Pizza order"
37
+ description="Choose as many toppings as you would like."
38
+ groupName="Toppings"
39
+ onChange={setSelectedValues}
40
+ selectedValues={selectedValues}
41
+ >
42
+ <Choice label="Pepperoni" value="pepperoni" />
43
+ <Choice
44
+ label="Sausage"
45
+ value="sausage"
46
+ description="Imported from Italy"
47
+ />
48
+ <Choice label="Extra cheese" value="cheese" />
49
+ <Choice label="Green pepper" value="pepper" />
50
+ <Choice label="Mushroom" value="mushroom" />
51
+ <Choice {...args} />
52
+ </CheckboxGroup>
53
+ <Strut size={Spacing.xLarge_32} />
54
+ <RadioGroup
55
+ label="Pizza order"
56
+ description="Choose only one topping."
57
+ groupName="Toppings"
58
+ onChange={setSelectedValue}
59
+ selectedValue={selectedValue}
60
+ >
61
+ <Choice label="Pepperoni" value="pepperoni" />
62
+ <Choice
63
+ label="Sausage"
64
+ value="sausage"
65
+ description="Imported from Italy"
66
+ />
67
+ <Choice label="Extra cheese" value="cheese" />
68
+ <Choice label="Green pepper" value="pepper" />
69
+ <Choice label="Mushroom" value="mushroom" />
70
+ <Choice {...args} />
71
+ </RadioGroup>
72
+ </View>
73
+ );
74
+ };
75
+
76
+ Default.args = {
77
+ label: "Pineapple (Control)",
78
+ value: "pineapple",
79
+ description: "Does in fact belong on pizzas",
80
+ };
81
+
82
+ const styles = StyleSheet.create({
83
+ row: {
84
+ flexDirection: "row",
85
+ },
86
+ });