@orangesk/orange-design-system 3.9.0 → 3.11.0

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.
Files changed (61) hide show
  1. package/build/components/AnchorNavigation/style.css +1 -1
  2. package/build/components/AnchorNavigation/style.css.map +1 -1
  3. package/build/components/Carousel/style.css +1 -1
  4. package/build/components/Carousel/style.css.map +1 -1
  5. package/build/components/Megamenu/style.css +1 -1
  6. package/build/components/Megamenu/style.css.map +1 -1
  7. package/build/components/index.js +1 -1
  8. package/build/components/index.js.map +1 -1
  9. package/build/components/types/index.d.ts +6 -2
  10. package/build/footer-sprite-dark.svg +1 -0
  11. package/build/footer-sprite-light.svg +1 -0
  12. package/build/lib/components.css +1 -1
  13. package/build/lib/components.css.map +1 -1
  14. package/build/lib/megamenu.css +1 -1
  15. package/build/lib/megamenu.css.map +1 -1
  16. package/build/lib/scripts.js +1 -1
  17. package/build/lib/scripts.js.map +1 -1
  18. package/build/lib/style.css +1 -1
  19. package/build/lib/style.css.map +1 -1
  20. package/build/megamenu-sprite-dark.svg +1 -0
  21. package/build/megamenu-sprite-light.svg +1 -0
  22. package/package.json +27 -27
  23. package/public/footer-sprite-dark.svg +1 -0
  24. package/public/footer-sprite-light.svg +1 -0
  25. package/src/assets/footer/appstore.svg +31 -0
  26. package/src/assets/footer/googleplay.svg +52 -0
  27. package/src/assets/footer/logo.svg +33 -0
  28. package/src/{components/Footer/PlanObnovy.tsx → assets/footer/plan-obnovy.svg} +53 -211
  29. package/src/assets/megamenu/input-search.svg +1 -0
  30. package/src/assets/megamenu/input-valid.svg +1 -0
  31. package/src/assets/megamenu/logo-line.svg +5 -0
  32. package/src/assets/megamenu/megamenu-logo.svg +61 -0
  33. package/src/assets/megamenu/store-apple--white.svg +5 -0
  34. package/src/assets/megamenu/store-apple.svg +4 -0
  35. package/src/assets/megamenu/store-huawei--white.svg +5 -0
  36. package/src/assets/megamenu/store-huawei.svg +4 -0
  37. package/src/assets/megamenu/store-play--white.svg +7 -0
  38. package/src/assets/megamenu/store-play.svg +7 -0
  39. package/src/components/AnchorNavigation/styles/mixins.scss +7 -9
  40. package/src/components/BlockAction/CloneElementWithClassName.tsx +10 -7
  41. package/src/components/BlockAction/tests/CloneElementWithClassName.unit.test.jsx +28 -1
  42. package/src/components/Carousel/Carousel.static.ts +111 -14
  43. package/src/components/Carousel/Carousel.tsx +35 -12
  44. package/src/components/Carousel/constants.ts +2 -0
  45. package/src/components/Carousel/styles/mixins.scss +61 -0
  46. package/src/components/Carousel/styles/style.scss +7 -0
  47. package/src/components/Carousel/tests/Carousel.lifecycle.test.ts +223 -0
  48. package/src/components/Footer/Footer.tsx +44 -54
  49. package/src/components/Footer/FooterIcon.tsx +12 -0
  50. package/src/components/Footer/data.ts +4 -2
  51. package/src/components/Footer/tests/Footer.unit.test.jsx +63 -0
  52. package/src/components/Forms/TextInput/styles/mixins.scss +4 -2
  53. package/src/components/Megamenu/Logo.tsx +7 -7
  54. package/src/components/Megamenu/LogoJeTu.tsx +6 -58
  55. package/src/components/Megamenu/MegaMenuIcon.tsx +20 -11
  56. package/src/components/Megamenu/Megamenu.tsx +58 -48
  57. package/src/components/Megamenu/MegamenuBlog.tsx +14 -2
  58. package/src/components/Megamenu/MegamenuSearchContent.tsx +13 -0
  59. package/src/components/Megamenu/MyOrangeMobilePanel.tsx +3 -9
  60. package/src/components/Megamenu/styles/mixins.scss +21 -34
  61. package/src/components/Megamenu/tests/Megamenu.unit.test.jsx +158 -0
@@ -13,12 +13,15 @@ const CloneElementWithClassName: React.FC<CloneElementWithClassNameProps> = ({
13
13
  children,
14
14
  ...other
15
15
  }) =>
16
- React.cloneElement(children, {
17
- ...(typeof children.props === "object" && children.props !== null
18
- ? children.props
19
- : {}),
20
- ...other,
21
- className: cx(children.props && children.props.className, className),
22
- });
16
+ // Children.map resolves lazy element references received through RSC payloads.
17
+ React.Children.map(children, (child) =>
18
+ React.cloneElement(child, {
19
+ ...(typeof child.props === "object" && child.props !== null
20
+ ? child.props
21
+ : {}),
22
+ ...other,
23
+ className: cx(child.props && child.props.className, className),
24
+ }),
25
+ );
23
26
 
24
27
  export { CloneElementWithClassName };
@@ -1,4 +1,4 @@
1
- import { render } from "@testing-library/react";
1
+ import { fireEvent, render } from "@testing-library/react";
2
2
 
3
3
  import { CloneElementWithClassName } from "../CloneElementWithClassName";
4
4
 
@@ -31,3 +31,30 @@ describe("rendering CloneElementWithClassName", () => {
31
31
  });
32
32
  });
33
33
  });
34
+
35
+ describe("CloneElementWithClassName", () => {
36
+ it("clones a lazy element received through the RSC payload", () => {
37
+ const onClick = vi.fn();
38
+ const element = <button className="original">Open</button>;
39
+ // RSC can wrap repeated elements in lazy references rather than JSX elements.
40
+ const child = {
41
+ $$typeof: Symbol.for("react.lazy"),
42
+ _payload: element,
43
+ _init: (payload) => payload,
44
+ };
45
+
46
+ const { getByRole } = render(
47
+ <CloneElementWithClassName
48
+ className="block-action__control"
49
+ onClick={onClick}
50
+ >
51
+ {child}
52
+ </CloneElementWithClassName>,
53
+ );
54
+
55
+ const button = getByRole("button", { name: "Open" });
56
+ expect(button).toHaveClass("original", "block-action__control");
57
+ fireEvent.click(button);
58
+ expect(onClick).toHaveBeenCalledOnce();
59
+ });
60
+ });
@@ -18,6 +18,8 @@ import {
18
18
  CLASS_DOT,
19
19
  CLASS_SCROLLBAR_DRAG,
20
20
  CLASS_SCROLLBAR_HORIZONTAL,
21
+ CLASS_SIDE_ARROWS,
22
+ CLASS_SIDE_ARROWS_VARIANT,
21
23
  CLASS_SLIDE,
22
24
  CLASS_SLIDE_NEXT,
23
25
  CLASS_SLIDE_PREV,
@@ -94,8 +96,8 @@ export const defaultConfig: SwiperOptions = {
94
96
  };
95
97
 
96
98
  export default class Carousel {
97
- element: HTMLElement;
98
- config: SwiperOptions;
99
+ element!: HTMLElement;
100
+ config!: SwiperOptions;
99
101
  viewport!: HTMLElement;
100
102
  track!: HTMLElement;
101
103
  instance!: Swiper;
@@ -104,8 +106,9 @@ export default class Carousel {
104
106
  private externalControlsState: ExternalControlsState | null = null;
105
107
  private resizeObserver?: ResizeObserver;
106
108
  private resizeRafId?: number;
107
- private boundWindowResizeHandler: () => void;
109
+ private boundWindowResizeHandler!: () => void;
108
110
  private bleedResizeHandler?: () => void;
111
+ private destroyed = false;
109
112
  private static readonly OVERFLOW_EPSILON_PX = 1;
110
113
 
111
114
  private getViewportWrapper(): HTMLElement | null {
@@ -139,6 +142,17 @@ export default class Carousel {
139
142
  return this.track?.scrollWidth || 0;
140
143
  }
141
144
 
145
+ const sizes = this.instance.slidesSizesGrid;
146
+ const positions = this.instance.slidesGrid;
147
+ if (sizes?.length && positions?.length === sizes.length) {
148
+ const last = sizes.length - 1;
149
+ // Swiper's grid preserves fractional widths and resolved percentage gaps.
150
+ const edgesWidth = this.instance.params.centeredSlides
151
+ ? (sizes[0] + sizes[last]) / 2
152
+ : sizes[last];
153
+ return positions[last] - positions[0] + edgesWidth;
154
+ }
155
+
142
156
  const slides = Array.from(this.instance.slides) as HTMLElement[];
143
157
  const widthsSum = slides.reduce((sum, slide) => sum + slide.offsetWidth, 0);
144
158
  const spaceBetween = Number(this.instance.params?.spaceBetween) || 0;
@@ -153,17 +167,18 @@ export default class Carousel {
153
167
  return measuredWidth;
154
168
  }
155
169
 
156
- private getOverflowWidth(viewportWrapper?: HTMLElement): number {
170
+ private getOverflowWidth(viewportWrapper?: HTMLElement): number | null {
157
171
  const isBleedRight = this.isBleedRight();
158
172
  const containerWidth = isBleedRight
159
173
  ? this.element.clientWidth || viewportWrapper?.clientWidth || 0
160
174
  : this.viewport?.clientWidth || 0;
161
175
 
162
176
  if (containerWidth <= 0) {
163
- return 0;
177
+ return null;
164
178
  }
165
179
 
166
180
  const contentWidth = this.getSlidesContentWidth();
181
+ if (contentWidth <= 0) return null;
167
182
 
168
183
  return contentWidth - containerWidth;
169
184
  }
@@ -174,7 +189,7 @@ export default class Carousel {
174
189
  }
175
190
 
176
191
  const overflowWidth = this.getOverflowWidth(viewportWrapper);
177
- if (overflowWidth !== 0) {
192
+ if (overflowWidth !== null) {
178
193
  return overflowWidth > Carousel.OVERFLOW_EPSILON_PX;
179
194
  }
180
195
 
@@ -185,6 +200,8 @@ export default class Carousel {
185
200
  }
186
201
 
187
202
  constructor(element: HTMLElement, config?: Partial<SwiperOptions>) {
203
+ const existing = Carousel.getInstance(element);
204
+ if (existing) return existing;
188
205
  const scrollbarEl = element.querySelector(
189
206
  SELECTOR_SCROLLBAR,
190
207
  ) as HTMLElement | null;
@@ -225,6 +242,7 @@ export default class Carousel {
225
242
  }
226
243
 
227
244
  init() {
245
+ if (this.destroyed || this.instance) return;
228
246
  this.getElements();
229
247
 
230
248
  if (this.element.hasAttribute("data-swiper-options")) {
@@ -280,7 +298,7 @@ export default class Carousel {
280
298
 
281
299
  // Trigger a final update to notify listeners (like SameHeight) that carousel is ready
282
300
  requestAnimationFrame(() => {
283
- if (this.instance) {
301
+ if (!this.destroyed && this.instance) {
284
302
  this.instance.update();
285
303
  }
286
304
  });
@@ -303,6 +321,7 @@ export default class Carousel {
303
321
  }
304
322
 
305
323
  this.instance.update();
324
+ this.updateSideArrowGeometry();
306
325
  this.updateCarouselEnabledState();
307
326
  this.bleedResizeHandler?.();
308
327
  this.updateExternalControlsState();
@@ -316,7 +335,7 @@ export default class Carousel {
316
335
  */
317
336
  syncScrollbar() {
318
337
  requestAnimationFrame(() => {
319
- if (this.instance?.scrollbar) {
338
+ if (!this.destroyed && this.instance?.scrollbar) {
320
339
  this.instance.scrollbar.updateSize();
321
340
  }
322
341
  });
@@ -328,8 +347,12 @@ export default class Carousel {
328
347
  }
329
348
 
330
349
  this.resizeObserver?.disconnect();
350
+ const firstSlide = this.instance?.slides?.[0] as HTMLElement | undefined;
351
+ let viewportWidth = this.viewport.clientWidth;
352
+ let rootWidth = this.element.clientWidth;
353
+ let slideWidth = firstSlide?.offsetWidth;
331
354
  this.resizeObserver = new ResizeObserver(() => {
332
- if (!this.instance || !this.viewport) {
355
+ if (this.destroyed || !this.instance || !this.viewport) {
333
356
  return;
334
357
  }
335
358
 
@@ -337,12 +360,27 @@ export default class Carousel {
337
360
  return;
338
361
  }
339
362
 
340
- this.instance.update();
363
+ const widthChanged =
364
+ viewportWidth !== this.viewport.clientWidth ||
365
+ rootWidth !== this.element.clientWidth ||
366
+ slideWidth !== firstSlide?.offsetWidth;
367
+ if (widthChanged || this.instance.params.autoHeight) {
368
+ this.instance.update();
369
+ this.bleedResizeHandler?.();
370
+ this.instance.scrollbar?.updateSize();
371
+ }
372
+ // A height update from SameHeight must not start another Swiper update.
341
373
  this.updateCarouselEnabledState();
342
- this.instance.scrollbar?.updateSize();
374
+ viewportWidth = this.viewport.clientWidth;
375
+ rootWidth = this.element.clientWidth;
376
+ slideWidth = firstSlide?.offsetWidth;
343
377
  });
344
378
 
379
+ this.resizeObserver.observe(this.element);
345
380
  this.resizeObserver.observe(this.viewport);
381
+ if (firstSlide) {
382
+ this.resizeObserver.observe(firstSlide);
383
+ }
346
384
  }
347
385
 
348
386
  /**
@@ -355,7 +393,13 @@ export default class Carousel {
355
393
  const scrollbar = this.instance?.scrollbar;
356
394
  const swiper = this.instance;
357
395
 
358
- if (!viewportWrapper || !scrollbar || !scrollbar.dragEl || !swiper) {
396
+ if (
397
+ this.destroyed ||
398
+ !viewportWrapper ||
399
+ !scrollbar ||
400
+ !scrollbar.dragEl ||
401
+ !swiper
402
+ ) {
359
403
  return;
360
404
  }
361
405
 
@@ -477,9 +521,48 @@ export default class Carousel {
477
521
  this.instance.disable();
478
522
  }
479
523
 
524
+ this.updateSideArrowGeometry();
525
+ this.updateSideArrowVisibility(hasScrollableContent);
526
+
480
527
  this.setScrollbarVisible(this.instance.enabled);
481
528
  }
482
529
 
530
+ private updateSideArrowGeometry(): void {
531
+ if (!this.element.classList.contains(CLASS_SIDE_ARROWS_VARIANT)) {
532
+ return;
533
+ }
534
+
535
+ const firstSlide = this.instance?.slides?.[0] as HTMLElement | undefined;
536
+ if (!firstSlide) {
537
+ return;
538
+ }
539
+
540
+ this.element.style.setProperty(
541
+ "--carousel-side-arrows-width",
542
+ `${firstSlide.offsetWidth}px`,
543
+ );
544
+ const slidesHeight = this.viewport?.getBoundingClientRect().height;
545
+ if (slidesHeight) {
546
+ this.element.style.setProperty(
547
+ "--carousel-side-arrows-height",
548
+ `${slidesHeight}px`,
549
+ );
550
+ }
551
+ }
552
+
553
+ private updateSideArrowVisibility(isScrollable: boolean): void {
554
+ if (!this.element.classList.contains(CLASS_SIDE_ARROWS_VARIANT)) {
555
+ return;
556
+ }
557
+
558
+ const sideArrows = this.element.querySelector(
559
+ `.${CLASS_SIDE_ARROWS}`,
560
+ ) as HTMLElement | null;
561
+ if (sideArrows) {
562
+ sideArrows.hidden = !isScrollable;
563
+ }
564
+ }
565
+
483
566
  private applyBleedInsets(viewportWrapper: HTMLElement): void {
484
567
  if (!this.instance || !this.instance.params) {
485
568
  return;
@@ -584,7 +667,7 @@ export default class Carousel {
584
667
  */
585
668
  adjustConfigForBleedRight() {
586
669
  requestAnimationFrame(() => {
587
- if (!this.instance) return;
670
+ if (this.destroyed || !this.instance) return;
588
671
 
589
672
  const viewportWrapper = this.getViewportWrapper();
590
673
  if (!viewportWrapper) return;
@@ -929,6 +1012,8 @@ export default class Carousel {
929
1012
  }
930
1013
 
931
1014
  destroy() {
1015
+ if (this.destroyed) return;
1016
+ this.destroyed = true;
932
1017
  // Clean up external controls
933
1018
  if (this.carouselId) {
934
1019
  const controlElements = document.querySelectorAll(
@@ -943,6 +1028,13 @@ export default class Carousel {
943
1028
  );
944
1029
  delete (htmlControl as any)._carouselClickHandler;
945
1030
  }
1031
+ if ((htmlControl as any)._carouselKeydownHandler) {
1032
+ htmlControl.removeEventListener(
1033
+ "keydown",
1034
+ (htmlControl as any)._carouselKeydownHandler,
1035
+ );
1036
+ delete (htmlControl as any)._carouselKeydownHandler;
1037
+ }
946
1038
  htmlControl.removeAttribute("data-carousel-initialized");
947
1039
  });
948
1040
  }
@@ -967,6 +1059,8 @@ export default class Carousel {
967
1059
  this.externalControlsState = null;
968
1060
  this.resizeObserver?.disconnect();
969
1061
  this.resizeObserver = undefined;
1062
+ this.element.style.removeProperty("--carousel-side-arrows-width");
1063
+ this.element.style.removeProperty("--carousel-side-arrows-height");
970
1064
 
971
1065
  if ((this.element as any).ODS_Carousel === this) {
972
1066
  delete (this.element as any).ODS_Carousel;
@@ -974,8 +1068,11 @@ export default class Carousel {
974
1068
  }
975
1069
 
976
1070
  update() {
977
- if (this.instance) {
1071
+ if (!this.destroyed && this.instance) {
978
1072
  this.instance.update();
1073
+ this.bleedResizeHandler?.();
1074
+ this.updateCarouselEnabledState();
1075
+ this.updateExternalControlsState();
979
1076
  }
980
1077
  }
981
1078
 
@@ -17,6 +17,8 @@ import {
17
17
  CLASS_ROOT,
18
18
  CLASS_SCROLLBAR,
19
19
  CLASS_SCROLLBAR_DRAG,
20
+ CLASS_SIDE_ARROWS,
21
+ CLASS_SIDE_ARROWS_VARIANT,
20
22
  CLASS_TRACK,
21
23
  CLASS_VIEWPORT,
22
24
  CLASS_VIEWPORT_WRAPPER,
@@ -37,6 +39,8 @@ interface CarouselProps<T = ReactNode> extends HTMLAttributes<HTMLDivElement> {
37
39
  bleedRight?: boolean;
38
40
  /** Make carousel bleed right from its root edge without bleeding left */
39
41
  bleedRightNoLeft?: boolean;
42
+ /** Show navigation arrows beside the first visible slide */
43
+ showSideArrows?: boolean;
40
44
  className?: string;
41
45
  }
42
46
 
@@ -53,6 +57,7 @@ const Carousel = <T,>({
53
57
  showScrollbar = false,
54
58
  bleedRight = false,
55
59
  bleedRightNoLeft = false,
60
+ showSideArrows = false,
56
61
  ...other
57
62
  }: CarouselProps<T>) => {
58
63
  const [carouselRef] = useStatic(CarouselStatic);
@@ -77,6 +82,7 @@ const Carousel = <T,>({
77
82
  [`${CLASS_ROOT}--scrollbar`]: showScrollbar,
78
83
  [`${CLASS_ROOT}--bleed-right`]: bleedRight,
79
84
  [CLASS_BLEED_RIGHT_NO_LEFT]: bleedRightNoLeft,
85
+ [CLASS_SIDE_ARROWS_VARIANT]: showSideArrows,
80
86
  });
81
87
 
82
88
  const elementClasses = {
@@ -112,21 +118,38 @@ const Carousel = <T,>({
112
118
  </div>
113
119
  </div>
114
120
 
121
+ {showSideArrows && (
122
+ <div className={CLASS_SIDE_ARROWS}>
123
+ <Controls
124
+ className={elementClasses.prev}
125
+ icon="chevron-left"
126
+ aria-label="Naspäť"
127
+ />
128
+ <Controls
129
+ className={elementClasses.next}
130
+ icon="chevron-right"
131
+ aria-label="Ďalej"
132
+ />
133
+ </div>
134
+ )}
135
+
115
136
  {!showScrollbar && (
116
137
  <div className={elementClasses.navigation}>
117
138
  <div role="tablist" className={elementClasses.dots} />
118
- <div className={elementClasses.controls}>
119
- <Controls
120
- className={elementClasses.prev}
121
- icon="chevron-left"
122
- aria-label="Naspäť"
123
- />
124
- <Controls
125
- className={elementClasses.next}
126
- icon="chevron-right"
127
- aria-label="Ďalej"
128
- />
129
- </div>
139
+ {!showSideArrows && (
140
+ <div className={elementClasses.controls}>
141
+ <Controls
142
+ className={elementClasses.prev}
143
+ icon="chevron-left"
144
+ aria-label="Naspäť"
145
+ />
146
+ <Controls
147
+ className={elementClasses.next}
148
+ icon="chevron-right"
149
+ aria-label="Ďalej"
150
+ />
151
+ </div>
152
+ )}
130
153
  </div>
131
154
  )}
132
155
 
@@ -11,6 +11,7 @@ export const CLASS_NEXT = `${CLASS_ROOT}__next`;
11
11
  export const CLASS_DOTS = `${CLASS_ROOT}__pagination`;
12
12
  export const CLASS_NAVIGATION = `${CLASS_ROOT}__navigation`;
13
13
  export const CLASS_CONTROLS = `${CLASS_ROOT}__controls`;
14
+ export const CLASS_SIDE_ARROWS = `${CLASS_ROOT}__side-arrows`;
14
15
  export const CLASS_DOT = `${CLASS_ROOT}__pagination-item`;
15
16
  export const CLASS_SCROLLBAR = `${CLASS_ROOT}__scrollbar`;
16
17
  export const CLASS_SCROLLBAR_HORIZONTAL = `${CLASS_ROOT}__scrollbar-horizontal`;
@@ -19,6 +20,7 @@ export const CLASS_ACTIVE = "is-active";
19
20
  export const CLASS_SCROLLBAR_VARIANT = `${CLASS_ROOT}--scrollbar`;
20
21
  export const CLASS_BLEED_RIGHT = `${CLASS_ROOT}--bleed-right`;
21
22
  export const CLASS_BLEED_RIGHT_NO_LEFT = `${CLASS_ROOT}--bleed-right-no-left`;
23
+ export const CLASS_SIDE_ARROWS_VARIANT = `${CLASS_ROOT}--side-arrows`;
22
24
 
23
25
  export const SELECTOR_VIEWPORT = `.${CLASS_VIEWPORT}`;
24
26
  export const SELECTOR_TRACK = `.${CLASS_TRACK}`;
@@ -70,6 +70,67 @@
70
70
  gap: convert.to-rem(8px);
71
71
  }
72
72
 
73
+ @mixin side-arrows {
74
+ position: absolute;
75
+ inset-block-start: 0;
76
+ inset-inline-start: 0;
77
+ z-index: 2;
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: space-between;
81
+ width: 100%;
82
+ height: min(var(--carousel-side-arrows-height, 100%), 100vh);
83
+ pointer-events: none;
84
+
85
+ &[hidden] {
86
+ display: none;
87
+ }
88
+
89
+ .controls {
90
+ flex: 0 0 auto;
91
+ pointer-events: auto;
92
+ }
93
+
94
+ .controls.swiper-button-lock {
95
+ display: inline-flex;
96
+ }
97
+
98
+ .controls[disabled] {
99
+ display: none;
100
+ }
101
+
102
+ .carousel__prev {
103
+ position: absolute;
104
+ inset-inline-start: 0;
105
+ top: 50%;
106
+ transform: translate(-50%, -50%);
107
+ }
108
+
109
+ .carousel__next {
110
+ position: absolute;
111
+ inset-inline-end: 0;
112
+ top: 50%;
113
+ transform: translate(50%, -50%);
114
+ }
115
+
116
+ @include breakpoint.get("md", "down") {
117
+ width: var(--carousel-side-arrows-width, 100%);
118
+ }
119
+ }
120
+
121
+ @mixin centered-mobile-variant {
122
+ @include breakpoint.get("sm", "down") {
123
+ .carousel__slide {
124
+ width: calc(100% - 40px);
125
+ }
126
+
127
+ .carousel__side-arrows {
128
+ inset-inline-start: 20px;
129
+ width: calc(100% - 40px);
130
+ }
131
+ }
132
+ }
133
+
73
134
  @mixin track {
74
135
  transform: translateZ(0);
75
136
  width: 100%;
@@ -9,6 +9,13 @@
9
9
  @include mixins.scrollbar-variant;
10
10
  }
11
11
 
12
+ &--side-arrows {
13
+ .carousel__side-arrows {
14
+ @include mixins.side-arrows;
15
+ }
16
+ @include mixins.centered-mobile-variant;
17
+ }
18
+
12
19
  &--bleed-right,
13
20
  &--bleed-right-no-left {
14
21
  @include mixins.bleed-right-variant;