Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Align hover ripple for checkbox and radio components in IE11 #651

Merged
merged 8 commits into from
May 21, 2020
29 changes: 13 additions & 16 deletions modules/checkbox/react/lib/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ const CheckboxInputWrapper = styled('div')<Pick<CheckboxProps, 'disabled'>>({
alignSelf: 'flex-start',
});

const CheckboxRipple = styled('span')<Pick<CheckboxProps, 'disabled'>>({
borderRadius: borderRadius.circle,
boxShadow: `0 0 0 0 ${colors.soap200}`,
height: checkboxHeight,
transition: 'box-shadow 150ms ease-out',
width: checkboxWidth,
position: 'absolute',
pointerEvents: 'none', // This is a decorative element we don't want it to block clicks to input
zIndex: -1,
});

/**
* Note: `~ div:first-of-type` refers to `CheckboxBackground`
* and was easier to use than a component selector in this case.
Expand Down Expand Up @@ -157,23 +168,8 @@ const CheckboxInput = styled('input')<CheckboxProps>(
},
}),
}),

// Ripple
{
'& ~ div:first-of-type::after': {
borderRadius: borderRadius.circle,
boxShadow: `0 0 0 0 ${colors.soap200}`,
content: '""',
display: 'inline-block',
height: checkboxHeight,
transition: 'box-shadow 150ms ease-out',
width: checkboxWidth,
position: 'absolute',
zIndex: -1,
},
},
({disabled}) => ({
'&:hover ~ div:first-of-type::after': {
'&:hover ~ span:first-of-type': {
boxShadow: disabled ? undefined : `0 0 0 ${rippleRadius}px ${colors.soap200}`,
},
}),
Expand Down Expand Up @@ -309,6 +305,7 @@ export default class Checkbox extends React.Component<CheckboxProps> {
error={error}
{...elemProps}
/>
<CheckboxRipple />
<CheckboxBackground checked={checked} disabled={disabled}>
<CheckboxCheck checked={checked}>
{indeterminate ? (
Expand Down
48 changes: 27 additions & 21 deletions modules/radio/react/lib/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,17 @@ const RadioInputWrapper = styled('div')<Pick<RadioProps, 'disabled'>>({
width: radioWidth,
});

/**
* Note: `~ div:first-of-type` refers to `RadioBackground`
* and was easier to use than a component selector in this case.
*/
const RadioRipple = styled('span')<Pick<RadioProps, 'disabled'>>({
borderRadius: borderRadius.circle,
boxShadow: `0 0 0 0 ${colors.soap200}`,
height: radioHeight,
transition: 'box-shadow 150ms ease-out',
width: radioWidth,
position: 'absolute',
pointerEvents: 'none', // This is a decorative element we don't want it to block clicks to input
zIndex: -1,
});

const RadioInput = styled('input')<RadioProps>(
{
borderRadius: radioBorderRadius,
Expand All @@ -93,26 +100,25 @@ const RadioInput = styled('input')<RadioProps>(
outline: 'none',
},
},

// Ripple
{
'& ~ div:first-of-type::after': {
borderRadius: borderRadius.circle,
boxShadow: `0 0 0 0 ${colors.soap200}`,
content: '""',
display: 'inline-block',
height: radioHeight,
transition: 'box-shadow 150ms ease-out',
width: radioWidth,
position: 'absolute',
zIndex: -1,
},
},
({checked, disabled, theme}) => ({
cursor: disabled ? undefined : 'pointer',
'&:hover ~ div:first-of-type::after': {
/**
* These selectors are targetting various sibling elements (~) here because
* their styles need to be connected to changes around the input's state
* (e.g. hover, focus, etc.).
*
* We are choosing not to use component selectors from Emotion in this case.
* The Babel transforms have been problematic in the past.
*/

// `span:first-of-type` refers to `RadioRipple`, the light grey
// element that animates around the component on hover
'&:hover ~ span:first-of-type': {
boxShadow: disabled ? undefined : `0 0 0 ${rippleRadius}px ${colors.soap200}`,
},

// `div:first-of-type` refers to the `RadioBackground`, the visual facade of the
// input (which is visually hidden)
'&:hover ~ div:first-of-type': {
backgroundColor: checked
? theme.palette.primary.main
Expand All @@ -130,7 +136,6 @@ const RadioInput = styled('input')<RadioProps>(
'& ~ div:first-of-type': {
borderColor: checked ? theme.palette.primary.main : theme.palette.common.focusOutline,
borderWidth: '2px',
zIndex: 2,
},
},
'&:checked:focus ~ div:first-of-type': {
Expand Down Expand Up @@ -242,6 +247,7 @@ export default class Radio extends React.Component<RadioProps> {
aria-checked={checked}
{...elemProps}
/>
<RadioRipple />
<RadioBackground checked={checked} disabled={disabled}>
<RadioCheck checked={checked} />
</RadioBackground>
Expand Down