@spaced-out/ui-design-system
Version:
Sense UI components library
117 lines (107 loc) • 2.99 kB
Flow
// @flow strict
import * as React from 'react';
import type {GroupAlign} from '../../types/common';
import classify from '../../utils/classify';
import {BodySmall} from '../Text/Text';
import css from './CheckboxGroup.module.css';
type ClassNames = $ReadOnly<{
wrapper?: string,
checkboxGroup?: string,
errorText?: string,
}>;
export type CheckboxOptions = Array<{
label: React.Node,
value: string,
}>;
export type CheckboxGroupProps = {
align?: GroupAlign,
disabled?: boolean,
name: string,
value?: Array<string>,
onChange?: (value: Array<string>) => mixed,
classNames?: ClassNames,
error?: boolean,
errorText?: string,
children?: React.Node,
};
export const CheckboxGroup: React$AbstractComponent<
CheckboxGroupProps,
HTMLDivElement,
> = React.forwardRef<CheckboxGroupProps, HTMLDivElement>(
(
{
align = 'vertical',
disabled = false,
name,
value: checkedList,
onChange,
classNames,
error = false,
errorText = '',
children,
}: CheckboxGroupProps,
forwardRef,
): React.Node => {
const onChangeHandler = ({value, checked}) => {
const checkedListTemp = checkedList ? [...checkedList] : [];
if (checked && !checkedListTemp.includes(value)) {
checkedListTemp.push(value);
} else if (!checked && checkedListTemp.includes(value)) {
for (let i = 0; i < checkedListTemp.length; i++) {
if (checkedListTemp[i] === value) {
checkedListTemp.splice(i, 1);
break;
}
}
}
onChange && onChange(checkedListTemp);
};
const childrenWithProps = React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
const {
value,
disabled: disabledChild,
error: errorChild,
onChange,
} = child.props;
const childOnChange = (...params) => {
onChangeHandler(...params);
onChange && onChange(...params);
};
return React.cloneElement(child, {
name,
checked: !!checkedList?.includes(value),
onChange: childOnChange,
align,
error: errorChild || error,
disabled: disabledChild || disabled,
});
}
return child;
});
return (
<div
className={classify(css.checkboxGroupContainer, classNames?.wrapper)}
>
<div
className={classify(
{
[css.vertical]: align === 'vertical',
[css.horizontal]: align === 'horizontal-fixed',
[css.horizontalFluid]: align === 'horizontal-fluid',
},
classNames?.checkboxGroup,
)}
ref={forwardRef}
>
{childrenWithProps}
</div>
{error && (
<BodySmall className={classify(classNames?.errorText)} color="danger">
{errorText}
</BodySmall>
)}
</div>
);
},
);