Skip to content

Commit

Permalink
feat(numeral-date): update component to render as a fieldset element
Browse files Browse the repository at this point in the history
Updates NumeralDate component to render as a fieldset element.
  • Loading branch information
nuria1110 committed Nov 20, 2024
1 parent d95f27b commit 053a581
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 214 deletions.
45 changes: 37 additions & 8 deletions src/__internal__/fieldset/fieldset.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import {
StyledFieldset,
StyledLegend,
StyledLegendContent,
StyledIconWrapper,
} from "./fieldset.style";
import ValidationIcon from "../validations/validation-icon.component";
import NewValidationContext from "../../components/carbon-provider/__internal__/new-validation.context";
import { InputGroupBehaviour, InputGroupContext } from "../input-behaviour";
import useFormSpacing from "../../hooks/__internal__/useFormSpacing";
import Help from "../../components/help";

export interface FieldsetProps extends MarginProps {
/** Role */
Expand Down Expand Up @@ -54,6 +56,8 @@ export interface FieldsetProps extends MarginProps {
name?: string;
/** Set an id value on the component */
id?: string;
/** Content for the Help tooltip */
labelHelp?: React.ReactNode;
}

const Fieldset = ({
Expand All @@ -71,11 +75,13 @@ const Fieldset = ({
legendMargin = {},
isDisabled,
isOptional,
labelHelp,
...rest
}: FieldsetProps) => {
const { validationRedesignOptIn } = useContext(NewValidationContext);
const marginProps = useFormSpacing(rest);
const [ref, setRef] = useState<HTMLFieldSetElement | null>(null);
const [isFocused, setFocus] = useState(false);

useEffect(() => {
if (ref && isRequired) {
Expand All @@ -87,6 +93,36 @@ const Fieldset = ({
}
}, [ref, isRequired]);

const tooltipIcon = () => {
if (error || warning || info) {
return (
<StyledIconWrapper>
<ValidationIcon
error={error}
warning={warning}
info={info}
tooltipFlipOverrides={["top", "bottom"]}
/>
</StyledIconWrapper>
);
}

const helpProps = {
onFocus: () => setFocus(true),
onBlur: () => setFocus(false),
};

if (labelHelp) {
return (
<StyledIconWrapper {...helpProps}>
<Help isFocused={isFocused}>{labelHelp}</Help>
</StyledIconWrapper>
);
}

return null;
};

return (
<InputGroupBehaviour blockGroupBehaviour={blockGroupBehaviour}>
<StyledFieldset
Expand Down Expand Up @@ -115,14 +151,7 @@ const Fieldset = ({
isDisabled={isDisabled}
>
{legend}
{!validationRedesignOptIn && (
<ValidationIcon
error={error}
warning={warning}
info={info}
tooltipFlipOverrides={["top", "bottom"]}
/>
)}
{!validationRedesignOptIn && tooltipIcon()}
</StyledLegendContent>
</StyledLegend>
)}
Expand Down
6 changes: 5 additions & 1 deletion src/__internal__/fieldset/fieldset.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,8 @@ const StyledLegend = styled.legend<StyledLegendProps>`
${margin}
`;

export { StyledFieldset, StyledLegend, StyledLegendContent };
const StyledIconWrapper = styled.div`
margin-left: var(--spacing050);
`;

export { StyledFieldset, StyledLegend, StyledLegendContent, StyledIconWrapper };
27 changes: 27 additions & 0 deletions src/__internal__/fieldset/fieldset.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,33 @@ test("renders validation icon when `legend` and `info` are provided", () => {
expect(icon).toBeVisible();
});

test("renders help icon when `labelHelp` is provided", () => {
render(
<Fieldset legend="Legend" labelHelp="label help">
<input />
</Fieldset>,
);

const help = screen.getByRole("button", { name: "help" });

expect(help).toBeVisible();
});

// coverage - tested in Help component
test("sets `aria-describedby` on help icon as tooltip content when focused and removes it on blur", () => {
render(
<Fieldset legend="Legend" labelHelp="label help">
<input />
</Fieldset>,
);

const help = screen.getByRole("button", { name: "help" });
help.focus();
expect(help).toHaveAccessibleDescription("label help");
help.blur();
expect(help).not.toHaveAttribute("aria-describedby");
});

// coverage
test("renders legend with provided `legendWidth` when `inline` is true", () => {
render(
Expand Down
66 changes: 41 additions & 25 deletions src/components/numeral-date/numeral-date-test.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,50 @@ import CarbonProvider from "../carbon-provider";

export default {
title: "Numeral Date/Test",
component: NumeralDate,
parameters: {
info: { disable: true },
chromatic: {
disableSnapshot: true,
},
controls: {
exclude: [
"value",
"defaultValue",
"onChange",
"onBlur",
"dayRef",
"monthRef",
"yearRef",
],
},
},
argTypes: {
fieldHelp: {
control: {
type: "text",
},
},
labelHelp: {
control: {
type: "text",
},
},
error: {
control: {
type: "text",
},
},
warning: {
control: {
type: "text",
},
},
info: {
control: {
type: "text",
},
},
},
};

Expand Down Expand Up @@ -162,7 +201,7 @@ export const Validations = (args: NumeralDateProps<DayMonthDate>) => {

Validations.storyName = "validations";

export const NewDesignValidations = () => {
export const NewDesignValidations = (args: NumeralDateProps) => {
return (
<CarbonProvider validationRedesignOptIn>
<h4>New designs validation</h4>
Expand All @@ -174,6 +213,7 @@ export const NewDesignValidations = () => {
{...{ [validationType]: "Message" }}
size={size as NumeralDateProps["size"]}
m={4}
{...args}
/>
</div>
)),
Expand All @@ -184,30 +224,6 @@ export const NewDesignValidations = () => {

NewDesignValidations.storyName = "new design validations";

export const NewDesignValidationsWithLabelInline = () => {
return (
<CarbonProvider validationRedesignOptIn>
<h4>New designs validation</h4>
{["error", "warning"].map((validationType) =>
["small", "medium", "large"].map((size) => (
<div style={{ width: "296px" }} key={`${validationType}-${size}`}>
<NumeralDate
label={`${size} - ${validationType}`}
{...{ [validationType]: "Message" }}
size={size as NumeralDateProps["size"]}
m={4}
labelInline
/>
</div>
)),
)}
</CarbonProvider>
);
};

NewDesignValidationsWithLabelInline.storyName =
"new design validations with labelInline";

export const Required = () => {
return <NumeralDate label="Date of Birth" required />;
};
Expand Down
Loading

0 comments on commit 053a581

Please sign in to comment.