@khanacademy/wonder-blocks-form 4.2.3 → 4.3.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/components/checkbox-core.d.ts +13 -8
  3. package/dist/components/checkbox-core.js.flow +19 -10
  4. package/dist/components/checkbox-group.d.ts +2 -5
  5. package/dist/components/checkbox-group.js.flow +5 -6
  6. package/dist/components/checkbox.d.ts +33 -39
  7. package/dist/components/checkbox.js.flow +38 -41
  8. package/dist/components/choice-internal.d.ts +19 -31
  9. package/dist/components/choice-internal.js.flow +25 -32
  10. package/dist/components/choice.d.ts +50 -60
  11. package/dist/components/choice.js.flow +79 -84
  12. package/dist/components/radio-core.d.ts +13 -5
  13. package/dist/components/radio-core.js.flow +19 -7
  14. package/dist/components/radio-group.d.ts +2 -5
  15. package/dist/components/radio-group.js.flow +5 -6
  16. package/dist/components/radio.d.ts +18 -24
  17. package/dist/components/radio.js.flow +24 -27
  18. package/dist/es/index.js +262 -294
  19. package/dist/index.js +262 -294
  20. package/dist/util/types.d.ts +1 -1
  21. package/dist/util/types.js.flow +1 -1
  22. package/package.json +6 -6
  23. package/src/components/__tests__/{checkbox.test.js → checkbox.test.tsx} +55 -1
  24. package/src/components/checkbox-core.tsx +32 -31
  25. package/src/components/checkbox-group.tsx +33 -22
  26. package/src/components/checkbox.tsx +21 -16
  27. package/src/components/choice-internal.tsx +60 -58
  28. package/src/components/choice.tsx +39 -32
  29. package/src/components/radio-core.tsx +16 -14
  30. package/src/components/radio-group.tsx +14 -11
  31. package/src/components/radio.tsx +21 -16
  32. package/src/util/types.ts +1 -1
  33. package/tsconfig-build.tsbuildinfo +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-form",
3
- "version": "4.2.3",
3
+ "version": "4.3.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.1.0",
19
+ "@khanacademy/wonder-blocks-clickable": "^3.1.1",
20
20
  "@khanacademy/wonder-blocks-color": "^2.0.1",
21
- "@khanacademy/wonder-blocks-core": "^5.2.3",
22
- "@khanacademy/wonder-blocks-icon": "^2.0.13",
23
- "@khanacademy/wonder-blocks-layout": "^2.0.13",
21
+ "@khanacademy/wonder-blocks-core": "^5.3.0",
22
+ "@khanacademy/wonder-blocks-icon": "^2.0.14",
23
+ "@khanacademy/wonder-blocks-layout": "^2.0.14",
24
24
  "@khanacademy/wonder-blocks-spacing": "^4.0.1",
25
- "@khanacademy/wonder-blocks-typography": "^2.0.13"
25
+ "@khanacademy/wonder-blocks-typography": "^2.1.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "aphrodite": "^1.2.5",
@@ -1,4 +1,3 @@
1
- //@flow
2
1
  import * as React from "react";
3
2
  import {render, screen} from "@testing-library/react";
4
3
 
@@ -81,4 +80,59 @@ describe("Checkbox", () => {
81
80
  // Assert
82
81
  expect(onChangeSpy).toHaveBeenCalled();
83
82
  });
83
+
84
+ test.each`
85
+ indeterminateValue | checkedValue
86
+ ${true} | ${null}
87
+ ${false} | ${true}
88
+ ${false} | ${false}
89
+ `(
90
+ "sets the indeterminate property to $indeterminateValue when checked is $checkedValue (with ref)",
91
+ ({indeterminateValue, checkedValue}) => {
92
+ // Arrange
93
+ const ref = React.createRef<HTMLInputElement>();
94
+
95
+ // Act
96
+ render(
97
+ <Checkbox
98
+ label="Some label"
99
+ description="Some description"
100
+ checked={checkedValue}
101
+ onChange={() => {}}
102
+ ref={ref}
103
+ />,
104
+ );
105
+
106
+ // Assert
107
+ expect(ref?.current?.indeterminate).toBe(indeterminateValue);
108
+ },
109
+ );
110
+
111
+ test.each`
112
+ indeterminateValue | checkedValue
113
+ ${true} | ${null}
114
+ ${false} | ${true}
115
+ ${false} | ${false}
116
+ `(
117
+ "sets the indeterminate property to $indeterminateValue when checked is $checkedValue (innerRef)",
118
+ ({indeterminateValue, checkedValue}) => {
119
+ // Arrange
120
+ render(
121
+ <Checkbox
122
+ label="Some label"
123
+ description="Some description"
124
+ checked={checkedValue}
125
+ onChange={() => {}}
126
+ />,
127
+ );
128
+
129
+ // Act
130
+ const inputElement = screen.getByRole(
131
+ "checkbox",
132
+ ) as HTMLInputElement;
133
+
134
+ // Assert
135
+ expect(inputElement.indeterminate).toBe(indeterminateValue);
136
+ },
137
+ );
84
138
  });
@@ -39,27 +39,8 @@ const indeterminatePath: IconAsset = {
39
39
  /**
40
40
  * The internal stateless ☑️ Checkbox
41
41
  */
42
- export default class CheckboxCore extends React.Component<ChoiceCoreProps> {
43
- componentDidMount(): void {
44
- if (this.props.checked == null && this.inputRef.current != null) {
45
- this.inputRef.current.indeterminate = true;
46
- }
47
- }
48
-
49
- componentDidUpdate(prevProps: Readonly<ChoiceCoreProps>): void {
50
- if (this.inputRef.current != null) {
51
- this.inputRef.current.indeterminate = this.props.checked == null;
52
- }
53
- }
54
-
55
- inputRef: React.RefObject<HTMLInputElement> = React.createRef();
56
-
57
- handleChange: () => void = () => {
58
- // Empty because change is handled by ClickableBehavior
59
- return;
60
- };
61
-
62
- render(): React.ReactNode {
42
+ const CheckboxCore = React.forwardRef(
43
+ (props: ChoiceCoreProps, ref: React.ForwardedRef<HTMLInputElement>) => {
63
44
  const {
64
45
  checked,
65
46
  disabled,
@@ -68,7 +49,21 @@ export default class CheckboxCore extends React.Component<ChoiceCoreProps> {
68
49
  id,
69
50
  testId,
70
51
  ...sharedProps
71
- } = this.props;
52
+ } = props;
53
+
54
+ const innerRef = React.useRef<HTMLInputElement>(null);
55
+
56
+ React.useEffect(() => {
57
+ // Keep the indeterminate state in sync with the checked prop
58
+ if (innerRef.current != null) {
59
+ innerRef.current.indeterminate = checked == null;
60
+ }
61
+ }, [checked, innerRef]);
62
+
63
+ const handleChange: () => void = () => {
64
+ // Empty because change is handled by ClickableBehavior
65
+ return;
66
+ };
72
67
 
73
68
  const stateStyles = _generateStyles(checked, error);
74
69
 
@@ -79,10 +74,6 @@ export default class CheckboxCore extends React.Component<ChoiceCoreProps> {
79
74
  disabled && sharedStyles.disabled,
80
75
  ];
81
76
 
82
- const props = {
83
- "data-test-id": testId,
84
- } as const;
85
-
86
77
  const checkboxIcon = (
87
78
  <Icon
88
79
  color={disabled ? offBlack32 : white}
@@ -98,7 +89,15 @@ export default class CheckboxCore extends React.Component<ChoiceCoreProps> {
98
89
  <React.Fragment>
99
90
  <StyledInput
100
91
  {...sharedProps}
101
- ref={this.inputRef}
92
+ ref={(node) => {
93
+ // @ts-expect-error: current is not actually read-only
94
+ innerRef.current = node;
95
+ if (typeof ref === "function") {
96
+ ref(node);
97
+ } else if (ref != null) {
98
+ ref.current = node;
99
+ }
100
+ }}
102
101
  type="checkbox"
103
102
  aria-checked={ariaChecked}
104
103
  aria-invalid={error}
@@ -108,15 +107,15 @@ export default class CheckboxCore extends React.Component<ChoiceCoreProps> {
108
107
  name={groupName}
109
108
  // Need to specify because this is a controlled React form
110
109
  // component, but we handle the click via ClickableBehavior
111
- onChange={this.handleChange}
110
+ onChange={handleChange}
112
111
  style={defaultStyle}
113
- {...props}
112
+ data-test-id={testId}
114
113
  />
115
114
  {checked || checked == null ? checkboxIcon : <></>}
116
115
  </React.Fragment>
117
116
  );
118
- }
119
- }
117
+ },
118
+ );
120
119
 
121
120
  const size = 16;
122
121
 
@@ -237,3 +236,5 @@ const _generateStyles = (checked: Checked, error: boolean) => {
237
236
  styles[styleKey] = StyleSheet.create(newStyles);
238
237
  return styles[styleKey];
239
238
  };
239
+
240
+ export default CheckboxCore;
@@ -95,38 +95,47 @@ const StyledLegend = addStyle("legend");
95
95
  * </CheckboxGroup>
96
96
  * ```
97
97
  */
98
- export default class CheckboxGroup extends React.Component<CheckboxGroupProps> {
99
- handleChange(changedValue: string, originalCheckedState: boolean) {
100
- const {onChange, selectedValues} = this.props;
101
-
102
- if (originalCheckedState) {
103
- const index = selectedValues.indexOf(changedValue);
104
- const updatedSelection = [
105
- ...selectedValues.slice(0, index),
106
- ...selectedValues.slice(index + 1),
107
- ];
108
- onChange(updatedSelection);
109
- } else {
110
- onChange([...selectedValues, changedValue]);
111
- }
112
- }
113
-
114
- render(): React.ReactNode {
98
+ const CheckboxGroup = React.forwardRef(
99
+ (
100
+ props: CheckboxGroupProps,
101
+ ref: React.ForwardedRef<HTMLFieldSetElement>,
102
+ ) => {
115
103
  const {
116
104
  children,
117
105
  label,
118
106
  description,
119
107
  errorMessage,
120
108
  groupName,
109
+ onChange,
121
110
  selectedValues,
122
111
  style,
123
112
  testId,
124
- } = this.props;
113
+ } = props;
114
+
115
+ const handleChange = (
116
+ changedValue: string,
117
+ originalCheckedState: boolean,
118
+ ) => {
119
+ if (originalCheckedState) {
120
+ const index = selectedValues.indexOf(changedValue);
121
+ const updatedSelection = [
122
+ ...selectedValues.slice(0, index),
123
+ ...selectedValues.slice(index + 1),
124
+ ];
125
+ onChange(updatedSelection);
126
+ } else {
127
+ onChange([...selectedValues, changedValue]);
128
+ }
129
+ };
125
130
 
126
131
  const allChildren = React.Children.toArray(children).filter(Boolean);
127
132
 
128
133
  return (
129
- <StyledFieldset data-test-id={testId} style={styles.fieldset}>
134
+ <StyledFieldset
135
+ data-test-id={testId}
136
+ style={styles.fieldset}
137
+ ref={ref}
138
+ >
130
139
  {/* We have a View here because fieldset cannot be used with flexbox*/}
131
140
  <View style={style}>
132
141
  {label && (
@@ -159,7 +168,7 @@ export default class CheckboxGroup extends React.Component<CheckboxGroupProps> {
159
168
  groupName: groupName,
160
169
  id: `${groupName}-${value}`,
161
170
  key: value,
162
- onChange: () => this.handleChange(value, checked),
171
+ onChange: () => handleChange(value, checked),
163
172
  style: [index > 0 && styles.defaultLineGap, style],
164
173
  variant: "checkbox",
165
174
  });
@@ -167,5 +176,7 @@ export default class CheckboxGroup extends React.Component<CheckboxGroupProps> {
167
176
  </View>
168
177
  </StyledFieldset>
169
178
  );
170
- }
171
- }
179
+ },
180
+ );
181
+
182
+ export default CheckboxGroup;
@@ -14,11 +14,11 @@ type ChoiceComponentProps = AriaProps & {
14
14
  /**
15
15
  * Whether this component is disabled
16
16
  */
17
- disabled: boolean;
17
+ disabled?: boolean;
18
18
  /**
19
19
  * Whether this component should show an error state
20
20
  */
21
- error: boolean;
21
+ error?: boolean;
22
22
  /**
23
23
  * Callback when this component is selected. The newCheckedState is the
24
24
  * new checked state of the component.
@@ -58,11 +58,6 @@ type ChoiceComponentProps = AriaProps & {
58
58
  groupName?: string;
59
59
  };
60
60
 
61
- type DefaultProps = {
62
- disabled: ChoiceComponentProps["disabled"];
63
- error: ChoiceComponentProps["error"];
64
- };
65
-
66
61
  /**
67
62
  * ☑️ A nicely styled checkbox for all your checking needs. Can optionally take
68
63
  * label and description props.
@@ -84,13 +79,23 @@ type DefaultProps = {
84
79
  * <Checkbox checked={checked} onChange={setChecked} />
85
80
  * ```
86
81
  */
87
- export default class Checkbox extends React.Component<ChoiceComponentProps> {
88
- static defaultProps: DefaultProps = {
89
- disabled: false,
90
- error: false,
91
- };
82
+ const Checkbox = React.forwardRef(
83
+ (
84
+ props: ChoiceComponentProps,
85
+ ref: React.ForwardedRef<HTMLInputElement>,
86
+ ) => {
87
+ const {disabled = false, error = false} = props;
88
+
89
+ return (
90
+ <ChoiceInternal
91
+ {...props}
92
+ variant="checkbox"
93
+ disabled={disabled}
94
+ error={error}
95
+ ref={ref}
96
+ />
97
+ );
98
+ },
99
+ );
92
100
 
93
- render(): React.ReactNode {
94
- return <ChoiceInternal variant="checkbox" {...this.props} />;
95
- }
96
- }
101
+ export default Checkbox;
@@ -14,9 +14,9 @@ type Props = AriaProps & {
14
14
  /** Whether this choice is checked. */
15
15
  checked: boolean | null | undefined;
16
16
  /** Whether this choice option is disabled. */
17
- disabled: boolean;
17
+ disabled?: boolean;
18
18
  /** Whether this choice is in error mode. */
19
- error: boolean;
19
+ error?: boolean;
20
20
  /** Returns the new checked state of the component. */
21
21
  onChange: (newCheckedState: boolean) => unknown;
22
22
  /**
@@ -48,11 +48,6 @@ type Props = AriaProps & {
48
48
  variant: "radio" | "checkbox";
49
49
  };
50
50
 
51
- type DefaultProps = {
52
- disabled: Props["disabled"];
53
- error: Props["error"];
54
- };
55
-
56
51
  /**
57
52
  * This is a potentially labeled 🔘 or ☑️ item. This is an internal component
58
53
  * that's wrapped by Checkbox and Radio. Choice is a wrapper for Checkbox and
@@ -60,60 +55,61 @@ type DefaultProps = {
60
55
  * and RadioGroup. This design allows for more explicit prop typing. For
61
56
  * example, we can make onChange a required prop on Checkbox but not on Choice
62
57
  * (because for Choice, that prop would be auto-populated by CheckboxGroup).
63
- */ export default class ChoiceInternal extends React.Component<Props> {
64
- static defaultProps: DefaultProps = {
65
- disabled: false,
66
- error: false,
67
- };
68
-
69
- handleClick: () => void = () => {
70
- const {checked, onChange, variant} = this.props;
71
- // Radio buttons cannot be unchecked
72
- if (variant === "radio" && checked) {
73
- return;
74
- }
75
- onChange(!checked);
76
- };
77
-
78
- getChoiceCoreComponent(): typeof RadioCore | typeof CheckboxCore {
79
- if (this.props.variant === "radio") {
80
- return RadioCore;
81
- } else {
82
- return CheckboxCore;
83
- }
84
- }
85
- getLabel(id: string): React.ReactNode {
86
- const {disabled, label} = this.props;
87
- return (
88
- <LabelMedium
89
- style={[styles.label, disabled && styles.disabledLabel]}
90
- >
91
- <label htmlFor={id}>{label}</label>
92
- </LabelMedium>
93
- );
94
- }
95
- getDescription(id?: string): React.ReactNode {
96
- const {description} = this.props;
97
- return (
98
- <LabelSmall style={styles.description} id={id}>
99
- {description}
100
- </LabelSmall>
101
- );
102
- }
103
- render(): React.ReactNode {
58
+ */ const ChoiceInternal = React.forwardRef(
59
+ (props: Props, ref: React.ForwardedRef<HTMLInputElement>) => {
104
60
  const {
105
- label,
61
+ checked,
106
62
  description,
63
+ disabled = false,
64
+ error = false,
107
65
  id,
66
+ label,
108
67
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
109
68
  onChange,
110
69
  style,
111
70
  className,
112
71
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
113
72
  variant,
114
- ...coreProps
115
- } = this.props;
116
- const ChoiceCore = this.getChoiceCoreComponent();
73
+ // ...coreProps
74
+ } = props;
75
+
76
+ const handleClick: () => void = () => {
77
+ // Radio buttons cannot be unchecked
78
+ if (variant === "radio" && checked) {
79
+ return;
80
+ }
81
+ onChange(!checked);
82
+ };
83
+
84
+ const getChoiceCoreComponent = ():
85
+ | typeof RadioCore
86
+ | typeof CheckboxCore => {
87
+ if (variant === "radio") {
88
+ return RadioCore;
89
+ } else {
90
+ return CheckboxCore;
91
+ }
92
+ };
93
+
94
+ const getLabel = (id: string): React.ReactNode => {
95
+ return (
96
+ <LabelMedium
97
+ style={[styles.label, disabled && styles.disabledLabel]}
98
+ >
99
+ <label htmlFor={id}>{label}</label>
100
+ </LabelMedium>
101
+ );
102
+ };
103
+
104
+ const getDescription = (id?: string): React.ReactNode => {
105
+ return (
106
+ <LabelSmall style={styles.description} id={id}>
107
+ {description}
108
+ </LabelSmall>
109
+ );
110
+ };
111
+
112
+ const ChoiceCore = getChoiceCoreComponent();
117
113
 
118
114
  return (
119
115
  <UniqueIDProvider mockOnFirstRender={true} scope="choice">
@@ -142,22 +138,26 @@ type DefaultProps = {
142
138
  tabIndex={-1}
143
139
  >
144
140
  <ChoiceCore
145
- {...coreProps}
141
+ {...props}
146
142
  id={uniqueId}
147
143
  aria-describedby={descriptionId}
148
- onClick={this.handleClick}
144
+ onClick={handleClick}
145
+ disabled={disabled}
146
+ error={error}
147
+ ref={ref}
149
148
  />
150
149
  <Strut size={Spacing.xSmall_8} />
151
- {label && this.getLabel(uniqueId)}
150
+ {label && getLabel(uniqueId)}
152
151
  </View>
153
- {description && this.getDescription(descriptionId)}
152
+ {description && getDescription(descriptionId)}
154
153
  </View>
155
154
  );
156
155
  }}
157
156
  </UniqueIDProvider>
158
157
  );
159
- }
160
- }
158
+ },
159
+ );
160
+
161
161
  const styles = StyleSheet.create({
162
162
  wrapper: {
163
163
  flexDirection: "row",
@@ -181,3 +181,5 @@ const styles = StyleSheet.create({
181
181
  color: Color.offBlack64,
182
182
  },
183
183
  });
184
+
185
+ export default ChoiceInternal;
@@ -12,7 +12,7 @@ type Props = AriaProps & {
12
12
  /** User-defined. Should be distinct for each item in the group. */
13
13
  value: string;
14
14
  /** User-defined. Whether this choice option is disabled. Default false. */
15
- disabled: boolean;
15
+ disabled?: boolean;
16
16
  /** User-defined. Optional id for testing purposes. */
17
17
  testId?: string;
18
18
  /** User-defined. Optional additional styling. */
@@ -21,7 +21,7 @@ type Props = AriaProps & {
21
21
  * Auto-populated by parent. Whether this choice is checked.
22
22
  * @ignore
23
23
  */
24
- checked: boolean;
24
+ checked?: boolean;
25
25
  /**
26
26
  * Auto-populated by parent. Whether this choice is in error mode (everything
27
27
  * in a choice group would be in error mode at the same time).
@@ -43,7 +43,7 @@ type Props = AriaProps & {
43
43
  * Auto-populated by parent. Returns the new checked state of the component.
44
44
  * @ignore
45
45
  */
46
- onChange: (newCheckedState: boolean) => unknown;
46
+ onChange?: (newCheckedState: boolean) => unknown;
47
47
  /**
48
48
  * Auto-populated by parent.
49
49
  * @ignore
@@ -51,12 +51,6 @@ type Props = AriaProps & {
51
51
  variant?: "radio" | "checkbox";
52
52
  };
53
53
 
54
- type DefaultProps = {
55
- checked: Props["checked"];
56
- disabled: Props["disabled"];
57
- onChange: Props["onChange"];
58
- };
59
-
60
54
  /**
61
55
  * This is a labeled 🔘 or ☑️ item. Choice is meant to be used as children of
62
56
  * CheckboxGroup and RadioGroup because many of its props are auto-populated
@@ -123,27 +117,40 @@ type DefaultProps = {
123
117
  * </RadioGroup>
124
118
  * ```
125
119
  */
126
- export default class Choice extends React.Component<Props> {
127
- static defaultProps: DefaultProps = {
128
- checked: false,
129
- disabled: false,
130
- onChange: () => {},
131
- };
120
+ const Choice = React.forwardRef(
121
+ (props: Props, ref: React.ForwardedRef<HTMLInputElement>) => {
122
+ const {
123
+ checked = false,
124
+ disabled = false,
125
+ onChange = () => {},
126
+ // we don't need this going into the ChoiceComponent
127
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
128
+ value,
129
+ variant,
130
+ ...remainingProps
131
+ } = props;
132
+
133
+ const getChoiceComponent = (
134
+ variant?: string | null,
135
+ ): typeof Radio | typeof Checkbox => {
136
+ if (variant === "checkbox") {
137
+ return Checkbox;
138
+ } else {
139
+ return Radio;
140
+ }
141
+ };
142
+
143
+ const ChoiceComponent = getChoiceComponent(variant);
144
+ return (
145
+ <ChoiceComponent
146
+ {...remainingProps}
147
+ checked={checked}
148
+ disabled={disabled}
149
+ onChange={onChange}
150
+ ref={ref}
151
+ />
152
+ );
153
+ },
154
+ );
132
155
 
133
- getChoiceComponent(
134
- variant?: string | null,
135
- ): typeof Radio | typeof Checkbox {
136
- if (variant === "checkbox") {
137
- return Checkbox;
138
- } else {
139
- return Radio;
140
- }
141
- }
142
- render(): React.ReactNode {
143
- // we don't need this going into the ChoiceComponent
144
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
145
- const {value, variant, ...remainingProps} = this.props;
146
- const ChoiceComponent = this.getChoiceComponent(variant);
147
- return <ChoiceComponent {...remainingProps} />;
148
- }
149
- }
156
+ export default Choice;
@@ -12,13 +12,13 @@ const StyledInput = addStyle("input");
12
12
 
13
13
  /**
14
14
  * The internal stateless 🔘 Radio button
15
- */ export default class RadioCore extends React.Component<ChoiceCoreProps> {
16
- handleChange: () => void = () => {
17
- // Empty because change is handled by ClickableBehavior
18
- return;
19
- };
15
+ */ const RadioCore = React.forwardRef(
16
+ (props: ChoiceCoreProps, ref: React.ForwardedRef<HTMLInputElement>) => {
17
+ const handleChange = () => {
18
+ // Empty because change is handled by ClickableBehavior
19
+ return;
20
+ };
20
21
 
21
- render(): React.ReactNode {
22
22
  const {
23
23
  checked,
24
24
  disabled,
@@ -27,7 +27,7 @@ const StyledInput = addStyle("input");
27
27
  id,
28
28
  testId,
29
29
  ...sharedProps
30
- } = this.props;
30
+ } = props;
31
31
 
32
32
  const stateStyles = _generateStyles(checked, error);
33
33
  const defaultStyle = [
@@ -36,9 +36,7 @@ const StyledInput = addStyle("input");
36
36
  !disabled && stateStyles.default,
37
37
  disabled && sharedStyles.disabled,
38
38
  ];
39
- const props = {
40
- "data-test-id": testId,
41
- } as const;
39
+
42
40
  return (
43
41
  <React.Fragment>
44
42
  <StyledInput
@@ -51,15 +49,17 @@ const StyledInput = addStyle("input");
51
49
  name={groupName}
52
50
  // Need to specify because this is a controlled React form
53
51
  // component, but we handle the click via ClickableBehavior
54
- onChange={this.handleChange}
52
+ onChange={handleChange}
55
53
  style={defaultStyle}
56
- {...props}
54
+ data-test-id={testId}
55
+ ref={ref}
57
56
  />
58
57
  {disabled && checked && <span style={disabledChecked} />}
59
58
  </React.Fragment>
60
59
  );
61
- }
62
- }
60
+ },
61
+ );
62
+
63
63
  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
64
64
  const disabledChecked = {
65
65
  position: "absolute",
@@ -175,3 +175,5 @@ const _generateStyles = (checked: Checked, error: boolean) => {
175
175
  styles[styleKey] = StyleSheet.create(newStyles);
176
176
  return styles[styleKey];
177
177
  };
178
+
179
+ export default RadioCore;