|
- import * as React from 'react'
- import * as PropTypes from 'prop-types'
- import styled from 'styled-components'
- import stringify from '../../services/stringify'
-
- const Base = styled('div')({
- display: 'block',
- })
-
- const CaptureArea = styled('label')({
- marginTop: '0.25rem',
- '::after': {
- content: '""',
- clear: 'both',
- },
- })
-
- CaptureArea.displayName = 'label'
-
- const Input = styled('input')({
- position: 'absolute',
- left: -999999,
- width: 1,
- height: 1,
- })
-
- Input.displayName = 'input'
-
- const IndicatorWrapper = styled('span')({
- borderColor: 'var(--color-accent, blue)',
- boxSizing: 'border-box',
- backgroundColor: 'transparent',
- borderRadius: '0.75rem',
- position: 'relative',
- width: '1.5rem',
- height: '1.5rem',
- minWidth: '1.5rem',
- maxWidth: '1.5rem',
- display: 'inline-flex',
- verticalAlign: 'top',
- justifyContent: 'center',
- alignItems: 'center',
- cursor: 'pointer',
- transitionProperty: 'border-color',
- [`${Input}:focus ~ &`]: {
- '--color-accent': 'var(--color-active, Highlight)',
- },
- [`${Input}:disabled ~ &`]: {
- cursor: 'not-allowed',
- opacity: 0.5,
- },
- })
-
- const Border = styled('span')({
- borderColor: 'var(--color-accent, blue)',
- boxSizing: 'border-box',
- display: 'inline-block',
- borderWidth: '0.125rem',
- borderStyle: 'solid',
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- borderRadius: 'inherit',
- transitionProperty: 'border-color',
- '::before': {
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- content: "''",
- borderRadius: '0.75rem',
- opacity: 0.5,
- pointerEvents: 'none',
- },
- [`${Base}:focus-within &::before`]: {
- boxShadow: '0 0 0 0.375rem var(--color-accent, blue)',
- },
- })
-
- const Indicator = styled('span')({
- backgroundColor: 'var(--color-accent, blue)',
- color: 'var(--color-bg, white)',
- width: 0,
- height: 0,
- opacity: 0,
- boxSizing: 'border-box',
- display: 'inline-grid',
- placeContent: 'center',
- borderRadius: '50%',
- transitionProperty: 'background-color, color, width, height, opacity',
- [`${Input}:checked + ${IndicatorWrapper} &`]: {
- width: `${(100 * 2) / 3}%`,
- height: `${(100 * 2) / 3}%`,
- opacity: 1,
- },
- })
-
- const Label = styled('span')({
- display: 'block',
- verticalAlign: 'top',
- float: 'right',
- width: 'calc(100% - 2.5rem)',
- fontFamily: 'var(--font-family-base, sans-serif)',
- pointerEvents: 'none',
- })
-
- const LabelContent = styled('span')({
- display: 'inline',
- pointerEvents: 'auto',
- })
-
- const propTypes = {
- /**
- * Group where the component belongs.
- */
- name: PropTypes.string.isRequired,
- /**
- * Short textual description indicating the nature of the component's value.
- */
- label: PropTypes.any,
- /**
- * Event handler triggered when the component is selected.
- */
- onChange: PropTypes.func,
- /**
- * Event handler triggered when the component receives focus.
- */
- onFocus: PropTypes.func,
- /**
- * Event handler triggered when the component loses focus.
- */
- onBlur: PropTypes.func,
- }
-
- type Props = PropTypes.InferProps<typeof propTypes>
-
- /**
- * Component for values which are to be selected from a few list of options.
- * @see {@link Checkbox} for a similar component on selecting values among very few choices.
- * @see {@link Select} for a similar component suitable for selecting more values.
- * @type {React.ComponentType<{readonly label?: string, readonly name?: string} & React.ClassAttributes<unknown>>}
- */
- const RadioButton = React.forwardRef<HTMLInputElement, Props>(
- ({ label = '', name, onChange, onFocus, onBlur }, ref) => (
- <Base>
- <CaptureArea>
- <Input
- ref={ref}
- name={name}
- type="radio"
- onChange={onChange as React.ChangeEventHandler}
- onFocus={onFocus as React.FocusEventHandler}
- onBlur={onBlur as React.FocusEventHandler}
- />
- <IndicatorWrapper>
- <Border />
- <Indicator />
- </IndicatorWrapper>
- {typeof label! !== 'undefined' && label !== null && ' '}
- <Label>
- <LabelContent>{stringify(label)}</LabelContent>
- </Label>
- </CaptureArea>
- </Base>
- ),
- )
-
- RadioButton.propTypes = propTypes
-
- RadioButton.displayName = 'RadioButton'
-
- export default RadioButton
|