Skip to content

Commit b5b12ab

Browse files
committed
Refactor Card Radio to rely on Card Radio Group
1 parent 0d27743 commit b5b12ab

File tree

3 files changed

+54
-126
lines changed

3 files changed

+54
-126
lines changed

src/components/card2/CardRadio.tsx

Lines changed: 26 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,23 @@ import * as React from 'react';
22
import cx from 'classnames';
33
import Radio from '../form-elements/radio/Radio';
44
import generateRandomString from '../../js/generateRandomString';
5+
import {useCardRadioGroupContext} from './CardRadioGroupContext';
56

67
export interface CardRadioPropsType {
7-
/**
8-
* Optional string. Variant of the card. Default is 'outline'.
9-
*/
8+
value: string;
9+
required?: boolean;
10+
disabled?: boolean;
11+
invalid?: boolean;
12+
id?: string;
1013
variant?: 'solid' | 'outline';
11-
1214
color?: 'light' | 'dark';
13-
14-
/**
15-
* Optional string. Additional class names.
16-
*/
1715
className?: string;
18-
19-
/**
20-
* Optional React.ReactNode. Children of the card. This is the place where label should be used and connected to the card.
21-
* @example <CardRadio>Card content</CardRadio>
22-
*/
2316
children?: React.ReactNode;
24-
25-
/**
26-
* Optional string. Width of the card.
27-
* @default auto
28-
* @example <CardRadio width="100px" />
29-
**/
3017
width?: React.CSSProperties['width'];
31-
32-
/**
33-
* Optional string. Height of the card.
34-
* @default auto
35-
* @example <CardRadio height="100px" />
36-
*/
3718
height?: React.CSSProperties['height'];
38-
39-
/**
40-
* Optional object. Inline styles.
41-
* @example <CardRadio style={--card-background-color: var(--green-20)} />
42-
*/
4319
style?: React.CSSProperties;
44-
45-
/**
46-
* Optional boolean. Whether the Radio is checked.
47-
*/
48-
checked?: boolean;
49-
50-
/**
51-
* Optional boolean. Whether the Radio is checked by default. Only works when `checked` is not defined.
52-
*/
53-
defaultChecked?: boolean;
54-
55-
/**
56-
* Optional boolean. Whether the Radio is disabled.
57-
*/
58-
disabled?: boolean;
59-
60-
/**
61-
* Optional string. ID of the Radio.
62-
*/
63-
id?: string;
64-
65-
/**
66-
* Optional boolean. Whether the Radio is invalid.
67-
* @default <CardRadio invalid />
68-
*/
69-
invalid?: boolean;
70-
71-
/**
72-
* Optional boolean. Whether the Radio is required.
73-
* @default <CardRadio required />
74-
*/
75-
required?: boolean;
76-
77-
/**
78-
* Value of the CardRadio input.
79-
* @example <CardRadio value="1" />
80-
*/
81-
value?: string;
82-
83-
/**
84-
* Name of the CardRadio input.
85-
* @example <CardRadio name="radio" />
86-
*/
87-
name?: string;
88-
89-
/**
90-
* Function called whenever the state of the Radio changes.
91-
*/
9220
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
93-
94-
/**
95-
* Function called whenever the mouse enters the Radio.
96-
*/
9721
onMouseEnter?: (e: React.MouseEvent<HTMLDivElement>) => void;
98-
99-
/**
100-
* Function called whenever the mouse leaves the Radio.
101-
*/
10222
onMouseLeave?: (e: React.MouseEvent<HTMLDivElement>) => void;
10323
}
10424

@@ -124,43 +44,37 @@ const CardRadio = ({
12444
style,
12545

12646
// radio related props
127-
checked,
128-
defaultChecked = false,
129-
disabled,
47+
13048
id,
131-
invalid = false,
49+
disabled,
13250
required = false,
51+
invalid = false,
13352
value,
134-
name,
13553
onChange,
13654
onMouseEnter,
13755
onMouseLeave,
13856
...props
13957
}: CardRadioPropsType) => {
58+
const context = useCardRadioGroupContext();
59+
14060
const [hover, setHover] = React.useState(false);
141-
const isControlled = checked !== undefined;
14261
const inputRef = React.useRef<HTMLInputElement>(null);
143-
const [isChecked, setIsChecked] = React.useState(
144-
isControlled ? checked : defaultChecked
145-
);
146-
14762
const cardId = React.useMemo(() => id || generateRandomString(), [id]);
63+
const isChecked = context.value === value;
64+
const isRequired = context.required || required;
65+
const isDisabled = context.disabled || disabled;
66+
const isInvalid = context.invalid || invalid;
14867

14968
const cssVariables = {
15069
'--card-width': width,
15170
'--card-height': height,
15271
};
15372

154-
const handleInputChange = React.useCallback(
155-
e => {
156-
if (!isControlled) {
157-
setIsChecked(val => !val);
158-
}
159-
160-
if (onChange) onChange(e);
161-
},
162-
[onChange, isControlled]
163-
);
73+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
74+
if (context.onChange) {
75+
context.onChange(e.target.value);
76+
}
77+
};
16478

16579
// handle onmouseenter and onmouseleave
16680
const handleMouseEnter = React.useCallback(
@@ -197,8 +111,8 @@ const CardRadio = ({
197111
data-color={color}
198112
data-hover={hover}
199113
data-checked={isChecked}
200-
data-invalid={invalid}
201-
data-disabled={disabled}
114+
data-invalid={isInvalid}
115+
data-disabled={isDisabled}
202116
>
203117
<input
204118
aria-labelledby={`label-${cardId}`}
@@ -207,12 +121,12 @@ const CardRadio = ({
207121
className="sg-card-new__input"
208122
type="Radio"
209123
checked={isChecked}
210-
disabled={disabled}
211-
name={name}
124+
disabled={isDisabled}
125+
name={context.name}
212126
onChange={handleInputChange}
213-
required={required}
127+
required={isRequired}
214128
value={value}
215-
aria-invalid={invalid ? true : undefined}
129+
aria-invalid={isInvalid}
216130
suppressHydrationWarning
217131
{...props}
218132
/>

src/components/card2/CardRadioGroup.tsx

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,7 @@ import * as React from 'react';
22
import {generateId} from '../utils';
33
import cx from 'classnames';
44
import Flex from '../flex/Flex';
5-
6-
type CardRadioGroupContextType = {
7-
name?: string;
8-
required: boolean;
9-
disabled: boolean;
10-
invalid?: boolean;
11-
value?: string;
12-
onChange?(value: string): void;
13-
};
14-
15-
const CardRadioGroupContext = React.createContext<CardRadioGroupContextType>({
16-
required: false,
17-
disabled: false,
18-
});
5+
import {CardRadioGroupContext} from './CardRadioGroupContext';
196

207
interface CardRadioGroupProps {
218
name?: string;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from 'react';
2+
3+
export type CardRadioGroupContextType = {
4+
name?: string;
5+
required: boolean;
6+
disabled: boolean;
7+
invalid?: boolean;
8+
value?: string;
9+
onChange?(value: string): void;
10+
};
11+
12+
export const CardRadioGroupContext =
13+
React.createContext<CardRadioGroupContextType>({
14+
required: false,
15+
disabled: false,
16+
});
17+
18+
export const useCardRadioGroupContext = () => {
19+
const context = React.useContext(CardRadioGroupContext);
20+
21+
if (!context) {
22+
throw new Error(
23+
'Component using useCardRadioGroupContext must be used within a CardRadioGroupProvider'
24+
);
25+
}
26+
return context;
27+
};

0 commit comments

Comments
 (0)