@primer/react
Version:
An implementation of GitHub's Primer Design System using React
102 lines (99 loc) • 4.62 kB
JavaScript
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 };