New source found from dndbeyond.com
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
import clsx from "clsx";
|
||||
import { orderBy } from "lodash";
|
||||
import { ChangeEvent, FC, HTMLAttributes, ReactNode } from "react";
|
||||
|
||||
import { Accordion, AccordionProps } from "../Accordion";
|
||||
import { Checkbox } from "../Checkbox";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export interface CheckboxInfo {
|
||||
description?: string;
|
||||
disabled?: boolean;
|
||||
initiallyEnabled: boolean;
|
||||
label: string;
|
||||
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
onChangeConfirm?: (
|
||||
newIsEnabled: boolean,
|
||||
accept: () => void,
|
||||
reject: () => void
|
||||
) => void;
|
||||
sortOrder?: number;
|
||||
value?: string | number;
|
||||
}
|
||||
|
||||
interface CheckboxGroupProps
|
||||
extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
||||
accordionDefaultOpen?: boolean;
|
||||
accordionSummary?: string;
|
||||
checkboxes: Array<CheckboxInfo>;
|
||||
disabled?: boolean;
|
||||
description?: ReactNode;
|
||||
name: string;
|
||||
onToggleAll?: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
showAccordion?: boolean;
|
||||
themed?: boolean;
|
||||
toggleAllLabel?: string;
|
||||
title: ReactNode;
|
||||
variant?: "default" | "inline" | "collapse";
|
||||
}
|
||||
|
||||
export const CheckboxGroup: FC<CheckboxGroupProps> = ({
|
||||
accordionSummary = "Options",
|
||||
accordionDefaultOpen,
|
||||
checkboxes,
|
||||
className,
|
||||
disabled,
|
||||
description,
|
||||
name,
|
||||
onToggleAll,
|
||||
showAccordion,
|
||||
themed,
|
||||
title,
|
||||
toggleAllLabel = "Enable All Options",
|
||||
variant = "default",
|
||||
...props
|
||||
}) => {
|
||||
const isInlineVariant = variant === "inline";
|
||||
const isCollapseVariant = variant === "collapse";
|
||||
const sortedCheckboxes = orderBy(checkboxes, "sortOrder");
|
||||
|
||||
const allChecksEnabled = sortedCheckboxes.every(
|
||||
(checkbox) => checkbox.initiallyEnabled
|
||||
);
|
||||
|
||||
// Determine whether to render a div or an Accordion
|
||||
const ContentWrapper = showAccordion ? Accordion : "div";
|
||||
// Set props specific to Accordion if needed
|
||||
const accordionProps = showAccordion
|
||||
? {
|
||||
summary: accordionSummary,
|
||||
forceShow: accordionDefaultOpen,
|
||||
variant: "text",
|
||||
}
|
||||
: {};
|
||||
|
||||
const checkboxList = sortedCheckboxes.map((checkbox, i) => {
|
||||
const id = `${name}-${i}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={styles.checkboxOption}
|
||||
data-testid="form-checkbox-group"
|
||||
>
|
||||
<Checkbox
|
||||
className={styles.checkbox}
|
||||
id={id}
|
||||
name={name}
|
||||
checked={checkbox.initiallyEnabled}
|
||||
disabled={disabled || checkbox.disabled}
|
||||
themed={themed}
|
||||
onChange={checkbox.onChange}
|
||||
onChangeConfirm={checkbox.onChangeConfirm}
|
||||
value={checkbox.value}
|
||||
/>
|
||||
<div className={styles.optionContent}>
|
||||
<label className={styles.label} htmlFor={id}>
|
||||
{checkbox.label}
|
||||
</label>
|
||||
{checkbox.description && (
|
||||
<div
|
||||
className={styles.description}
|
||||
dangerouslySetInnerHTML={{ __html: checkbox.description }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
/** Handle Collapse Variant separately since it's structure is different */
|
||||
if (isCollapseVariant)
|
||||
return (
|
||||
<Accordion
|
||||
className={clsx([
|
||||
styles.checkboxGroup,
|
||||
styles.collapse,
|
||||
themed && styles.themed,
|
||||
className,
|
||||
])}
|
||||
summary={<p className={styles.checkboxGroupTitle}>{title}</p>}
|
||||
variant="text"
|
||||
forceShow={accordionDefaultOpen}
|
||||
{...props}
|
||||
>
|
||||
{description && (
|
||||
<div className={styles.checkboxGroupDescription}>{description}</div>
|
||||
)}
|
||||
{onToggleAll && (
|
||||
<Checkbox
|
||||
className={clsx([styles.checkbox, styles.toggleAll])}
|
||||
id={`${name}-toggle-all`}
|
||||
checked={allChecksEnabled}
|
||||
aria-label="Check/Uncheck all"
|
||||
onChange={onToggleAll}
|
||||
themed={themed}
|
||||
label={toggleAllLabel}
|
||||
/>
|
||||
)}
|
||||
{checkboxList}
|
||||
</Accordion>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx([
|
||||
styles.checkboxGroup,
|
||||
styles[variant],
|
||||
themed && styles.themed,
|
||||
className,
|
||||
])}
|
||||
{...props}
|
||||
>
|
||||
<header>
|
||||
<div className={styles.checkboxGroupHeader}>
|
||||
<p className={styles.checkboxGroupTitle}>{title}</p>
|
||||
{isInlineVariant && checkboxes.length < 2 && (
|
||||
<Checkbox
|
||||
className={styles.checkbox}
|
||||
id={`${name}-0`}
|
||||
name={name}
|
||||
checked={checkboxes[0].initiallyEnabled}
|
||||
disabled={disabled || checkboxes[0].disabled}
|
||||
themed={themed}
|
||||
onChange={checkboxes[0].onChange}
|
||||
onChangeConfirm={checkboxes[0].onChangeConfirm}
|
||||
value={checkboxes[0].value}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{description && (
|
||||
<div className={styles.checkboxGroupDescription}>{description}</div>
|
||||
)}
|
||||
</header>
|
||||
{!isInlineVariant && onToggleAll && (
|
||||
<Checkbox
|
||||
className={clsx([styles.checkbox, styles.toggleAll])}
|
||||
id={`${name}-toggle-all`}
|
||||
checked={allChecksEnabled}
|
||||
aria-label="Check/Uncheck all"
|
||||
onChange={onToggleAll}
|
||||
themed={themed}
|
||||
label={toggleAllLabel}
|
||||
/>
|
||||
)}
|
||||
{!isInlineVariant && (
|
||||
<ContentWrapper
|
||||
className={styles.checkboxOptions}
|
||||
{...(accordionProps as AccordionProps)}
|
||||
>
|
||||
{checkboxList}
|
||||
</ContentWrapper>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user