Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add types to CheckboxGroup #16642

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions packages/react/src/components/CheckboxGroup/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import PropTypes from 'prop-types';
import React, { ReactNode } from 'react';
import cx from 'classnames';
import { usePrefix } from '../../internal/usePrefix';
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
import setupGetInstanceId from '../../tools/setupGetInstanceId';

const getInstanceId = setupGetInstanceId();

export interface CheckboxGroupProps {
children?: ReactNode;
className?: string;
helperText?: ReactNode;
invalid?: boolean;
invalidText?: ReactNode;
legendId?: ReactNode;
orientation?: 'horizontal' | 'vertical';
legendText: ReactNode;
readOnly?: boolean;
slug?: ReactNode;
warn?: boolean;
warnText?: ReactNode;
}

export interface CustomType {
size: string;
kind: string;
}

const CheckboxGroup: React.FC<CheckboxGroupProps> = ({
children,
className,
helperText,
invalid,
invalidText,
legendId,
legendText,
readOnly,
warn,
warnText,
slug,
orientation = 'vertical',
...rest
}) => {
const prefix = usePrefix();

const showWarning = !readOnly && !invalid && warn;
const showHelper = !invalid && !warn;

const checkboxGroupInstanceId = getInstanceId();

const helperId = !helperText
? undefined
: `checkbox-group-helper-text-${checkboxGroupInstanceId}`;

const helper = helperText ? (
<div id={helperId} className={`${prefix}--form__helper-text`}>
{helperText}
</div>
) : null;

const fieldsetClasses = cx(`${prefix}--checkbox-group`, className, {
[`${prefix}--checkbox-group--${orientation}`]: orientation === 'horizontal',
[`${prefix}--checkbox-group--readonly`]: readOnly,
[`${prefix}--checkbox-group--invalid`]: !readOnly && invalid,
[`${prefix}--checkbox-group--warning`]: showWarning,
[`${prefix}--checkbox-group--slug`]: slug,
});

// Slug is always size `mini`
let normalizedSlug;
if (
React.isValidElement(slug) &&
(slug['type'] as any)?.displayName === 'Slug'
) {
normalizedSlug = React.cloneElement(slug, {
size: 'mini',
kind: 'default',
} as CustomType);
}
return (
<fieldset
className={fieldsetClasses}
data-invalid={invalid ? true : undefined}
aria-labelledby={rest['aria-labelledby'] || legendId}
aria-readonly={readOnly}
aria-describedby={!invalid && !warn && helper ? helperId : undefined}
{...rest}>
<legend
className={`${prefix}--label`}
id={legendId || rest['aria-labelledby']}>
{legendText}
{normalizedSlug}
</legend>
{children}
<div className={`${prefix}--checkbox-group__validation-msg`}>
{!readOnly && invalid && (
<>
<WarningFilled className={`${prefix}--checkbox__invalid-icon`} />
<div className={`${prefix}--form-requirement`}>{invalidText}</div>
</>
)}
{showWarning && (
<>
<WarningAltFilled
className={`${prefix}--checkbox__invalid-icon ${prefix}--checkbox__invalid-icon--warning`}
/>
<div className={`${prefix}--form-requirement`}>{warnText}</div>
</>
)}
</div>
{showHelper && helper}
</fieldset>
);
};

CheckboxGroup.propTypes = {
/**
* Provide the children form elements to be rendered inside of the <fieldset>
*/
children: PropTypes.node,

/**
* Provide a custom className to be applied to the containing <fieldset> node
*/
className: PropTypes.string,

/**
* Provide text for the form group for additional help
*/
helperText: PropTypes.node,

/**
* Specify whether the form group is currently invalid
*/
invalid: PropTypes.bool,

/**
* Provide the text that is displayed when the form group is in an invalid state
*/
invalidText: PropTypes.node,

/**
* Provide id for the fieldset <legend> which corresponds to the fieldset
* `aria-labelledby`
*/
legendId: PropTypes.node,

/**
* Provide the text to be rendered inside of the fieldset <legend>
*/
legendText: PropTypes.node.isRequired,

/**
* Provide the orientation for how the checkbox should be displayed
*/
orientation: PropTypes.oneOf(['horizontal', 'vertical']),
/**
* Whether the CheckboxGroup should be read-only
*/
readOnly: PropTypes.bool,

/**
* **Experimental**: Provide a `Slug` component to be rendered inside the `CheckboxGroup` component
*/
slug: PropTypes.node,

/**
* Specify whether the form group is currently in warning state
*/
warn: PropTypes.bool,

/**
* Provide the text that is displayed when the form group is in warning state
*/
warnText: PropTypes.node,
};

export default CheckboxGroup;
Loading