@orangesk/orange-design-system 2.0.0-beta.7 → 2.0.0-beta.9
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/index.js +4 -4
- package/build/components/index.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/index.d.ts +12 -8
- package/build/components/types/src/components/AnchorNavigation/AnchorNavigation.d.ts +1 -1
- package/build/components/types/src/components/AnchorNavigation/AnchorNavigation.static.d.ts +19 -17
- package/build/components/types/src/components/Button/Button.d.ts +1 -0
- package/build/components/types/src/components/Card/Card.d.ts +2 -1
- package/build/components/types/src/components/Carousel/Carousel.d.ts +4 -0
- package/build/components/types/src/components/Carousel/Carousel.static.d.ts +1 -0
- package/build/components/types/src/components/Carousel/constants.d.ts +2 -0
- package/build/components/types/src/components/Megamenu/constants.d.ts +2 -0
- package/build/components/types/src/components/Pill/Pill.d.ts +1 -1
- package/build/components/types/src/components/PromoBanner/PromoBanner.d.ts +3 -5
- package/build/components/types/src/scripts/index.d.ts +5 -0
- package/build/lib/after-components.css +1 -1
- package/build/lib/after-components.css.map +1 -1
- package/build/lib/before-components.css +1 -1
- package/build/lib/before-components.css.map +1 -1
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/megamenu.css +1 -1
- package/build/lib/megamenu.css.map +1 -1
- package/build/lib/megamenu.js +1 -1
- package/build/lib/megamenu.js.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/build/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/src/components/AnchorNavigation/AnchorNavigation.static.ts +253 -73
- package/src/components/AnchorNavigation/AnchorNavigation.tsx +31 -24
- package/src/components/AnchorNavigation/styles/mixins.scss +14 -17
- package/src/components/AnchorNavigation/tests/AnchorNavigation.conformance.test.js +67 -0
- package/src/components/AnchorNavigation/tests/AnchorNavigation.unit.test.js +163 -0
- package/src/components/BlockAction/styles/mixins.scss +0 -6
- package/src/components/Button/Button.tsx +2 -0
- package/src/components/Button/styles/mixins.scss +5 -0
- package/src/components/Button/styles/style.scss +4 -0
- package/src/components/Card/Card.tsx +5 -1
- package/src/components/Card/styles/style.scss +4 -0
- package/src/components/Carousel/Carousel.static.ts +67 -1
- package/src/components/Carousel/Carousel.tsx +41 -19
- package/src/components/Carousel/constants.ts +2 -0
- package/src/components/Carousel/styles/config.scss +1 -2
- package/src/components/Carousel/styles/mixins.scss +35 -2
- package/src/components/Carousel/styles/style.scss +8 -0
- package/src/components/Icon/styles/style.scss +11 -0
- package/src/components/Icon/tests/Pictogram.unit.test.js +38 -0
- package/src/components/Link/styles/style.scss +1 -1
- package/src/components/Link/tests/Link.conformance.test.js +5 -20
- package/src/components/Link/tests/Link.unit.test.js +1 -10
- package/src/components/Megamenu/Megamenu.static.ts +2 -0
- package/src/components/Megamenu/Megamenu.tsx +671 -665
- package/src/components/Megamenu/MegamenuBlog.tsx +187 -183
- package/src/components/Megamenu/constants.ts +2 -0
- package/src/components/Megamenu/styles/mixins.scss +30 -1
- package/src/components/Megamenu/styles/style.scss +8 -0
- package/src/components/Pill/Pill.tsx +1 -1
- package/src/components/Pill/styles/config.scss +4 -0
- package/src/components/Preview/PreviewGenerator.tsx +48 -21
- package/src/components/PromoBanner/PromoBanner.tsx +14 -26
- package/src/components/PromoBanner/styles/mixins.scss +20 -21
- package/src/components/PromoBanner/styles/style.scss +0 -6
- package/src/styles/base/globals.scss +19 -0
- package/src/styles/utilities/color.scss +94 -20
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { render } from "@testing-library/react";
|
|
2
|
+
|
|
3
|
+
import { AnchorNavigation } from "../AnchorNavigation";
|
|
4
|
+
|
|
5
|
+
const basicItems = [
|
|
6
|
+
{ label: "Key Features", href: "#features", isActive: true },
|
|
7
|
+
{ label: "Pricing", href: "#pricing" },
|
|
8
|
+
{ label: "Getting Started", href: "#getting-started" },
|
|
9
|
+
{ label: "Contact", href: "#contact" },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const moreItems = [
|
|
13
|
+
{ label: "Overview", href: "#overview", isActive: true },
|
|
14
|
+
{ label: "Features", href: "#features" },
|
|
15
|
+
{ label: "Documentation", href: "#docs" },
|
|
16
|
+
{ label: "API Reference", href: "#api" },
|
|
17
|
+
{ label: "Examples", href: "#examples" },
|
|
18
|
+
{ label: "Support", href: "#support" },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
describe("rendering AnchorNavigation", () => {
|
|
22
|
+
describe("initial state", () => {
|
|
23
|
+
it("has default class anchor-navigation", () => {
|
|
24
|
+
const { getByTestId } = render(
|
|
25
|
+
<AnchorNavigation data-testid="test-id" items={basicItems} />,
|
|
26
|
+
);
|
|
27
|
+
expect(getByTestId("test-id")).toHaveClass("anchor-navigation");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("has data-anchor-navigation attribute", () => {
|
|
31
|
+
const { getByTestId } = render(
|
|
32
|
+
<AnchorNavigation data-testid="test-id" items={basicItems} />,
|
|
33
|
+
);
|
|
34
|
+
expect(getByTestId("test-id")).toHaveAttribute("data-anchor-navigation");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("renders container with anchor-navigation__content class", () => {
|
|
38
|
+
const { container } = render(<AnchorNavigation items={basicItems} />);
|
|
39
|
+
expect(
|
|
40
|
+
container.querySelector(".anchor-navigation__content"),
|
|
41
|
+
).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("renders grid with correct classes", () => {
|
|
45
|
+
const { container } = render(<AnchorNavigation items={basicItems} />);
|
|
46
|
+
const grid = container.querySelector(".anchor-navigation__content-left");
|
|
47
|
+
expect(grid).toBeInTheDocument();
|
|
48
|
+
expect(grid).toHaveClass("list-inline");
|
|
49
|
+
expect(grid).toHaveClass("horizontal-scroll");
|
|
50
|
+
expect(grid).toHaveClass("mb-none");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("passed props", () => {
|
|
55
|
+
it("renders all navigation items", () => {
|
|
56
|
+
const { getByText } = render(<AnchorNavigation items={basicItems} />);
|
|
57
|
+
|
|
58
|
+
expect(getByText("Key Features")).toBeInTheDocument();
|
|
59
|
+
expect(getByText("Pricing")).toBeInTheDocument();
|
|
60
|
+
expect(getByText("Getting Started")).toBeInTheDocument();
|
|
61
|
+
expect(getByText("Contact")).toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("renders navigation items as links with correct href", () => {
|
|
65
|
+
const { container } = render(<AnchorNavigation items={basicItems} />);
|
|
66
|
+
|
|
67
|
+
const featuresLink = container.querySelector('a[href="#features"]');
|
|
68
|
+
const pricingLink = container.querySelector('a[href="#pricing"]');
|
|
69
|
+
|
|
70
|
+
expect(featuresLink).toBeInTheDocument();
|
|
71
|
+
expect(featuresLink).toHaveTextContent("Key Features");
|
|
72
|
+
expect(pricingLink).toBeInTheDocument();
|
|
73
|
+
expect(pricingLink).toHaveTextContent("Pricing");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("applies active class to items with isActive prop", () => {
|
|
77
|
+
const { container } = render(<AnchorNavigation items={basicItems} />);
|
|
78
|
+
|
|
79
|
+
const activeLink = container.querySelector('a[href="#features"]');
|
|
80
|
+
const inactiveLink = container.querySelector('a[href="#pricing"]');
|
|
81
|
+
|
|
82
|
+
expect(activeLink).toHaveClass("is-active");
|
|
83
|
+
expect(inactiveLink).not.toHaveClass("is-active");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("applies anchor-navigation__item class to all links", () => {
|
|
87
|
+
const { container } = render(<AnchorNavigation items={basicItems} />);
|
|
88
|
+
|
|
89
|
+
const links = container.querySelectorAll(".anchor-navigation__item");
|
|
90
|
+
expect(links).toHaveLength(basicItems.length);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("renders multiple items correctly", () => {
|
|
94
|
+
const { getByText } = render(<AnchorNavigation items={moreItems} />);
|
|
95
|
+
|
|
96
|
+
expect(getByText("Overview")).toBeInTheDocument();
|
|
97
|
+
expect(getByText("Features")).toBeInTheDocument();
|
|
98
|
+
expect(getByText("Documentation")).toBeInTheDocument();
|
|
99
|
+
expect(getByText("API Reference")).toBeInTheDocument();
|
|
100
|
+
expect(getByText("Examples")).toBeInTheDocument();
|
|
101
|
+
expect(getByText("Support")).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("applies custom className", () => {
|
|
105
|
+
const { getByTestId } = render(
|
|
106
|
+
<AnchorNavigation
|
|
107
|
+
data-testid="test-id"
|
|
108
|
+
items={basicItems}
|
|
109
|
+
className="custom-class"
|
|
110
|
+
/>,
|
|
111
|
+
);
|
|
112
|
+
expect(getByTestId("test-id")).toHaveClass("anchor-navigation");
|
|
113
|
+
expect(getByTestId("test-id")).toHaveClass("custom-class");
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("children content", () => {
|
|
118
|
+
it("renders children in content-right section when provided", () => {
|
|
119
|
+
const { container, getByText } = render(
|
|
120
|
+
<AnchorNavigation items={basicItems}>
|
|
121
|
+
<div>Additional Content</div>
|
|
122
|
+
</AnchorNavigation>,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const contentRight = container.querySelector(
|
|
126
|
+
".anchor-navigation__content-right",
|
|
127
|
+
);
|
|
128
|
+
expect(contentRight).toBeInTheDocument();
|
|
129
|
+
expect(getByText("Additional Content")).toBeInTheDocument();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("does not render content-right section when no children", () => {
|
|
133
|
+
const { container } = render(<AnchorNavigation items={basicItems} />);
|
|
134
|
+
|
|
135
|
+
const contentRight = container.querySelector(
|
|
136
|
+
".anchor-navigation__content-right",
|
|
137
|
+
);
|
|
138
|
+
expect(contentRight).not.toBeInTheDocument();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("renders complex children content", () => {
|
|
142
|
+
const { getByText, getByRole } = render(
|
|
143
|
+
<AnchorNavigation items={basicItems}>
|
|
144
|
+
<div className="pricing">
|
|
145
|
+
<div className="bold">2 €</div>
|
|
146
|
+
<div>No commitment</div>
|
|
147
|
+
</div>
|
|
148
|
+
<button>Get Started</button>
|
|
149
|
+
</AnchorNavigation>,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
expect(getByText("2 €")).toBeInTheDocument();
|
|
153
|
+
expect(getByText("No commitment")).toBeInTheDocument();
|
|
154
|
+
expect(getByRole("button", { name: "Get Started" })).toBeInTheDocument();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("displayName", () => {
|
|
159
|
+
it("has correct displayName", () => {
|
|
160
|
+
expect(AnchorNavigation.displayName).toBe("AnchorNavigation");
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
@@ -16,6 +16,7 @@ interface CommonProps {
|
|
|
16
16
|
type?: ButtonType;
|
|
17
17
|
className?: string;
|
|
18
18
|
children?: React.ReactNode;
|
|
19
|
+
preserveWidth?: boolean;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
type AnchorProps = CommonProps &
|
|
@@ -62,6 +63,7 @@ const Button = React.forwardRef<any, ButtonProps>((props, ref) => {
|
|
|
62
63
|
[`${CLASS_ROOT}--${size}`]: size,
|
|
63
64
|
[`${CLASS_ROOT}--${type}`]: type,
|
|
64
65
|
[`${CLASS_ROOT}--default`]: isDefault,
|
|
66
|
+
[`${CLASS_ROOT}--preserve-width`]: props.preserveWidth,
|
|
65
67
|
"is-dark": colorScheme === "dark",
|
|
66
68
|
"is-light": colorScheme === "light",
|
|
67
69
|
"is-active": isActive,
|
|
@@ -6,6 +6,7 @@ export const cardColors = [
|
|
|
6
6
|
"black",
|
|
7
7
|
"orange",
|
|
8
8
|
"gray",
|
|
9
|
+
"gray-lighter",
|
|
9
10
|
"blue",
|
|
10
11
|
"green",
|
|
11
12
|
"pink",
|
|
@@ -14,22 +15,25 @@ export const cardColors = [
|
|
|
14
15
|
"accent1-blog",
|
|
15
16
|
"accent2-blog",
|
|
16
17
|
"accent",
|
|
18
|
+
"none",
|
|
17
19
|
] as const;
|
|
18
20
|
export type CardColor = (typeof cardColors)[number];
|
|
19
21
|
|
|
20
22
|
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
21
23
|
/** Custom background color */
|
|
22
24
|
color?: CardColor;
|
|
25
|
+
noBorder?: boolean;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export const CLASS_ROOT = "card";
|
|
26
29
|
|
|
27
30
|
const Card = React.forwardRef<HTMLDivElement, CardProps>(
|
|
28
|
-
({ className, color = "white", ...other }, ref) => {
|
|
31
|
+
({ className, color = "white", noBorder, ...other }, ref) => {
|
|
29
32
|
const classes = cx(
|
|
30
33
|
CLASS_ROOT,
|
|
31
34
|
{
|
|
32
35
|
[`bg-${color}`]: color !== "white",
|
|
36
|
+
[`${CLASS_ROOT}--no-border`]: noBorder,
|
|
33
37
|
},
|
|
34
38
|
className,
|
|
35
39
|
);
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
SELECTOR_ACTIVE,
|
|
27
27
|
CLASS_SLIDE_NEXT,
|
|
28
28
|
CLASS_SLIDE_PREV,
|
|
29
|
+
CLASS_BLEED_RIGHT,
|
|
29
30
|
} from "./constants";
|
|
30
31
|
|
|
31
32
|
export const defaultConfig: SwiperOptions = {
|
|
@@ -124,6 +125,11 @@ export default class Carousel {
|
|
|
124
125
|
slideChange: this.handleSlideChange,
|
|
125
126
|
},
|
|
126
127
|
});
|
|
128
|
+
|
|
129
|
+
// Check if this is a bleed-right carousel and adjust after initialization
|
|
130
|
+
if (this.element.classList.contains(CLASS_BLEED_RIGHT)) {
|
|
131
|
+
this.adjustConfigForBleedRight();
|
|
132
|
+
}
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
getElements() {
|
|
@@ -148,7 +154,7 @@ export default class Carousel {
|
|
|
148
154
|
...((this.config.pagination ?? {}) as object),
|
|
149
155
|
el: paginationEl,
|
|
150
156
|
clickable: true,
|
|
151
|
-
bulletClass:
|
|
157
|
+
bulletClass: CLASS_DOT,
|
|
152
158
|
bulletActiveClass: CLASS_ACTIVE,
|
|
153
159
|
},
|
|
154
160
|
};
|
|
@@ -172,6 +178,66 @@ export default class Carousel {
|
|
|
172
178
|
};
|
|
173
179
|
}
|
|
174
180
|
|
|
181
|
+
adjustConfigForBleedRight() {
|
|
182
|
+
// For bleed-right variant, calculate the exact bleed amount dynamically
|
|
183
|
+
// This allows the last slide to scroll back to align with container edge
|
|
184
|
+
|
|
185
|
+
// Wait for next frame to ensure container has final dimensions
|
|
186
|
+
requestAnimationFrame(() => {
|
|
187
|
+
// Find the container element
|
|
188
|
+
const container = this.element.closest(".container") as HTMLElement;
|
|
189
|
+
if (!container || !this.instance) return;
|
|
190
|
+
|
|
191
|
+
// Calculate the actual bleed amount with limits to match CSS
|
|
192
|
+
const containerWidth = container.offsetWidth;
|
|
193
|
+
const halfViewportWidth = window.innerWidth / 2;
|
|
194
|
+
const halfContainerWidth = containerWidth / 2;
|
|
195
|
+
let bleedAmount = halfViewportWidth - halfContainerWidth;
|
|
196
|
+
|
|
197
|
+
// On very large screens (above 2K), stop the bleeding effect entirely
|
|
198
|
+
if (window.innerWidth >= 2560) {
|
|
199
|
+
bleedAmount = 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Only add offset if there's actual bleeding (positive value)
|
|
203
|
+
if (bleedAmount > 0) {
|
|
204
|
+
// Update the Swiper configuration
|
|
205
|
+
this.instance.params.slidesOffsetAfter = bleedAmount;
|
|
206
|
+
this.instance.update();
|
|
207
|
+
} else {
|
|
208
|
+
// Remove offset if no bleeding should occur
|
|
209
|
+
this.instance.params.slidesOffsetAfter = 0;
|
|
210
|
+
this.instance.update();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Also listen for window resize to recalculate
|
|
214
|
+
const handleResize = () => {
|
|
215
|
+
if (this.instance && container) {
|
|
216
|
+
const newContainerWidth = container.offsetWidth;
|
|
217
|
+
const newHalfViewportWidth = window.innerWidth / 2;
|
|
218
|
+
const newHalfContainerWidth = newContainerWidth / 2;
|
|
219
|
+
let newBleedAmount = newHalfViewportWidth - newHalfContainerWidth;
|
|
220
|
+
|
|
221
|
+
// Apply same limits as above
|
|
222
|
+
if (window.innerWidth >= 2560) {
|
|
223
|
+
newBleedAmount = 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (newBleedAmount > 0) {
|
|
227
|
+
this.instance.params.slidesOffsetAfter = newBleedAmount;
|
|
228
|
+
} else {
|
|
229
|
+
this.instance.params.slidesOffsetAfter = 0;
|
|
230
|
+
}
|
|
231
|
+
this.instance.update();
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Remove any existing resize listener to avoid duplicates
|
|
236
|
+
window.removeEventListener("resize", handleResize);
|
|
237
|
+
window.addEventListener("resize", handleResize);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
175
241
|
/**
|
|
176
242
|
* Handles the slide change event on the carousel.
|
|
177
243
|
* Updates the tooltip position for the active slide and hides tooltips for non-active slides.
|
|
@@ -27,6 +27,10 @@ interface CarouselProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
27
27
|
colorScheme?: "light" | "dark";
|
|
28
28
|
/** Carousel items */
|
|
29
29
|
items: ReactNode[];
|
|
30
|
+
/** Always show scrollbar and hide dots */
|
|
31
|
+
showScrollbar?: boolean;
|
|
32
|
+
/** Make carousel bleed to the right edge of screen while keeping left aligned with container */
|
|
33
|
+
bleedRight?: boolean;
|
|
30
34
|
className?: string;
|
|
31
35
|
}
|
|
32
36
|
|
|
@@ -35,6 +39,8 @@ const Carousel: React.FC<CarouselProps> = ({
|
|
|
35
39
|
swiperOptions,
|
|
36
40
|
items,
|
|
37
41
|
colorScheme,
|
|
42
|
+
showScrollbar = false,
|
|
43
|
+
bleedRight = false,
|
|
38
44
|
...other
|
|
39
45
|
}) => {
|
|
40
46
|
const [carouselRef] = useStatic(CarouselStatic);
|
|
@@ -46,21 +52,33 @@ const Carousel: React.FC<CarouselProps> = ({
|
|
|
46
52
|
const classes = cx(CLASS_ROOT, className, {
|
|
47
53
|
"is-dark": colorScheme === "dark",
|
|
48
54
|
"is-light": colorScheme === "light",
|
|
55
|
+
[`${CLASS_ROOT}--scrollbar`]: showScrollbar,
|
|
56
|
+
[`${CLASS_ROOT}--bleed-right`]: bleedRight,
|
|
49
57
|
});
|
|
50
58
|
|
|
51
59
|
const elementClasses = {
|
|
52
60
|
prev: cx(CLASS_PREV),
|
|
53
61
|
next: cx(CLASS_NEXT),
|
|
54
|
-
dots: cx(CLASS_DOTS, "show-md"),
|
|
62
|
+
dots: cx(CLASS_DOTS, showScrollbar ? "hide" : "show-md"),
|
|
55
63
|
};
|
|
56
64
|
|
|
65
|
+
// Only override pagination when showScrollbar is true
|
|
66
|
+
const customSwiperOptions = showScrollbar
|
|
67
|
+
? {
|
|
68
|
+
pagination: {
|
|
69
|
+
enabled: false,
|
|
70
|
+
},
|
|
71
|
+
...swiperOptions,
|
|
72
|
+
}
|
|
73
|
+
: swiperOptions;
|
|
74
|
+
|
|
57
75
|
return (
|
|
58
76
|
<div
|
|
59
77
|
className={classes}
|
|
60
78
|
ref={carouselRef}
|
|
61
79
|
data-carousel
|
|
62
|
-
{...(swiperOptions
|
|
63
|
-
? { "data-swiper-options": JSON.stringify(
|
|
80
|
+
{...(showScrollbar || swiperOptions
|
|
81
|
+
? { "data-swiper-options": JSON.stringify(customSwiperOptions) }
|
|
64
82
|
: {})}
|
|
65
83
|
{...other}
|
|
66
84
|
>
|
|
@@ -68,25 +86,29 @@ const Carousel: React.FC<CarouselProps> = ({
|
|
|
68
86
|
<div className={CLASS_VIEWPORT}>
|
|
69
87
|
<div className={CLASS_TRACK}>{carouselItems}</div>
|
|
70
88
|
</div>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
{showScrollbar ? null : (
|
|
90
|
+
<>
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
aria-label="Naspäť"
|
|
94
|
+
className={elementClasses.prev}
|
|
95
|
+
>
|
|
96
|
+
<Icon size="medium" name="chevron-left" />
|
|
97
|
+
</button>
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
aria-label="Ďalej"
|
|
101
|
+
className={elementClasses.next}
|
|
102
|
+
>
|
|
103
|
+
<Icon size="medium" name="chevron-right" />
|
|
104
|
+
</button>
|
|
105
|
+
</>
|
|
106
|
+
)}
|
|
85
107
|
</div>
|
|
86
108
|
|
|
87
|
-
<div role="tablist" className={elementClasses.dots} />
|
|
109
|
+
{!showScrollbar && <div role="tablist" className={elementClasses.dots} />}
|
|
88
110
|
|
|
89
|
-
<div className={cx(CLASS_SCROLLBAR, "hide-md")}>
|
|
111
|
+
<div className={cx(CLASS_SCROLLBAR, !showScrollbar && "hide-md")}>
|
|
90
112
|
<div className={CLASS_SCROLLBAR_DRAG} />
|
|
91
113
|
</div>
|
|
92
114
|
</div>
|
|
@@ -14,6 +14,8 @@ export const CLASS_SCROLLBAR = `${CLASS_ROOT}__scrollbar`;
|
|
|
14
14
|
export const CLASS_SCROLLBAR_HORIZONTAL = `${CLASS_ROOT}__scrollbar-horizontal`;
|
|
15
15
|
export const CLASS_SCROLLBAR_DRAG = `${CLASS_ROOT}__scrollbar-drag`;
|
|
16
16
|
export const CLASS_ACTIVE = "is-active";
|
|
17
|
+
export const CLASS_SCROLLBAR_VARIANT = `${CLASS_ROOT}--scrollbar`;
|
|
18
|
+
export const CLASS_BLEED_RIGHT = `${CLASS_ROOT}--bleed-right`;
|
|
17
19
|
|
|
18
20
|
export const SELECTOR_VIEWPORT = `.${CLASS_VIEWPORT}`;
|
|
19
21
|
export const SELECTOR_TRACK = `.${CLASS_TRACK}`;
|
|
@@ -43,6 +43,11 @@
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
.carousel--scrollbar & {
|
|
47
|
+
margin-left: 0;
|
|
48
|
+
margin-right: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
@include breakpoint.get("sm", "down") {
|
|
47
52
|
padding-bottom: math.div(config.$space, 2);
|
|
48
53
|
}
|
|
@@ -88,15 +93,19 @@
|
|
|
88
93
|
margin-right: -#{convert.to-rem(60px)};
|
|
89
94
|
}
|
|
90
95
|
}
|
|
96
|
+
|
|
97
|
+
&.carousel--bleed-right {
|
|
98
|
+
margin-left: 0;
|
|
99
|
+
margin-right: 0;
|
|
100
|
+
}
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
@mixin slide-base {
|
|
94
104
|
display: flex;
|
|
95
105
|
flex-direction: column;
|
|
96
106
|
max-width: 100%;
|
|
97
|
-
// width: auto !important;
|
|
98
107
|
flex: 0 0 auto;
|
|
99
|
-
padding: 0
|
|
108
|
+
padding: 0 convert.to-rem(20px) 0 0;
|
|
100
109
|
user-select: none;
|
|
101
110
|
|
|
102
111
|
> * {
|
|
@@ -193,4 +202,28 @@
|
|
|
193
202
|
opacity: 1;
|
|
194
203
|
background-color: var(--color-fill-contrast);
|
|
195
204
|
border-radius: 99px;
|
|
205
|
+
height: convert.to-rem(6px);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@mixin scrollbar-variant {
|
|
209
|
+
margin-left: 0 !important;
|
|
210
|
+
margin-right: 0 !important;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@mixin bleed-right-variant {
|
|
214
|
+
.carousel__viewport {
|
|
215
|
+
// Extend the viewport to the right edge of the screen
|
|
216
|
+
width: calc(100% + 50vw - 50%);
|
|
217
|
+
margin-right: 0;
|
|
218
|
+
|
|
219
|
+
// Keep left margin for container alignment
|
|
220
|
+
@include breakpoint.get("md") {
|
|
221
|
+
margin-left: convert.to-rem(50px);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// On very large screens (above 2K), stop the bleeding effect entirely
|
|
225
|
+
@media (min-width: 2560px) {
|
|
226
|
+
width: 100%;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
196
229
|
}
|
|
@@ -117,4 +117,42 @@ describe("Pictogram component", () => {
|
|
|
117
117
|
expect(getByTestId("test-pictogram")).toHaveClass("custom-class");
|
|
118
118
|
});
|
|
119
119
|
});
|
|
120
|
+
|
|
121
|
+
describe("theme switching", () => {
|
|
122
|
+
it("shows light version by default", () => {
|
|
123
|
+
const { container } = render(<Pictogram name="pictogram-skylink" />);
|
|
124
|
+
const lightUse = container.querySelector(".icon__use--light");
|
|
125
|
+
const darkUse = container.querySelector(".icon__use--dark");
|
|
126
|
+
|
|
127
|
+
expect(lightUse).toBeInTheDocument();
|
|
128
|
+
expect(darkUse).toBeInTheDocument();
|
|
129
|
+
// Note: CSS display logic is tested via CSS rules, not inline styles
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("renders correctly within is-light context", () => {
|
|
133
|
+
const { container } = render(
|
|
134
|
+
<div className="is-light">
|
|
135
|
+
<Pictogram name="pictogram-skylink" />
|
|
136
|
+
</div>,
|
|
137
|
+
);
|
|
138
|
+
const lightUse = container.querySelector(".icon__use--light");
|
|
139
|
+
const darkUse = container.querySelector(".icon__use--dark");
|
|
140
|
+
|
|
141
|
+
expect(lightUse).toBeInTheDocument();
|
|
142
|
+
expect(darkUse).toBeInTheDocument();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("renders correctly within is-dark context", () => {
|
|
146
|
+
const { container } = render(
|
|
147
|
+
<div className="is-dark">
|
|
148
|
+
<Pictogram name="pictogram-skylink" />
|
|
149
|
+
</div>,
|
|
150
|
+
);
|
|
151
|
+
const lightUse = container.querySelector(".icon__use--light");
|
|
152
|
+
const darkUse = container.querySelector(".icon__use--dark");
|
|
153
|
+
|
|
154
|
+
expect(lightUse).toBeInTheDocument();
|
|
155
|
+
expect(darkUse).toBeInTheDocument();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
120
158
|
});
|
|
@@ -125,21 +125,6 @@ describe("Link Conformance Tests", () => {
|
|
|
125
125
|
expect(results).toHaveNoViolations();
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
it("has no accessibility violations for inverse links", async () => {
|
|
129
|
-
const { container } = render(
|
|
130
|
-
<div>
|
|
131
|
-
<Link href="#" isInverse>
|
|
132
|
-
Inverse link
|
|
133
|
-
</Link>
|
|
134
|
-
<Link href="#" color="orange" isInverse>
|
|
135
|
-
Orange inverse link
|
|
136
|
-
</Link>
|
|
137
|
-
</div>,
|
|
138
|
-
);
|
|
139
|
-
const results = await axe(container);
|
|
140
|
-
expect(results).toHaveNoViolations();
|
|
141
|
-
});
|
|
142
|
-
|
|
143
128
|
it("has no accessibility violations for links with custom attributes", async () => {
|
|
144
129
|
const { container } = render(
|
|
145
130
|
<div>
|
|
@@ -212,11 +197,11 @@ describe("Link Conformance Tests", () => {
|
|
|
212
197
|
describe("Cross-browser Compatibility", () => {
|
|
213
198
|
it("renders consistently across different prop combinations", () => {
|
|
214
199
|
const testCases = [
|
|
215
|
-
{ href: "/", color: "default"
|
|
216
|
-
{ href: "/", color: "orange"
|
|
217
|
-
{ href: "/", color: "black"
|
|
218
|
-
{ tag: "button", type: "button", color: "default"
|
|
219
|
-
{ tag: "button", type: "button", color: "orange"
|
|
200
|
+
{ href: "/", color: "default" },
|
|
201
|
+
{ href: "/", color: "orange" },
|
|
202
|
+
{ href: "/", color: "black" },
|
|
203
|
+
{ tag: "button", type: "button", color: "default" },
|
|
204
|
+
{ tag: "button", type: "button", color: "orange" },
|
|
220
205
|
];
|
|
221
206
|
|
|
222
207
|
testCases.forEach((props, index) => {
|