@orangesk/orange-design-system 2.0.0-beta.17 → 2.0.0-beta.19
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/style.css +1 -1
- package/build/components/Accordion/style.css.map +1 -1
- package/build/components/AnchorNavigation/style.css +1 -1
- package/build/components/AnchorNavigation/style.css.map +1 -1
- package/build/components/Grid/style.css +1 -1
- package/build/components/Grid/style.css.map +1 -1
- package/build/components/Megamenu/style.css +1 -1
- package/build/components/Megamenu/style.css.map +1 -1
- package/build/components/PromoBanner/style.css +1 -1
- package/build/components/PromoBanner/style.css.map +1 -1
- package/build/components/index.js +1 -23
- package/build/components/index.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/index.d.ts +5 -3
- package/build/components/types/src/components/Accordion/Accordion.d.ts +2 -2
- package/build/components/types/src/components/Accordion/Accordion.static.d.ts +1 -0
- package/build/components/types/src/components/Carousel/Carousel.static.d.ts +38 -18
- package/build/components/types/src/components/Grid/Grid.d.ts +1 -1
- package/build/components/types/src/components/Megamenu/Megamenu.d.ts +6 -1
- package/build/components/types/src/components/Megamenu/MegamenuBlog.d.ts +2 -1
- package/build/components/types/src/components/Megamenu/constants.d.ts +2 -0
- package/build/components/types/src/components/Modal/ModalProductHeader.d.ts +2 -0
- package/build/lib/base.css +1 -1
- package/build/lib/base.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 +1 -9
- 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 +2 -2
- package/src/components/Accordion/Accordion.static.ts +36 -30
- package/src/components/Accordion/Accordion.tsx +4 -4
- package/src/components/Accordion/AccordionHeader.tsx +0 -10
- package/src/components/Accordion/styles/mixins.scss +0 -6
- package/src/components/Accordion/styles/style.scss +2 -2
- package/src/components/Accordion/tests/Accordion.unit.test.js +12 -26
- package/src/components/AnchorNavigation/AnchorNavigation.static.ts +0 -1
- package/src/components/AnchorNavigation/styles/mixins.scss +4 -0
- package/src/components/Carousel/Carousel.static.ts +177 -91
- package/src/components/Carousel/tests/Carousel.static.test.js +213 -0
- package/src/components/Carousel/tests/Carousel.unit.test.js +58 -0
- package/src/components/Expander/Expander.static.ts +11 -12
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Footer/tests/Footer.conformance.test.js +4 -4
- package/src/components/Footer/tests/Footer.unit.test.js +4 -4
- package/src/components/Grid/Grid.tsx +1 -1
- package/src/components/Grid/styles/config.scss +5 -3
- package/src/components/Grid/styles/mixins.scss +29 -19
- package/src/components/Grid/tests/Grid.unit.test.js +11 -0
- package/src/components/Megamenu/Megamenu.tsx +142 -68
- package/src/components/Megamenu/MegamenuBlog.tsx +41 -27
- package/src/components/Megamenu/constants.ts +2 -0
- package/src/components/Megamenu/static.ts +0 -9
- package/src/components/Megamenu/styles/mixins.scss +20 -2
- package/src/components/Megamenu/styles/style.scss +2 -0
- package/src/components/Modal/ModalProductHeader.tsx +6 -2
- package/src/components/Modal/tests/ModalProductHeader.unit.test.js +12 -0
- package/src/components/PromoBanner/PromoBanner.tsx +3 -1
- package/src/components/PromoBanner/styles/mixins.scss +5 -0
- package/src/styles/typography/mixins.scss +4 -5
- package/build/search-index.json +0 -406
|
@@ -13,9 +13,15 @@ jest.mock("swiper", () => ({
|
|
|
13
13
|
destroy: jest.fn(),
|
|
14
14
|
update: jest.fn(),
|
|
15
15
|
on: jest.fn(),
|
|
16
|
+
enable: jest.fn(),
|
|
17
|
+
disable: jest.fn(),
|
|
16
18
|
activeIndex: 0,
|
|
17
19
|
isBeginning: true,
|
|
18
20
|
isEnd: false,
|
|
21
|
+
slides: [{}, {}, {}],
|
|
22
|
+
params: {
|
|
23
|
+
slidesPerView: 1,
|
|
24
|
+
},
|
|
19
25
|
})),
|
|
20
26
|
}));
|
|
21
27
|
|
|
@@ -44,9 +50,15 @@ describe("Carousel Static - External Controls", () => {
|
|
|
44
50
|
destroy: jest.fn(),
|
|
45
51
|
update: jest.fn(),
|
|
46
52
|
on: jest.fn(),
|
|
53
|
+
enable: jest.fn(),
|
|
54
|
+
disable: jest.fn(),
|
|
47
55
|
activeIndex: 0,
|
|
48
56
|
isBeginning: true,
|
|
49
57
|
isEnd: false,
|
|
58
|
+
slides: [{}, {}, {}],
|
|
59
|
+
params: {
|
|
60
|
+
slidesPerView: 1,
|
|
61
|
+
},
|
|
50
62
|
};
|
|
51
63
|
|
|
52
64
|
Swiper.mockImplementation(() => mockSwiperInstance);
|
|
@@ -189,6 +201,7 @@ describe("Carousel Static - External Controls", () => {
|
|
|
189
201
|
it("should disable next button when at end", () => {
|
|
190
202
|
mockSwiperInstance.isBeginning = false;
|
|
191
203
|
mockSwiperInstance.isEnd = true;
|
|
204
|
+
mockSwiperInstance.activeIndex = 2; // Set to last slide so activeIndex + slidesPerView >= slidesCount
|
|
192
205
|
|
|
193
206
|
carouselInstance.updateExternalControlsState();
|
|
194
207
|
|
|
@@ -401,3 +414,203 @@ describe("Carousel Static - External Controls", () => {
|
|
|
401
414
|
});
|
|
402
415
|
});
|
|
403
416
|
});
|
|
417
|
+
|
|
418
|
+
describe("Carousel Static - Auto-Disable Feature", () => {
|
|
419
|
+
let carouselElement;
|
|
420
|
+
let carouselInstance;
|
|
421
|
+
let mockSwiperInstance;
|
|
422
|
+
|
|
423
|
+
beforeEach(() => {
|
|
424
|
+
jest.clearAllMocks();
|
|
425
|
+
|
|
426
|
+
// Create mock Swiper instance with slides array
|
|
427
|
+
mockSwiperInstance = {
|
|
428
|
+
slideNext: jest.fn(),
|
|
429
|
+
slidePrev: jest.fn(),
|
|
430
|
+
destroy: jest.fn(),
|
|
431
|
+
update: jest.fn(),
|
|
432
|
+
on: jest.fn(),
|
|
433
|
+
enable: jest.fn(),
|
|
434
|
+
disable: jest.fn(),
|
|
435
|
+
activeIndex: 0,
|
|
436
|
+
isBeginning: true,
|
|
437
|
+
isEnd: false,
|
|
438
|
+
slides: [], // Will be populated in tests
|
|
439
|
+
params: {
|
|
440
|
+
slidesPerView: 1.2,
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
Swiper.mockImplementation(() => mockSwiperInstance);
|
|
445
|
+
|
|
446
|
+
document.body.innerHTML = `
|
|
447
|
+
<div class="carousel" data-carousel-id="test-carousel" id="test-carousel">
|
|
448
|
+
<div class="carousel__viewport">
|
|
449
|
+
<div class="carousel__track">
|
|
450
|
+
<div class="carousel__slide">Slide 1</div>
|
|
451
|
+
<div class="carousel__slide">Slide 2</div>
|
|
452
|
+
<div class="carousel__slide">Slide 3</div>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
<div class="carousel__pagination"></div>
|
|
456
|
+
</div>
|
|
457
|
+
`;
|
|
458
|
+
|
|
459
|
+
carouselElement = document.querySelector(".carousel");
|
|
460
|
+
global.requestAnimationFrame = jest.fn((cb) => cb());
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
afterEach(() => {
|
|
464
|
+
document.body.innerHTML = "";
|
|
465
|
+
global.requestAnimationFrame = undefined;
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
describe("Auto-disable when content fits", () => {
|
|
469
|
+
it("should enable carousel when more slides than slidesPerView", () => {
|
|
470
|
+
// 3 slides, slidesPerView 1.2
|
|
471
|
+
mockSwiperInstance.slides = [
|
|
472
|
+
document.createElement("div"),
|
|
473
|
+
document.createElement("div"),
|
|
474
|
+
document.createElement("div"),
|
|
475
|
+
];
|
|
476
|
+
mockSwiperInstance.params.slidesPerView = 1.2;
|
|
477
|
+
|
|
478
|
+
carouselInstance = new Carousel(carouselElement);
|
|
479
|
+
|
|
480
|
+
expect(mockSwiperInstance.enable).toHaveBeenCalled();
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it("should disable carousel when slides match slidesPerView", () => {
|
|
484
|
+
// 2 slides, slidesPerView 2
|
|
485
|
+
mockSwiperInstance.slides = [
|
|
486
|
+
document.createElement("div"),
|
|
487
|
+
document.createElement("div"),
|
|
488
|
+
];
|
|
489
|
+
mockSwiperInstance.params.slidesPerView = 2;
|
|
490
|
+
|
|
491
|
+
carouselInstance = new Carousel(carouselElement);
|
|
492
|
+
|
|
493
|
+
expect(mockSwiperInstance.disable).toHaveBeenCalled();
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
it("should disable carousel when slides less than slidesPerView", () => {
|
|
497
|
+
// 1 slide, slidesPerView 3
|
|
498
|
+
mockSwiperInstance.slides = [document.createElement("div")];
|
|
499
|
+
mockSwiperInstance.params.slidesPerView = 3;
|
|
500
|
+
|
|
501
|
+
carouselInstance = new Carousel(carouselElement);
|
|
502
|
+
|
|
503
|
+
expect(mockSwiperInstance.disable).toHaveBeenCalled();
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it("should enable carousel when slides exceed slidesPerView by more than 1", () => {
|
|
507
|
+
// 5 slides, slidesPerView 2
|
|
508
|
+
mockSwiperInstance.slides = [
|
|
509
|
+
document.createElement("div"),
|
|
510
|
+
document.createElement("div"),
|
|
511
|
+
document.createElement("div"),
|
|
512
|
+
document.createElement("div"),
|
|
513
|
+
document.createElement("div"),
|
|
514
|
+
];
|
|
515
|
+
mockSwiperInstance.params.slidesPerView = 2;
|
|
516
|
+
|
|
517
|
+
carouselInstance = new Carousel(carouselElement);
|
|
518
|
+
|
|
519
|
+
expect(mockSwiperInstance.enable).toHaveBeenCalled();
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
describe("Update state on resize/breakpoint change", () => {
|
|
524
|
+
it("should update carousel enabled state on resize event", () => {
|
|
525
|
+
mockSwiperInstance.slides = [
|
|
526
|
+
document.createElement("div"),
|
|
527
|
+
document.createElement("div"),
|
|
528
|
+
];
|
|
529
|
+
mockSwiperInstance.params.slidesPerView = 2;
|
|
530
|
+
|
|
531
|
+
carouselInstance = new Carousel(carouselElement);
|
|
532
|
+
|
|
533
|
+
// Clear previous calls
|
|
534
|
+
mockSwiperInstance.disable.mockClear();
|
|
535
|
+
mockSwiperInstance.enable.mockClear();
|
|
536
|
+
|
|
537
|
+
// Simulate resize event with different breakpoint
|
|
538
|
+
mockSwiperInstance.slides = [
|
|
539
|
+
document.createElement("div"),
|
|
540
|
+
document.createElement("div"),
|
|
541
|
+
document.createElement("div"),
|
|
542
|
+
document.createElement("div"),
|
|
543
|
+
];
|
|
544
|
+
mockSwiperInstance.params.slidesPerView = 3;
|
|
545
|
+
|
|
546
|
+
// Get the resize callback
|
|
547
|
+
const resizeCallback = mockSwiperInstance.on.mock.calls.find(
|
|
548
|
+
(call) => call[0] === "resize",
|
|
549
|
+
);
|
|
550
|
+
if (resizeCallback) {
|
|
551
|
+
resizeCallback[1]();
|
|
552
|
+
expect(mockSwiperInstance.enable).toHaveBeenCalled();
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it("should handle resize with decimal slidesPerView", () => {
|
|
557
|
+
mockSwiperInstance.slides = [
|
|
558
|
+
document.createElement("div"),
|
|
559
|
+
document.createElement("div"),
|
|
560
|
+
document.createElement("div"),
|
|
561
|
+
document.createElement("div"),
|
|
562
|
+
];
|
|
563
|
+
mockSwiperInstance.params.slidesPerView = 2.5;
|
|
564
|
+
|
|
565
|
+
carouselInstance = new Carousel(carouselElement);
|
|
566
|
+
|
|
567
|
+
// 4 slides > 2.5, should be enabled
|
|
568
|
+
expect(mockSwiperInstance.enable).toHaveBeenCalled();
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
describe("Edge cases for auto-disable", () => {
|
|
573
|
+
it("should handle carousel with no slides", () => {
|
|
574
|
+
mockSwiperInstance.slides = [];
|
|
575
|
+
mockSwiperInstance.params.slidesPerView = 1;
|
|
576
|
+
|
|
577
|
+
carouselInstance = new Carousel(carouselElement);
|
|
578
|
+
|
|
579
|
+
expect(mockSwiperInstance.disable).toHaveBeenCalled();
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
it("should handle slidesPerView as string number", () => {
|
|
583
|
+
mockSwiperInstance.slides = [
|
|
584
|
+
document.createElement("div"),
|
|
585
|
+
document.createElement("div"),
|
|
586
|
+
];
|
|
587
|
+
mockSwiperInstance.params.slidesPerView = "2";
|
|
588
|
+
|
|
589
|
+
carouselInstance = new Carousel(carouselElement);
|
|
590
|
+
|
|
591
|
+
expect(mockSwiperInstance.disable).toHaveBeenCalled();
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
it("should default to slidesPerView 1 if not specified", () => {
|
|
595
|
+
mockSwiperInstance.slides = [
|
|
596
|
+
document.createElement("div"),
|
|
597
|
+
document.createElement("div"),
|
|
598
|
+
];
|
|
599
|
+
mockSwiperInstance.params.slidesPerView = undefined;
|
|
600
|
+
|
|
601
|
+
carouselInstance = new Carousel(carouselElement);
|
|
602
|
+
|
|
603
|
+
// 2 slides > 1 (default), should be enabled
|
|
604
|
+
expect(mockSwiperInstance.enable).toHaveBeenCalled();
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
it("should not crash if updateCarouselEnabledState called without instance", () => {
|
|
608
|
+
carouselInstance = new Carousel(carouselElement);
|
|
609
|
+
carouselInstance.instance = null;
|
|
610
|
+
|
|
611
|
+
expect(() => {
|
|
612
|
+
carouselInstance.updateCarouselEnabledState();
|
|
613
|
+
}).not.toThrow();
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
});
|
|
@@ -272,4 +272,62 @@ describe("rendering Carousel", () => {
|
|
|
272
272
|
expect(carousel).toHaveAttribute("data-carousel-id", "test-data-id");
|
|
273
273
|
});
|
|
274
274
|
});
|
|
275
|
+
|
|
276
|
+
describe("Auto-disable feature", () => {
|
|
277
|
+
const items = [
|
|
278
|
+
<p key="item1">item1</p>,
|
|
279
|
+
<p key="item2">item2</p>,
|
|
280
|
+
<p key="item3">item3</p>,
|
|
281
|
+
];
|
|
282
|
+
|
|
283
|
+
it("should render carousel element with id for auto-disable feature", () => {
|
|
284
|
+
const { container } = render(
|
|
285
|
+
<Carousel id="auto-disable-test" items={items} />,
|
|
286
|
+
);
|
|
287
|
+
const carousel = container.querySelector(".carousel");
|
|
288
|
+
expect(carousel).toHaveAttribute("id", "auto-disable-test");
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("should support swiperOptions with slidesPerView for auto-disable", () => {
|
|
292
|
+
const swiperOptions = {
|
|
293
|
+
slidesPerView: 2,
|
|
294
|
+
breakpoints: {
|
|
295
|
+
1240: {
|
|
296
|
+
slidesPerView: 3,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
const { container } = render(
|
|
301
|
+
<Carousel items={items} swiperOptions={swiperOptions} />,
|
|
302
|
+
);
|
|
303
|
+
const carousel = container.querySelector(".carousel");
|
|
304
|
+
expect(carousel.getAttribute("data-swiper-options")).toContain(
|
|
305
|
+
"slidesPerView",
|
|
306
|
+
);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("should work with bleedRight carousel and auto-disable", () => {
|
|
310
|
+
const { container } = render(
|
|
311
|
+
<Carousel items={items} bleedRight showScrollbar />,
|
|
312
|
+
);
|
|
313
|
+
const carousel = container.querySelector(".carousel");
|
|
314
|
+
expect(carousel).toHaveClass("carousel--bleed-right");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("should support minimal slides for testing auto-disable", () => {
|
|
318
|
+
const minimalItems = [<p key="item1">item1</p>];
|
|
319
|
+
const { container } = render(<Carousel items={minimalItems} />);
|
|
320
|
+
const slides = container.getElementsByClassName("carousel__slide");
|
|
321
|
+
expect(slides.length).toBe(1);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("should support many slides for testing auto-disable with high slidesPerView", () => {
|
|
325
|
+
const manyItems = Array.from({ length: 10 }, (_, i) => (
|
|
326
|
+
<p key={`item${i}`}>item{i}</p>
|
|
327
|
+
));
|
|
328
|
+
const { container } = render(<Carousel items={manyItems} />);
|
|
329
|
+
const slides = container.getElementsByClassName("carousel__slide");
|
|
330
|
+
expect(slides.length).toBe(10);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
275
333
|
});
|
|
@@ -13,35 +13,34 @@ export default class Expander {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
toggle() {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const summary = this.element.querySelector("summary");
|
|
17
|
+
|
|
19
18
|
if (!summary) {
|
|
20
19
|
return;
|
|
21
20
|
}
|
|
22
|
-
|
|
23
|
-
const summaryText = summary.getAttribute(
|
|
24
|
-
const summaryOpenedText = summary.getAttribute(
|
|
21
|
+
|
|
22
|
+
const summaryText = summary.getAttribute("data-summary");
|
|
23
|
+
const summaryOpenedText = summary.getAttribute("data-summary-opened");
|
|
25
24
|
|
|
26
25
|
summary.setAttribute(
|
|
27
|
-
|
|
28
|
-
summary.getAttribute(
|
|
26
|
+
"aria-expanded",
|
|
27
|
+
summary.getAttribute("aria-expanded") === "true" ? "false" : "true",
|
|
29
28
|
);
|
|
30
29
|
|
|
31
30
|
if (summaryOpenedText) {
|
|
32
31
|
const text =
|
|
33
|
-
summary.getAttribute(
|
|
32
|
+
summary.getAttribute("aria-expanded") === "true"
|
|
34
33
|
? summaryOpenedText
|
|
35
34
|
: summaryText;
|
|
36
35
|
|
|
37
36
|
if (text) {
|
|
38
|
-
summary.setAttribute(
|
|
37
|
+
summary.setAttribute("aria-label", text);
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
init() {
|
|
44
|
-
this.element.addEventListener(
|
|
43
|
+
this.element.addEventListener("toggle", this.toggle);
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
update() {
|
|
@@ -50,7 +49,7 @@ export default class Expander {
|
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
destroy() {
|
|
53
|
-
this.element.removeEventListener(
|
|
52
|
+
this.element.removeEventListener("toggle", this.toggle);
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
static getInstance(el: HTMLElementWithExpander | null): Expander | null {
|
|
@@ -68,7 +68,7 @@ const Footer: React.FC<FooterProps> = ({ className, data = footerData }) => {
|
|
|
68
68
|
<div className={CLASS_GRID}>
|
|
69
69
|
{data.columns.map((column, index) => (
|
|
70
70
|
<div key={`footer-column-${index}`}>
|
|
71
|
-
<
|
|
71
|
+
<p className={CLASS_TITLE}>{column.title}</p>
|
|
72
72
|
<ul className={CLASS_LIST}>
|
|
73
73
|
{column.links.map((link, linkIndex) => (
|
|
74
74
|
<li
|
|
@@ -107,14 +107,14 @@ describe("Footer Conformance Tests", () => {
|
|
|
107
107
|
|
|
108
108
|
describe("Semantic HTML", () => {
|
|
109
109
|
it("uses proper semantic elements", () => {
|
|
110
|
-
const { getByRole, getAllByRole } = render(<Footer />);
|
|
110
|
+
const { getByRole, getAllByRole, container } = render(<Footer />);
|
|
111
111
|
|
|
112
112
|
// Footer should be a landmark
|
|
113
113
|
expect(getByRole("contentinfo")).toBeInTheDocument();
|
|
114
114
|
|
|
115
|
-
// Should have proper
|
|
116
|
-
const
|
|
117
|
-
expect(
|
|
115
|
+
// Should have proper column titles (now rendered as paragraphs with footer__title class)
|
|
116
|
+
const titles = container.querySelectorAll(".footer__title");
|
|
117
|
+
expect(titles.length).toBe(4); // One for each column
|
|
118
118
|
|
|
119
119
|
// Should have navigation lists
|
|
120
120
|
const lists = getAllByRole("list");
|
|
@@ -115,14 +115,14 @@ describe("Footer", () => {
|
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
it("has proper semantic structure", () => {
|
|
118
|
-
const { getByRole, getAllByRole } = render(<Footer />);
|
|
118
|
+
const { getByRole, getAllByRole, container } = render(<Footer />);
|
|
119
119
|
|
|
120
120
|
// Should have footer landmark
|
|
121
121
|
expect(getByRole("contentinfo")).toBeInTheDocument();
|
|
122
122
|
|
|
123
|
-
// Should have
|
|
124
|
-
const
|
|
125
|
-
expect(
|
|
123
|
+
// Should have column titles (now rendered as paragraphs with footer__title class)
|
|
124
|
+
const titles = container.querySelectorAll(".footer__title");
|
|
125
|
+
expect(titles).toHaveLength(4); // 4 columns
|
|
126
126
|
|
|
127
127
|
// Should have lists for navigation
|
|
128
128
|
const lists = getAllByRole("list");
|
|
@@ -9,7 +9,7 @@ export type GridRowGapSize =
|
|
|
9
9
|
| "large"
|
|
10
10
|
| "xlarge"
|
|
11
11
|
| Record<string, "medium" | "large" | "xlarge">;
|
|
12
|
-
export type GridColumnGapSize = "none";
|
|
12
|
+
export type GridColumnGapSize = "none" | "small" | "default" | "large";
|
|
13
13
|
|
|
14
14
|
export interface GridProps extends React.HTMLAttributes<HTMLElement> {
|
|
15
15
|
vAlign?: GridVAlign;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
@use
|
|
1
|
+
@use "../../../styles/tokens/space";
|
|
2
2
|
|
|
3
3
|
$grid-base: 12 !default;
|
|
4
4
|
|
|
5
|
-
$grid-row-gap-sizes: (
|
|
5
|
+
$grid-row-gap-sizes: ("medium", "large", "xlarge");
|
|
6
6
|
|
|
7
7
|
$column-gap: (
|
|
8
|
-
|
|
8
|
+
small: space.get("xsmall"),
|
|
9
|
+
default: space.get("small"),
|
|
10
|
+
large: space.get("medium"),
|
|
9
11
|
none: 0,
|
|
10
12
|
);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
@use "sass:map";
|
|
2
|
-
@use
|
|
2
|
+
@use "sass:math";
|
|
3
3
|
|
|
4
|
-
@use
|
|
5
|
-
@use
|
|
6
|
-
@use
|
|
7
|
-
@use
|
|
8
|
-
@use
|
|
4
|
+
@use "./../../../styles/tools/generate";
|
|
5
|
+
@use "./../../../styles/tools/layout";
|
|
6
|
+
@use "./../../../styles/tokens/breakpoint";
|
|
7
|
+
@use "./../../../styles/tokens/space";
|
|
8
|
+
@use "./config";
|
|
9
9
|
|
|
10
10
|
@mixin grid-base() {
|
|
11
11
|
display: flex;
|
|
@@ -16,18 +16,23 @@
|
|
|
16
16
|
|
|
17
17
|
/* Fixes VoiceOver no announcing unordered lists */
|
|
18
18
|
> li::before {
|
|
19
|
-
content:
|
|
19
|
+
content: " ";
|
|
20
20
|
position: absolute;
|
|
21
21
|
width: 0;
|
|
22
22
|
height: 0;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
@mixin grid-column-gap($size:
|
|
26
|
+
@mixin grid-column-gap($size: "default", $column-gap: config.$column-gap) {
|
|
27
27
|
$gap: map.get($column-gap, $size);
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
@if ($size == "default") {
|
|
30
|
+
margin-left: -$gap;
|
|
31
|
+
margin-right: -$gap;
|
|
32
|
+
} @else {
|
|
33
|
+
margin-left: -$gap !important;
|
|
34
|
+
margin-right: -$gap !important;
|
|
35
|
+
}
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
@mixin grid-with-equal-height-content(
|
|
@@ -53,7 +58,7 @@
|
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
@mixin grid-row-gap(
|
|
56
|
-
$size:
|
|
61
|
+
$size: "medium",
|
|
57
62
|
$grid-col-selector: '[class*="grid__col"]'
|
|
58
63
|
) {
|
|
59
64
|
margin-top: #{space.get($size) * -1};
|
|
@@ -70,11 +75,16 @@
|
|
|
70
75
|
max-width: 100%;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
@mixin grid-col-column-gap($size:
|
|
78
|
+
@mixin grid-col-column-gap($size: "default", $column-gap: config.$column-gap) {
|
|
74
79
|
$gap: map.get($column-gap, $size);
|
|
75
80
|
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
@if ($size == "default") {
|
|
82
|
+
padding-left: $gap;
|
|
83
|
+
padding-right: $gap;
|
|
84
|
+
} @else {
|
|
85
|
+
padding-left: $gap !important;
|
|
86
|
+
padding-right: $gap !important;
|
|
87
|
+
}
|
|
78
88
|
}
|
|
79
89
|
|
|
80
90
|
@mixin column-size($width: config.$grid-base, $grid-base: config.$grid-base) {
|
|
@@ -100,25 +110,25 @@
|
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
@mixin column-classes() {
|
|
103
|
-
*[class*=
|
|
113
|
+
*[class*="grid__col"] {
|
|
104
114
|
@include grid-col-base();
|
|
105
115
|
}
|
|
106
116
|
|
|
107
117
|
@include breakpoint.each using ($breakpoint) {
|
|
108
|
-
.grid__col-#{generate.variant-name($breakpoint,
|
|
118
|
+
.grid__col-#{generate.variant-name($breakpoint, "-")}-shrink {
|
|
109
119
|
@include column-shrink;
|
|
110
120
|
}
|
|
111
121
|
|
|
112
|
-
.grid__col-#{generate.variant-name($breakpoint,
|
|
122
|
+
.grid__col-#{generate.variant-name($breakpoint, "-")}-fill {
|
|
113
123
|
@include column-fill;
|
|
114
124
|
}
|
|
115
125
|
|
|
116
|
-
.grid__col-#{generate.variant-name($breakpoint,
|
|
126
|
+
.grid__col-#{generate.variant-name($breakpoint, "-")}-auto {
|
|
117
127
|
@include column-auto;
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
@for $i from 1 through config.$grid-base {
|
|
121
|
-
.grid__col-#{generate.variant-name($breakpoint,
|
|
131
|
+
.grid__col-#{generate.variant-name($breakpoint, "-")}-#{$i} {
|
|
122
132
|
@include column-size($i);
|
|
123
133
|
}
|
|
124
134
|
}
|
|
@@ -62,6 +62,17 @@ describe("Grid", () => {
|
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
+
["small", "large", "none"].forEach((columnGapSize) => {
|
|
66
|
+
it(`applies grid--column-gap-${columnGapSize} class when columnGapSize is ${columnGapSize}`, () => {
|
|
67
|
+
const { getByTestId } = render(
|
|
68
|
+
<Grid data-testid="test-id" columnGapSize={columnGapSize} />,
|
|
69
|
+
);
|
|
70
|
+
expect(getByTestId("test-id")).toHaveClass(
|
|
71
|
+
`grid--column-gap-${columnGapSize}`,
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
65
76
|
it("merges additional className", () => {
|
|
66
77
|
const { getByTestId } = render(
|
|
67
78
|
<Grid data-testid="test-id" className="test-class" />,
|