This repository has been archived by the owner on Mar 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 177
/
RadioGroup.tsx
116 lines (105 loc) · 2.72 KB
/
RadioGroup.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
import React, {
ComponentProps,
ChangeEventHandler,
ReactElement,
forwardRef,
ComponentPropsWithRef,
FC,
} from 'react';
import styled from 'styled-components';
import css from '@styled-system/css';
import omit from 'lodash.omit';
import pick from 'lodash.pick';
import { margin, MarginProps } from '@modulz/radix-system';
export type RadioGroupProps = ComponentProps<'div'> & {
name: string;
value?: string;
as?: any;
onChange?: ChangeEventHandler<HTMLInputElement>;
children: ReactElement<RadioProps>[];
};
export const RadioGroup = (props: RadioGroupProps) => {
const { name, value, onChange, children, ...rootProps } = props;
const isControlled = Boolean(value);
return (
<div {...rootProps}>
{React.Children.map(children, (radio: ReactElement<RadioProps>) =>
React.cloneElement(radio, {
name,
onChange,
...(isControlled ? { checked: value === radio.props.value } : {}),
})
)}
</div>
);
};
const marginPropNames = margin.propNames;
type Ref = HTMLInputElement;
export type RadioProps = MarginProps & ComponentPropsWithRef<'input'>;
export const Radio: FC<RadioProps> = forwardRef<Ref, RadioProps>((props, forwardedRef) => {
const { children, ...otherProps } = props;
const systemProps = pick(otherProps, marginPropNames);
const inputProps = omit(otherProps, marginPropNames);
return (
<RadioWrapper {...systemProps}>
<Input {...inputProps} type="radio" ref={forwardedRef} />
<FakeRadio />
{children && <TextWrapper>{children}</TextWrapper>}
</RadioWrapper>
);
});
const RadioWrapper = styled('label')<MarginProps>({ position: 'relative' }, margin);
const Input = styled('input')({
appearance: 'none',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: 0,
outline: 'none',
margin: 0,
opacity: 0,
WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',
});
const TextWrapper = styled('span')(
css({
lineHeight: '5',
fontFamily: 'normal',
fontSize: 2,
marginLeft: 1,
marginRight: 3,
userSelect: 'none',
verticalAlign: 'middle',
})
);
const FakeRadio = styled('div')(
css({
width: 4,
height: 4,
color: 'transparent',
borderRadius: '50%',
border: '1px solid',
borderColor: 'gray400',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
'&::before': {
content: `''`,
width: 2,
height: 2,
color: 'inherit',
borderRadius: 'inherit',
backgroundColor: 'currentColor',
},
[`${Input}:checked + &`]: {
color: 'blue600',
},
[`${Input}:hover + &`]: {
borderColor: 'gray500',
},
[`${Input}:focus + &`]: {
borderColor: 'blue600',
},
})
);