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(radio-button-group, checkbox-group): add id prop #7195

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
9 changes: 7 additions & 2 deletions src/__internal__/fieldset/fieldset.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import NewValidationContext from "../../components/carbon-provider/__internal__/
import { InputGroupBehaviour, InputGroupContext } from "../input-behaviour";
import useFormSpacing from "../../hooks/__internal__/useFormSpacing";
import Help from "../../components/help";
import Typography from "../../components/typography";

export interface FieldsetProps extends MarginProps {
/** Role */
Expand Down Expand Up @@ -100,13 +101,12 @@ const Fieldset = ({
const tooltipIcon = () => {
if (error || warning || info) {
return (
<StyledIconWrapper>
<StyledIconWrapper aria-hidden="true">
<ValidationIcon
error={error}
warning={warning}
info={info}
tooltipFlipOverrides={["top", "bottom"]}
tooltipId={validationId}
/>
</StyledIconWrapper>
);
Expand Down Expand Up @@ -171,6 +171,11 @@ const Fieldset = ({
)}
</InputGroupContext.Consumer>
)}
{!validationRedesignOptIn && (
<Typography screenReaderOnly id={validationId}>
{error || warning || info}
</Typography>
)}
{children}
</StyledFieldset>
</InputGroupBehaviour>
Expand Down
18 changes: 12 additions & 6 deletions src/__internal__/fieldset/fieldset.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,40 +41,46 @@ test("sets child inputs as required when `isRequired` is true", () => {
expect(inputs[1]).toBeRequired();
});

test("renders validation icon when `legend` and `error` are provided", () => {
test("renders validation icon and hidden message when `legend` and `error` are provided", () => {
render(
<Fieldset legend="Legend" error="error">
<Fieldset legend="Legend" error="error message">
<input />
</Fieldset>,
);

const icon = screen.getByTestId("icon-error");
const message = screen.getByText("error message");

expect(icon).toBeVisible();
expect(message).toBeInTheDocument();
});

test("renders validation icon when `legend` and `warning` are provided", () => {
test("renders validation icon and hidden message when `legend` and `warning` are provided", () => {
render(
<Fieldset legend="Legend" warning="warning">
<Fieldset legend="Legend" warning="warning message">
<input />
</Fieldset>,
);

const icon = screen.getByTestId("icon-warning");
const message = screen.getByText("warning message");

expect(icon).toBeVisible();
expect(message).toBeInTheDocument();
});

test("renders validation icon when `legend` and `info` are provided", () => {
test("renders validation icon and hidden message when `legend` and `info` are provided", () => {
render(
<Fieldset legend="Legend" info="info">
<Fieldset legend="Legend" info="info message">
<input />
</Fieldset>,
);

const icon = screen.getByTestId("icon-info");
const message = screen.getByText("info message");

expect(icon).toBeVisible();
expect(message).toBeInTheDocument();
});

test("renders help icon when `labelHelp` is provided", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from "react";
import React, { useContext, useRef } from "react";
import { MarginProps } from "styled-system";
import tagComponent from "../../../__internal__/utils/helpers/tags/tags";
import StyledCheckboxGroup, { StyledHintText } from "./checkbox-group.style";
Expand All @@ -12,8 +12,15 @@ import ValidationMessage from "../../../__internal__/validation-message/validati
import Box from "../../box";
import { ErrorBorder } from "../../textbox/textbox.style";
import CheckboxGroupContext from "./__internal__/checkbox-group.context";
import guid from "../../../__internal__/utils/helpers/guid";
import useInputAccessibility from "../../../hooks/__internal__/useInputAccessibility";

export interface CheckboxGroupProps extends ValidationProps, MarginProps {
/**
* Unique identifier for the component.
* Will use a randomly generated GUID if none is provided.
*/
id?: string;
/** The content for the CheckboxGroup Legend */
legend?: string;
/**
Expand Down Expand Up @@ -43,53 +50,73 @@ export interface CheckboxGroupProps extends ValidationProps, MarginProps {
inline?: boolean;
}

export const CheckboxGroup = (props: CheckboxGroupProps) => {
export const CheckboxGroup = ({
children,
legend,
error,
warning,
info,
required,
isOptional,
legendInline,
legendWidth,
legendAlign = "left",
legendSpacing,
legendHelp,
tooltipPosition,
inline,
id,
...rest
}: CheckboxGroupProps) => {
const { validationRedesignOptIn } = useContext(NewValidationContext);
const { current: uniqueId } = useRef(id || guid());
const inputHintId = useRef(legendHelp ? `${uniqueId}-hint` : undefined);

const {
children,
legend,
const { validationId, ariaDescribedBy } = useInputAccessibility({
id: uniqueId,
validationRedesignOptIn: true,
error,
warning,
info,
required,
isOptional,
legendInline,
legendWidth,
legendAlign = "left",
legendSpacing,
legendHelp,
tooltipPosition,
inline,
} = props;
});

const combinedAriaDescribedBy = [ariaDescribedBy, inputHintId.current]
.filter(Boolean)
.join(" ");

return (
<>
{validationRedesignOptIn ? (
<Fieldset
id={uniqueId}
legend={legend}
inline={legendInline}
legendWidth={legendWidth}
legendAlign={legendAlign}
legendSpacing={legendSpacing}
error={error}
warning={warning}
isRequired={required}
isOptional={isOptional}
{...tagComponent("checkboxgroup", props)}
aria-describedby={combinedAriaDescribedBy}
{...tagComponent("checkboxgroup", rest)}
blockGroupBehaviour={!(error || warning)}
{...filterStyledSystemMarginProps(props)}
{...filterStyledSystemMarginProps(rest)}
>
{legendHelp && <StyledHintText>{legendHelp}</StyledHintText>}
{legendHelp && (
<StyledHintText id={inputHintId.current}>
{legendHelp}
</StyledHintText>
)}
<Box position="relative">
<ValidationMessage error={error} warning={warning} />
<ValidationMessage
error={error}
warning={warning}
validationId={validationId}
/>
{(error || warning) && (
<ErrorBorder warning={!!(!error && warning)} inline={inline} />
)}
<StyledCheckboxGroup
data-component="checkbox-group"
data-role="checkbox-group"
legendInline={legendInline}
inline={inline}
>
<CheckboxGroupContext.Provider
Expand All @@ -108,6 +135,7 @@ export const CheckboxGroup = (props: CheckboxGroupProps) => {
) : (
<TooltipProvider tooltipPosition={tooltipPosition}>
<Fieldset
id={uniqueId}
legend={legend}
inline={legendInline}
legendWidth={legendWidth}
Expand All @@ -118,9 +146,11 @@ export const CheckboxGroup = (props: CheckboxGroupProps) => {
info={info}
isRequired={required}
isOptional={isOptional}
{...tagComponent("checkboxgroup", props)}
aria-describedby={ariaDescribedBy}
validationId={validationId}
{...tagComponent("checkboxgroup", rest)}
blockGroupBehaviour={!(error || warning || info)}
{...filterStyledSystemMarginProps(props)}
{...filterStyledSystemMarginProps(rest)}
>
<StyledCheckboxGroup
data-component="checkbox-group"
Expand Down
114 changes: 88 additions & 26 deletions src/components/checkbox/checkbox-group/checkbox-group.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,6 @@ test("should render with the provided legend", () => {
expect(screen.getByText("legend")).toBeVisible();
});

test("should render legendHelp as a hint text when validationRedesignOptIn is true", () => {
render(
<CarbonProvider validationRedesignOptIn>
<CheckboxGroup legend="legend" legendHelp="legendHelp">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>
</CarbonProvider>,
);

expect(screen.getByText("legendHelp")).toBeVisible();
});

test("should render required checkbox children when required prop is set", () => {
render(
<CheckboxGroup legend="legend" required>
Expand Down Expand Up @@ -66,28 +54,37 @@ it("should append (optional) text on the legend when isOptional prop is set", ()
);
});

test("should render error message when error prop is set and validationRedesignOptIn is true", () => {
it("should render with accessible description when `error` prop is set", () => {
render(
<CarbonProvider validationRedesignOptIn>
<CheckboxGroup legend="legend" error="error">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>
</CarbonProvider>,
<CheckboxGroup legend="legend" error="error message">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>,
);

expect(screen.getByText("error")).toBeVisible();
const fieldset = screen.getByRole("group", { name: "legend" });
expect(fieldset).toHaveAccessibleDescription("error message");
});

test("should render warning message when warning prop is set and validationRedesignOptIn is true", () => {
it("should render with accessible description when `warning` prop is set", () => {
render(
<CarbonProvider validationRedesignOptIn>
<CheckboxGroup legend="legend" warning="warning">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>
</CarbonProvider>,
<CheckboxGroup legend="legend" warning="warning message">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>,
);

const fieldset = screen.getByRole("group", { name: "legend" });
expect(fieldset).toHaveAccessibleDescription("warning message");
});

it("should render with accessible description when `info` prop is set", () => {
render(
<CheckboxGroup legend="legend" info="info message">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>,
);

expect(screen.getByText("warning")).toBeVisible();
const fieldset = screen.getByRole("group", { name: "legend" });
expect(fieldset).toHaveAccessibleDescription("info message");
});

test("should render with expected styles when legendInline is true", () => {
Expand Down Expand Up @@ -121,6 +118,71 @@ test("should render with expected styles when inline is true", () => {
});
});

describe("when the `validationRedesignOptIn` flag is true", () => {
it("should render `legendHelp` as a hint text", () => {
render(
<CarbonProvider validationRedesignOptIn>
<CheckboxGroup legend="legend" legendHelp="legendHelp">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>
</CarbonProvider>,
);

const fieldset = screen.getByRole("group", { name: "legend" });

expect(screen.getByText("legendHelp")).toBeVisible();
expect(fieldset).toHaveAccessibleDescription("legendHelp");
});

it("should render with error message when `error` prop is set", () => {
render(
<CarbonProvider validationRedesignOptIn>
<CheckboxGroup legend="legend" error="error message">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>
</CarbonProvider>,
);

const fieldset = screen.getByRole("group", { name: "legend" });

expect(screen.getByText("error message")).toBeVisible();
expect(fieldset).toHaveAccessibleDescription("error message");
});

it("should render with warning message when `warning` prop is set", () => {
render(
<CarbonProvider validationRedesignOptIn>
<CheckboxGroup legend="legend" warning="warning message">
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>
</CarbonProvider>,
);

const fieldset = screen.getByRole("group", { name: "legend" });

expect(screen.getByText("warning message")).toBeVisible();
expect(fieldset).toHaveAccessibleDescription("warning message");
});

it("should render with combined validation and legendHelp messages as the fieldset's accessible description", () => {
render(
<CarbonProvider validationRedesignOptIn>
<CheckboxGroup
legend="legend"
legendHelp="legendHelp"
error="error message"
>
<Checkbox value="1" label="label" onChange={() => {}} />
</CheckboxGroup>
</CarbonProvider>,
);

const fieldset = screen.getByRole("group", { name: "legend" });

expect(fieldset).toHaveAccessibleDescription("error message legendHelp");
});
});

testStyledSystemMargin(
(props) => (
<CheckboxGroup
Expand Down
Loading
Loading