/
Radio.tsx
124 lines (116 loc) · 3.78 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
import * as React from 'react';
import * as PropTypes from 'prop-types';
import {useUID} from '@twilio-paste/uid-library';
import {Box} from '@twilio-paste/box';
import type {BoxProps} from '@twilio-paste/box';
import {
BaseRadioCheckboxControl,
BaseRadioCheckboxLabel,
BaseRadioCheckboxLabelText,
BaseRadioCheckboxHelpText,
} from '@twilio-paste/base-radio-checkbox';
import {RadioContext} from './RadioContext';
export interface RadioProps extends React.InputHTMLAttributes<HTMLInputElement> {
id?: string;
value?: string;
name?: string;
checked?: boolean;
disabled?: boolean;
hasError?: boolean;
helpText?: string | React.ReactNode;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
children: NonNullable<React.ReactNode>;
element?: BoxProps['element'];
}
type HiddenRadioProps = Pick<RadioProps, 'checked' | 'value' | 'id' | 'disabled' | 'name' | 'onChange'> & {
ref?: any | undefined;
};
const HiddenRadio = React.forwardRef<HTMLInputElement, HiddenRadioProps>((props, ref) => (
<Box
as="input"
type="radio"
size="size0"
border="none"
overflow="hidden"
padding="space0"
margin="space0"
whiteSpace="nowrap"
textTransform="none"
position="absolute"
clip="rect(0 0 0 0)"
ref={ref}
{...props}
/>
));
HiddenRadio.displayName = 'HiddenRadio';
const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
({id, name, element = 'RADIO', value, checked, disabled, hasError, onChange, children, helpText, ...props}, ref) => {
const helpTextId = useUID();
const radioGroupContext = React.useContext(RadioContext);
const state = {
name: name != null ? name : radioGroupContext.name,
checked: checked != null ? checked : radioGroupContext.value === value,
disabled: disabled != null ? disabled : radioGroupContext.disabled,
hasError: hasError != null ? hasError : radioGroupContext.hasError,
onChange: onChange != null ? onChange : radioGroupContext.onChange,
};
return (
<Box
element={element}
position="relative"
display="inline-flex"
alignItems="flex-start"
flexDirection="column"
verticalAlign="top"
>
<HiddenRadio
{...props}
{...state}
value={value}
aria-describedby={helpTextId}
aria-invalid={state.hasError}
id={id}
ref={ref}
/>
<BaseRadioCheckboxLabel disabled={state.disabled} htmlFor={id}>
<BaseRadioCheckboxControl
element={`${element}_CONTROL`}
borderRadius="borderRadiusCircle"
disabled={state.disabled}
type="radio"
>
<Box
as="span"
backgroundColor={state.disabled && state.checked ? 'colorBackgroundStrongest' : 'colorBackgroundBody'}
borderRadius="borderRadiusCircle"
height="sizeSquare25"
width="sizeSquare25"
/>
</BaseRadioCheckboxControl>
<BaseRadioCheckboxLabelText element={`${element}_LABEL_TEXT`}>{children}</BaseRadioCheckboxLabelText>
</BaseRadioCheckboxLabel>
{helpText && (
<BaseRadioCheckboxHelpText element={`${element}_HELP_TEXT_WRAPPER`} helpTextId={helpTextId}>
{helpText}
</BaseRadioCheckboxHelpText>
)}
</Box>
);
}
);
Radio.displayName = 'Radio';
if (process.env.NODE_ENV === 'development') {
Radio.propTypes = {
id: PropTypes.string,
value: PropTypes.string,
name: PropTypes.string,
checked: PropTypes.bool,
disabled: PropTypes.bool,
hasError: PropTypes.bool,
helpText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
onChange: PropTypes.func,
children: PropTypes.node.isRequired,
element: PropTypes.string,
};
}
export {Radio};