@windstream/react-shared-components 0.1.93 → 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.esm.js +3 -3
- 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 +6 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +13 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/next/index.esm.js +2 -2
- package/dist/next/index.esm.js.map +1 -1
- package/dist/next/index.js +2 -2
- package/dist/next/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/index.esm.js +1 -1
- package/dist/utils/index.esm.js.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +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 -138
- package/src/contentful/blocks/find-kinetic/types.ts +20 -20
- 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 -78
- package/src/contentful/blocks/navigation/Navigation.stories.tsx +138 -138
- 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 -141
- package/src/contentful/blocks/navigation/index.test.tsx +924 -0
- package/src/contentful/blocks/navigation/index.tsx +569 -569
- 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
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
-
import type { ButtonProps } from "../../button/types";
|
|
3
|
-
|
|
4
|
-
export type PinwheelColor =
|
|
5
|
-
| "Blue-#307998"
|
|
6
|
-
| "Green-#209A61"
|
|
7
|
-
| "Orange-#DE7E0A"
|
|
8
|
-
| "Purple-#7E1458"
|
|
9
|
-
| (string & {});
|
|
10
|
-
|
|
11
|
-
export type SimpleCardCtaBottom = {
|
|
12
|
-
title?: string;
|
|
13
|
-
href?: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export type Item = {
|
|
17
|
-
title?: string;
|
|
18
|
-
image?: string;
|
|
19
|
-
imageAlt?: string;
|
|
20
|
-
imageWidth?: number;
|
|
21
|
-
imageHeight?: number;
|
|
22
|
-
imageAlignment?: "left" | "right" | "center";
|
|
23
|
-
iconAlignment?: "left" | "right" | "center";
|
|
24
|
-
/**
|
|
25
|
-
* Layout variant for the image. `standard` / `icon` render an inline
|
|
26
|
-
* icon above the content. `full` renders a full-bleed top image.
|
|
27
|
-
* `margin` is `full` with horizontal padding.
|
|
28
|
-
*/
|
|
29
|
-
imageView?: "standard" | "icon" | "full" | "margin" | "inset";
|
|
30
|
-
body?: ReactNode;
|
|
31
|
-
/** Optional secondary rich-text region (port of local `richText`). */
|
|
32
|
-
richText?: ReactNode;
|
|
33
|
-
cta?: ButtonProps;
|
|
34
|
-
ctaAlignment?: "left" | "right" | "center";
|
|
35
|
-
/** Top "location" CTA, rendered above the title with a `location_on` icon. */
|
|
36
|
-
ctaBottom?: SimpleCardCtaBottom;
|
|
37
|
-
ctaAlignmentBottom?: "left" | "right" | "center";
|
|
38
|
-
/** Legacy token-based card background (mapped via `backgroundColorMap`). */
|
|
39
|
-
backgroundColor?: string;
|
|
40
|
-
/** Raw color value used when `applyCardBackgroundColor` is true. */
|
|
41
|
-
applyCardBackgroundColor?: boolean;
|
|
42
|
-
textColor?: string;
|
|
43
|
-
showBackgroundImage?: boolean;
|
|
44
|
-
pinwheelColor?: PinwheelColor;
|
|
45
|
-
/** On `lg:` and up, lays out icon + content side-by-side. */
|
|
46
|
-
imageToRichTextAlignment?: boolean;
|
|
47
|
-
/** Bold label between title and the phone/hours table. */
|
|
48
|
-
titleLocation?: string;
|
|
49
|
-
phoneNumber?: string[];
|
|
50
|
-
/** Each entry uses a `label|value` separator. */
|
|
51
|
-
workingHours?: string[];
|
|
52
|
-
shadow?: boolean;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export type SimpleCardProps = {
|
|
56
|
-
card: Item;
|
|
57
|
-
lgWidth?: string;
|
|
58
|
-
mdWidth?: string;
|
|
59
|
-
className?: string;
|
|
60
|
-
contentClassName?: string;
|
|
61
|
-
style?: CSSProperties;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export const backgroundColorMap: Record<string, string> = {
|
|
65
|
-
blue: "bg-fill-brand",
|
|
66
|
-
green: "bg-fill-brand-accent",
|
|
67
|
-
navy: "bg-fill-inverse",
|
|
68
|
-
purple: "bg-fill-brand-tertiary",
|
|
69
|
-
white: "bg-white",
|
|
70
|
-
yellow: "bg-[#F5FF1E]",
|
|
71
|
-
};
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import type { ButtonProps } from "../../button/types";
|
|
3
|
+
|
|
4
|
+
export type PinwheelColor =
|
|
5
|
+
| "Blue-#307998"
|
|
6
|
+
| "Green-#209A61"
|
|
7
|
+
| "Orange-#DE7E0A"
|
|
8
|
+
| "Purple-#7E1458"
|
|
9
|
+
| (string & {});
|
|
10
|
+
|
|
11
|
+
export type SimpleCardCtaBottom = {
|
|
12
|
+
title?: string;
|
|
13
|
+
href?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type Item = {
|
|
17
|
+
title?: string;
|
|
18
|
+
image?: string;
|
|
19
|
+
imageAlt?: string;
|
|
20
|
+
imageWidth?: number;
|
|
21
|
+
imageHeight?: number;
|
|
22
|
+
imageAlignment?: "left" | "right" | "center";
|
|
23
|
+
iconAlignment?: "left" | "right" | "center";
|
|
24
|
+
/**
|
|
25
|
+
* Layout variant for the image. `standard` / `icon` render an inline
|
|
26
|
+
* icon above the content. `full` renders a full-bleed top image.
|
|
27
|
+
* `margin` is `full` with horizontal padding.
|
|
28
|
+
*/
|
|
29
|
+
imageView?: "standard" | "icon" | "full" | "margin" | "inset";
|
|
30
|
+
body?: ReactNode;
|
|
31
|
+
/** Optional secondary rich-text region (port of local `richText`). */
|
|
32
|
+
richText?: ReactNode;
|
|
33
|
+
cta?: ButtonProps;
|
|
34
|
+
ctaAlignment?: "left" | "right" | "center";
|
|
35
|
+
/** Top "location" CTA, rendered above the title with a `location_on` icon. */
|
|
36
|
+
ctaBottom?: SimpleCardCtaBottom;
|
|
37
|
+
ctaAlignmentBottom?: "left" | "right" | "center";
|
|
38
|
+
/** Legacy token-based card background (mapped via `backgroundColorMap`). */
|
|
39
|
+
backgroundColor?: string;
|
|
40
|
+
/** Raw color value used when `applyCardBackgroundColor` is true. */
|
|
41
|
+
applyCardBackgroundColor?: boolean;
|
|
42
|
+
textColor?: string;
|
|
43
|
+
showBackgroundImage?: boolean;
|
|
44
|
+
pinwheelColor?: PinwheelColor;
|
|
45
|
+
/** On `lg:` and up, lays out icon + content side-by-side. */
|
|
46
|
+
imageToRichTextAlignment?: boolean;
|
|
47
|
+
/** Bold label between title and the phone/hours table. */
|
|
48
|
+
titleLocation?: string;
|
|
49
|
+
phoneNumber?: string[];
|
|
50
|
+
/** Each entry uses a `label|value` separator. */
|
|
51
|
+
workingHours?: string[];
|
|
52
|
+
shadow?: boolean;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type SimpleCardProps = {
|
|
56
|
+
card: Item;
|
|
57
|
+
lgWidth?: string;
|
|
58
|
+
mdWidth?: string;
|
|
59
|
+
className?: string;
|
|
60
|
+
contentClassName?: string;
|
|
61
|
+
style?: CSSProperties;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const backgroundColorMap: Record<string, string> = {
|
|
65
|
+
blue: "bg-fill-brand",
|
|
66
|
+
green: "bg-fill-brand-accent",
|
|
67
|
+
navy: "bg-fill-inverse",
|
|
68
|
+
purple: "bg-fill-brand-tertiary",
|
|
69
|
+
white: "bg-white",
|
|
70
|
+
yellow: "bg-[#F5FF1E]",
|
|
71
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TestimonialCard } from "./index";
|
|
3
|
+
|
|
4
|
+
import { render, screen } from "@testing-library/react";
|
|
5
|
+
|
|
6
|
+
jest.mock("@shared/components/material-icon", () => ({
|
|
7
|
+
MaterialIcon: ({ name, className }: any) => (
|
|
8
|
+
<span data-testid="material-icon" className={className}>
|
|
9
|
+
{name}
|
|
10
|
+
</span>
|
|
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("next/image", () => {
|
|
21
|
+
const MockImage = ({ src, alt, className }: any) => (
|
|
22
|
+
<img data-testid="avatar-image" src={src} alt={alt} className={className} />
|
|
23
|
+
);
|
|
24
|
+
return MockImage;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
jest.mock(
|
|
28
|
+
"clsx",
|
|
29
|
+
() =>
|
|
30
|
+
(...args: any[]) =>
|
|
31
|
+
args.flat().filter(Boolean).join(" ")
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
describe("TestimonialCard", () => {
|
|
35
|
+
const defaultProps = {
|
|
36
|
+
title: "Great Service",
|
|
37
|
+
quote: "This is an amazing product!",
|
|
38
|
+
rating: 4,
|
|
39
|
+
author: "John Doe",
|
|
40
|
+
role: "CEO",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
describe("Rendering", () => {
|
|
44
|
+
it("renders the figure element", () => {
|
|
45
|
+
const { container } = render(<TestimonialCard {...defaultProps} />);
|
|
46
|
+
expect(container.querySelector("figure")).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("renders title", () => {
|
|
50
|
+
render(<TestimonialCard {...defaultProps} />);
|
|
51
|
+
expect(screen.getByText("Great Service")).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("renders quote", () => {
|
|
55
|
+
render(<TestimonialCard {...defaultProps} />);
|
|
56
|
+
expect(
|
|
57
|
+
screen.getByText("This is an amazing product!")
|
|
58
|
+
).toBeInTheDocument();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("renders author name", () => {
|
|
62
|
+
render(<TestimonialCard {...defaultProps} />);
|
|
63
|
+
expect(screen.getByText("John Doe")).toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("renders author role", () => {
|
|
67
|
+
render(<TestimonialCard {...defaultProps} />);
|
|
68
|
+
expect(screen.getByText("CEO")).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("Rating", () => {
|
|
73
|
+
it("renders 5 star icons", () => {
|
|
74
|
+
render(<TestimonialCard {...defaultProps} rating={4} />);
|
|
75
|
+
const icons = screen.getAllByTestId("material-icon");
|
|
76
|
+
expect(icons).toHaveLength(5);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("applies filled class to rated stars", () => {
|
|
80
|
+
render(<TestimonialCard {...defaultProps} rating={3} />);
|
|
81
|
+
const icons = screen.getAllByTestId("material-icon");
|
|
82
|
+
const filledIcons = icons.filter(icon =>
|
|
83
|
+
icon.className.includes("text-text")
|
|
84
|
+
);
|
|
85
|
+
expect(filledIcons.length).toBe(3);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("applies unfilled class to remaining stars", () => {
|
|
89
|
+
render(<TestimonialCard {...defaultProps} rating={3} />);
|
|
90
|
+
const icons = screen.getAllByTestId("material-icon");
|
|
91
|
+
const unfilledIcons = icons.filter(icon =>
|
|
92
|
+
icon.className.includes("text-gray-300")
|
|
93
|
+
);
|
|
94
|
+
expect(unfilledIcons.length).toBe(2);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("does not render rating section when rating is undefined", () => {
|
|
98
|
+
render(<TestimonialCard {...defaultProps} rating={undefined} />);
|
|
99
|
+
expect(screen.queryByTestId("material-icon")).not.toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("renders rating aria-label", () => {
|
|
103
|
+
const { container } = render(
|
|
104
|
+
<TestimonialCard {...defaultProps} rating={4} />
|
|
105
|
+
);
|
|
106
|
+
const ratingDiv = container.querySelector("[aria-label]");
|
|
107
|
+
expect(ratingDiv).toHaveAttribute("aria-label", "Rating: 4 out of 5");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("Avatar", () => {
|
|
112
|
+
it("renders avatar image when avatarUrl is provided", () => {
|
|
113
|
+
render(<TestimonialCard {...defaultProps} avatarUrl="/avatar.jpg" />);
|
|
114
|
+
expect(screen.getByTestId("avatar-image")).toBeInTheDocument();
|
|
115
|
+
expect(screen.getByTestId("avatar-image")).toHaveAttribute(
|
|
116
|
+
"src",
|
|
117
|
+
"/avatar.jpg"
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("renders initials when avatarUrl is not provided", () => {
|
|
122
|
+
render(<TestimonialCard {...defaultProps} />);
|
|
123
|
+
expect(screen.getByText("J")).toBeInTheDocument();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe("Active state", () => {
|
|
128
|
+
it("applies active styles when isActive is true", () => {
|
|
129
|
+
const { container } = render(
|
|
130
|
+
<TestimonialCard {...defaultProps} isActive={true} />
|
|
131
|
+
);
|
|
132
|
+
const figure = container.querySelector("figure");
|
|
133
|
+
expect(figure?.className).toContain("bg-bg-surface-secondary");
|
|
134
|
+
expect(figure?.className).toContain("shadow-drop");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("applies inactive styles when isActive is false", () => {
|
|
138
|
+
const { container } = render(
|
|
139
|
+
<TestimonialCard {...defaultProps} isActive={false} />
|
|
140
|
+
);
|
|
141
|
+
const figure = container.querySelector("figure");
|
|
142
|
+
expect(figure?.className).toContain("opacity-40");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("defaults to inactive", () => {
|
|
146
|
+
const { container } = render(<TestimonialCard {...defaultProps} />);
|
|
147
|
+
const figure = container.querySelector("figure");
|
|
148
|
+
expect(figure?.className).toContain("opacity-40");
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("Custom className", () => {
|
|
153
|
+
it("applies custom className", () => {
|
|
154
|
+
const { container } = render(
|
|
155
|
+
<TestimonialCard {...defaultProps} className="custom-card" />
|
|
156
|
+
);
|
|
157
|
+
const figure = container.querySelector("figure");
|
|
158
|
+
expect(figure?.className).toContain("custom-card");
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("Author section", () => {
|
|
163
|
+
it("does not render author section when author is not provided", () => {
|
|
164
|
+
const { container } = render(
|
|
165
|
+
<TestimonialCard
|
|
166
|
+
title="Test"
|
|
167
|
+
quote="Quote"
|
|
168
|
+
rating={5}
|
|
169
|
+
author={undefined}
|
|
170
|
+
/>
|
|
171
|
+
);
|
|
172
|
+
expect(container.querySelector("figcaption")).not.toBeInTheDocument();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("renders figcaption when author is provided", () => {
|
|
176
|
+
const { container } = render(<TestimonialCard {...defaultProps} />);
|
|
177
|
+
expect(container.querySelector("figcaption")).toBeInTheDocument();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { TestimonialCardProps } from "./types";
|
|
3
|
-
import clsx from "clsx";
|
|
4
|
-
import Image from "next/image";
|
|
5
|
-
|
|
6
|
-
import { MaterialIcon } from "@shared/components/material-icon";
|
|
7
|
-
import { Text } from "@shared/components/text";
|
|
8
|
-
|
|
9
|
-
export const TestimonialCard: React.FC<TestimonialCardProps> = ({
|
|
10
|
-
title,
|
|
11
|
-
quote,
|
|
12
|
-
rating,
|
|
13
|
-
author,
|
|
14
|
-
role,
|
|
15
|
-
avatarUrl,
|
|
16
|
-
isActive = false,
|
|
17
|
-
className,
|
|
18
|
-
}) => {
|
|
19
|
-
return (
|
|
20
|
-
<figure
|
|
21
|
-
className={clsx(
|
|
22
|
-
"flex w-full flex-col gap-6 rounded-card-lg p-6 transition-all duration-300 md:gap-10 md:p-14",
|
|
23
|
-
isActive
|
|
24
|
-
? "bg-bg-surface-secondary shadow-drop"
|
|
25
|
-
: "bg-gray-50 opacity-40", // Active vs Inactive styles
|
|
26
|
-
className
|
|
27
|
-
)}
|
|
28
|
-
>
|
|
29
|
-
<div className="flex flex-col justify-start gap-3 md:gap-5">
|
|
30
|
-
<header>
|
|
31
|
-
<Text as="h3" className="label1 text-text">
|
|
32
|
-
{title}
|
|
33
|
-
</Text>
|
|
34
|
-
</header>
|
|
35
|
-
<blockquote className="body1 text-text">{quote}</blockquote>
|
|
36
|
-
|
|
37
|
-
{/* Rating Stars */}
|
|
38
|
-
{rating ? (
|
|
39
|
-
<div className="flex" aria-label={`Rating: ${rating} out of 5`}>
|
|
40
|
-
{[...Array(5)].map((_, i) => (
|
|
41
|
-
<MaterialIcon
|
|
42
|
-
key={i}
|
|
43
|
-
size={24}
|
|
44
|
-
name="star"
|
|
45
|
-
fill={1}
|
|
46
|
-
className={clsx(
|
|
47
|
-
"h-[21px] w-[21px]",
|
|
48
|
-
i < rating ? "text-text" : "text-gray-300"
|
|
49
|
-
)}
|
|
50
|
-
aria-hidden="true"
|
|
51
|
-
/>
|
|
52
|
-
))}
|
|
53
|
-
</div>
|
|
54
|
-
) : null}
|
|
55
|
-
</div>
|
|
56
|
-
|
|
57
|
-
{/* Author Block */}
|
|
58
|
-
{author && (
|
|
59
|
-
<figcaption className="flex gap-3 md:gap-5">
|
|
60
|
-
<div className="relative h-12 w-12 shrink-0 overflow-hidden rounded-full bg-gray-300">
|
|
61
|
-
{avatarUrl ? (
|
|
62
|
-
<Image
|
|
63
|
-
src={avatarUrl}
|
|
64
|
-
alt={author}
|
|
65
|
-
fill={true}
|
|
66
|
-
className="object-cover"
|
|
67
|
-
sizes="40px"
|
|
68
|
-
/>
|
|
69
|
-
) : (
|
|
70
|
-
<div className="flex h-full w-full items-center justify-center bg-gray-500 text-xs font-bold text-white">
|
|
71
|
-
{author.charAt(0)}
|
|
72
|
-
</div>
|
|
73
|
-
)}
|
|
74
|
-
</div>
|
|
75
|
-
|
|
76
|
-
<div className="flex flex-col">
|
|
77
|
-
<cite className="label3 font-bold not-italic text-text">
|
|
78
|
-
{author}
|
|
79
|
-
</cite>
|
|
80
|
-
<Text as="p" className="body3 text-text">
|
|
81
|
-
{role}
|
|
82
|
-
</Text>
|
|
83
|
-
</div>
|
|
84
|
-
</figcaption>
|
|
85
|
-
)}
|
|
86
|
-
</figure>
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export default TestimonialCard;
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TestimonialCardProps } from "./types";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import Image from "next/image";
|
|
5
|
+
|
|
6
|
+
import { MaterialIcon } from "@shared/components/material-icon";
|
|
7
|
+
import { Text } from "@shared/components/text";
|
|
8
|
+
|
|
9
|
+
export const TestimonialCard: React.FC<TestimonialCardProps> = ({
|
|
10
|
+
title,
|
|
11
|
+
quote,
|
|
12
|
+
rating,
|
|
13
|
+
author,
|
|
14
|
+
role,
|
|
15
|
+
avatarUrl,
|
|
16
|
+
isActive = false,
|
|
17
|
+
className,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<figure
|
|
21
|
+
className={clsx(
|
|
22
|
+
"flex w-full flex-col gap-6 rounded-card-lg p-6 transition-all duration-300 md:gap-10 md:p-14",
|
|
23
|
+
isActive
|
|
24
|
+
? "bg-bg-surface-secondary shadow-drop"
|
|
25
|
+
: "bg-gray-50 opacity-40", // Active vs Inactive styles
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
<div className="flex flex-col justify-start gap-3 md:gap-5">
|
|
30
|
+
<header>
|
|
31
|
+
<Text as="h3" className="label1 text-text">
|
|
32
|
+
{title}
|
|
33
|
+
</Text>
|
|
34
|
+
</header>
|
|
35
|
+
<blockquote className="body1 text-text">{quote}</blockquote>
|
|
36
|
+
|
|
37
|
+
{/* Rating Stars */}
|
|
38
|
+
{rating ? (
|
|
39
|
+
<div className="flex" aria-label={`Rating: ${rating} out of 5`}>
|
|
40
|
+
{[...Array(5)].map((_, i) => (
|
|
41
|
+
<MaterialIcon
|
|
42
|
+
key={i}
|
|
43
|
+
size={24}
|
|
44
|
+
name="star"
|
|
45
|
+
fill={1}
|
|
46
|
+
className={clsx(
|
|
47
|
+
"h-[21px] w-[21px]",
|
|
48
|
+
i < rating ? "text-text" : "text-gray-300"
|
|
49
|
+
)}
|
|
50
|
+
aria-hidden="true"
|
|
51
|
+
/>
|
|
52
|
+
))}
|
|
53
|
+
</div>
|
|
54
|
+
) : null}
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
{/* Author Block */}
|
|
58
|
+
{author && (
|
|
59
|
+
<figcaption className="flex gap-3 md:gap-5">
|
|
60
|
+
<div className="relative h-12 w-12 shrink-0 overflow-hidden rounded-full bg-gray-300">
|
|
61
|
+
{avatarUrl ? (
|
|
62
|
+
<Image
|
|
63
|
+
src={avatarUrl}
|
|
64
|
+
alt={author}
|
|
65
|
+
fill={true}
|
|
66
|
+
className="object-cover"
|
|
67
|
+
sizes="40px"
|
|
68
|
+
/>
|
|
69
|
+
) : (
|
|
70
|
+
<div className="flex h-full w-full items-center justify-center bg-gray-500 text-xs font-bold text-white">
|
|
71
|
+
{author.charAt(0)}
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div className="flex flex-col">
|
|
77
|
+
<cite className="label3 font-bold not-italic text-text">
|
|
78
|
+
{author}
|
|
79
|
+
</cite>
|
|
80
|
+
<Text as="p" className="body3 text-text">
|
|
81
|
+
{role}
|
|
82
|
+
</Text>
|
|
83
|
+
</div>
|
|
84
|
+
</figcaption>
|
|
85
|
+
)}
|
|
86
|
+
</figure>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export default TestimonialCard;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
export interface TestimonialCardProps {
|
|
4
|
-
title?: string;
|
|
5
|
-
quote?: ReactNode;
|
|
6
|
-
rating?: number;
|
|
7
|
-
author?: string;
|
|
8
|
-
role?: string;
|
|
9
|
-
avatarUrl?: string;
|
|
10
|
-
isActive?: boolean;
|
|
11
|
-
className?: string;
|
|
12
|
-
}
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
export interface TestimonialCardProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
quote?: ReactNode;
|
|
6
|
+
rating?: number;
|
|
7
|
+
author?: string;
|
|
8
|
+
role?: string;
|
|
9
|
+
avatarUrl?: string;
|
|
10
|
+
isActive?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type CardsProps = {};
|
|
1
|
+
export type CardsProps = {};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { Carousel } from "./index";
|
|
2
|
-
|
|
3
|
-
import { DocsPage } from "@shared/stories/DocsTemplate";
|
|
4
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof Carousel> = {
|
|
7
|
-
title: "Contentful Blocks/Carousel",
|
|
8
|
-
component: Carousel,
|
|
9
|
-
tags: ["autodocs"],
|
|
10
|
-
parameters: {
|
|
11
|
-
layout: "centered",
|
|
12
|
-
docs: {
|
|
13
|
-
page: DocsPage,
|
|
14
|
-
description: {
|
|
15
|
-
component: "Contentful carousel block.",
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
args: {},
|
|
20
|
-
};
|
|
21
|
-
export default meta;
|
|
22
|
-
type Story = StoryObj<typeof meta>;
|
|
23
|
-
export const Default: Story = {};
|
|
1
|
+
import { Carousel } from "./index";
|
|
2
|
+
|
|
3
|
+
import { DocsPage } from "@shared/stories/DocsTemplate";
|
|
4
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Carousel> = {
|
|
7
|
+
title: "Contentful Blocks/Carousel",
|
|
8
|
+
component: Carousel,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "centered",
|
|
12
|
+
docs: {
|
|
13
|
+
page: DocsPage,
|
|
14
|
+
description: {
|
|
15
|
+
component: "Contentful carousel block.",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
args: {},
|
|
20
|
+
};
|
|
21
|
+
export default meta;
|
|
22
|
+
type Story = StoryObj<typeof meta>;
|
|
23
|
+
export const Default: Story = {};
|