UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

102 lines (99 loc) 4.62 kB
import React from 'react'; import ValidationAnimationContainer from '../ValidationAnimationContainer.js'; import { useId } from '../../../hooks/useId.js'; import CheckboxOrRadioGroupCaption from './CheckboxOrRadioGroupCaption.js'; import CheckboxOrRadioGroupLabel from './CheckboxOrRadioGroupLabel.js'; import CheckboxOrRadioGroupValidation from './CheckboxOrRadioGroupValidation.js'; import CheckboxOrRadioGroupContext from './CheckboxOrRadioGroupContext.js'; import VisuallyHidden from '../../../_VisuallyHidden.js'; import { useSlots } from '../../../hooks/useSlots.js'; import classes from './CheckboxOrRadioGroup.module.css.js'; import { clsx } from 'clsx'; import { BoxWithFallback } from '../BoxWithFallback.js'; import { jsx, jsxs } from 'react/jsx-runtime'; const CheckboxOrRadioGroup = ({ 'aria-labelledby': ariaLabelledby, children, disabled = false, id: idProp, required = false, className, sx }) => { const [slots, rest] = useSlots(children, { caption: CheckboxOrRadioGroupCaption, label: CheckboxOrRadioGroupLabel, validation: CheckboxOrRadioGroupValidation }); const labelChild = React.Children.toArray(children).find(child => /*#__PURE__*/React.isValidElement(child) && child.type === CheckboxOrRadioGroupLabel); const validationChild = React.Children.toArray(children).find(child => /*#__PURE__*/React.isValidElement(child) && child.type === CheckboxOrRadioGroupValidation ? child : null); const captionChild = React.Children.toArray(children).find(child => /*#__PURE__*/React.isValidElement(child) && child.type === CheckboxOrRadioGroupCaption ? child : null); const id = useId(idProp); const validationMessageId = validationChild ? `${id}-validationMessage` : undefined; const captionId = captionChild ? `${id}-caption` : undefined; if (!labelChild && !ariaLabelledby) { // eslint-disable-next-line no-console console.warn('A choice group must be labelled using a `CheckboxOrRadioGroup.Label` child, or by passing `aria-labelledby` to the CheckboxOrRadioGroup component.'); } const isLegendVisible = /*#__PURE__*/React.isValidElement(labelChild) && !labelChild.props.visuallyHidden; return /*#__PURE__*/jsx(CheckboxOrRadioGroupContext.Provider, { value: { disabled, required, captionId, validationMessageId }, children: /*#__PURE__*/jsxs("div", { children: [/*#__PURE__*/jsxs(BoxWithFallback, { className: clsx(className, classes.GroupFieldset), "data-validation": validationChild ? '' : undefined, ...(labelChild ? { as: 'fieldset', disabled } : {}), sx: sx, children: [labelChild ? /*#__PURE__*/ /* Placing the caption text and validation text in the <legend> provides a better user experience for more screenreaders. Reference: https://blog.tenon.io/accessible-validation-of-checkbox-and-radiobutton-groups/ */ jsxs("legend", { className: classes.GroupLegend, "data-legend-visible": isLegendVisible ? '' : undefined, children: [slots.label, slots.caption, /*#__PURE__*/React.isValidElement(slots.validation) && slots.validation.props.children && /*#__PURE__*/jsx(VisuallyHidden, { children: slots.validation.props.children })] }) : ( /* If CheckboxOrRadioGroup.Label wasn't passed as a child, we don't render a <legend> but we still want to render a caption */ slots.caption), /*#__PURE__*/jsx("div", { className: classes.Body, ...(!labelChild ? { ['aria-labelledby']: ariaLabelledby, ['aria-describedby']: [validationMessageId, captionId].filter(Boolean).join(' '), as: 'div', role: 'group' } : {}), children: React.Children.toArray(rest).filter(child => /*#__PURE__*/React.isValidElement(child)) })] }), validationChild && /*#__PURE__*/jsx(ValidationAnimationContainer // If we have CheckboxOrRadioGroup.Label as a child, we render a screenreader-accessible validation message in the <legend> , { "aria-hidden": Boolean(labelChild), show: true, children: slots.validation })] }) }); }; CheckboxOrRadioGroup.displayName = "CheckboxOrRadioGroup"; var CheckboxOrRadioGroup$1 = Object.assign(CheckboxOrRadioGroup, { Caption: CheckboxOrRadioGroupCaption, Label: CheckboxOrRadioGroupLabel, Validation: CheckboxOrRadioGroupValidation }); export { CheckboxOrRadioGroup$1 as default };