Skip to content

Commit 71449a5

Browse files
authored
Merge pull request #1828 from dxc-technology/gomezivann/breadcrumbs
New Breadcrumbs component
2 parents 8b295c2 + 1849ef6 commit 71449a5

File tree

17 files changed

+740
-83
lines changed

17 files changed

+740
-83
lines changed

lib/.storybook/components/ExampleContainer.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import React from "react";
22
import styled from "styled-components";
33

4+
type PseudoStates =
5+
| "pseudo-active"
6+
| "pseudo-focus"
7+
| "pseudo-focus-visible"
8+
| "pseudo-focus-within"
9+
| "pseudo-hover"
10+
| "pseudo-link"
11+
| "pseudo-target"
12+
| "pseudo-visited";
13+
414
type Props = {
515
children?: React.ReactNode;
6-
pseudoState?: string;
16+
pseudoState?: PseudoStates;
717
expanded?: boolean;
818
};
919

lib/package-lock.json

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
"@testing-library/react": "^13.0.0",
5757
"@testing-library/user-event": "^13.0.0",
5858
"@types/color": "^3.0.3",
59+
"@types/jest": "^29.5.12",
60+
"@types/jest-axe": "^3.5.9",
5961
"@types/react": "^18.0.18",
6062
"@types/styled-components": "5.1.29",
6163
"@types/uuid": "^9.0.6",
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from "react";
2+
import { render } from "@testing-library/react";
3+
import { axe } from "../../test/accessibility/axe-helper.js";
4+
import DxcBreadcrumbs from "./Breadcrumbs";
5+
import { disabledRules as rules } from "../../test/accessibility/rules/specific/breadcrumbs/disabledRules.js";
6+
7+
const disabledRules = {
8+
rules: rules.reduce((rulesObj, rule) => {
9+
rulesObj[rule] = { enabled: false };
10+
return rulesObj;
11+
}, {}),
12+
};
13+
14+
const items = [
15+
{
16+
label: "Home",
17+
href: "/",
18+
},
19+
{
20+
label: "User Menu",
21+
href: "",
22+
},
23+
{
24+
label: "Preferences",
25+
href: "",
26+
},
27+
{
28+
label: "Dark Mode",
29+
href: "",
30+
},
31+
];
32+
33+
describe("Breadcrumbs component accessibility tests", () => {
34+
it("Should not have basic accessibility issues", async () => {
35+
const { container } = render(<DxcBreadcrumbs items={items} ariaLabel="example" />);
36+
const results = await axe(container, disabledRules);
37+
expect(results).toHaveNoViolations();
38+
});
39+
it("Should not have basic accessibility issues when collapsed", async () => {
40+
const { container } = render(<DxcBreadcrumbs items={items} itemsBeforeCollapse={3} ariaLabel="example" />);
41+
const results = await axe(container, disabledRules);
42+
expect(results).toHaveNoViolations();
43+
});
44+
it("Should not have basic accessibility issues without root", async () => {
45+
const { container } = render(
46+
<DxcBreadcrumbs items={items} itemsBeforeCollapse={3} ariaLabel="example" showRoot={false} />
47+
);
48+
const results = await axe(container, disabledRules);
49+
expect(results).toHaveNoViolations();
50+
});
51+
});
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import React from "react";
2+
import Title from "../../.storybook/components/Title";
3+
import ExampleContainer from "../../.storybook/components/ExampleContainer";
4+
import DxcBreadcrumbs from "./Breadcrumbs";
5+
import DxcContainer from "../container/Container";
6+
import { HalstackProvider } from "../HalstackContext";
7+
import { userEvent, within } from "@storybook/testing-library";
8+
import { disabledRules } from "../../test/accessibility/rules/specific/breadcrumbs/disabledRules";
9+
import preview from "../../.storybook/preview";
10+
11+
export default {
12+
title: "Breadcrumbs",
13+
component: DxcBreadcrumbs,
14+
parameters: {
15+
a11y: {
16+
config: {
17+
rules: [
18+
...disabledRules.map((ruleId) => ({ id: ruleId, enabled: false })),
19+
...preview?.parameters?.a11y?.config?.rules,
20+
],
21+
},
22+
},
23+
},
24+
};
25+
26+
const items = [
27+
{
28+
label: "Home",
29+
href: "/",
30+
},
31+
{
32+
label: "User Menu",
33+
href: "",
34+
},
35+
{
36+
label: "Preferences",
37+
href: "",
38+
},
39+
{
40+
label: "Customization",
41+
href: "",
42+
},
43+
{
44+
label: "Dark Mode",
45+
href: "",
46+
},
47+
];
48+
49+
const Breadcrumbs = () => (
50+
<>
51+
<Title title="Default" theme="light" level={3} />
52+
<ExampleContainer>
53+
<DxcBreadcrumbs
54+
items={[
55+
{
56+
label: "Home",
57+
href: "/",
58+
},
59+
{
60+
label: "User Menu",
61+
href: "",
62+
},
63+
{
64+
label: "Preferences",
65+
href: "",
66+
},
67+
{
68+
label: "Dark Mode",
69+
href: "",
70+
},
71+
]}
72+
/>
73+
</ExampleContainer>
74+
<Title title="Collapsed variant" theme="light" level={3} />
75+
<ExampleContainer>
76+
<DxcBreadcrumbs items={items} />
77+
</ExampleContainer>
78+
<Title title="Collapsed variant without root" theme="light" level={3} />
79+
<ExampleContainer>
80+
<DxcBreadcrumbs items={items} showRoot={false} />
81+
</ExampleContainer>
82+
<Title title="Collapsed variant with dropdown menu opened" theme="light" level={3} />
83+
<ExampleContainer>
84+
<DxcContainer height="150px">
85+
<DxcBreadcrumbs items={items} />
86+
</DxcContainer>
87+
</ExampleContainer>
88+
<Title title="Focus state" theme="light" level={3} />
89+
<ExampleContainer pseudoState="pseudo-focus">
90+
<DxcBreadcrumbs items={items} />
91+
</ExampleContainer>
92+
<Title title="Hover state" theme="light" level={3} />
93+
<ExampleContainer pseudoState="pseudo-hover">
94+
<DxcBreadcrumbs items={items} />
95+
</ExampleContainer>
96+
<Title title="Active state" theme="light" level={3} />
97+
<ExampleContainer pseudoState="pseudo-active">
98+
<DxcBreadcrumbs items={items} />
99+
</ExampleContainer>
100+
<Title title="Truncation and text ellipsis with tooltip (only when collapsed)" theme="light" level={3} />
101+
<ExampleContainer>
102+
<DxcContainer width="200px">
103+
<DxcBreadcrumbs
104+
items={[
105+
{
106+
label: "Root",
107+
href: "/",
108+
},
109+
{
110+
label: "Main folder",
111+
href: "",
112+
},
113+
{
114+
label: "User",
115+
href: "",
116+
},
117+
{
118+
label: "Very long label for the link",
119+
href: "",
120+
},
121+
]}
122+
itemsBeforeCollapse={3}
123+
/>
124+
</DxcContainer>
125+
</ExampleContainer>
126+
<Title title="Truncation, text ellipsis with tooltip and without root" theme="light" level={3} />
127+
<ExampleContainer>
128+
<DxcContainer width="200px">
129+
<DxcBreadcrumbs
130+
items={[
131+
{
132+
label: "Root",
133+
href: "/",
134+
},
135+
{
136+
label: "Main folder",
137+
href: "",
138+
},
139+
{
140+
label: "User",
141+
href: "",
142+
},
143+
{
144+
label: "Very long label for the link",
145+
href: "",
146+
},
147+
]}
148+
itemsBeforeCollapse={3}
149+
showRoot={false}
150+
/>
151+
</DxcContainer>
152+
</ExampleContainer>
153+
<Title title="Dropdown theming doesn't affect the collapsed trigger" theme="light" level={3} />
154+
<ExampleContainer>
155+
<Title title="Opinionated theming" theme="light" level={4} />
156+
<ExampleContainer>
157+
<HalstackProvider
158+
theme={{
159+
dropdown: {
160+
baseColor: "#fabada",
161+
fontColor: "#999",
162+
optionFontColor: "#4d4d4d",
163+
},
164+
}}
165+
>
166+
<DxcBreadcrumbs items={items} itemsBeforeCollapse={3} />
167+
</HalstackProvider>
168+
</ExampleContainer>
169+
<Title title="Advanced theming" theme="light" level={4} />
170+
<ExampleContainer>
171+
<HalstackProvider
172+
advancedTheme={{
173+
dropdown: {
174+
buttonBackgroundColor: "#fabada",
175+
buttonHeight: "100px",
176+
buttonBorderThickness: "2px",
177+
buttonBorderStyle: "solid",
178+
buttonBorderColor: "#000",
179+
},
180+
}}
181+
>
182+
<DxcBreadcrumbs items={items} itemsBeforeCollapse={3} />
183+
</HalstackProvider>
184+
</ExampleContainer>
185+
</ExampleContainer>
186+
</>
187+
);
188+
189+
export const Chromatic = Breadcrumbs.bind({});
190+
Chromatic.play = async ({ canvasElement }) => {
191+
const canvas = within(canvasElement);
192+
const dropdowns = canvas.getAllByRole("button");
193+
await userEvent.click(dropdowns[2]);
194+
};

0 commit comments

Comments
 (0)