@windstream/react-shared-components 0.1.92 → 0.1.94
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/README.md +635 -635
- package/dist/contentful/index.d.ts +1 -0
- package/dist/contentful/index.esm.js +2 -2
- package/dist/contentful/index.esm.js.map +1 -1
- package/dist/contentful/index.js +3 -3
- package/dist/contentful/index.js.map +1 -1
- package/dist/core.d.ts +5 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/index.esm.js +1 -1
- package/dist/utils/index.js +1 -1
- package/package.json +191 -185
- package/src/components/accordion/Accordion.stories.tsx +230 -230
- package/src/components/accordion/index.test.tsx +270 -0
- package/src/components/accordion/index.tsx +70 -70
- package/src/components/accordion/types.ts +12 -12
- package/src/components/alert-card/AlertCard.stories.tsx +171 -171
- package/src/components/alert-card/index.test.tsx +152 -0
- package/src/components/alert-card/index.tsx +41 -41
- package/src/components/alert-card/types.ts +13 -13
- package/src/components/animation-wrapper/index.test.tsx +424 -0
- package/src/components/animation-wrapper/index.tsx +129 -129
- package/src/components/animation-wrapper/types.ts +11 -11
- package/src/components/brand-button/BrandButton.stories.tsx +223 -223
- package/src/components/brand-button/helpers.ts +35 -35
- package/src/components/brand-button/index.test.tsx +292 -0
- package/src/components/brand-button/index.tsx +120 -120
- package/src/components/brand-button/types.ts +38 -38
- package/src/components/button/Button.stories.tsx +108 -108
- package/src/components/button/index.test.tsx +91 -0
- package/src/components/button/index.tsx +27 -27
- package/src/components/button/types.ts +14 -14
- package/src/components/call-button/CallButton.stories.tsx +324 -324
- package/src/components/call-button/index.test.tsx +260 -0
- package/src/components/call-button/index.tsx +106 -106
- package/src/components/call-button/types.ts +16 -16
- package/src/components/checkbox/Checkbox.stories.tsx +247 -247
- package/src/components/checkbox/index.test.tsx +252 -0
- package/src/components/checkbox/index.tsx +197 -197
- package/src/components/checkbox/types.ts +27 -27
- package/src/components/checklist/Checklist.stories.tsx +150 -150
- package/src/components/checklist/index.test.tsx +231 -0
- package/src/components/checklist/index.tsx +96 -61
- package/src/components/checklist/types.ts +23 -17
- package/src/components/collapse/Collapse.stories.tsx +255 -255
- package/src/components/collapse/index.test.tsx +277 -0
- package/src/components/collapse/index.tsx +47 -46
- package/src/components/collapse/types.ts +6 -6
- package/src/components/divider/Divider.stories.tsx +205 -205
- package/src/components/divider/index.test.tsx +53 -0
- package/src/components/divider/index.tsx +22 -22
- package/src/components/divider/type.ts +3 -3
- package/src/components/image/Image.stories.tsx +113 -113
- package/src/components/image/index.test.tsx +174 -0
- package/src/components/image/index.tsx +25 -25
- package/src/components/image/types.ts +40 -40
- package/src/components/input/Input.stories.tsx +325 -325
- package/src/components/input/index.test.tsx +348 -0
- package/src/components/input/index.tsx +177 -177
- package/src/components/input/types.ts +37 -37
- package/src/components/link/Link.stories.tsx +163 -163
- package/src/components/link/index.test.tsx +199 -0
- package/src/components/link/index.tsx +116 -116
- package/src/components/link/types.ts +25 -25
- package/src/components/list/List.stories.tsx +272 -272
- package/src/components/list/index.test.tsx +166 -0
- package/src/components/list/index.tsx +88 -88
- package/src/components/list/list-item/index.tsx +38 -38
- package/src/components/list/list-item/types.ts +13 -13
- package/src/components/list/types.ts +29 -29
- package/src/components/material-icon/MaterialIcon.stories.tsx +322 -322
- package/src/components/material-icon/constants.ts +99 -99
- package/src/components/material-icon/index.test.tsx +130 -0
- package/src/components/material-icon/index.tsx +47 -47
- package/src/components/material-icon/types.ts +31 -31
- package/src/components/modal/Modal.stories.tsx +171 -171
- package/src/components/modal/index.test.tsx +310 -0
- package/src/components/modal/index.tsx +164 -164
- package/src/components/modal/types.ts +24 -24
- package/src/components/next-image/index.test.tsx +406 -0
- package/src/components/next-image/index.tsx +74 -74
- package/src/components/next-image/types.ts +1 -1
- package/src/components/pagination/index.test.tsx +521 -0
- package/src/components/pagination/index.tsx +91 -91
- package/src/components/pagination/types.ts +6 -6
- package/src/components/radio-button/RadioButton.stories.tsx +307 -307
- package/src/components/radio-button/index.test.tsx +151 -0
- package/src/components/radio-button/index.tsx +75 -75
- package/src/components/radio-button/types.ts +21 -21
- package/src/components/see-more/SeeMore.stories.tsx +181 -181
- package/src/components/see-more/index.test.tsx +96 -0
- package/src/components/see-more/index.tsx +44 -44
- package/src/components/see-more/types.ts +4 -4
- package/src/components/select/Select.stories.tsx +411 -411
- package/src/components/select/index.test.tsx +256 -0
- package/src/components/select/index.tsx +155 -155
- package/src/components/select/types.ts +36 -36
- package/src/components/select-plan-button/SelectPlanButton.stories.tsx +184 -184
- package/src/components/select-plan-button/index.test.tsx +173 -0
- package/src/components/select-plan-button/index.tsx +63 -63
- package/src/components/select-plan-button/types.ts +17 -17
- package/src/components/skeleton/Skeleton.stories.tsx +179 -179
- package/src/components/skeleton/index.test.tsx +74 -0
- package/src/components/skeleton/index.tsx +61 -61
- package/src/components/skeleton/types.ts +4 -4
- package/src/components/spinner/Spinner.stories.tsx +335 -335
- package/src/components/spinner/index.test.tsx +76 -0
- package/src/components/spinner/index.tsx +44 -44
- package/src/components/spinner/types.ts +5 -5
- package/src/components/text/Text.stories.tsx +321 -321
- package/src/components/text/index.test.tsx +65 -0
- package/src/components/text/index.tsx +25 -25
- package/src/components/text/types.ts +45 -45
- package/src/components/tooltip/Tooltip.stories.tsx +219 -219
- package/src/components/tooltip/index.test.tsx +50 -0
- package/src/components/tooltip/index.tsx +74 -74
- package/src/components/tooltip/types.ts +7 -7
- package/src/components/view-cart-button/ViewCartButton.stories.tsx +252 -252
- package/src/components/view-cart-button/index.test.tsx +57 -0
- package/src/components/view-cart-button/index.tsx +42 -42
- package/src/components/view-cart-button/types.ts +5 -5
- package/src/contentful/blocks/accordion/Accordion.stories.mocks.tsx +128 -128
- package/src/contentful/blocks/accordion/Accordion.stories.tsx +98 -98
- package/src/contentful/blocks/accordion/index.test.tsx +218 -0
- package/src/contentful/blocks/accordion/index.tsx +114 -112
- package/src/contentful/blocks/accordion/types.ts +34 -34
- package/src/contentful/blocks/address-input-banner/index.test.tsx +132 -0
- package/src/contentful/blocks/address-input-banner/index.tsx +52 -52
- package/src/contentful/blocks/address-input-banner/types.ts +14 -14
- package/src/contentful/blocks/anchored-bottom-banner/index.test.tsx +287 -0
- package/src/contentful/blocks/anchored-bottom-banner/index.tsx +181 -181
- package/src/contentful/blocks/anchored-bottom-banner/types.ts +13 -13
- package/src/contentful/blocks/blogs-grid/BlogGrid.stories.mocks.tsx +144 -144
- package/src/contentful/blocks/blogs-grid/BlogGrid.stories.tsx +157 -156
- package/src/contentful/blocks/blogs-grid/index.test.tsx +355 -0
- package/src/contentful/blocks/blogs-grid/index.tsx +134 -134
- package/src/contentful/blocks/blogs-grid/types.ts +26 -26
- package/src/contentful/blocks/blogs-grid-base/index.test.tsx +274 -0
- package/src/contentful/blocks/blogs-grid-base/index.tsx +119 -119
- package/src/contentful/blocks/blogs-grid-base/types.ts +36 -36
- package/src/contentful/blocks/breadcrumbs/BreadcrumbNavigation.stories.tsx +147 -147
- package/src/contentful/blocks/breadcrumbs/index.test.tsx +281 -0
- package/src/contentful/blocks/breadcrumbs/index.tsx +95 -95
- package/src/contentful/blocks/breadcrumbs/types.ts +8 -8
- package/src/contentful/blocks/button/Button.stories.tsx +40 -40
- package/src/contentful/blocks/button/index.test.tsx +339 -0
- package/src/contentful/blocks/button/index.tsx +131 -131
- package/src/contentful/blocks/button/types.ts +39 -39
- package/src/contentful/blocks/callout/Callout.stories.tsx +23 -23
- package/src/contentful/blocks/callout/index.test.tsx +539 -0
- package/src/contentful/blocks/callout/index.tsx +277 -277
- package/src/contentful/blocks/callout/types.ts +78 -78
- package/src/contentful/blocks/cards/Cards.stories.tsx +23 -23
- package/src/contentful/blocks/cards/blog-card/index.test.tsx +218 -0
- package/src/contentful/blocks/cards/blog-card/index.tsx +129 -129
- package/src/contentful/blocks/cards/blog-card/types.ts +34 -34
- package/src/contentful/blocks/cards/floating-image-card/index.test.tsx +201 -0
- package/src/contentful/blocks/cards/floating-image-card/index.tsx +119 -119
- package/src/contentful/blocks/cards/floating-image-card/types.ts +30 -30
- package/src/contentful/blocks/cards/full-image-card/index.test.tsx +216 -0
- package/src/contentful/blocks/cards/full-image-card/index.tsx +130 -130
- package/src/contentful/blocks/cards/full-image-card/types.ts +29 -29
- package/src/contentful/blocks/cards/index.test.tsx +39 -0
- package/src/contentful/blocks/cards/index.tsx +13 -13
- package/src/contentful/blocks/cards/product-card/index.test.tsx +263 -0
- package/src/contentful/blocks/cards/product-card/index.tsx +251 -251
- package/src/contentful/blocks/cards/product-card/types.ts +28 -28
- package/src/contentful/blocks/cards/simple-card/index.test.tsx +364 -0
- package/src/contentful/blocks/cards/simple-card/index.tsx +325 -325
- package/src/contentful/blocks/cards/simple-card/types.ts +71 -71
- package/src/contentful/blocks/cards/testimonial-card/index.test.tsx +180 -0
- package/src/contentful/blocks/cards/testimonial-card/index.tsx +90 -90
- package/src/contentful/blocks/cards/testimonial-card/types.tsx +12 -12
- package/src/contentful/blocks/cards/types.ts +1 -1
- package/src/contentful/blocks/carousel/Carousel.stories.tsx +23 -23
- package/src/contentful/blocks/carousel/helper.test.tsx +539 -0
- package/src/contentful/blocks/carousel/helper.tsx +494 -494
- package/src/contentful/blocks/carousel/index.test.tsx +308 -0
- package/src/contentful/blocks/carousel/index.tsx +87 -87
- package/src/contentful/blocks/carousel/types.test.ts +16 -0
- package/src/contentful/blocks/carousel/types.ts +145 -145
- package/src/contentful/blocks/cart-retention-banner/index.test.tsx +409 -0
- package/src/contentful/blocks/cart-retention-banner/index.tsx +109 -109
- package/src/contentful/blocks/cart-retention-banner/types.ts +11 -11
- package/src/contentful/blocks/comparison-table/index.test.tsx +114 -0
- package/src/contentful/blocks/comparison-table/index.tsx +29 -29
- package/src/contentful/blocks/comparison-table/types.ts +6 -6
- package/src/contentful/blocks/cookiebanner/index.test.tsx +277 -0
- package/src/contentful/blocks/cookiebanner/index.tsx +146 -146
- package/src/contentful/blocks/cookiebanner/type.ts +7 -7
- package/src/contentful/blocks/cta-callout/CtaCallout.stories.tsx +46 -46
- package/src/contentful/blocks/cta-callout/index.test.tsx +244 -0
- package/src/contentful/blocks/cta-callout/index.tsx +73 -73
- package/src/contentful/blocks/cta-callout/types.ts +26 -26
- package/src/contentful/blocks/dynamic-tabs/index.test.tsx +240 -0
- package/src/contentful/blocks/dynamic-tabs/index.tsx +204 -204
- package/src/contentful/blocks/dynamic-tabs/types.ts +21 -21
- package/src/contentful/blocks/email-input-block/index.test.tsx +213 -0
- package/src/contentful/blocks/email-input-block/index.tsx +121 -116
- package/src/contentful/blocks/email-input-block/types.ts +16 -16
- package/src/contentful/blocks/find-kinetic/FindKinetic.stories.tsx +23 -23
- package/src/contentful/blocks/find-kinetic/index.test.tsx +269 -0
- package/src/contentful/blocks/find-kinetic/index.tsx +138 -130
- package/src/contentful/blocks/find-kinetic/types.ts +20 -19
- package/src/contentful/blocks/floating-banner/FloatingBanner.stories.tsx +34 -34
- package/src/contentful/blocks/floating-banner/index.test.tsx +246 -0
- package/src/contentful/blocks/floating-banner/index.tsx +97 -97
- package/src/contentful/blocks/floating-banner/types.ts +22 -22
- package/src/contentful/blocks/footer/Footer.stories.tsx +317 -317
- package/src/contentful/blocks/footer/index.test.tsx +302 -0
- package/src/contentful/blocks/footer/index.tsx +91 -91
- package/src/contentful/blocks/footer/types.ts +13 -13
- package/src/contentful/blocks/image-promo-bar/ImagePromoBar.stories.tsx +23 -23
- package/src/contentful/blocks/image-promo-bar/helper.test.tsx +61 -0
- package/src/contentful/blocks/image-promo-bar/helper.tsx +28 -28
- package/src/contentful/blocks/image-promo-bar/index.test.tsx +467 -0
- package/src/contentful/blocks/image-promo-bar/index.tsx +246 -246
- package/src/contentful/blocks/image-promo-bar/types.ts +44 -44
- package/src/contentful/blocks/image-promo-bar/vimeo-embed.test.tsx +142 -0
- package/src/contentful/blocks/image-promo-bar/vimeo-embed.tsx +93 -93
- package/src/contentful/blocks/image-promo-bar/youtube-embed.test.tsx +104 -0
- package/src/contentful/blocks/image-promo-bar/youtube-embed.tsx +46 -46
- package/src/contentful/blocks/modal/constants.ts +53 -53
- package/src/contentful/blocks/modal/index.test.tsx +209 -0
- package/src/contentful/blocks/modal/index.tsx +108 -108
- package/src/contentful/blocks/modal/types.ts +12 -12
- package/src/contentful/blocks/navigation/Navigation.stories.mocks.tsx +78 -0
- package/src/contentful/blocks/navigation/Navigation.stories.tsx +138 -0
- package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.test.tsx +208 -0
- package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.tsx +141 -139
- package/src/contentful/blocks/navigation/index.test.tsx +924 -0
- package/src/contentful/blocks/navigation/index.tsx +569 -568
- package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.test.tsx +131 -0
- package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.tsx +82 -82
- package/src/contentful/blocks/navigation/types.ts +71 -71
- package/src/contentful/blocks/primary-hero/PrimaryHero.stories.tsx +23 -23
- package/src/contentful/blocks/primary-hero/index.test.tsx +286 -0
- package/src/contentful/blocks/primary-hero/index.tsx +239 -236
- package/src/contentful/blocks/primary-hero/types.ts +37 -37
- package/src/contentful/blocks/search-block/index.test.tsx +268 -0
- package/src/contentful/blocks/search-block/index.tsx +90 -90
- package/src/contentful/blocks/search-block/types.ts +15 -15
- package/src/contentful/blocks/shape-background-wrapper/ShapeBackgroundWrapper.stories.tsx +26 -26
- package/src/contentful/blocks/shape-background-wrapper/index.test.tsx +284 -0
- package/src/contentful/blocks/shape-background-wrapper/index.tsx +124 -124
- package/src/contentful/blocks/shape-background-wrapper/types.ts +36 -36
- package/src/contentful/blocks/text/Text.stories.tsx +23 -23
- package/src/contentful/blocks/text/index.test.tsx +36 -0
- package/src/contentful/blocks/text/index.tsx +12 -12
- package/src/contentful/blocks/text/types.ts +1 -1
- package/src/contentful/index.test.ts +45 -0
- package/src/contentful/index.ts +105 -105
- package/src/global-mocks/contentful/to-document.ts +25 -0
- package/src/global-mocks/cookie.ts +48 -0
- package/src/global-mocks/cx.ts +37 -0
- package/src/global-mocks/index.ts +89 -0
- package/src/global-mocks/speed-card-bg.ts +27 -0
- package/src/global-mocks/utm.ts +49 -0
- package/src/hooks/contentful/use-contentful-rich-text.test.tsx +1758 -0
- package/src/hooks/contentful/use-contentful-rich-text.tsx +309 -309
- package/src/hooks/contentful/use-processed-check-list.test.tsx +277 -0
- package/src/hooks/contentful/use-processed-check-list.ts +63 -63
- package/src/hooks/use-body-scroll-lock.test.ts +134 -0
- package/src/hooks/use-body-scroll-lock.ts +34 -34
- package/src/hooks/use-carousel-swipe.test.ts +393 -0
- package/src/hooks/use-carousel-swipe.ts +264 -264
- package/src/hooks/use-outside-click.test.ts +142 -0
- package/src/hooks/use-outside-click.ts +17 -17
- package/src/index.ts +107 -107
- package/src/next/index.test.ts +7 -0
- package/src/next/index.ts +5 -5
- package/src/setupTests.ts +52 -46
- package/src/stories/DocsTemplate.tsx +24 -24
- package/src/styles/globals.css +343 -343
- package/src/types/global.d.ts +9 -9
- package/src/types/micro-components.ts +99 -99
- package/src/types/utm.ts +49 -49
- package/src/utils/contentful/to-document.test.ts +85 -0
- package/src/utils/contentful/to-document.ts +24 -24
- package/src/utils/cookie.test.ts +180 -0
- package/src/utils/cookie.ts +84 -84
- package/src/utils/cx.test.ts +90 -0
- package/src/utils/cx.ts +49 -49
- package/src/utils/index.test.ts +115 -0
- package/src/utils/index.ts +41 -41
- package/src/utils/speed-card-bg.test.ts +46 -0
- package/src/utils/speed-card-bg.ts +24 -24
- package/src/utils/utm.test.ts +359 -0
- package/src/utils/utm.ts +221 -221
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Footer } from "./index";
|
|
3
|
+
import { FooterProps } from "./types";
|
|
4
|
+
|
|
5
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
6
|
+
|
|
7
|
+
// Mock dependencies
|
|
8
|
+
jest.mock("@shared/components/divider", () => ({
|
|
9
|
+
Divider: ({ className }: { className?: string }) => (
|
|
10
|
+
<hr data-testid="divider" className={className} />
|
|
11
|
+
),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
jest.mock("@shared/components/text", () => ({
|
|
15
|
+
Text: ({ as: Tag = "span", children, className }: any) => (
|
|
16
|
+
<Tag className={className}>{children}</Tag>
|
|
17
|
+
),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
jest.mock("../button", () => ({
|
|
21
|
+
Button: ({
|
|
22
|
+
onClick,
|
|
23
|
+
linkClassName,
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
|
+
linkVariant,
|
|
26
|
+
buttonLabel,
|
|
27
|
+
...rest
|
|
28
|
+
}: any) => (
|
|
29
|
+
<button
|
|
30
|
+
data-testid="footer-button"
|
|
31
|
+
className={linkClassName}
|
|
32
|
+
onClick={onClick}
|
|
33
|
+
>
|
|
34
|
+
{buttonLabel || rest.children || "Link"}
|
|
35
|
+
</button>
|
|
36
|
+
),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
const mockLinks = [
|
|
40
|
+
{
|
|
41
|
+
title: "Products",
|
|
42
|
+
items: {
|
|
43
|
+
items: [
|
|
44
|
+
{ buttonLabel: "Internet", href: "/internet" },
|
|
45
|
+
{ buttonLabel: "TV", href: "/tv" },
|
|
46
|
+
{ buttonLabel: "Phone", href: "/phone" },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: "Support",
|
|
52
|
+
items: {
|
|
53
|
+
items: [
|
|
54
|
+
{ buttonLabel: "Help Center", href: "/help" },
|
|
55
|
+
{ buttonLabel: "Contact Us", href: "/contact" },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const mockBottomLinks = [
|
|
62
|
+
{ buttonLabel: "Privacy Policy", href: "/privacy" },
|
|
63
|
+
{ buttonLabel: "Terms of Use", href: "/terms" },
|
|
64
|
+
{ buttonLabel: "Accessibility", href: "/accessibility" },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const defaultProps: FooterProps = {
|
|
68
|
+
body: <p>Promotional content and disclaimers go here.</p>,
|
|
69
|
+
links: mockLinks,
|
|
70
|
+
bottomLinks: mockBottomLinks,
|
|
71
|
+
copyrights: "All rights reserved.",
|
|
72
|
+
terms: "Kinetic by Windstream.",
|
|
73
|
+
maxWidth: true,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
describe("Footer", () => {
|
|
77
|
+
describe("Rendering", () => {
|
|
78
|
+
it("renders with all props", () => {
|
|
79
|
+
render(<Footer {...defaultProps} />);
|
|
80
|
+
expect(
|
|
81
|
+
screen.getByText("Promotional content and disclaimers go here.")
|
|
82
|
+
).toBeInTheDocument();
|
|
83
|
+
expect(screen.getByText("Products")).toBeInTheDocument();
|
|
84
|
+
expect(screen.getByText("Support")).toBeInTheDocument();
|
|
85
|
+
expect(screen.getByText("All rights reserved.")).toBeInTheDocument();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("renders with minimal props (body only)", () => {
|
|
89
|
+
render(<Footer body={<span>Minimal body</span>} />);
|
|
90
|
+
expect(screen.getByText("Minimal body")).toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("renders body content in aside with proper aria-label", () => {
|
|
94
|
+
render(<Footer {...defaultProps} />);
|
|
95
|
+
const aside = screen.getByLabelText("Promotions and disclaimers");
|
|
96
|
+
expect(aside.tagName).toBe("ASIDE");
|
|
97
|
+
expect(aside).toHaveClass("break-words");
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("Promotional section (body)", () => {
|
|
102
|
+
it("renders ReactNode body content", () => {
|
|
103
|
+
render(
|
|
104
|
+
<Footer
|
|
105
|
+
body={
|
|
106
|
+
<div data-testid="promo">
|
|
107
|
+
<strong>Big Sale!</strong> Save 50%
|
|
108
|
+
</div>
|
|
109
|
+
}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
expect(screen.getByTestId("promo")).toBeInTheDocument();
|
|
113
|
+
expect(screen.getByText("Save 50%")).toBeInTheDocument();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("renders plain text body", () => {
|
|
117
|
+
render(<Footer body="Simple promotional text" />);
|
|
118
|
+
expect(screen.getByText("Simple promotional text")).toBeInTheDocument();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("Footer link groups", () => {
|
|
123
|
+
it("renders link group titles", () => {
|
|
124
|
+
render(<Footer {...defaultProps} />);
|
|
125
|
+
expect(screen.getByText("Products")).toBeInTheDocument();
|
|
126
|
+
expect(screen.getByText("Support")).toBeInTheDocument();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("renders all link items within groups", () => {
|
|
130
|
+
render(<Footer {...defaultProps} />);
|
|
131
|
+
const buttons = screen.getAllByTestId("footer-button");
|
|
132
|
+
// 3 Products links + 2 Support links + 3 bottom links = 8
|
|
133
|
+
expect(buttons).toHaveLength(8);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("renders nav elements with proper aria-labelledby", () => {
|
|
137
|
+
const { container } = render(<Footer {...defaultProps} />);
|
|
138
|
+
const navs = container.querySelectorAll("nav.site-links-group");
|
|
139
|
+
expect(navs).toHaveLength(2);
|
|
140
|
+
expect(navs[0]).toHaveAttribute("aria-labelledby", "footer-Products");
|
|
141
|
+
expect(navs[1]).toHaveAttribute("aria-labelledby", "footer-Support");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("renders no link groups when links is undefined", () => {
|
|
145
|
+
render(<Footer body="No links" />);
|
|
146
|
+
expect(screen.queryByText("Products")).not.toBeInTheDocument();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("renders no link groups when links is empty", () => {
|
|
150
|
+
render(<Footer body="No links" links={[]} />);
|
|
151
|
+
expect(screen.queryByText("Products")).not.toBeInTheDocument();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("handles link groups with missing title and items gracefully", () => {
|
|
155
|
+
const partialLinks = [
|
|
156
|
+
{ title: undefined, items: undefined },
|
|
157
|
+
{ title: "Valid", items: { items: undefined } },
|
|
158
|
+
{ title: "Also Valid", items: { items: [] } },
|
|
159
|
+
];
|
|
160
|
+
const { container } = render(
|
|
161
|
+
<Footer body="Partial" links={partialLinks} />
|
|
162
|
+
);
|
|
163
|
+
const navs = container.querySelectorAll("nav.site-links-group");
|
|
164
|
+
expect(navs).toHaveLength(3);
|
|
165
|
+
expect(screen.getByText("Valid")).toBeInTheDocument();
|
|
166
|
+
expect(screen.getByText("Also Valid")).toBeInTheDocument();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("renders dividers between link groups on mobile", () => {
|
|
170
|
+
render(<Footer {...defaultProps} />);
|
|
171
|
+
const dividers = screen.getAllByTestId("divider");
|
|
172
|
+
// 1 main divider + 2 mobile dividers (one per link group) + 1 bottom divider = 4
|
|
173
|
+
expect(dividers.length).toBeGreaterThanOrEqual(3);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe("Footer layout", () => {
|
|
178
|
+
it("renders with 4-column grid layout", () => {
|
|
179
|
+
const { container } = render(<Footer {...defaultProps} />);
|
|
180
|
+
const grid = container.querySelector(".lg\\:grid-cols-4");
|
|
181
|
+
expect(grid).toBeInTheDocument();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("applies inverse background and white text", () => {
|
|
185
|
+
const { container } = render(<Footer {...defaultProps} />);
|
|
186
|
+
expect(container.firstChild).toHaveClass("bg-bg-inverse");
|
|
187
|
+
expect(container.firstChild).toHaveClass("text-white");
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe("Max width", () => {
|
|
192
|
+
it("applies max-w-120 when maxWidth is true (default)", () => {
|
|
193
|
+
const { container } = render(<Footer {...defaultProps} />);
|
|
194
|
+
const wrapper = container.querySelector(".max-w-120");
|
|
195
|
+
expect(wrapper).toBeInTheDocument();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("does not apply max-w-120 when maxWidth is false", () => {
|
|
199
|
+
const { container } = render(
|
|
200
|
+
<Footer {...defaultProps} maxWidth={false} />
|
|
201
|
+
);
|
|
202
|
+
const wrapper = container.querySelector(".max-w-120");
|
|
203
|
+
expect(wrapper).not.toBeInTheDocument();
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe("Copyright and terms", () => {
|
|
208
|
+
it("renders copyright year with current year", () => {
|
|
209
|
+
render(<Footer {...defaultProps} />);
|
|
210
|
+
const currentYear = new Date().getFullYear().toString();
|
|
211
|
+
const termsEl = screen.getByText(
|
|
212
|
+
content =>
|
|
213
|
+
content.includes(currentYear) &&
|
|
214
|
+
content.includes("Kinetic by Windstream.")
|
|
215
|
+
);
|
|
216
|
+
expect(termsEl).toBeInTheDocument();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("renders copyrights text", () => {
|
|
220
|
+
render(<Footer {...defaultProps} />);
|
|
221
|
+
expect(screen.getByText("All rights reserved.")).toBeInTheDocument();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("renders terms with copyright symbol", () => {
|
|
225
|
+
render(<Footer {...defaultProps} />);
|
|
226
|
+
const termsEl = screen.getByText(/©.*Kinetic by Windstream/);
|
|
227
|
+
expect(termsEl).toBeInTheDocument();
|
|
228
|
+
expect(termsEl).toHaveClass("terms-text");
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("renders copyrights with whitespace-pre-line class", () => {
|
|
232
|
+
render(<Footer {...defaultProps} />);
|
|
233
|
+
const copyEl = screen.getByText("All rights reserved.");
|
|
234
|
+
expect(copyEl).toHaveClass("copy-rights");
|
|
235
|
+
expect(copyEl).toHaveClass("whitespace-pre-line");
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe("Bottom links", () => {
|
|
240
|
+
it("renders bottom links", () => {
|
|
241
|
+
render(<Footer {...defaultProps} />);
|
|
242
|
+
const legalNav = screen.getByLabelText("Footer legal");
|
|
243
|
+
expect(legalNav).toBeInTheDocument();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("renders correct number of bottom links", () => {
|
|
247
|
+
render(<Footer {...defaultProps} />);
|
|
248
|
+
const legalNav = screen.getByLabelText("Footer legal");
|
|
249
|
+
const items = legalNav.querySelectorAll("li");
|
|
250
|
+
expect(items).toHaveLength(3);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("renders no bottom links when not provided", () => {
|
|
254
|
+
render(<Footer body="No bottom" />);
|
|
255
|
+
const legalNav = screen.getByLabelText("Footer legal");
|
|
256
|
+
const items = legalNav.querySelectorAll("li");
|
|
257
|
+
expect(items).toHaveLength(0);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe("onClick handler", () => {
|
|
262
|
+
it("calls onClick when a site link is clicked", () => {
|
|
263
|
+
const handleClick = jest.fn();
|
|
264
|
+
render(<Footer {...defaultProps} onClick={handleClick} />);
|
|
265
|
+
const buttons = screen.getAllByTestId("footer-button");
|
|
266
|
+
fireEvent.click(buttons[0]);
|
|
267
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("calls onClick for each link clicked", () => {
|
|
271
|
+
const handleClick = jest.fn();
|
|
272
|
+
render(<Footer {...defaultProps} onClick={handleClick} />);
|
|
273
|
+
const buttons = screen.getAllByTestId("footer-button");
|
|
274
|
+
fireEvent.click(buttons[0]);
|
|
275
|
+
fireEvent.click(buttons[1]);
|
|
276
|
+
expect(handleClick).toHaveBeenCalledTimes(2);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("does not error when onClick is not provided", () => {
|
|
280
|
+
render(<Footer body="No click handler" links={mockLinks} />);
|
|
281
|
+
const buttons = screen.getAllByTestId("footer-button");
|
|
282
|
+
expect(() => fireEvent.click(buttons[0])).not.toThrow();
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe("Dividers", () => {
|
|
287
|
+
it("renders main divider between body and links", () => {
|
|
288
|
+
render(<Footer {...defaultProps} />);
|
|
289
|
+
const dividers = screen.getAllByTestId("divider");
|
|
290
|
+
expect(dividers.length).toBeGreaterThanOrEqual(1);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("renders dividers with inverse border class", () => {
|
|
294
|
+
render(<Footer {...defaultProps} />);
|
|
295
|
+
const dividers = screen.getAllByTestId("divider");
|
|
296
|
+
const inverseDividers = dividers.filter(d =>
|
|
297
|
+
d.className.includes("border-border-inverse")
|
|
298
|
+
);
|
|
299
|
+
expect(inverseDividers.length).toBeGreaterThanOrEqual(1);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
});
|
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Button } from "../button";
|
|
3
|
-
import { FooterProps } from "./types";
|
|
4
|
-
|
|
5
|
-
import { Divider } from "@shared/components/divider";
|
|
6
|
-
import { Text } from "@shared/components/text";
|
|
7
|
-
|
|
8
|
-
export const Footer: React.FC<FooterProps> = ({
|
|
9
|
-
body,
|
|
10
|
-
links,
|
|
11
|
-
bottomLinks,
|
|
12
|
-
copyrights,
|
|
13
|
-
terms,
|
|
14
|
-
maxWidth = true,
|
|
15
|
-
onClick,
|
|
16
|
-
}) => {
|
|
17
|
-
function footerClick(
|
|
18
|
-
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
19
|
-
): void {
|
|
20
|
-
onClick?.(event);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<div className="component-container bg-bg-inverse text-white">
|
|
25
|
-
<div className={` ${maxWidth ? "mx-auto max-w-120" : ""} px-5 py-8`}>
|
|
26
|
-
<aside className="break-words" aria-label="Promotions and disclaimers">
|
|
27
|
-
{body}
|
|
28
|
-
</aside>
|
|
29
|
-
<Divider className="my-8 border-border-inverse lg:my-16" />
|
|
30
|
-
<div className="grid-1 grid gap-8 md:grid-cols-2 lg:grid-cols-4">
|
|
31
|
-
{links?.map((link: any, index: number) => (
|
|
32
|
-
<React.Fragment key={`footer-link-group-${index}`}>
|
|
33
|
-
<div key={`footer-link-group-${index}`}>
|
|
34
|
-
<nav
|
|
35
|
-
aria-labelledby={`footer-${link?.title}`}
|
|
36
|
-
className="site-links-group"
|
|
37
|
-
key={`link-group-${index}`}
|
|
38
|
-
>
|
|
39
|
-
<Text as="div" className="label3">
|
|
40
|
-
{link?.title}
|
|
41
|
-
</Text>
|
|
42
|
-
<ul className="flex flex-col">
|
|
43
|
-
{link?.items?.items?.map((site: any, _index: number) => (
|
|
44
|
-
<li className="pt-3" key={`site-links-${_index}`}>
|
|
45
|
-
<Button
|
|
46
|
-
{...site}
|
|
47
|
-
linkVariant="unstyled"
|
|
48
|
-
linkClassName="text-white body3 hover:underline underline-offset-4"
|
|
49
|
-
onClick={footerClick}
|
|
50
|
-
/>
|
|
51
|
-
</li>
|
|
52
|
-
))}
|
|
53
|
-
</ul>
|
|
54
|
-
</nav>
|
|
55
|
-
</div>
|
|
56
|
-
<Divider className="border-border-inverse md:hidden" />
|
|
57
|
-
</React.Fragment>
|
|
58
|
-
))}
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<div className="py-8">
|
|
62
|
-
<Divider className="my-8 hidden border-border-inverse md:my-8 md:block" />
|
|
63
|
-
|
|
64
|
-
<p className="terms-text footnote text-white">
|
|
65
|
-
© {new Date().getFullYear()} {terms}
|
|
66
|
-
</p>
|
|
67
|
-
<p className="copy-rights whitespace-pre-line">{copyrights}</p>
|
|
68
|
-
<nav aria-label="Footer legal">
|
|
69
|
-
<ul className="bottom-links list-none">
|
|
70
|
-
{bottomLinks?.map((link: any, index: number) => (
|
|
71
|
-
<li
|
|
72
|
-
key={`links-${index}`}
|
|
73
|
-
className="relative float-left pl-[8px] before:absolute before:left-[3px] before:top-1/2 before:-translate-y-1/2 before:text-[14px] before:content-['•'] first-of-type:pl-0 first-of-type:before:content-['']"
|
|
74
|
-
>
|
|
75
|
-
<Button
|
|
76
|
-
{...link}
|
|
77
|
-
linkClassName="footnote text-white hover:underline underline-offset-4"
|
|
78
|
-
linkVariant="unstyled"
|
|
79
|
-
onClick={footerClick}
|
|
80
|
-
/>
|
|
81
|
-
</li>
|
|
82
|
-
))}
|
|
83
|
-
</ul>
|
|
84
|
-
</nav>
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export default Footer;
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Button } from "../button";
|
|
3
|
+
import { FooterProps } from "./types";
|
|
4
|
+
|
|
5
|
+
import { Divider } from "@shared/components/divider";
|
|
6
|
+
import { Text } from "@shared/components/text";
|
|
7
|
+
|
|
8
|
+
export const Footer: React.FC<FooterProps> = ({
|
|
9
|
+
body,
|
|
10
|
+
links,
|
|
11
|
+
bottomLinks,
|
|
12
|
+
copyrights,
|
|
13
|
+
terms,
|
|
14
|
+
maxWidth = true,
|
|
15
|
+
onClick,
|
|
16
|
+
}) => {
|
|
17
|
+
function footerClick(
|
|
18
|
+
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
19
|
+
): void {
|
|
20
|
+
onClick?.(event);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="component-container bg-bg-inverse text-white">
|
|
25
|
+
<div className={` ${maxWidth ? "mx-auto max-w-120" : ""} px-5 py-8`}>
|
|
26
|
+
<aside className="break-words" aria-label="Promotions and disclaimers">
|
|
27
|
+
{body}
|
|
28
|
+
</aside>
|
|
29
|
+
<Divider className="my-8 border-border-inverse lg:my-16" />
|
|
30
|
+
<div className="grid-1 grid gap-8 md:grid-cols-2 lg:grid-cols-4">
|
|
31
|
+
{links?.map((link: any, index: number) => (
|
|
32
|
+
<React.Fragment key={`footer-link-group-${index}`}>
|
|
33
|
+
<div key={`footer-link-group-${index}`}>
|
|
34
|
+
<nav
|
|
35
|
+
aria-labelledby={`footer-${link?.title}`}
|
|
36
|
+
className="site-links-group"
|
|
37
|
+
key={`link-group-${index}`}
|
|
38
|
+
>
|
|
39
|
+
<Text as="div" className="label3">
|
|
40
|
+
{link?.title}
|
|
41
|
+
</Text>
|
|
42
|
+
<ul className="flex flex-col">
|
|
43
|
+
{link?.items?.items?.map((site: any, _index: number) => (
|
|
44
|
+
<li className="pt-3" key={`site-links-${_index}`}>
|
|
45
|
+
<Button
|
|
46
|
+
{...site}
|
|
47
|
+
linkVariant="unstyled"
|
|
48
|
+
linkClassName="text-white body3 hover:underline underline-offset-4"
|
|
49
|
+
onClick={footerClick}
|
|
50
|
+
/>
|
|
51
|
+
</li>
|
|
52
|
+
))}
|
|
53
|
+
</ul>
|
|
54
|
+
</nav>
|
|
55
|
+
</div>
|
|
56
|
+
<Divider className="border-border-inverse md:hidden" />
|
|
57
|
+
</React.Fragment>
|
|
58
|
+
))}
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div className="py-8">
|
|
62
|
+
<Divider className="my-8 hidden border-border-inverse md:my-8 md:block" />
|
|
63
|
+
|
|
64
|
+
<p className="terms-text footnote text-white">
|
|
65
|
+
© {new Date().getFullYear()} {terms}
|
|
66
|
+
</p>
|
|
67
|
+
<p className="copy-rights whitespace-pre-line">{copyrights}</p>
|
|
68
|
+
<nav aria-label="Footer legal">
|
|
69
|
+
<ul className="bottom-links list-none">
|
|
70
|
+
{bottomLinks?.map((link: any, index: number) => (
|
|
71
|
+
<li
|
|
72
|
+
key={`links-${index}`}
|
|
73
|
+
className="relative float-left pl-[8px] before:absolute before:left-[3px] before:top-1/2 before:-translate-y-1/2 before:text-[14px] before:content-['•'] first-of-type:pl-0 first-of-type:before:content-['']"
|
|
74
|
+
>
|
|
75
|
+
<Button
|
|
76
|
+
{...link}
|
|
77
|
+
linkClassName="footnote text-white hover:underline underline-offset-4"
|
|
78
|
+
linkVariant="unstyled"
|
|
79
|
+
onClick={footerClick}
|
|
80
|
+
/>
|
|
81
|
+
</li>
|
|
82
|
+
))}
|
|
83
|
+
</ul>
|
|
84
|
+
</nav>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default Footer;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
export type FooterProps = {
|
|
4
|
-
body: React.ReactNode;
|
|
5
|
-
links?: Array<any>;
|
|
6
|
-
bottomLinks?: Array<any>;
|
|
7
|
-
copyrights?: React.ReactNode;
|
|
8
|
-
terms?: string;
|
|
9
|
-
maxWidth?: boolean;
|
|
10
|
-
onClick?: (
|
|
11
|
-
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
12
|
-
) => void;
|
|
13
|
-
};
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
export type FooterProps = {
|
|
4
|
+
body: React.ReactNode;
|
|
5
|
+
links?: Array<any>;
|
|
6
|
+
bottomLinks?: Array<any>;
|
|
7
|
+
copyrights?: React.ReactNode;
|
|
8
|
+
terms?: string;
|
|
9
|
+
maxWidth?: boolean;
|
|
10
|
+
onClick?: (
|
|
11
|
+
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
12
|
+
) => void;
|
|
13
|
+
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { ImagePromoBar } from "./index";
|
|
2
|
-
|
|
3
|
-
import { DocsPage } from "@shared/stories/DocsTemplate";
|
|
4
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof ImagePromoBar> = {
|
|
7
|
-
title: "Contentful Blocks/ImagePromoBar",
|
|
8
|
-
component: ImagePromoBar,
|
|
9
|
-
tags: ["autodocs"],
|
|
10
|
-
parameters: {
|
|
11
|
-
layout: "centered",
|
|
12
|
-
docs: {
|
|
13
|
-
page: DocsPage,
|
|
14
|
-
description: {
|
|
15
|
-
component: "Contentful image promo bar block.",
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
args: {},
|
|
20
|
-
};
|
|
21
|
-
export default meta;
|
|
22
|
-
type Story = StoryObj<typeof meta>;
|
|
23
|
-
export const Default: Story = {};
|
|
1
|
+
import { ImagePromoBar } from "./index";
|
|
2
|
+
|
|
3
|
+
import { DocsPage } from "@shared/stories/DocsTemplate";
|
|
4
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof ImagePromoBar> = {
|
|
7
|
+
title: "Contentful Blocks/ImagePromoBar",
|
|
8
|
+
component: ImagePromoBar,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "centered",
|
|
12
|
+
docs: {
|
|
13
|
+
page: DocsPage,
|
|
14
|
+
description: {
|
|
15
|
+
component: "Contentful image promo bar block.",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
args: {},
|
|
20
|
+
};
|
|
21
|
+
export default meta;
|
|
22
|
+
type Story = StoryObj<typeof meta>;
|
|
23
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { PlayButton } from "./helper";
|
|
3
|
+
|
|
4
|
+
import { render, screen } from "@testing-library/react";
|
|
5
|
+
|
|
6
|
+
jest.mock("@shared/components/material-icon", () => ({
|
|
7
|
+
MaterialIcon: ({ name, size, fill, className }: any) => (
|
|
8
|
+
<span
|
|
9
|
+
data-testid="material-icon"
|
|
10
|
+
data-name={name}
|
|
11
|
+
data-size={size}
|
|
12
|
+
data-fill={fill}
|
|
13
|
+
className={className}
|
|
14
|
+
/>
|
|
15
|
+
),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe("PlayButton", () => {
|
|
19
|
+
it("renders button with aria-label", () => {
|
|
20
|
+
render(<PlayButton />);
|
|
21
|
+
expect(
|
|
22
|
+
screen.getByRole("button", { name: "Play button" })
|
|
23
|
+
).toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("renders MaterialIcon with play_arrow", () => {
|
|
27
|
+
render(<PlayButton />);
|
|
28
|
+
expect(screen.getByTestId("material-icon")).toHaveAttribute(
|
|
29
|
+
"data-name",
|
|
30
|
+
"play_arrow"
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("applies text-text-brand when isHovered is true", () => {
|
|
35
|
+
render(<PlayButton isHovered={true} />);
|
|
36
|
+
expect(screen.getByTestId("material-icon").className).toContain(
|
|
37
|
+
"text-text-brand"
|
|
38
|
+
);
|
|
39
|
+
expect(screen.getByTestId("material-icon").className).not.toContain(
|
|
40
|
+
"text-slate-500"
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("applies text-slate-500 when isHovered is false", () => {
|
|
45
|
+
render(<PlayButton isHovered={false} />);
|
|
46
|
+
expect(screen.getByTestId("material-icon").className).toContain(
|
|
47
|
+
"text-slate-500"
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("applies containerClassName when provided", () => {
|
|
52
|
+
render(<PlayButton containerClassName="custom-class" />);
|
|
53
|
+
expect(screen.getByRole("button").className).toContain("custom-class");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("does not add extra class when containerClassName is undefined", () => {
|
|
57
|
+
const { container } = render(<PlayButton />);
|
|
58
|
+
const btn = container.querySelector("button");
|
|
59
|
+
expect(btn?.className).not.toContain("undefined");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { PlayButtonProps } from "./types";
|
|
3
|
-
|
|
4
|
-
import { MaterialIcon } from "@shared/components/material-icon";
|
|
5
|
-
|
|
6
|
-
export const PlayButton: React.FC<PlayButtonProps> = ({
|
|
7
|
-
isHovered: isOuterHovered,
|
|
8
|
-
containerClassName,
|
|
9
|
-
}) => {
|
|
10
|
-
return (
|
|
11
|
-
<button
|
|
12
|
-
tabIndex={-1}
|
|
13
|
-
className={`group flex h-20 w-20 items-center justify-center rounded-full bg-white shadow-xl transition-all duration-300 hover:scale-110 active:scale-95 ${containerClassName || ""}`}
|
|
14
|
-
aria-label="Play button"
|
|
15
|
-
>
|
|
16
|
-
<MaterialIcon
|
|
17
|
-
name="play_arrow"
|
|
18
|
-
size={72 as any}
|
|
19
|
-
fill={1}
|
|
20
|
-
className={`transition-colors duration-300 ${
|
|
21
|
-
isOuterHovered
|
|
22
|
-
? "text-text-brand"
|
|
23
|
-
: "text-slate-500 group-hover:text-text-brand"
|
|
24
|
-
}`}
|
|
25
|
-
/>
|
|
26
|
-
</button>
|
|
27
|
-
);
|
|
28
|
-
};
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { PlayButtonProps } from "./types";
|
|
3
|
+
|
|
4
|
+
import { MaterialIcon } from "@shared/components/material-icon";
|
|
5
|
+
|
|
6
|
+
export const PlayButton: React.FC<PlayButtonProps> = ({
|
|
7
|
+
isHovered: isOuterHovered,
|
|
8
|
+
containerClassName,
|
|
9
|
+
}) => {
|
|
10
|
+
return (
|
|
11
|
+
<button
|
|
12
|
+
tabIndex={-1}
|
|
13
|
+
className={`group flex h-20 w-20 items-center justify-center rounded-full bg-white shadow-xl transition-all duration-300 hover:scale-110 active:scale-95 ${containerClassName || ""}`}
|
|
14
|
+
aria-label="Play button"
|
|
15
|
+
>
|
|
16
|
+
<MaterialIcon
|
|
17
|
+
name="play_arrow"
|
|
18
|
+
size={72 as any}
|
|
19
|
+
fill={1}
|
|
20
|
+
className={`transition-colors duration-300 ${
|
|
21
|
+
isOuterHovered
|
|
22
|
+
? "text-text-brand"
|
|
23
|
+
: "text-slate-500 group-hover:text-text-brand"
|
|
24
|
+
}`}
|
|
25
|
+
/>
|
|
26
|
+
</button>
|
|
27
|
+
);
|
|
28
|
+
};
|