@khanacademy/wonder-blocks-form 4.9.2 → 4.9.3
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 +13 -0
- package/dist/components/checkbox-core.d.ts +2 -2
- package/dist/components/checkbox.d.ts +2 -2
- package/dist/components/choice-internal.d.ts +2 -2
- package/dist/components/choice.d.ts +2 -2
- package/dist/components/radio-core.d.ts +2 -2
- package/dist/components/radio.d.ts +2 -2
- package/dist/components/text-area.d.ts +2 -2
- package/package.json +7 -7
- package/src/__tests__/__snapshots__/custom-snapshot.test.tsx.snap +0 -247
- package/src/__tests__/custom-snapshot.test.tsx +0 -48
- package/src/components/__tests__/checkbox-group.test.tsx +0 -162
- package/src/components/__tests__/checkbox.test.tsx +0 -138
- package/src/components/__tests__/field-heading.test.tsx +0 -225
- package/src/components/__tests__/labeled-text-field.test.tsx +0 -750
- package/src/components/__tests__/radio-group.test.tsx +0 -182
- package/src/components/__tests__/text-area.test.tsx +0 -1286
- package/src/components/__tests__/text-field.test.tsx +0 -562
- package/src/components/checkbox-core.tsx +0 -239
- package/src/components/checkbox-group.tsx +0 -174
- package/src/components/checkbox.tsx +0 -99
- package/src/components/choice-internal.tsx +0 -184
- package/src/components/choice.tsx +0 -157
- package/src/components/field-heading.tsx +0 -169
- package/src/components/group-styles.ts +0 -33
- package/src/components/labeled-text-field.tsx +0 -317
- package/src/components/radio-core.tsx +0 -171
- package/src/components/radio-group.tsx +0 -159
- package/src/components/radio.tsx +0 -82
- package/src/components/text-area.tsx +0 -430
- package/src/components/text-field.tsx +0 -399
- package/src/index.ts +0 -17
- package/src/util/types.ts +0 -85
- package/tsconfig-build.json +0 -19
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {StyleSheet} from "aphrodite";
|
|
3
|
-
|
|
4
|
-
import {mix, color} from "@khanacademy/wonder-blocks-tokens";
|
|
5
|
-
import {addStyle} from "@khanacademy/wonder-blocks-core";
|
|
6
|
-
|
|
7
|
-
import type {ChoiceCoreProps, Checked} from "../util/types";
|
|
8
|
-
|
|
9
|
-
const {blue, red, white, offWhite, offBlack16, offBlack32, offBlack50} = color;
|
|
10
|
-
|
|
11
|
-
const StyledInput = addStyle("input");
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* The internal stateless 🔘 Radio button
|
|
15
|
-
*/ const RadioCore = React.forwardRef(function RadioCore(
|
|
16
|
-
props: ChoiceCoreProps,
|
|
17
|
-
ref: React.ForwardedRef<HTMLInputElement>,
|
|
18
|
-
) {
|
|
19
|
-
const handleChange = () => {
|
|
20
|
-
// Empty because change is handled by ClickableBehavior
|
|
21
|
-
return;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const {checked, disabled, error, groupName, id, testId, ...sharedProps} =
|
|
25
|
-
props;
|
|
26
|
-
|
|
27
|
-
const stateStyles = _generateStyles(checked, error);
|
|
28
|
-
const defaultStyle = [
|
|
29
|
-
sharedStyles.inputReset,
|
|
30
|
-
sharedStyles.default,
|
|
31
|
-
!disabled && stateStyles.default,
|
|
32
|
-
disabled && sharedStyles.disabled,
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<React.Fragment>
|
|
37
|
-
<StyledInput
|
|
38
|
-
{...sharedProps}
|
|
39
|
-
type="radio"
|
|
40
|
-
aria-invalid={error}
|
|
41
|
-
checked={checked ?? undefined}
|
|
42
|
-
disabled={disabled}
|
|
43
|
-
id={id}
|
|
44
|
-
name={groupName}
|
|
45
|
-
// Need to specify because this is a controlled React form
|
|
46
|
-
// component, but we handle the click via ClickableBehavior
|
|
47
|
-
onChange={handleChange}
|
|
48
|
-
style={defaultStyle}
|
|
49
|
-
data-testid={testId}
|
|
50
|
-
ref={ref}
|
|
51
|
-
/>
|
|
52
|
-
{disabled && checked && <span style={disabledChecked} />}
|
|
53
|
-
</React.Fragment>
|
|
54
|
-
);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const size = 16; // circle with a different color. Here, we add that center circle. // If the checkbox is disabled and selected, it has a border but also an inner
|
|
58
|
-
const disabledChecked = {
|
|
59
|
-
position: "absolute",
|
|
60
|
-
top: size / 4,
|
|
61
|
-
left: size / 4,
|
|
62
|
-
height: size / 2,
|
|
63
|
-
width: size / 2,
|
|
64
|
-
borderRadius: "50%",
|
|
65
|
-
backgroundColor: offBlack32,
|
|
66
|
-
} as const;
|
|
67
|
-
const sharedStyles = StyleSheet.create({
|
|
68
|
-
// Reset the default styled input element
|
|
69
|
-
inputReset: {
|
|
70
|
-
appearance: "none",
|
|
71
|
-
WebkitAppearance: "none",
|
|
72
|
-
MozAppearance: "none",
|
|
73
|
-
},
|
|
74
|
-
default: {
|
|
75
|
-
height: size,
|
|
76
|
-
width: size,
|
|
77
|
-
minHeight: size,
|
|
78
|
-
minWidth: size,
|
|
79
|
-
margin: 0,
|
|
80
|
-
outline: "none",
|
|
81
|
-
boxSizing: "border-box",
|
|
82
|
-
borderStyle: "solid",
|
|
83
|
-
borderWidth: 1,
|
|
84
|
-
borderRadius: "50%",
|
|
85
|
-
},
|
|
86
|
-
disabled: {
|
|
87
|
-
cursor: "auto",
|
|
88
|
-
backgroundColor: offWhite,
|
|
89
|
-
borderColor: offBlack16,
|
|
90
|
-
borderWidth: 1,
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
const fadedBlue = mix(color.fadedBlue16, white);
|
|
94
|
-
const fadedRed = mix(color.fadedRed8, white);
|
|
95
|
-
const colors = {
|
|
96
|
-
default: {
|
|
97
|
-
faded: fadedBlue,
|
|
98
|
-
base: blue,
|
|
99
|
-
active: color.activeBlue,
|
|
100
|
-
},
|
|
101
|
-
error: {
|
|
102
|
-
faded: fadedRed,
|
|
103
|
-
base: red,
|
|
104
|
-
active: color.activeRed,
|
|
105
|
-
},
|
|
106
|
-
} as const;
|
|
107
|
-
const styles: Record<string, any> = {};
|
|
108
|
-
const _generateStyles = (checked: Checked, error: boolean) => {
|
|
109
|
-
// "hash" the parameters
|
|
110
|
-
const styleKey = `${String(checked)}-${String(error)}`;
|
|
111
|
-
if (styles[styleKey]) {
|
|
112
|
-
return styles[styleKey];
|
|
113
|
-
}
|
|
114
|
-
const palette = error ? colors.error : colors.default;
|
|
115
|
-
let newStyles: Record<string, any> = {};
|
|
116
|
-
if (checked) {
|
|
117
|
-
newStyles = {
|
|
118
|
-
default: {
|
|
119
|
-
backgroundColor: white,
|
|
120
|
-
borderColor: palette.base,
|
|
121
|
-
borderWidth: size / 4,
|
|
122
|
-
|
|
123
|
-
// Focus and hover have the same style. Focus style only shows
|
|
124
|
-
// up with keyboard navigation.
|
|
125
|
-
":focus-visible": {
|
|
126
|
-
boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.base}`,
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
":hover": {
|
|
130
|
-
boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.base}`,
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
":active": {
|
|
134
|
-
boxShadow: `0 0 0 1px ${white}, 0 0 0 3px ${palette.active}`,
|
|
135
|
-
borderColor: palette.active,
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
} else {
|
|
140
|
-
newStyles = {
|
|
141
|
-
default: {
|
|
142
|
-
backgroundColor: error ? fadedRed : white,
|
|
143
|
-
borderColor: error ? red : offBlack50,
|
|
144
|
-
|
|
145
|
-
// Focus and hover have the same style. Focus style only shows
|
|
146
|
-
// up with keyboard navigation.
|
|
147
|
-
":focus-visible": {
|
|
148
|
-
backgroundColor: error ? fadedRed : white,
|
|
149
|
-
borderColor: palette.base,
|
|
150
|
-
borderWidth: 2,
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
":hover": {
|
|
154
|
-
backgroundColor: error ? fadedRed : white,
|
|
155
|
-
borderColor: palette.base,
|
|
156
|
-
borderWidth: 2,
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
":active": {
|
|
160
|
-
backgroundColor: palette.faded,
|
|
161
|
-
borderColor: error ? color.activeRed : blue,
|
|
162
|
-
borderWidth: 2,
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
styles[styleKey] = StyleSheet.create(newStyles);
|
|
168
|
-
return styles[styleKey];
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
export default RadioCore;
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import {View, addStyle} from "@khanacademy/wonder-blocks-core";
|
|
4
|
-
import {Strut} from "@khanacademy/wonder-blocks-layout";
|
|
5
|
-
import {spacing} from "@khanacademy/wonder-blocks-tokens";
|
|
6
|
-
import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography";
|
|
7
|
-
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
8
|
-
|
|
9
|
-
import styles from "./group-styles";
|
|
10
|
-
import Choice from "./choice";
|
|
11
|
-
|
|
12
|
-
// Keep synced with RadioGroupProps in ../util/types.js
|
|
13
|
-
type RadioGroupProps = {
|
|
14
|
-
/**
|
|
15
|
-
* Children should be Choice components.
|
|
16
|
-
*/
|
|
17
|
-
children: Array<
|
|
18
|
-
| React.ReactElement<React.ComponentProps<typeof Choice>>
|
|
19
|
-
| false
|
|
20
|
-
| null
|
|
21
|
-
| undefined
|
|
22
|
-
>;
|
|
23
|
-
/**
|
|
24
|
-
* Group name for this checkbox or radio group. Should be unique for all
|
|
25
|
-
* such groups displayed on a page.
|
|
26
|
-
*/
|
|
27
|
-
groupName: string;
|
|
28
|
-
/**
|
|
29
|
-
* Optional label for the group. This label is optional to allow for
|
|
30
|
-
* greater flexibility in implementing checkbox and radio groups.
|
|
31
|
-
*/
|
|
32
|
-
label?: React.ReactNode;
|
|
33
|
-
/**
|
|
34
|
-
* Optional description for the group.
|
|
35
|
-
*/
|
|
36
|
-
description?: React.ReactNode;
|
|
37
|
-
/**
|
|
38
|
-
* Optional error message. If supplied, the group will be displayed in an
|
|
39
|
-
* error state, along with this error message. If no error state is desired,
|
|
40
|
-
* simply do not supply this prop, or pass along null.
|
|
41
|
-
*/
|
|
42
|
-
errorMessage?: string;
|
|
43
|
-
/**
|
|
44
|
-
* Custom styling for this group of checkboxes.
|
|
45
|
-
*/
|
|
46
|
-
style?: StyleType;
|
|
47
|
-
/**
|
|
48
|
-
* Callback for when the selected value of the radio group has changed.
|
|
49
|
-
*/
|
|
50
|
-
onChange: (selectedValue: string) => unknown;
|
|
51
|
-
/**
|
|
52
|
-
* Value of the selected radio item.
|
|
53
|
-
*/
|
|
54
|
-
selectedValue: string;
|
|
55
|
-
/**
|
|
56
|
-
* Test ID used for e2e testing.
|
|
57
|
-
*/
|
|
58
|
-
testId?: string;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const StyledFieldset = addStyle("fieldset");
|
|
62
|
-
const StyledLegend = addStyle("legend");
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* A radio group allows only single selection. Like CheckboxGroup, this
|
|
66
|
-
* component auto-populates many props for its children Choice components. The
|
|
67
|
-
* Choice component is exposed for the user to apply custom styles or to
|
|
68
|
-
* indicate which choices are disabled. The use of the groupName prop is
|
|
69
|
-
* important to maintain expected keyboard navigation behavior for
|
|
70
|
-
* accessibility.
|
|
71
|
-
*
|
|
72
|
-
* ### Usage
|
|
73
|
-
*
|
|
74
|
-
* ```jsx
|
|
75
|
-
* import {Choice, RadioGroup} from "@khanacademy/wonder-blocks-form";
|
|
76
|
-
*
|
|
77
|
-
* const [selectedValue, setSelectedValue] = React.useState("");
|
|
78
|
-
*
|
|
79
|
-
* <RadioGroup
|
|
80
|
-
* label="some-label"
|
|
81
|
-
* description="some-description"
|
|
82
|
-
* groupName="some-group-name"
|
|
83
|
-
* onChange={setSelectedValue}
|
|
84
|
-
* selectedValue={selectedValue}
|
|
85
|
-
* >
|
|
86
|
-
* // Add as many choices as necessary
|
|
87
|
-
* <Choice
|
|
88
|
-
* label="Choice 1"
|
|
89
|
-
* value="some-choice-value"
|
|
90
|
-
* />
|
|
91
|
-
* <Choice
|
|
92
|
-
* label="Choice 2"
|
|
93
|
-
* value="some-choice-value-2"
|
|
94
|
-
* description="Some choice description."
|
|
95
|
-
* />
|
|
96
|
-
* </RadioGroup>
|
|
97
|
-
* ```
|
|
98
|
-
*/
|
|
99
|
-
const RadioGroup = React.forwardRef(function RadioGroup(
|
|
100
|
-
props: RadioGroupProps,
|
|
101
|
-
ref: React.ForwardedRef<HTMLFieldSetElement>,
|
|
102
|
-
) {
|
|
103
|
-
const {
|
|
104
|
-
children,
|
|
105
|
-
label,
|
|
106
|
-
description,
|
|
107
|
-
errorMessage,
|
|
108
|
-
groupName,
|
|
109
|
-
onChange,
|
|
110
|
-
selectedValue,
|
|
111
|
-
style,
|
|
112
|
-
testId,
|
|
113
|
-
} = props;
|
|
114
|
-
|
|
115
|
-
const allChildren = React.Children.toArray(children).filter(Boolean);
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<StyledFieldset data-testid={testId} style={styles.fieldset} ref={ref}>
|
|
119
|
-
{/* We have a View here because fieldset cannot be used with flexbox*/}
|
|
120
|
-
<View style={style}>
|
|
121
|
-
{label && (
|
|
122
|
-
<StyledLegend style={styles.legend}>
|
|
123
|
-
<LabelMedium>{label}</LabelMedium>
|
|
124
|
-
</StyledLegend>
|
|
125
|
-
)}
|
|
126
|
-
{description && (
|
|
127
|
-
<LabelSmall style={styles.description}>
|
|
128
|
-
{description}
|
|
129
|
-
</LabelSmall>
|
|
130
|
-
)}
|
|
131
|
-
{errorMessage && (
|
|
132
|
-
<LabelSmall style={styles.error}>{errorMessage}</LabelSmall>
|
|
133
|
-
)}
|
|
134
|
-
{(label || description || errorMessage) && (
|
|
135
|
-
<Strut size={spacing.small_12} />
|
|
136
|
-
)}
|
|
137
|
-
|
|
138
|
-
{allChildren.map((child, index) => {
|
|
139
|
-
// @ts-expect-error [FEI-5019] - TS2339 - Property 'props' does not exist on type 'ReactChild | ReactFragment | ReactPortal'.
|
|
140
|
-
const {style, value} = child.props;
|
|
141
|
-
const checked = selectedValue === value;
|
|
142
|
-
// @ts-expect-error [FEI-5019] - TS2769 - No overload matches this call.
|
|
143
|
-
return React.cloneElement(child, {
|
|
144
|
-
checked: checked,
|
|
145
|
-
error: !!errorMessage,
|
|
146
|
-
groupName: groupName,
|
|
147
|
-
id: `${groupName}-${value}`,
|
|
148
|
-
key: value,
|
|
149
|
-
onChange: () => onChange(value),
|
|
150
|
-
style: [index > 0 && styles.defaultLineGap, style],
|
|
151
|
-
variant: "radio",
|
|
152
|
-
});
|
|
153
|
-
})}
|
|
154
|
-
</View>
|
|
155
|
-
</StyledFieldset>
|
|
156
|
-
);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
export default RadioGroup;
|
package/src/components/radio.tsx
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import type {AriaProps, StyleType} from "@khanacademy/wonder-blocks-core";
|
|
4
|
-
import ChoiceInternal from "./choice-internal";
|
|
5
|
-
|
|
6
|
-
// Keep synced with ChoiceComponentProps in ../util/types.js
|
|
7
|
-
type ChoiceComponentProps = AriaProps & {
|
|
8
|
-
/**
|
|
9
|
-
* Whether this component is checked
|
|
10
|
-
*/
|
|
11
|
-
checked: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Whether this component is disabled
|
|
14
|
-
*/
|
|
15
|
-
disabled?: boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Whether this component should show an error state
|
|
18
|
-
*/
|
|
19
|
-
error?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Callback when this component is selected. The newCheckedState is the
|
|
22
|
-
* new checked state of the component.
|
|
23
|
-
*/
|
|
24
|
-
onChange: (newCheckedState: boolean) => unknown;
|
|
25
|
-
/**
|
|
26
|
-
* Optional label for the field.
|
|
27
|
-
*/
|
|
28
|
-
label?: React.ReactNode;
|
|
29
|
-
/**
|
|
30
|
-
* Optional description for the field.
|
|
31
|
-
*/
|
|
32
|
-
description?: React.ReactNode;
|
|
33
|
-
/**
|
|
34
|
-
* Unique identifier attached to the HTML input element. If used, need to
|
|
35
|
-
* guarantee that the ID is unique within everything rendered on a page.
|
|
36
|
-
* Used to match `<label>` with `<input>` elements for screenreaders.
|
|
37
|
-
*/
|
|
38
|
-
id?: string;
|
|
39
|
-
/**
|
|
40
|
-
* Optional styling for the container. Does not style the component.
|
|
41
|
-
*/
|
|
42
|
-
style?: StyleType;
|
|
43
|
-
/**
|
|
44
|
-
* Adds CSS classes to the Checkbox.
|
|
45
|
-
*/
|
|
46
|
-
className?: string;
|
|
47
|
-
/**
|
|
48
|
-
* Optional test ID for e2e testing
|
|
49
|
-
*/
|
|
50
|
-
testId?: string;
|
|
51
|
-
/**
|
|
52
|
-
* Name for the checkbox or radio button group. Only applicable for group
|
|
53
|
-
* contexts, auto-populated by group components via Choice.
|
|
54
|
-
* @ignore
|
|
55
|
-
*/
|
|
56
|
-
groupName?: string;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 🔘 A nicely styled radio button for all your non-AMFM radio button needs. Can
|
|
61
|
-
* optionally take label and description props.
|
|
62
|
-
*
|
|
63
|
-
* This component should not really be used by itself because radio buttons are
|
|
64
|
-
* often grouped together. See RadioGroup.
|
|
65
|
-
*/ const Radio = React.forwardRef(function Radio(
|
|
66
|
-
props: ChoiceComponentProps,
|
|
67
|
-
ref: React.ForwardedRef<HTMLInputElement>,
|
|
68
|
-
) {
|
|
69
|
-
const {disabled = false, error = false, ...otherProps} = props;
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<ChoiceInternal
|
|
73
|
-
{...otherProps}
|
|
74
|
-
variant="radio"
|
|
75
|
-
disabled={disabled}
|
|
76
|
-
error={error}
|
|
77
|
-
ref={ref}
|
|
78
|
-
/>
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
export default Radio;
|