Skip to content

Commit 82da617

Browse files
jinlee93booc0mtaco
authored andcommitted
feat(radio)!: remove top level subcomponents (#1690)
* feat(radio)!: remove top level subcomponents * refactor(radio): use size tokens
1 parent b4b9276 commit 82da617

File tree

9 files changed

+170
-195
lines changed

9 files changed

+170
-195
lines changed

src/components/Radio/Radio.module.css

+86
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,89 @@
99
display: flex;
1010
gap: var(--eds-size-1);
1111
}
12+
13+
/**
14+
* Wraps the visually hidden radio input element and the visible sibling svg element.
15+
*/
16+
.input__wrapper {
17+
position: relative;
18+
/* Centers the radio icon in the wrapper. */
19+
display: inline-flex;
20+
align-items: center;
21+
/* Aligns the radio with the first line of the label. */
22+
align-self: flex-start;
23+
}
24+
/**
25+
* The visually hidden input element for the radio. The visual radio is provided by an svg element.
26+
*/
27+
.radio__input {
28+
/* Removes default margins placed by browser for radioes. */
29+
margin: 0;
30+
/* Remove the radio from the page flow, positioning it on top of the SVG. */
31+
position: absolute;
32+
left: var(--eds-size-half);
33+
/* Set same dimensions as the RadioSvg element. */
34+
height: var(--eds-size-2);
35+
width: var(--eds-size-2);
36+
/**
37+
* Hide the input element visually.
38+
* This ensures the radio is still "physically" present so that all users,
39+
* especially on touch screen readers, still interact with the real radio element
40+
* where it would naturally be present.
41+
*/
42+
opacity: 0;
43+
}
44+
45+
/**
46+
* The visible radio svg icon element.
47+
*/
48+
.radio__icon {
49+
color: var(--eds-theme-color-radio-brand-background);
50+
/* Creates space for the border so that there's no jitter when the focus border is visible. */
51+
border: var(--eds-border-width-sm) solid transparent;
52+
}
53+
.radio__input:focus-visible + .radio__icon {
54+
border: var(--eds-border-width-sm) solid var(--eds-theme-color-focus-ring);
55+
border-radius: var(--eds-border-radius-full);
56+
}
57+
58+
@supports not selector(:focus-visible) {
59+
.radio__input:focus + .radio__icon {
60+
border: var(--eds-border-width-sm) solid var(--eds-theme-color-focus-ring);
61+
border-radius: var(--eds-border-radius-full);
62+
}
63+
}
64+
65+
/**
66+
* The disabled variant of the visible radio svg icon.
67+
*/
68+
.radio__icon--disabled {
69+
color: var(--eds-theme-color-icon-disabled);
70+
}
71+
72+
/**
73+
* The disabled status of the visually hidden input element.
74+
*/
75+
.radio__input:disabled {
76+
/* Needed since the input element overlays the visible svg icon for user input and cursor. */
77+
cursor: not-allowed;
78+
}
79+
80+
/**
81+
* Text that labels a radio input.
82+
*/
83+
.radio__label {
84+
position: relative;
85+
}
86+
87+
/**
88+
* Radio label size variants.
89+
* Used for centering the label with the radio input button.
90+
*/
91+
.radio__label--md {
92+
top: var(--eds-size-quarter);
93+
}
94+
.radio__label--lg {
95+
/* This is a 1px increase in top spacing from the md variant. Size is too specific to have a token. */
96+
top: 0.0625rem;
97+
}

src/components/Radio/Radio.tsx

+84-6
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ import clsx from 'clsx';
22
import React from 'react';
33
import { useId } from '../../util/useId';
44
import type { EitherInclusive } from '../../util/utility-types';
5-
import type { RadioInputProps } from '../RadioInput';
6-
import RadioInput from '../RadioInput';
7-
import type { RadioLabelProps } from '../RadioLabel';
8-
import RadioLabel from '../RadioLabel';
5+
import Icon from '../Icon';
6+
import { InputLabel, type InputLabelProps } from '../InputLabel/InputLabel';
97
import styles from './Radio.module.css';
108

11-
export type RadioProps = RadioInputProps & {
9+
type RadioProps = RadioInputProps & {
1210
/**
1311
* HTML id attribute. If not passed, this component
1412
* will generate an id to use for accessibility.
@@ -17,7 +15,7 @@ export type RadioProps = RadioInputProps & {
1715
/**
1816
* Size of the radio label.
1917
*/
20-
size?: RadioLabelProps['size'];
18+
size?: InputLabelProps['size'];
2119
} & EitherInclusive<
2220
{
2321
/**
@@ -32,6 +30,86 @@ export type RadioProps = RadioInputProps & {
3230
'aria-label': string;
3331
}
3432
>;
33+
type RadioInputProps = Omit<
34+
React.InputHTMLAttributes<HTMLInputElement>,
35+
'id' | 'size'
36+
> & {
37+
/**
38+
* Additional classnames passed in for styling.
39+
*/
40+
className?: string;
41+
/**
42+
* Radio ID. Used to connect the input with a label for accessibility purposes.
43+
*/
44+
id?: string;
45+
};
46+
47+
const RadioSvg = ({
48+
checked,
49+
disabled,
50+
}: {
51+
checked?: boolean;
52+
disabled?: boolean;
53+
}) => {
54+
const iconClassName = clsx(
55+
styles['radio__icon'],
56+
disabled && styles['radio__icon--disabled'],
57+
);
58+
return (
59+
<Icon
60+
className={iconClassName}
61+
name={checked ? 'radio-selected' : 'radio-unselected'}
62+
purpose="decorative"
63+
size="1.625rem"
64+
/>
65+
);
66+
};
67+
68+
/**
69+
* Radio input element, exported for greater flexibility.
70+
* You must provide an `id` prop and connect it to a visible label.
71+
*/
72+
export const RadioInput = ({
73+
checked = false,
74+
className,
75+
disabled,
76+
...other
77+
}: RadioInputProps) => {
78+
return (
79+
<span
80+
className={clsx(
81+
styles['input__wrapper'],
82+
disabled && styles['input__wrapper--disabled'],
83+
)}
84+
>
85+
<input
86+
checked={checked}
87+
className={clsx(className, styles['radio__input'])}
88+
disabled={disabled}
89+
type="radio"
90+
{...other}
91+
/>
92+
<RadioSvg checked={checked} disabled={disabled} />
93+
</span>
94+
);
95+
};
96+
97+
/**
98+
* Radio label element, styles and relies on the InputLabel component.
99+
*/
100+
export const RadioLabel = ({
101+
className,
102+
size = 'lg',
103+
...other
104+
}: InputLabelProps) => {
105+
const componentClassName = clsx(
106+
styles['radio__label'],
107+
styles[`radio__label--${size}`],
108+
className,
109+
);
110+
111+
return <InputLabel className={componentClassName} size={size} {...other} />;
112+
};
35113

36114
/**
37115
* `import {Radio} from "@chanzuckerberg/eds";`

src/components/RadioInput/RadioInput.module.css

-70
This file was deleted.

src/components/RadioInput/RadioInput.tsx

-68
This file was deleted.

src/components/RadioInput/index.ts

-2
This file was deleted.

src/components/RadioLabel/RadioLabel.module.css

-21
This file was deleted.

src/components/RadioLabel/RadioLabel.tsx

-24
This file was deleted.

src/components/RadioLabel/index.ts

-2
This file was deleted.

0 commit comments

Comments
 (0)