@orangesk/orange-design-system 2.0.0-beta.3 → 2.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/Accordion/tsconfig.tsbuildinfo +1 -1
- package/build/components/Alert/tsconfig.tsbuildinfo +1 -1
- package/build/components/AnchorNavigation/tsconfig.tsbuildinfo +1 -1
- package/build/components/Bar/tsconfig.tsbuildinfo +1 -1
- package/build/components/BlockAction/tsconfig.tsbuildinfo +1 -1
- package/build/components/BodyBanner/tsconfig.tsbuildinfo +1 -1
- package/build/components/Breadcrumbs/tsconfig.tsbuildinfo +1 -1
- package/build/components/Button/tsconfig.tsbuildinfo +1 -1
- package/build/components/Buttons/tsconfig.tsbuildinfo +1 -1
- package/build/components/Card/tsconfig.tsbuildinfo +1 -1
- package/build/components/Carousel/tsconfig.tsbuildinfo +1 -1
- package/build/components/CarouselHero/index.js +16 -0
- package/build/components/CarouselHero/index.js.map +1 -0
- package/build/components/CarouselHero/tsconfig.tsbuildinfo +1 -0
- package/build/components/CarouselPromotions/tsconfig.tsbuildinfo +1 -1
- package/build/components/CartTable/tsconfig.tsbuildinfo +1 -1
- package/build/components/Code/tsconfig.tsbuildinfo +1 -1
- package/build/components/Container/tsconfig.tsbuildinfo +1 -1
- package/build/components/Controls/tsconfig.tsbuildinfo +1 -1
- package/build/components/Cover/tsconfig.tsbuildinfo +1 -1
- package/build/components/Divider/tsconfig.tsbuildinfo +1 -1
- package/build/components/DocumentationSidebar/index.js +1 -1
- package/build/components/DocumentationSidebar/tsconfig.tsbuildinfo +1 -1
- package/build/components/Dropdown/tsconfig.tsbuildinfo +1 -1
- package/build/components/Expander/tsconfig.tsbuildinfo +1 -1
- package/build/components/FeatureAccordion/tsconfig.tsbuildinfo +1 -1
- package/build/components/Footer/tsconfig.tsbuildinfo +1 -1
- package/build/components/Forms/tsconfig.tsbuildinfo +1 -1
- package/build/components/Gauge/tsconfig.tsbuildinfo +1 -1
- package/build/components/Grid/tsconfig.tsbuildinfo +1 -1
- package/build/components/Hero/tsconfig.tsbuildinfo +1 -1
- package/build/components/Icon/tsconfig.tsbuildinfo +1 -1
- package/build/components/IconList/tsconfig.tsbuildinfo +1 -1
- package/build/components/Image/tsconfig.tsbuildinfo +1 -1
- package/build/components/Link/tsconfig.tsbuildinfo +1 -1
- package/build/components/List/tsconfig.tsbuildinfo +1 -1
- package/build/components/Loader/tsconfig.tsbuildinfo +1 -1
- package/build/components/Megamenu/tsconfig.tsbuildinfo +1 -1
- package/build/components/Modal/tsconfig.tsbuildinfo +1 -1
- package/build/components/Pagination/tsconfig.tsbuildinfo +1 -1
- package/build/components/Pill/tsconfig.tsbuildinfo +1 -1
- package/build/components/Preview/tsconfig.tsbuildinfo +1 -1
- package/build/components/Progress/tsconfig.tsbuildinfo +1 -1
- package/build/components/PromoBanner/tsconfig.tsbuildinfo +1 -1
- package/build/components/PromotionCard/tsconfig.tsbuildinfo +1 -1
- package/build/components/Section/tsconfig.tsbuildinfo +1 -1
- package/build/components/Skeleton/tsconfig.tsbuildinfo +1 -1
- package/build/components/SkipLink/tsconfig.tsbuildinfo +1 -1
- package/build/components/Stepbar/tsconfig.tsbuildinfo +1 -1
- package/build/components/Sticker/tsconfig.tsbuildinfo +1 -1
- package/build/components/Table/tsconfig.tsbuildinfo +1 -1
- package/build/components/Tabs/tsconfig.tsbuildinfo +1 -1
- package/build/components/Tag/tsconfig.tsbuildinfo +1 -1
- package/build/components/Testimonial/tsconfig.tsbuildinfo +1 -1
- package/build/components/Tile/tsconfig.tsbuildinfo +1 -1
- package/build/components/Tooltip/tsconfig.tsbuildinfo +1 -1
- package/build/components/index.js +6 -6
- package/build/components/index.js.map +1 -1
- package/build/components/static.js +4 -4
- package/build/components/static.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/src/components/CarouselHero/CarouselHero.d.ts +18 -0
- package/build/components/types/src/components/CarouselHero/CarouselHero.static.d.ts +47 -0
- package/build/components/types/src/components/CarouselHero/CarouselHeroItem.d.ts +9 -0
- package/build/components/types/src/components/CarouselHero/constants.d.ts +34 -0
- package/build/components/types/src/components/CarouselHero/index.d.ts +2 -0
- package/build/components/types/src/components/index.d.ts +2 -1
- package/build/components/types/src/scripts/index.d.ts +5 -0
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/scripts.js +4 -4
- package/build/lib/scripts.js.map +1 -1
- package/build/lib/style.css +1 -1
- package/build/lib/style.css.map +1 -1
- package/package.json +1 -1
- package/src/components/CarouselHero/CarouselHero.static.ts +528 -0
- package/src/components/CarouselHero/CarouselHero.tsx +148 -0
- package/src/components/CarouselHero/CarouselHeroItem.tsx +41 -0
- package/src/components/CarouselHero/constants.ts +37 -0
- package/src/components/CarouselHero/index.ts +2 -0
- package/src/components/CarouselHero/styles/config.scss +54 -0
- package/src/components/CarouselHero/styles/mixins.scss +289 -0
- package/src/components/CarouselHero/styles/style.scss +67 -0
- package/src/components/CarouselHero/tests/CarouselHero.conformance.test.js +148 -0
- package/src/components/CarouselHero/tests/CarouselHero.unit.test.js +289 -0
- package/src/components/CarouselHero/tests/CarouselHeroItem.conformance.test.js +142 -0
- package/src/components/CarouselHero/tests/CarouselHeroItem.unit.test.js +210 -0
- package/src/components/Controls/styles/config.scss +2 -2
- package/src/components/index.ts +2 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { render } from "@testing-library/react";
|
|
2
|
+
|
|
3
|
+
import { CarouselHero } from "../CarouselHero";
|
|
4
|
+
import { CarouselHeroItem } from "../CarouselHeroItem";
|
|
5
|
+
|
|
6
|
+
describe("rendering CarouselHero", () => {
|
|
7
|
+
describe("initial state", () => {
|
|
8
|
+
it("has default class carousel-hero", () => {
|
|
9
|
+
const { getByTestId } = render(<CarouselHero data-testid="test-id" />);
|
|
10
|
+
expect(getByTestId("test-id")).toHaveClass("carousel-hero");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("has data-carousel-hero attribute", () => {
|
|
14
|
+
const { container } = render(<CarouselHero />);
|
|
15
|
+
expect(container.querySelector(".carousel-hero")).toHaveAttribute(
|
|
16
|
+
"data-carousel-hero",
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("has default class carousel-hero__viewport-wrapper", () => {
|
|
21
|
+
const { container } = render(<CarouselHero />);
|
|
22
|
+
expect(
|
|
23
|
+
container.getElementsByClassName("carousel-hero__viewport-wrapper")
|
|
24
|
+
.length,
|
|
25
|
+
).toBe(1);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("has default class carousel-hero__viewport", () => {
|
|
29
|
+
const { container } = render(<CarouselHero />);
|
|
30
|
+
expect(
|
|
31
|
+
container.getElementsByClassName("carousel-hero__viewport").length,
|
|
32
|
+
).toBe(1);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("has default class carousel-hero__track", () => {
|
|
36
|
+
const { container } = render(<CarouselHero />);
|
|
37
|
+
expect(
|
|
38
|
+
container.getElementsByClassName("carousel-hero__track").length,
|
|
39
|
+
).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("has default class carousel-hero__controls", () => {
|
|
43
|
+
const { container } = render(<CarouselHero />);
|
|
44
|
+
expect(
|
|
45
|
+
container.getElementsByClassName("carousel-hero__controls").length,
|
|
46
|
+
).toBe(1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("has default class carousel-hero__navigation", () => {
|
|
50
|
+
const { container } = render(<CarouselHero />);
|
|
51
|
+
expect(
|
|
52
|
+
container.getElementsByClassName("carousel-hero__navigation").length,
|
|
53
|
+
).toBe(1);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("has default class carousel-hero__pagination", () => {
|
|
57
|
+
const { container } = render(<CarouselHero />);
|
|
58
|
+
expect(
|
|
59
|
+
container.getElementsByClassName("carousel-hero__pagination").length,
|
|
60
|
+
).toBe(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("renders navigation controls (prev/next)", () => {
|
|
64
|
+
const { container } = render(<CarouselHero />);
|
|
65
|
+
expect(
|
|
66
|
+
container.getElementsByClassName("carousel-hero__prev").length,
|
|
67
|
+
).toBe(1);
|
|
68
|
+
expect(
|
|
69
|
+
container.getElementsByClassName("carousel-hero__next").length,
|
|
70
|
+
).toBe(1);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("passed props", () => {
|
|
75
|
+
const tabs = [{ label: "Tab 1" }, { label: "Tab 2" }, { label: "Tab 3" }];
|
|
76
|
+
|
|
77
|
+
const children = (
|
|
78
|
+
<>
|
|
79
|
+
<CarouselHeroItem
|
|
80
|
+
key="slide-1"
|
|
81
|
+
title="Test Title 1"
|
|
82
|
+
image="https://placehold.co/720x560"
|
|
83
|
+
>
|
|
84
|
+
<p>Test content 1</p>
|
|
85
|
+
</CarouselHeroItem>
|
|
86
|
+
<CarouselHeroItem
|
|
87
|
+
key="slide-2"
|
|
88
|
+
title="Test Title 2"
|
|
89
|
+
image="https://placehold.co/720x560"
|
|
90
|
+
>
|
|
91
|
+
<p>Test content 2</p>
|
|
92
|
+
</CarouselHeroItem>
|
|
93
|
+
</>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
it("renders children slides", () => {
|
|
97
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
98
|
+
const slides = container.getElementsByClassName("carousel-hero__slide");
|
|
99
|
+
expect(slides.length).toBe(2);
|
|
100
|
+
expect(slides[0]).toHaveTextContent("Test Title 1");
|
|
101
|
+
expect(slides[1]).toHaveTextContent("Test Title 2");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("has additional class when className is set", () => {
|
|
105
|
+
const { getByTestId } = render(
|
|
106
|
+
<CarouselHero data-testid="test-id" className="test-class" />,
|
|
107
|
+
);
|
|
108
|
+
expect(getByTestId("test-id")).toHaveClass("carousel-hero");
|
|
109
|
+
expect(getByTestId("test-id")).toHaveClass("test-class");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("has is-light class when colorScheme is light", () => {
|
|
113
|
+
const { getByTestId } = render(
|
|
114
|
+
<CarouselHero data-testid="test-id" colorScheme="light" />,
|
|
115
|
+
);
|
|
116
|
+
expect(getByTestId("test-id")).toHaveClass("is-light");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("does not have is-light class by default", () => {
|
|
120
|
+
const { getByTestId } = render(<CarouselHero data-testid="test-id" />);
|
|
121
|
+
expect(getByTestId("test-id")).not.toHaveClass("is-light");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("renders tabs when tabs prop is provided", () => {
|
|
125
|
+
const { container } = render(
|
|
126
|
+
<CarouselHero tabs={tabs}>{children}</CarouselHero>,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const tabsContainer = container.querySelector(".carousel-hero__tabs");
|
|
130
|
+
expect(tabsContainer).toBeInTheDocument();
|
|
131
|
+
expect(tabsContainer).toHaveAttribute("role", "tablist");
|
|
132
|
+
|
|
133
|
+
const tabButtons = container.querySelectorAll(".carousel-hero__tab");
|
|
134
|
+
expect(tabButtons.length).toBe(3);
|
|
135
|
+
expect(tabButtons[0]).toHaveTextContent("Tab 1");
|
|
136
|
+
expect(tabButtons[1]).toHaveTextContent("Tab 2");
|
|
137
|
+
expect(tabButtons[2]).toHaveTextContent("Tab 3");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("does not render tabs when tabs prop is empty", () => {
|
|
141
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
142
|
+
|
|
143
|
+
const tabsContainer = container.querySelector(".carousel-hero__tabs");
|
|
144
|
+
expect(tabsContainer).not.toBeInTheDocument();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("sets proper ARIA attributes on tabs", () => {
|
|
148
|
+
const { container } = render(
|
|
149
|
+
<CarouselHero tabs={tabs}>{children}</CarouselHero>,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const tabButtons = container.querySelectorAll(".carousel-hero__tab");
|
|
153
|
+
|
|
154
|
+
// First tab should be active
|
|
155
|
+
expect(tabButtons[0]).toHaveAttribute("role", "tab");
|
|
156
|
+
expect(tabButtons[0]).toHaveAttribute("aria-selected", "true");
|
|
157
|
+
expect(tabButtons[0]).toHaveAttribute("tabIndex", "0");
|
|
158
|
+
|
|
159
|
+
// Other tabs should not be active
|
|
160
|
+
expect(tabButtons[1]).toHaveAttribute("aria-selected", "false");
|
|
161
|
+
expect(tabButtons[1]).toHaveAttribute("tabIndex", "-1");
|
|
162
|
+
expect(tabButtons[2]).toHaveAttribute("aria-selected", "false");
|
|
163
|
+
expect(tabButtons[2]).toHaveAttribute("tabIndex", "-1");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("shows play/pause button when interval is provided", () => {
|
|
167
|
+
const { container } = render(
|
|
168
|
+
<CarouselHero interval={3000}>{children}</CarouselHero>,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
expect(
|
|
172
|
+
container.getElementsByClassName("carousel-hero__play-pause").length,
|
|
173
|
+
).toBe(1);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("does not show play/pause button when interval is not provided", () => {
|
|
177
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
178
|
+
|
|
179
|
+
expect(
|
|
180
|
+
container.getElementsByClassName("carousel-hero__play-pause").length,
|
|
181
|
+
).toBe(0);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("does not show play/pause button when interval is 0", () => {
|
|
185
|
+
const { container } = render(
|
|
186
|
+
<CarouselHero interval={0}>{children}</CarouselHero>,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
expect(
|
|
190
|
+
container.getElementsByClassName("carousel-hero__play-pause").length,
|
|
191
|
+
).toBe(0);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("sets data-interval attribute when interval is provided", () => {
|
|
195
|
+
const { container } = render(
|
|
196
|
+
<CarouselHero interval={5000}>{children}</CarouselHero>,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const carousel = container.querySelector(".carousel-hero");
|
|
200
|
+
expect(carousel).toHaveAttribute("data-interval", "5000");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("does not set data-interval attribute when interval is not provided", () => {
|
|
204
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
205
|
+
|
|
206
|
+
const carousel = container.querySelector(".carousel-hero");
|
|
207
|
+
expect(carousel).not.toHaveAttribute("data-interval");
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe("swiperOptions prop", () => {
|
|
212
|
+
const children = (
|
|
213
|
+
<CarouselHeroItem
|
|
214
|
+
key="slide-1"
|
|
215
|
+
title="Test Title"
|
|
216
|
+
image="https://placehold.co/720x560"
|
|
217
|
+
>
|
|
218
|
+
<p>Test content</p>
|
|
219
|
+
</CarouselHeroItem>
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
it("sets data-swiper-options attribute when swiperOptions prop is provided", () => {
|
|
223
|
+
const swiperOptions = { speed: 500, loop: true };
|
|
224
|
+
const { container } = render(
|
|
225
|
+
<CarouselHero swiperOptions={swiperOptions}>{children}</CarouselHero>,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const carousel = container.querySelector(".carousel-hero");
|
|
229
|
+
expect(carousel.getAttribute("data-swiper-options")).toBe(
|
|
230
|
+
JSON.stringify(swiperOptions),
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("does not set data-swiper-options attribute when swiperOptions prop is not provided", () => {
|
|
235
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
236
|
+
|
|
237
|
+
const carousel = container.querySelector(".carousel-hero");
|
|
238
|
+
expect(carousel.hasAttribute("data-swiper-options")).toBe(false);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("Swiper integration", () => {
|
|
243
|
+
const children = (
|
|
244
|
+
<>
|
|
245
|
+
<CarouselHeroItem
|
|
246
|
+
key="slide-1"
|
|
247
|
+
title="Test Title 1"
|
|
248
|
+
image="https://placehold.co/720x560"
|
|
249
|
+
>
|
|
250
|
+
<p>Test content 1</p>
|
|
251
|
+
</CarouselHeroItem>
|
|
252
|
+
<CarouselHeroItem
|
|
253
|
+
key="slide-2"
|
|
254
|
+
title="Test Title 2"
|
|
255
|
+
image="https://placehold.co/720x560"
|
|
256
|
+
>
|
|
257
|
+
<p>Test content 2</p>
|
|
258
|
+
</CarouselHeroItem>
|
|
259
|
+
</>
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
it("track element uses carousel-hero__track class which maps to swiper-wrapper", () => {
|
|
263
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
264
|
+
expect(
|
|
265
|
+
container.querySelector(".carousel-hero__track"),
|
|
266
|
+
).toBeInTheDocument();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("slide elements use carousel-hero__slide class which maps to swiper-slide", () => {
|
|
270
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
271
|
+
const slides = container.getElementsByClassName("carousel-hero__slide");
|
|
272
|
+
expect(slides.length).toBe(2);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("viewport element uses carousel-hero__viewport class which maps to swiper-container", () => {
|
|
276
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
277
|
+
expect(
|
|
278
|
+
container.querySelector(".carousel-hero__viewport"),
|
|
279
|
+
).toBeInTheDocument();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("pagination element uses carousel-hero__pagination class which maps to swiper-pagination", () => {
|
|
283
|
+
const { container } = render(<CarouselHero>{children}</CarouselHero>);
|
|
284
|
+
expect(
|
|
285
|
+
container.querySelector(".carousel-hero__pagination"),
|
|
286
|
+
).toBeInTheDocument();
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { render } from "@testing-library/react";
|
|
2
|
+
import { axe } from "jest-axe";
|
|
3
|
+
|
|
4
|
+
import { CarouselHeroItem } from "../";
|
|
5
|
+
|
|
6
|
+
const basicExample = (
|
|
7
|
+
<CarouselHeroItem
|
|
8
|
+
title="Basic Slide Title"
|
|
9
|
+
image="https://placehold.co/720x560?text=Basic"
|
|
10
|
+
>
|
|
11
|
+
<p>Basic slide content</p>
|
|
12
|
+
</CarouselHeroItem>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const exampleWithButton = (
|
|
16
|
+
<CarouselHeroItem
|
|
17
|
+
title="Slide with Button"
|
|
18
|
+
image="https://placehold.co/720x560?text=Button"
|
|
19
|
+
>
|
|
20
|
+
<p>This slide has interactive content.</p>
|
|
21
|
+
<button type="button">Click me</button>
|
|
22
|
+
</CarouselHeroItem>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const exampleWithComplexContent = (
|
|
26
|
+
<CarouselHeroItem
|
|
27
|
+
title="Complex Content Slide"
|
|
28
|
+
image="https://placehold.co/720x560?text=Complex"
|
|
29
|
+
>
|
|
30
|
+
<p>This slide contains various content types:</p>
|
|
31
|
+
<ul>
|
|
32
|
+
<li>List item 1</li>
|
|
33
|
+
<li>List item 2</li>
|
|
34
|
+
<li>List item 3</li>
|
|
35
|
+
</ul>
|
|
36
|
+
<div>
|
|
37
|
+
<button type="button">Primary Action</button>
|
|
38
|
+
<button type="button">Secondary Action</button>
|
|
39
|
+
</div>
|
|
40
|
+
</CarouselHeroItem>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const exampleWithLongTitle = (
|
|
44
|
+
<CarouselHeroItem
|
|
45
|
+
title="This is a Very Long Title That Should Still Be Accessible and Properly Rendered"
|
|
46
|
+
image="https://placehold.co/720x560?text=Long+Title"
|
|
47
|
+
>
|
|
48
|
+
<p>Content for slide with long title.</p>
|
|
49
|
+
</CarouselHeroItem>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const exampleWithSpecialCharacters = (
|
|
53
|
+
<CarouselHeroItem
|
|
54
|
+
title="Špeciálny Titul s Diakritikou & Symbolmi €"
|
|
55
|
+
image="https://placehold.co/720x560?text=Special+Chars"
|
|
56
|
+
>
|
|
57
|
+
<p>Obsah so špeciálnymi znakmi: áéíóúôäňľščťžý.</p>
|
|
58
|
+
<p>Mathematical symbols: ∑ ∞ ± × ÷</p>
|
|
59
|
+
</CarouselHeroItem>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const exampleWithCustomClassName = (
|
|
63
|
+
<CarouselHeroItem
|
|
64
|
+
className="custom-slide-class"
|
|
65
|
+
title="Custom Styled Slide"
|
|
66
|
+
image="https://placehold.co/720x560?text=Custom"
|
|
67
|
+
>
|
|
68
|
+
<p>This slide has custom styling.</p>
|
|
69
|
+
</CarouselHeroItem>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
describe("CarouselHeroItem conformance", () => {
|
|
73
|
+
it("is valid html", () => {
|
|
74
|
+
const { container } = render(basicExample);
|
|
75
|
+
expect(container).toHTMLValidate();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("is accessible", async () => {
|
|
79
|
+
const { container } = render(basicExample);
|
|
80
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("CarouselHeroItem with button conformance", () => {
|
|
85
|
+
it("is valid html", () => {
|
|
86
|
+
const { container } = render(exampleWithButton);
|
|
87
|
+
expect(container).toHTMLValidate();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("is accessible", async () => {
|
|
91
|
+
const { container } = render(exampleWithButton);
|
|
92
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("CarouselHeroItem with complex content conformance", () => {
|
|
97
|
+
it("is valid html", () => {
|
|
98
|
+
const { container } = render(exampleWithComplexContent);
|
|
99
|
+
expect(container).toHTMLValidate();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("is accessible", async () => {
|
|
103
|
+
const { container } = render(exampleWithComplexContent);
|
|
104
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("CarouselHeroItem with long title conformance", () => {
|
|
109
|
+
it("is valid html", () => {
|
|
110
|
+
const { container } = render(exampleWithLongTitle);
|
|
111
|
+
expect(container).toHTMLValidate();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("is accessible", async () => {
|
|
115
|
+
const { container } = render(exampleWithLongTitle);
|
|
116
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe("CarouselHeroItem with special characters conformance", () => {
|
|
121
|
+
it("is valid html", () => {
|
|
122
|
+
const { container } = render(exampleWithSpecialCharacters);
|
|
123
|
+
expect(container).toHTMLValidate();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("is accessible", async () => {
|
|
127
|
+
const { container } = render(exampleWithSpecialCharacters);
|
|
128
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("CarouselHeroItem with custom class conformance", () => {
|
|
133
|
+
it("is valid html", () => {
|
|
134
|
+
const { container } = render(exampleWithCustomClassName);
|
|
135
|
+
expect(container).toHTMLValidate();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("is accessible", async () => {
|
|
139
|
+
const { container } = render(exampleWithCustomClassName);
|
|
140
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { render } from "@testing-library/react";
|
|
2
|
+
|
|
3
|
+
import { CarouselHeroItem } from "../CarouselHeroItem";
|
|
4
|
+
|
|
5
|
+
describe("rendering CarouselHeroItem", () => {
|
|
6
|
+
describe("initial state", () => {
|
|
7
|
+
it("has default class carousel-hero__slide", () => {
|
|
8
|
+
const { getByTestId } = render(
|
|
9
|
+
<CarouselHeroItem
|
|
10
|
+
data-testid="test-id"
|
|
11
|
+
title="Test Title"
|
|
12
|
+
image="https://placehold.co/720x560"
|
|
13
|
+
/>,
|
|
14
|
+
);
|
|
15
|
+
expect(getByTestId("test-id")).toHaveClass("carousel-hero__slide");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("has bg-black class by default", () => {
|
|
19
|
+
const { getByTestId } = render(
|
|
20
|
+
<CarouselHeroItem
|
|
21
|
+
data-testid="test-id"
|
|
22
|
+
title="Test Title"
|
|
23
|
+
image="https://placehold.co/720x560"
|
|
24
|
+
/>,
|
|
25
|
+
);
|
|
26
|
+
expect(getByTestId("test-id")).toHaveClass("bg-black");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("renders slide content container", () => {
|
|
30
|
+
const { container } = render(
|
|
31
|
+
<CarouselHeroItem
|
|
32
|
+
title="Test Title"
|
|
33
|
+
image="https://placehold.co/720x560"
|
|
34
|
+
/>,
|
|
35
|
+
);
|
|
36
|
+
expect(
|
|
37
|
+
container.getElementsByClassName("carousel-hero__slide-content").length,
|
|
38
|
+
).toBe(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("renders slide title", () => {
|
|
42
|
+
const { container } = render(
|
|
43
|
+
<CarouselHeroItem
|
|
44
|
+
title="Test Title"
|
|
45
|
+
image="https://placehold.co/720x560"
|
|
46
|
+
/>,
|
|
47
|
+
);
|
|
48
|
+
const titleElement = container.querySelector(
|
|
49
|
+
".carousel-hero__slide-title",
|
|
50
|
+
);
|
|
51
|
+
expect(titleElement).toBeInTheDocument();
|
|
52
|
+
expect(titleElement).toHaveTextContent("Test Title");
|
|
53
|
+
expect(titleElement.tagName).toBe("H1");
|
|
54
|
+
expect(titleElement).toHaveClass("h1");
|
|
55
|
+
expect(titleElement).toHaveClass("thin");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("renders image with proper attributes", () => {
|
|
59
|
+
const imageUrl = "https://placehold.co/720x560";
|
|
60
|
+
const title = "Test Title";
|
|
61
|
+
const { container } = render(
|
|
62
|
+
<CarouselHeroItem title={title} image={imageUrl} />,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const imageElement = container.querySelector(
|
|
66
|
+
".carousel-hero__slide-image",
|
|
67
|
+
);
|
|
68
|
+
expect(imageElement).toBeInTheDocument();
|
|
69
|
+
expect(imageElement).toHaveAttribute("src", imageUrl);
|
|
70
|
+
expect(imageElement).toHaveAttribute("alt", `Obrázok ${title}`);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("passed props", () => {
|
|
75
|
+
it("renders children content", () => {
|
|
76
|
+
const { getByText } = render(
|
|
77
|
+
<CarouselHeroItem
|
|
78
|
+
title="Test Title"
|
|
79
|
+
image="https://placehold.co/720x560"
|
|
80
|
+
>
|
|
81
|
+
<p>Test content</p>
|
|
82
|
+
<button>Test button</button>
|
|
83
|
+
</CarouselHeroItem>,
|
|
84
|
+
);
|
|
85
|
+
expect(getByText("Test content")).toBeInTheDocument();
|
|
86
|
+
expect(getByText("Test button")).toBeInTheDocument();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("has additional class when className is set", () => {
|
|
90
|
+
const { getByTestId } = render(
|
|
91
|
+
<CarouselHeroItem
|
|
92
|
+
data-testid="test-id"
|
|
93
|
+
className="test-class"
|
|
94
|
+
title="Test Title"
|
|
95
|
+
image="https://placehold.co/720x560"
|
|
96
|
+
/>,
|
|
97
|
+
);
|
|
98
|
+
expect(getByTestId("test-id")).toHaveClass("carousel-hero__slide");
|
|
99
|
+
expect(getByTestId("test-id")).toHaveClass("bg-black");
|
|
100
|
+
expect(getByTestId("test-id")).toHaveClass("test-class");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("passes through other HTML attributes", () => {
|
|
104
|
+
const { getByTestId } = render(
|
|
105
|
+
<CarouselHeroItem
|
|
106
|
+
data-testid="test-id"
|
|
107
|
+
id="custom-id"
|
|
108
|
+
role="tabpanel"
|
|
109
|
+
title="Test Title"
|
|
110
|
+
image="https://placehold.co/720x560"
|
|
111
|
+
/>,
|
|
112
|
+
);
|
|
113
|
+
expect(getByTestId("test-id")).toHaveAttribute("id", "custom-id");
|
|
114
|
+
expect(getByTestId("test-id")).toHaveAttribute("role", "tabpanel");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("renders with different title text", () => {
|
|
118
|
+
const customTitle = "Custom Hero Title";
|
|
119
|
+
const { container } = render(
|
|
120
|
+
<CarouselHeroItem
|
|
121
|
+
title={customTitle}
|
|
122
|
+
image="https://placehold.co/720x560"
|
|
123
|
+
/>,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const titleElement = container.querySelector(
|
|
127
|
+
".carousel-hero__slide-title",
|
|
128
|
+
);
|
|
129
|
+
expect(titleElement).toHaveTextContent(customTitle);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("renders with different image source", () => {
|
|
133
|
+
const customImage = "https://example.com/custom-image.jpg";
|
|
134
|
+
const title = "Test Title";
|
|
135
|
+
const { container } = render(
|
|
136
|
+
<CarouselHeroItem title={title} image={customImage} />,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const imageElement = container.querySelector(
|
|
140
|
+
".carousel-hero__slide-image",
|
|
141
|
+
);
|
|
142
|
+
expect(imageElement).toHaveAttribute("src", customImage);
|
|
143
|
+
expect(imageElement).toHaveAttribute("alt", `Obrázok ${title}`);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("handles special characters in title for image alt text", () => {
|
|
147
|
+
const titleWithSpecialChars = "Špeciálny Titul s Diakritikou & Symbolmi";
|
|
148
|
+
const { container } = render(
|
|
149
|
+
<CarouselHeroItem
|
|
150
|
+
title={titleWithSpecialChars}
|
|
151
|
+
image="https://placehold.co/720x560"
|
|
152
|
+
/>,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const imageElement = container.querySelector(
|
|
156
|
+
".carousel-hero__slide-image",
|
|
157
|
+
);
|
|
158
|
+
expect(imageElement).toHaveAttribute(
|
|
159
|
+
"alt",
|
|
160
|
+
`Obrázok ${titleWithSpecialChars}`,
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("renders children in proper content container", () => {
|
|
165
|
+
const { container } = render(
|
|
166
|
+
<CarouselHeroItem
|
|
167
|
+
title="Test Title"
|
|
168
|
+
image="https://placehold.co/720x560"
|
|
169
|
+
>
|
|
170
|
+
<p data-testid="child-content">Child content</p>
|
|
171
|
+
</CarouselHeroItem>,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const contentContainer = container.querySelector(
|
|
175
|
+
".carousel-hero__slide-content",
|
|
176
|
+
);
|
|
177
|
+
const childContent = container.querySelector(
|
|
178
|
+
"[data-testid='child-content']",
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(contentContainer).toContainElement(childContent);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("maintains proper DOM structure", () => {
|
|
185
|
+
const { container } = render(
|
|
186
|
+
<CarouselHeroItem
|
|
187
|
+
title="Test Title"
|
|
188
|
+
image="https://placehold.co/720x560"
|
|
189
|
+
>
|
|
190
|
+
<p>Content</p>
|
|
191
|
+
</CarouselHeroItem>,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const slide = container.querySelector(".carousel-hero__slide");
|
|
195
|
+
const slideContent = container.querySelector(
|
|
196
|
+
".carousel-hero__slide-content",
|
|
197
|
+
);
|
|
198
|
+
const slideTitle = container.querySelector(".carousel-hero__slide-title");
|
|
199
|
+
const slideImage = container.querySelector(".carousel-hero__slide-image");
|
|
200
|
+
|
|
201
|
+
// Check that slide contains both content and image
|
|
202
|
+
expect(slide).toContainElement(slideContent);
|
|
203
|
+
expect(slide).toContainElement(slideImage);
|
|
204
|
+
|
|
205
|
+
// Check that slide content contains title and children
|
|
206
|
+
expect(slideContent).toContainElement(slideTitle);
|
|
207
|
+
expect(slideContent).toHaveTextContent("Content");
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
@@ -22,8 +22,8 @@ $base: (
|
|
|
22
22
|
$states: (
|
|
23
23
|
default: (
|
|
24
24
|
color: var(--color-text-default),
|
|
25
|
-
background-color: var(--color-fill-
|
|
26
|
-
border-color: var(--color-fill-
|
|
25
|
+
background-color: var(--color-fill-moderate),
|
|
26
|
+
border-color: var(--color-fill-moderate),
|
|
27
27
|
),
|
|
28
28
|
hover: (
|
|
29
29
|
color: var(--color-text-inverse),
|
package/src/components/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "./Button";
|
|
21
21
|
import { Buttons } from "./Buttons";
|
|
22
22
|
import { Carousel } from "./Carousel";
|
|
23
|
+
import { CarouselHero } from "./CarouselHero";
|
|
23
24
|
import { CarouselPromotions } from "./CarouselPromotions";
|
|
24
25
|
import { CartTable } from "./CartTable";
|
|
25
26
|
import { Container } from "./Container";
|
|
@@ -114,6 +115,7 @@ export {
|
|
|
114
115
|
CardProductHeader,
|
|
115
116
|
CardSection,
|
|
116
117
|
Carousel,
|
|
118
|
+
CarouselHero,
|
|
117
119
|
CarouselPromotions,
|
|
118
120
|
CartTable,
|
|
119
121
|
Checkbox,
|