|
- import * as React from 'react'
- import * as PropTypes from 'prop-types'
- import styled from 'styled-components'
- import stringify from '../../services/stringify'
- import Icon from '../Icon/Icon'
-
- const Base = styled('div')({
- display: 'block',
- })
-
- const CaptureArea = styled('label')({
- 'marginTop': '0.25rem',
- '::after': {
- content: '""',
- },
- })
-
- 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.25rem',
- 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.125rem',
- 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,
- position: 'relative',
- boxSizing: 'border-box',
- display: 'inline-grid',
- placeContent: 'center',
- borderRadius: 'inherit',
- lineHeight: 1,
- transitionProperty: 'background-color, color, width, height, opacity',
- [`${Input}:checked + ${IndicatorWrapper} &`]: {
- opacity: 1,
- width: '100%',
- height: '100%',
- },
- })
-
- const Label = styled('span')({
- display: 'block',
- verticalAlign: 'top',
- float: 'right',
- width: 'calc(100% - 2.5rem)',
- fontFamily: 'var(--font-family-base)',
- pointerEvents: 'none',
- })
-
- const LabelContent = styled('span')({
- display: 'inline',
- pointerEvents: 'auto',
- })
-
- const propTypes = {
- /**
- * Short textual description indicating the nature of the component's value.
- */
- label: PropTypes.any,
- }
-
- type Props = PropTypes.InferProps<typeof propTypes>
-
- /**
- * Component for values that have an on/off state.
- * @see {@link Select} for a similar component suitable for selecting more values.
- * @see {@link RadioButton} for a similar component on selecting a single value among very few choices.
- * @type {React.ComponentType<{readonly label?: string} & React.ClassAttributes<unknown>>}
- */
- const Checkbox = React.forwardRef<HTMLInputElement, Props>(({ label = '', ...etcProps }, ref) => (
- <Base>
- <CaptureArea>
- <Input {...etcProps} ref={ref} type="checkbox" />
- <IndicatorWrapper>
- <Border />
- <Indicator>
- <Icon name="check" label="" />
- </Indicator>
- </IndicatorWrapper>
- {typeof label! !== 'undefined' && label !== null && ' '}
- <Label>
- <LabelContent>{stringify(label)}</LabelContent>
- </Label>
- </CaptureArea>
- </Base>
- ))
-
- Checkbox.propTypes = propTypes
-
- Checkbox.displayName = 'Checkbox'
-
- export default Checkbox
|