This repository has been archived by the owner on Dec 6, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Radio.tsx
132 lines (125 loc) · 3.23 KB
/
Radio.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import React, { ReactNode, InputHTMLAttributes } from 'react';
import {
label,
labelWithSupportingText,
radio,
labelText,
labelTextWithSupportingText,
supportingText,
} from './styles';
import { Props } from '@guardian/src-helpers';
const LabelText = ({
hasSupportingText,
children,
}: {
hasSupportingText?: boolean;
children: ReactNode;
}) => {
return (
<div
css={(theme) => [
hasSupportingText ? labelTextWithSupportingText : '',
labelText(theme.radio && theme),
]}
className="src-radio-label-text"
>
{children}
</div>
);
};
const SupportingText = ({ children }: { children: ReactNode }) => {
return (
<div css={(theme) => supportingText(theme.radio && theme)}>
{children}
</div>
);
};
export interface RadioProps
extends InputHTMLAttributes<HTMLInputElement>,
Props {
/**
* Whether radio button is checked. This is necessary when using the
* [controlled approach](https://reactjs.org/docs/forms.html#controlled-components)
* (recommended) to form state management.
*
* _Note: if you pass the `checked` prop, you MUST also pass an `onChange`
* handler, or the field will be rendered as read-only._
*/
checked?: boolean;
/**
* When using the [uncontrolled approach](https://reactjs.org/docs/uncontrolled-components.html),
* use defaultChecked to indicate the initially checked button.
*/
defaultChecked?: boolean;
/**
* Appears to the right of the radio button. If a visible label is
* undesirable (e.g. for layout reasons) use `aria-label` instead.
*
* If label is omitted, supporting text will not appear either.
*/
label?: string | ReactNode;
/**
* Additional text or a component that appears below the label
*/
supporting?: string | ReactNode;
}
/**
* [Storybook](https://guardian.github.io/source/?path=/docs/source-src-radio-radio--demo) •
* [Design System](https://theguardian.design/2a1e5182b/p/2891dd-radio-button/b/46940d) •
* [GitHub](https://github.com/guardian/source/tree/main/src/core/components/radio) •
* [NPM](https://www.npmjs.com/package/@guardian/src-radio)
*
* Radio buttons allow users to make a single selection from a set of options.
*
* The following themes are supported: `default`, `brand`
*/
export const Radio = ({
label: labelContent,
value,
supporting,
checked,
defaultChecked,
cssOverrides,
...props
}: RadioProps) => {
const isChecked = (): boolean => {
if (checked != null) {
return checked;
}
return !!defaultChecked;
};
const radioControl = (
<input
type="radio"
css={(theme) => [radio(theme.radio && theme), cssOverrides]}
value={value}
aria-checked={isChecked()}
defaultChecked={defaultChecked != null ? defaultChecked : undefined}
checked={checked != null ? isChecked() : undefined}
{...props}
/>
);
const labelledRadioControl = (
<label
css={(theme) => [
label(theme.radio && theme),
supporting ? labelWithSupportingText : '',
]}
>
{radioControl}
{supporting ? (
<div>
<LabelText hasSupportingText={true}>
{labelContent}
</LabelText>
<SupportingText>{supporting}</SupportingText>
</div>
) : (
<LabelText>{labelContent}</LabelText>
)}
</label>
);
return (
<>{labelContent || supporting ? labelledRadioControl : radioControl}</>
);
};