import React, { ChangeEvent, useState } from 'react' import { styled } from '@styled-components' import focusShadowStyle from '../../utils/focus-shadow.style.js' import { CheckboxRadioContainer } from '../check-box/index.js' const Circle = styled.span` display: block; width: 8px; height: 8px; margin-left: -4px; margin-top: -4px; border-radius: 9999px; background: ${({ theme }) => theme.colors.white}; position: absolute; top: 50%; left: 50%; ` // Hide checkbox visually but remain accessible to screen readers. // Source: https://polished.js.org/docs/#hidevisually const HiddenRadio = styled.input.attrs({ type: 'radio' })` border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; white-space: nowrap; width: 1px; ` type StyledProps = { checked?: boolean; disabled?: boolean; } const radioBackground = (theme, checked, disabled): string => { if (checked) { return disabled ? theme.colors.grey40 : theme.colors.primary100 } return theme.colors.white } const StyledRadio = styled.span` display: inline-block; width: 16px; cursor: pointer; border: 1px solid ${({ theme, checked, disabled }): string => (checked && !disabled ? theme.colors.primary100 : theme.colors.grey40)}; border-radius: 1000px; height: 16px; transition: all 150ms; position: relative; ${HiddenRadio}:focus + & { ${({ theme }) => `box-shadow: ${focusShadowStyle(theme)}`}; } ${HiddenRadio}:hover + & { border-color: ${({ theme }) => theme.colors.grey60}; } ${Circle} { visibility: ${({ checked }): string => (checked ? 'visible' : 'hidden')}; } background: ${({ checked, theme, disabled }): string => radioBackground(theme, checked, disabled)}; ` export type RadioProps = React.HTMLProps /** * @typedef {object} RadioProps * @alias RadioProps * @memberof Radio * @property {string} [...] All props default to _radio_ html input like `onChange`, * `checked` etc. */ /** /** * @classdesc * * * * HTML Radio * * ### Usage * * ```javascript * import { Radio, RadioProps } from '@adminjs/design-system' * ``` * * @component * @see RadioProps * @see {@link https://storybook.adminjs.co/?path=/story/designsystem-atoms-radio--default StoryBook} * @hideconstructor * @subcategory Atoms * @example * return ( * * * * * ) * @section design-system */ const Radio: React.FC = (props) => { const { className, checked, onChange, disabled, ...restProps } = props const [isChecked, setChecked] = useState(checked ?? false) const actuallyChecked = checked ?? isChecked const handleChange = (event: ChangeEvent): void => { setChecked(!event.target.checked) if (onChange) { onChange(event) } } return ( handleChange && handleChange(event as any)} disabled={disabled} > ) } Radio.displayName = 'Radio' export { Radio } export default Radio