|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- 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,
- }
-
- 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, },
- ref
- ) => (
- <Base>
- <CaptureArea>
- <Input ref={ref} name={name} type="radio" />
- <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
|