@navinc/base-react-components
Version:
Nav's Pattern Library
137 lines (120 loc) • 3.17 kB
JavaScript
import React, { useRef, useEffect } from 'react'
import styled from 'styled-components'
import Copy from './copy'
import { focusWithoutScroll } from '@navinc/utils'
const getLabelStyling = ({ isInvalid, theme }) => `
margin: 0;
padding: 0;
color: ${isInvalid ? theme.error : 'inherit'};
`
const CopyLabel = styled(({ isInvalid, ...props }) => <Copy {...props} />)`
${getLabelStyling}
`
const DivLabel = styled.div`
${getLabelStyling}
`
const RadioItem = styled.label`
display: flex;
flex-flow: row nowrap;
align-items: center;
flex: 1 1 auto;
margin-bottom: 0;
cursor: pointer;
text-align: left;
${({ asideContent, hasBorder, theme }) =>
(asideContent || hasBorder) &&
`
border-radius: 12px;
border: 1px solid ${theme.border};
padding: 8px;
padding-left: 16px;
padding-right: 16px;
min-height: 62px;
`}
${({ checked, checkedBackgroundColor }) =>
checked &&
checkedBackgroundColor &&
`
background-color: ${checkedBackgroundColor};
border-color: ${checkedBackgroundColor};
`}
& > :first-child {
margin-right: 16px;
}
`
const AsideContainer = styled.div`
display: flex;
flex: 1;
justify-content: flex-end;
margin-left: 8px;
`
const RadioIndicator = styled.input.attrs(() => ({ type: 'radio' }))`
box-sizing: border-box;
border-radius: 50%;
background-color: ${({ checked, theme }) => (checked ? theme.navBlue : 'transparent')};
height: 12px;
width: 12px;
appearance: none;
margin: 0;
font-size: inherit;
transition: background-color 300ms ease;
`
const RadioSpot = styled.div`
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
border-radius: 50%;
border-style: solid;
border-width: ${({ checked }) => (checked ? '2px' : '1px')};
border-color: ${({ disabled, theme }) => (disabled ? theme.scuttleGray300 : theme.bubbleBlue200)};
background: ${({ disabled, theme }) => (disabled ? theme.neutral100 : theme.bubbleBlue100)};
height: 24px;
flex: 0 0 auto;
width: 24px;
transition: box-shadow 300ms ease;
&:focus-within {
box-shadow: 0 0 0 8px ${({ theme }) => theme.bubbleBlue300};
& > ${RadioIndicator} {
outline: none;
}
}
`
export const Radio = ({
asideContent,
autoFocus,
checkedBackgroundColor,
children,
label,
className,
checked,
disabled,
hasBorder,
isInvalid,
...props
}) => {
const inputRef = useRef(null)
useEffect(() => {
if (autoFocus) {
focusWithoutScroll(inputRef.current)
}
}, [autoFocus])
const Label = typeof label === 'string' ? CopyLabel : DivLabel
return (
<RadioItem
asideContent={asideContent}
checked={checked}
className={className}
hasBorder={hasBorder}
checkedBackgroundColor={checkedBackgroundColor}
>
<RadioSpot {...{ checked, disabled }}>
<RadioIndicator ref={inputRef} {...{ checked, disabled }} {...props} />
</RadioSpot>
<Label isInvalid={isInvalid}>{label}</Label>
{asideContent && <AsideContainer>{asideContent}</AsideContainer>}
</RadioItem>
)
}
const StyledRadio = styled(Radio)``
export default StyledRadio