@khanacademy/wonder-blocks-form 2.2.1
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/LICENSE +21 -0
- package/dist/es/index.js +1100 -0
- package/dist/index.js +1419 -0
- package/dist/index.js.flow +2 -0
- package/docs.md +1 -0
- package/package.json +35 -0
- package/src/__tests__/__snapshots__/custom-snapshot.test.js.snap +1349 -0
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +6126 -0
- package/src/__tests__/custom-snapshot.test.js +66 -0
- package/src/__tests__/generated-snapshot.test.js +654 -0
- package/src/components/__tests__/checkbox-group.test.js +84 -0
- package/src/components/__tests__/field-heading.test.js +182 -0
- package/src/components/__tests__/labeled-text-field.test.js +442 -0
- package/src/components/__tests__/radio-group.test.js +84 -0
- package/src/components/__tests__/text-field.test.js +424 -0
- package/src/components/checkbox-core.js +201 -0
- package/src/components/checkbox-group.js +161 -0
- package/src/components/checkbox-group.md +200 -0
- package/src/components/checkbox.js +94 -0
- package/src/components/checkbox.md +134 -0
- package/src/components/choice-internal.js +206 -0
- package/src/components/choice.js +104 -0
- package/src/components/field-heading.js +157 -0
- package/src/components/field-heading.md +43 -0
- package/src/components/group-styles.js +35 -0
- package/src/components/labeled-text-field.js +265 -0
- package/src/components/labeled-text-field.md +535 -0
- package/src/components/labeled-text-field.stories.js +359 -0
- package/src/components/radio-core.js +176 -0
- package/src/components/radio-group.js +142 -0
- package/src/components/radio-group.md +129 -0
- package/src/components/radio.js +93 -0
- package/src/components/radio.md +26 -0
- package/src/components/text-field.js +326 -0
- package/src/components/text-field.md +770 -0
- package/src/components/text-field.stories.js +513 -0
- package/src/index.js +18 -0
- package/src/util/types.js +77 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
import {View, addStyle} from "@khanacademy/wonder-blocks-core";
|
|
6
|
+
import {Strut} from "@khanacademy/wonder-blocks-layout";
|
|
7
|
+
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
8
|
+
import {
|
|
9
|
+
type Typography,
|
|
10
|
+
LabelMedium,
|
|
11
|
+
LabelSmall,
|
|
12
|
+
} from "@khanacademy/wonder-blocks-typography";
|
|
13
|
+
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
14
|
+
|
|
15
|
+
import styles from "./group-styles.js";
|
|
16
|
+
import typeof Choice from "./choice.js";
|
|
17
|
+
|
|
18
|
+
// Keep synced with CheckboxGroupProps in ../util/types.js
|
|
19
|
+
type CheckboxGroupProps = {|
|
|
20
|
+
/**
|
|
21
|
+
* Children should be Choice components.
|
|
22
|
+
*/
|
|
23
|
+
children: Array<React.Element<Choice>>,
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Group name for this checkbox or radio group. Should be unique for all
|
|
27
|
+
* such groups displayed on a page.
|
|
28
|
+
*/
|
|
29
|
+
groupName: string,
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Optional label for the group. This label is optional to allow for
|
|
33
|
+
* greater flexibility in implementing checkbox and radio groups.
|
|
34
|
+
*/
|
|
35
|
+
label?: string | React.Element<Typography>,
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Optional description for the group.
|
|
39
|
+
*/
|
|
40
|
+
description?: string | React.Element<Typography>,
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Optional error message. If supplied, the group will be displayed in an
|
|
44
|
+
* error state, along with this error message. If no error state is desired,
|
|
45
|
+
* simply do not supply this prop, or pass along null.
|
|
46
|
+
*/
|
|
47
|
+
errorMessage?: string,
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Custom styling for this group of checkboxes.
|
|
51
|
+
*/
|
|
52
|
+
style?: StyleType,
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Callback for when selection of the group has changed. Passes the newly
|
|
56
|
+
* selected values.
|
|
57
|
+
*/
|
|
58
|
+
onChange: (selectedValues: Array<string>) => mixed,
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* An array of the values of the selected values in this checkbox group.
|
|
62
|
+
*/
|
|
63
|
+
selectedValues: Array<string>,
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Test ID used for e2e testing.
|
|
67
|
+
*/
|
|
68
|
+
testId?: string,
|
|
69
|
+
|};
|
|
70
|
+
|
|
71
|
+
const StyledFieldset = addStyle<"fieldset">("fieldset");
|
|
72
|
+
const StyledLegend = addStyle<"legend">("legend");
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A checkbox group allows multiple selection. This component auto-populates
|
|
76
|
+
* many props for its children Choice components. The Choice component is
|
|
77
|
+
* exposed for the user to apply custom styles or to indicate which choices are
|
|
78
|
+
* disabled.
|
|
79
|
+
*/
|
|
80
|
+
export default class CheckboxGroup extends React.Component<CheckboxGroupProps> {
|
|
81
|
+
handleChange(changedValue: string, originalCheckedState: boolean) {
|
|
82
|
+
const {onChange, selectedValues} = this.props;
|
|
83
|
+
|
|
84
|
+
if (originalCheckedState) {
|
|
85
|
+
const index = selectedValues.indexOf(changedValue);
|
|
86
|
+
const updatedSelection = [
|
|
87
|
+
...selectedValues.slice(0, index),
|
|
88
|
+
...selectedValues.slice(index + 1),
|
|
89
|
+
];
|
|
90
|
+
onChange(updatedSelection);
|
|
91
|
+
} else {
|
|
92
|
+
onChange([...selectedValues, changedValue]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
render(): React.Node {
|
|
97
|
+
const {
|
|
98
|
+
children,
|
|
99
|
+
label,
|
|
100
|
+
description,
|
|
101
|
+
errorMessage,
|
|
102
|
+
groupName,
|
|
103
|
+
selectedValues,
|
|
104
|
+
style,
|
|
105
|
+
testId,
|
|
106
|
+
} = this.props;
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<StyledFieldset data-test-id={testId} style={styles.fieldset}>
|
|
110
|
+
{/* We have a View here because fieldset cannot be used with flexbox*/}
|
|
111
|
+
<View style={style}>
|
|
112
|
+
{typeof label === "string" ? (
|
|
113
|
+
<StyledLegend style={styles.legend}>
|
|
114
|
+
<LabelMedium>{label}</LabelMedium>
|
|
115
|
+
</StyledLegend>
|
|
116
|
+
) : (
|
|
117
|
+
label && label
|
|
118
|
+
)}
|
|
119
|
+
{typeof description === "string" ? (
|
|
120
|
+
<LabelSmall style={styles.description}>
|
|
121
|
+
{description}
|
|
122
|
+
</LabelSmall>
|
|
123
|
+
) : (
|
|
124
|
+
description && description
|
|
125
|
+
)}
|
|
126
|
+
{errorMessage && (
|
|
127
|
+
<LabelSmall style={styles.error}>
|
|
128
|
+
{errorMessage}
|
|
129
|
+
</LabelSmall>
|
|
130
|
+
)}
|
|
131
|
+
{(label || description || errorMessage) && (
|
|
132
|
+
<Strut size={Spacing.small_12} />
|
|
133
|
+
)}
|
|
134
|
+
|
|
135
|
+
{React.Children.map(children, (child, index) => {
|
|
136
|
+
const {style, value} = child.props;
|
|
137
|
+
const checked = selectedValues.includes(value);
|
|
138
|
+
return (
|
|
139
|
+
<React.Fragment>
|
|
140
|
+
{React.cloneElement(child, {
|
|
141
|
+
checked: checked,
|
|
142
|
+
error: !!errorMessage,
|
|
143
|
+
groupName: groupName,
|
|
144
|
+
id: `${groupName}-${value}`,
|
|
145
|
+
key: value,
|
|
146
|
+
onChange: () =>
|
|
147
|
+
this.handleChange(value, checked),
|
|
148
|
+
style: [
|
|
149
|
+
index > 0 && styles.defaultLineGap,
|
|
150
|
+
style,
|
|
151
|
+
],
|
|
152
|
+
variant: "checkbox",
|
|
153
|
+
})}
|
|
154
|
+
</React.Fragment>
|
|
155
|
+
);
|
|
156
|
+
})}
|
|
157
|
+
</View>
|
|
158
|
+
</StyledFieldset>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
This example has two items with descriptions, and it sets an error state to the
|
|
2
|
+
entire group if more than three items are selected.
|
|
3
|
+
|
|
4
|
+
Try out the keyboard navigation! Use tab and shift+tab to navigate among the
|
|
5
|
+
choices, and use space to select/de-select each option.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import {StyleSheet} from "aphrodite";
|
|
9
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
10
|
+
import {CheckboxGroup, Choice} from "@khanacademy/wonder-blocks-form";
|
|
11
|
+
|
|
12
|
+
const styles = StyleSheet.create({
|
|
13
|
+
wrapper: {
|
|
14
|
+
width: 300,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
class CheckboxGroupPizzaExample extends React.Component {
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.state = {
|
|
22
|
+
selectedValues: ["pineapple"],
|
|
23
|
+
};
|
|
24
|
+
this.handleChange = this.handleChange.bind(this);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
handleChange(change) {
|
|
28
|
+
console.log(`${change} was selected!`);
|
|
29
|
+
const error = this.checkForError(change);
|
|
30
|
+
this.setState({
|
|
31
|
+
selectedValues: change,
|
|
32
|
+
error: error,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
checkForError(input) {
|
|
37
|
+
if (input.length > 3) {
|
|
38
|
+
return "You have selected too many toppings";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
render() {
|
|
43
|
+
return <CheckboxGroup
|
|
44
|
+
label="Pizza order"
|
|
45
|
+
description="You may choose at most three toppings"
|
|
46
|
+
errorMessage={this.state.error}
|
|
47
|
+
groupName="Toppings"
|
|
48
|
+
onChange={this.handleChange}
|
|
49
|
+
selectedValues={this.state.selectedValues}
|
|
50
|
+
>
|
|
51
|
+
<Choice label="Pepperoni" value="pepperoni" />
|
|
52
|
+
<Choice label="Sausage" value="sausage" description="Imported from Italy" />
|
|
53
|
+
<Choice label="Extra cheese" value="cheese" />
|
|
54
|
+
<Choice label="Green pepper" value="pepper" />
|
|
55
|
+
<Choice label="Mushroom" value="mushroom" />
|
|
56
|
+
<Choice label="Pineapple" value="pineapple" description="Does in fact belong on pizzas" />
|
|
57
|
+
</CheckboxGroup>
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
<View style={styles.wrapper}>
|
|
61
|
+
<CheckboxGroupPizzaExample />
|
|
62
|
+
</View>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This example shows how one can add custom styles to the checkbox group and to
|
|
66
|
+
each component to achieve desired custom layouts. This context is inspired by
|
|
67
|
+
the class selector modal. The label is created separately because we are
|
|
68
|
+
reflowing all the elements in the group to row.
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import {StyleSheet} from "aphrodite";
|
|
72
|
+
import Color from "@khanacademy/wonder-blocks-color";
|
|
73
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
74
|
+
import {CheckboxGroup, Choice} from "@khanacademy/wonder-blocks-form";
|
|
75
|
+
import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
|
|
76
|
+
|
|
77
|
+
const styles = StyleSheet.create({
|
|
78
|
+
wrapper: {
|
|
79
|
+
width: 650,
|
|
80
|
+
},
|
|
81
|
+
group: {
|
|
82
|
+
flexDirection: "row",
|
|
83
|
+
flexWrap: "wrap",
|
|
84
|
+
},
|
|
85
|
+
choice: {
|
|
86
|
+
marginTop: 8,
|
|
87
|
+
width: 200,
|
|
88
|
+
},
|
|
89
|
+
title: {
|
|
90
|
+
paddingBottom: 8,
|
|
91
|
+
borderBottom: `1px solid ${Color.offBlack64}`,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
class ClassSelectorExample extends React.Component {
|
|
96
|
+
constructor() {
|
|
97
|
+
super();
|
|
98
|
+
this.state = {
|
|
99
|
+
selectedValues: [],
|
|
100
|
+
};
|
|
101
|
+
this.handleChange = this.handleChange.bind(this);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
handleChange(change) {
|
|
105
|
+
console.log(`${change} was selected!`);
|
|
106
|
+
this.setState({
|
|
107
|
+
selectedValues: change,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
render() {
|
|
112
|
+
return <CheckboxGroup
|
|
113
|
+
groupName="science-classes"
|
|
114
|
+
onChange={this.handleChange}
|
|
115
|
+
selectedValues={this.state.selectedValues}
|
|
116
|
+
style={styles.group}
|
|
117
|
+
>
|
|
118
|
+
<Choice label="Biology" value="1" style={styles.choice} />
|
|
119
|
+
<Choice label="AP®︎ Biology" value="2" style={styles.choice} />
|
|
120
|
+
<Choice label="High school biology" value="3" style={styles.choice} />
|
|
121
|
+
<Choice label="Cosmology and astronomy" value="4" style={styles.choice} />
|
|
122
|
+
<Choice label="Electrical engineering" value="5" style={styles.choice} />
|
|
123
|
+
<Choice label="Health and medicine" value="6" style={styles.choice} />
|
|
124
|
+
</CheckboxGroup>
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
<View style={styles.wrapper}>
|
|
128
|
+
<LabelLarge style={styles.title}>Science</LabelLarge>
|
|
129
|
+
<ClassSelectorExample />
|
|
130
|
+
</View>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This example shows how to use custom styling to change the appearance of the
|
|
134
|
+
checkbox group to look more like a multiple choice question. You may also provide
|
|
135
|
+
custom typography to the label and description.
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
import {CheckboxGroup, Choice} from "@khanacademy/wonder-blocks-form";
|
|
139
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
140
|
+
import Color from "@khanacademy/wonder-blocks-color";
|
|
141
|
+
import {LabelLarge, LabelXSmall} from "@khanacademy/wonder-blocks-typography";
|
|
142
|
+
import {StyleSheet} from "aphrodite";
|
|
143
|
+
|
|
144
|
+
const styles = StyleSheet.create({
|
|
145
|
+
choice: {
|
|
146
|
+
margin: 0,
|
|
147
|
+
height: 48,
|
|
148
|
+
borderTop: "solid 1px #CCC",
|
|
149
|
+
justifyContent: "center",
|
|
150
|
+
":last-child": {
|
|
151
|
+
borderBottom: "solid 1px #CCC",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
description: {
|
|
155
|
+
marginTop: 5,
|
|
156
|
+
color: Color.offBlack64,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
class ClassSelectorExample extends React.Component {
|
|
161
|
+
constructor() {
|
|
162
|
+
super();
|
|
163
|
+
this.state = {
|
|
164
|
+
selectedValues: [],
|
|
165
|
+
};
|
|
166
|
+
this.handleChange = this.handleChange.bind(this);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
handleChange(change) {
|
|
170
|
+
console.log(`${change} was selected!`);
|
|
171
|
+
this.setState({
|
|
172
|
+
selectedValues: change,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
render() {
|
|
177
|
+
return <CheckboxGroup
|
|
178
|
+
label={<LabelLarge>Select all prime numbers</LabelLarge>}
|
|
179
|
+
description={
|
|
180
|
+
<LabelXSmall style={styles.description}>
|
|
181
|
+
Hint: There is at least one prime number
|
|
182
|
+
</LabelXSmall>
|
|
183
|
+
}
|
|
184
|
+
groupName="science-classes"
|
|
185
|
+
onChange={this.handleChange}
|
|
186
|
+
selectedValues={this.state.selectedValues}
|
|
187
|
+
>
|
|
188
|
+
<Choice label="1" value="1" style={styles.choice} />
|
|
189
|
+
<Choice label="2" value="2" style={styles.choice} />
|
|
190
|
+
<Choice label="3" value="3" style={styles.choice} />
|
|
191
|
+
<Choice label="4" value="4" style={styles.choice} />
|
|
192
|
+
<Choice label="5" value="5" style={styles.choice} />
|
|
193
|
+
</CheckboxGroup>
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
<View>
|
|
198
|
+
<ClassSelectorExample />
|
|
199
|
+
</View>
|
|
200
|
+
```
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
import type {AriaProps, StyleType} from "@khanacademy/wonder-blocks-core";
|
|
6
|
+
import ChoiceInternal from "./choice-internal.js";
|
|
7
|
+
|
|
8
|
+
// Keep synced with ChoiceComponentProps in ../util/types.js
|
|
9
|
+
type ChoiceComponentProps = {|
|
|
10
|
+
...AriaProps,
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Whether this component is checked
|
|
14
|
+
*/
|
|
15
|
+
checked: boolean,
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Whether this component is disabled
|
|
19
|
+
*/
|
|
20
|
+
disabled: boolean,
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether this component should show an error state
|
|
24
|
+
*/
|
|
25
|
+
error: boolean,
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Callback when this component is selected. The newCheckedState is the
|
|
29
|
+
* new checked state of the component.
|
|
30
|
+
*/
|
|
31
|
+
onChange: (newCheckedState: boolean) => mixed,
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Optional label for the field.
|
|
35
|
+
*/
|
|
36
|
+
label?: string,
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Optional description for the field.
|
|
40
|
+
*/
|
|
41
|
+
description?: string,
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Unique identifier attached to the HTML input element. If used, need to
|
|
45
|
+
* guarantee that the ID is unique within everything rendered on a page.
|
|
46
|
+
* Used to match `<label>` with `<input>` elements for screenreaders.
|
|
47
|
+
*/
|
|
48
|
+
id?: string,
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Optional styling for the container. Does not style the component.
|
|
52
|
+
*/
|
|
53
|
+
style?: StyleType,
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Adds CSS classes to the Checkbox.
|
|
57
|
+
*/
|
|
58
|
+
className?: string,
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Optional test ID for e2e testing
|
|
62
|
+
*/
|
|
63
|
+
testId?: string,
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Name for the checkbox or radio button group. Only applicable for group
|
|
67
|
+
* contexts, auto-populated by group components via Choice.
|
|
68
|
+
* @ignore
|
|
69
|
+
*/
|
|
70
|
+
groupName?: string,
|
|
71
|
+
|};
|
|
72
|
+
|
|
73
|
+
type DefaultProps = {|
|
|
74
|
+
disabled: $PropertyType<ChoiceComponentProps, "disabled">,
|
|
75
|
+
error: $PropertyType<ChoiceComponentProps, "error">,
|
|
76
|
+
|};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* ☑️ A nicely styled checkbox for all your checking needs. Can optionally take
|
|
80
|
+
* label and description props.
|
|
81
|
+
*
|
|
82
|
+
* If you want a whole group of Checkbox[es] that are related, see the Choice
|
|
83
|
+
* and CheckboxGroup components.
|
|
84
|
+
*/
|
|
85
|
+
export default class Checkbox extends React.Component<ChoiceComponentProps> {
|
|
86
|
+
static defaultProps: DefaultProps = {
|
|
87
|
+
disabled: false,
|
|
88
|
+
error: false,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
render(): React.Node {
|
|
92
|
+
return <ChoiceInternal variant="checkbox" {...this.props} />;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
The checkbox has various styles for clickable states. Here are sets of default checkboxes, checkboxes in an error state, and disabled checkboxes.
|
|
2
|
+
```js
|
|
3
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
4
|
+
import {Checkbox} from "@khanacademy/wonder-blocks-form";
|
|
5
|
+
import {StyleSheet} from "aphrodite";
|
|
6
|
+
|
|
7
|
+
const styles = StyleSheet.create({
|
|
8
|
+
row: {
|
|
9
|
+
flexDirection: "row",
|
|
10
|
+
},
|
|
11
|
+
marginRight: {
|
|
12
|
+
marginRight: 16,
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const handleChange = (checked) => console.log(`clicked on checkbox, will be checked=${checked.toString()}`);
|
|
17
|
+
|
|
18
|
+
<View style={styles.row}>
|
|
19
|
+
<Checkbox error={false} checked={false} style={styles.marginRight} onChange={handleChange} />
|
|
20
|
+
<Checkbox error={false} checked={true} style={styles.marginRight} onChange={handleChange} />
|
|
21
|
+
<Checkbox error={true} checked={false} style={styles.marginRight} onChange={handleChange} />
|
|
22
|
+
<Checkbox error={true} checked={true} style={styles.marginRight} onChange={handleChange} />
|
|
23
|
+
<Checkbox disabled={true} checked={false} style={styles.marginRight} onChange={handleChange} />
|
|
24
|
+
<Checkbox disabled={true} checked={true} style={styles.marginRight} onChange={handleChange} />
|
|
25
|
+
</View>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The checkbox can have a optional label and description. This allows it to be
|
|
29
|
+
used as a settings-like item. The user of this component is responsible for
|
|
30
|
+
keeping track of checked state and providing an onChange callback.
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
34
|
+
import {Checkbox} from "@khanacademy/wonder-blocks-form";
|
|
35
|
+
import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography";
|
|
36
|
+
import {StyleSheet} from "aphrodite";
|
|
37
|
+
|
|
38
|
+
class Settings extends React.Component {
|
|
39
|
+
constructor() {
|
|
40
|
+
super();
|
|
41
|
+
this.state = {
|
|
42
|
+
assignment: false,
|
|
43
|
+
};
|
|
44
|
+
this.handleChange = this.handleChange.bind(this);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
handleChange(checked) {
|
|
48
|
+
this.setState({
|
|
49
|
+
assignment: checked,
|
|
50
|
+
});
|
|
51
|
+
// Potentially do something here with this updated state information.
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
render() {
|
|
55
|
+
const handleChanged = (checked) => console.log(`clicked on checkbox with checked=${checked.toString()}`);
|
|
56
|
+
const headingText = "Functions";
|
|
57
|
+
|
|
58
|
+
return <View>
|
|
59
|
+
<Checkbox
|
|
60
|
+
label="Receive assignment reminders for Algebra"
|
|
61
|
+
description="You will receive a reminder 24 hours before each deadline"
|
|
62
|
+
checked={this.state.assignment}
|
|
63
|
+
id="assignment"
|
|
64
|
+
onChange={this.handleChange}
|
|
65
|
+
testId="algebra-assignment-test"
|
|
66
|
+
variant="checkbox"
|
|
67
|
+
/>
|
|
68
|
+
</View>;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
<Settings />
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Sometimes one may wish to use a checkbox in a different context (label may not
|
|
76
|
+
be right next to the checkbox), like in this example content item. Use a
|
|
77
|
+
`<label htmlFor={id}>` element where the id matches the `id` prop of the
|
|
78
|
+
Checkbox. This is for accessibility purposes, and doing this also automatically
|
|
79
|
+
makes the label a click target for the checkbox.
|
|
80
|
+
```js
|
|
81
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
82
|
+
import {Checkbox} from "@khanacademy/wonder-blocks-form";
|
|
83
|
+
import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography";
|
|
84
|
+
import {StyleSheet} from "aphrodite";
|
|
85
|
+
|
|
86
|
+
const styles = StyleSheet.create({
|
|
87
|
+
wrapper: {
|
|
88
|
+
flexDirection: "row",
|
|
89
|
+
alignItems: "center",
|
|
90
|
+
justifyContent: "space-evenly",
|
|
91
|
+
},
|
|
92
|
+
topic: {
|
|
93
|
+
maxWidth: 600,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
class ContentItem extends React.Component {
|
|
98
|
+
constructor() {
|
|
99
|
+
super();
|
|
100
|
+
this.state = {
|
|
101
|
+
checked: false,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
handleChange(checked) {
|
|
106
|
+
this.setState({
|
|
107
|
+
checked: checked,
|
|
108
|
+
});
|
|
109
|
+
// Potentially do something here with this updated state information.
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
render() {
|
|
113
|
+
const handleChanged = (checked) => console.log(`clicked on checkbox with checked=${checked.toString()}`);
|
|
114
|
+
const headingText = "Functions";
|
|
115
|
+
const descriptionText = `A great cook knows how to take basic ingredients and
|
|
116
|
+
prepare a delicious meal. In this topic, you will become function-chefs! You
|
|
117
|
+
will learn how to combine functions with arithmetic operations and how to
|
|
118
|
+
compose functions.`;
|
|
119
|
+
return <View style={styles.wrapper}>
|
|
120
|
+
<View style={styles.topic}>
|
|
121
|
+
<label htmlFor="topic-123"><LabelMedium>{headingText}</LabelMedium></label>
|
|
122
|
+
<LabelSmall>{descriptionText}</LabelSmall>
|
|
123
|
+
</View>
|
|
124
|
+
<Checkbox
|
|
125
|
+
checked={this.state.checked}
|
|
126
|
+
id="topic-123"
|
|
127
|
+
onChange={(checked) => this.handleChange(checked)}
|
|
128
|
+
/>
|
|
129
|
+
</View>;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
<ContentItem />
|
|
134
|
+
```
|