@windstream/react-shared-components 0.0.68 → 0.0.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +629 -629
  2. package/dist/contentful/index.d.ts +112 -9
  3. package/dist/contentful/index.esm.js +1 -1
  4. package/dist/contentful/index.esm.js.map +1 -1
  5. package/dist/contentful/index.js +1 -1
  6. package/dist/contentful/index.js.map +1 -1
  7. package/dist/core.d.ts +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.esm.js +1 -1
  10. package/dist/index.esm.js.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/styles.css +1 -1
  14. package/package.json +175 -175
  15. package/src/components/accordion/Accordion.stories.tsx +230 -230
  16. package/src/components/accordion/types.ts +10 -10
  17. package/src/components/alert-card/AlertCard.stories.tsx +171 -171
  18. package/src/components/alert-card/index.tsx +32 -32
  19. package/src/components/alert-card/types.ts +9 -9
  20. package/src/components/brand-button/BrandButton.stories.tsx +219 -219
  21. package/src/components/brand-button/helpers.ts +35 -35
  22. package/src/components/brand-button/index.tsx +93 -93
  23. package/src/components/brand-button/types.ts +25 -25
  24. package/src/components/button/Button.stories.tsx +108 -108
  25. package/src/components/button/index.tsx +27 -27
  26. package/src/components/button/types.ts +14 -14
  27. package/src/components/call-button/CallButton.stories.tsx +324 -324
  28. package/src/components/call-button/index.tsx +86 -79
  29. package/src/components/call-button/types.ts +11 -10
  30. package/src/components/checkbox/Checkbox.stories.tsx +247 -247
  31. package/src/components/checkbox/index.tsx +197 -197
  32. package/src/components/checkbox/types.ts +27 -27
  33. package/src/components/checklist/Checklist.stories.tsx +150 -150
  34. package/src/components/collapse/Collapse.stories.tsx +255 -255
  35. package/src/components/collapse/index.tsx +46 -46
  36. package/src/components/collapse/types.ts +6 -6
  37. package/src/components/divider/Divider.stories.tsx +205 -205
  38. package/src/components/divider/index.tsx +22 -22
  39. package/src/components/divider/type.ts +3 -3
  40. package/src/components/image/Image.stories.tsx +113 -113
  41. package/src/components/image/index.tsx +25 -25
  42. package/src/components/image/types.ts +40 -40
  43. package/src/components/input/Input.stories.tsx +325 -325
  44. package/src/components/input/index.tsx +177 -177
  45. package/src/components/input/types.ts +37 -37
  46. package/src/components/link/Link.stories.tsx +163 -163
  47. package/src/components/link/types.ts +25 -25
  48. package/src/components/list/List.stories.tsx +272 -272
  49. package/src/components/list/index.tsx +88 -88
  50. package/src/components/list/list-item/index.tsx +38 -38
  51. package/src/components/list/list-item/types.ts +13 -13
  52. package/src/components/list/types.ts +29 -29
  53. package/src/components/material-icon/MaterialIcon.stories.tsx +330 -330
  54. package/src/components/material-icon/constants.ts +96 -96
  55. package/src/components/material-icon/index.tsx +44 -44
  56. package/src/components/material-icon/types.ts +31 -31
  57. package/src/components/modal/Modal.stories.tsx +171 -171
  58. package/src/components/modal/index.tsx +164 -164
  59. package/src/components/modal/types.ts +24 -24
  60. package/src/components/next-image/index.tsx +32 -32
  61. package/src/components/next-image/types.ts +1 -1
  62. package/src/components/radio-button/RadioButton.stories.tsx +307 -307
  63. package/src/components/radio-button/index.tsx +75 -75
  64. package/src/components/radio-button/types.ts +21 -21
  65. package/src/components/see-more/SeeMore.stories.tsx +181 -181
  66. package/src/components/see-more/index.tsx +44 -44
  67. package/src/components/see-more/types.ts +4 -4
  68. package/src/components/select/Select.stories.tsx +411 -411
  69. package/src/components/select/index.tsx +150 -150
  70. package/src/components/select/types.ts +35 -35
  71. package/src/components/select-plan-button/SelectPlanButton.stories.tsx +184 -184
  72. package/src/components/select-plan-button/index.tsx +31 -31
  73. package/src/components/select-plan-button/types.ts +5 -5
  74. package/src/components/skeleton/Skeleton.stories.tsx +179 -179
  75. package/src/components/skeleton/index.tsx +61 -61
  76. package/src/components/skeleton/types.ts +4 -4
  77. package/src/components/spinner/Spinner.stories.tsx +335 -335
  78. package/src/components/spinner/index.tsx +44 -44
  79. package/src/components/spinner/types.ts +5 -5
  80. package/src/components/text/Text.stories.tsx +321 -321
  81. package/src/components/text/index.tsx +25 -25
  82. package/src/components/text/types.ts +45 -45
  83. package/src/components/tooltip/Tooltip.stories.tsx +219 -219
  84. package/src/components/tooltip/index.tsx +74 -74
  85. package/src/components/tooltip/types.ts +7 -7
  86. package/src/components/view-cart-button/ViewCartButton.stories.tsx +252 -252
  87. package/src/components/view-cart-button/index.tsx +44 -44
  88. package/src/components/view-cart-button/types.ts +5 -5
  89. package/src/contentful/blocks/button/Button.stories.tsx +40 -40
  90. package/src/contentful/blocks/button/index.tsx +64 -64
  91. package/src/contentful/blocks/button/types.ts +24 -24
  92. package/src/contentful/blocks/callout/Callout.stories.tsx +23 -23
  93. package/src/contentful/blocks/cards/Cards.stories.tsx +23 -23
  94. package/src/contentful/blocks/cards/index.tsx +13 -13
  95. package/src/contentful/blocks/cards/product-card/index.tsx +199 -199
  96. package/src/contentful/blocks/cards/product-card/types.ts +18 -18
  97. package/src/contentful/blocks/cards/testimonial-card/index.tsx +88 -88
  98. package/src/contentful/blocks/cards/testimonial-card/types.tsx +12 -12
  99. package/src/contentful/blocks/cards/types.ts +1 -1
  100. package/src/contentful/blocks/carousel/Carousel.stories.tsx +23 -23
  101. package/src/contentful/blocks/carousel/helper.tsx +314 -0
  102. package/src/contentful/blocks/carousel/index.tsx +50 -13
  103. package/src/contentful/blocks/carousel/types.ts +126 -1
  104. package/src/contentful/blocks/cta-callout/CtaCallout.stories.tsx +46 -46
  105. package/src/contentful/blocks/cta-callout/index.tsx +54 -54
  106. package/src/contentful/blocks/cta-callout/types.ts +22 -22
  107. package/src/contentful/blocks/floating-banner/FloatingBanner.stories.tsx +34 -34
  108. package/src/contentful/blocks/floating-banner/types.ts +22 -22
  109. package/src/contentful/blocks/footer/Footer.stories.tsx +30 -30
  110. package/src/contentful/blocks/image-promo-bar/ImagePromoBar.stories.tsx +23 -23
  111. package/src/contentful/blocks/image-promo-bar/types.ts +27 -27
  112. package/src/contentful/blocks/modal/Modal.stories.tsx +23 -23
  113. package/src/contentful/blocks/modal/index.tsx +12 -12
  114. package/src/contentful/blocks/modal/types.ts +1 -1
  115. package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.tsx +111 -111
  116. package/src/contentful/blocks/navigation/index.tsx +373 -366
  117. package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.tsx +80 -80
  118. package/src/contentful/blocks/navigation/types.ts +41 -39
  119. package/src/contentful/blocks/primary-hero/PrimaryHero.stories.tsx +23 -23
  120. package/src/contentful/blocks/primary-hero/index.tsx +160 -160
  121. package/src/contentful/blocks/primary-hero/types.ts +30 -30
  122. package/src/contentful/blocks/shape-background-wrapper/ShapeBackgroundWrapper.stories.tsx +26 -26
  123. package/src/contentful/blocks/shape-background-wrapper/index.tsx +124 -124
  124. package/src/contentful/blocks/shape-background-wrapper/types.ts +36 -36
  125. package/src/contentful/blocks/text/Text.stories.tsx +23 -23
  126. package/src/contentful/blocks/text/index.tsx +12 -12
  127. package/src/contentful/blocks/text/types.ts +1 -1
  128. package/src/contentful/index.ts +57 -57
  129. package/src/hooks/use-body-scroll-lock.ts +34 -34
  130. package/src/hooks/use-outside-click.ts +17 -17
  131. package/src/index.ts +96 -96
  132. package/src/next/index.ts +5 -5
  133. package/src/setupTests.ts +46 -46
  134. package/src/stories/DocsTemplate.tsx +24 -24
  135. package/src/styles/globals.css +307 -307
  136. package/src/types/global.d.ts +9 -9
  137. package/src/types/micro-components.ts +80 -80
  138. package/src/utils/index.ts +49 -49
@@ -1,80 +1,80 @@
1
- import React from "react";
2
-
3
- import { Button as CoreButton } from "@shared/components/button";
4
- import { MaterialIcon } from "@shared/components/material-icon";
5
- import { Button } from "@shared/contentful/blocks/button";
6
- import { ButtonProps as ContentfulButtonProps } from "@shared/contentful/blocks/button/types";
7
-
8
- type ComponentButtonGroup = {
9
- anchorId?: string | null;
10
- title?: string | null;
11
- items?: { items?: ContentfulButtonProps[] | null } | null;
12
- };
13
-
14
- type Link = ContentfulButtonProps | ComponentButtonGroup;
15
-
16
- type LinkGroupsProps = {
17
- link?: Link;
18
- };
19
-
20
- const isButton = (link: Link): link is ContentfulButtonProps => {
21
- // If your group never has `href`, this is a simple and effective guard
22
- return typeof (link as ContentfulButtonProps).href === "string";
23
- };
24
-
25
- export const MobileLinkGroups: React.FC<LinkGroupsProps> = ({ link }) => {
26
- const [isOpen, setIsOpen] = React.useState(false);
27
- if (!link) return null;
28
-
29
- // Single button
30
- if (isButton(link)) {
31
- return (
32
- <Button
33
- key={`submenu-link-btn-${link.anchorId}`}
34
- {...link}
35
- linkClassName="label3 flex items-center w-full h-11 px-4 text-text-link"
36
- linkVariant="unstyled"
37
- />
38
- );
39
- }
40
-
41
- // Group
42
- const { anchorId, title, items } = link;
43
- const subMenu = Array.isArray(items?.items) ? items!.items! : [];
44
-
45
- return (
46
- <>
47
- <CoreButton
48
- onClick={() => setIsOpen(prev => !prev)}
49
- aria-expanded={isOpen}
50
- className="label3 flex h-11 w-full items-center px-4"
51
- key={anchorId}
52
- >
53
- {title ?? null}
54
- <MaterialIcon
55
- weight="700"
56
- name={isOpen ? "keyboard_arrow_up" : "keyboard_arrow_down"}
57
- />
58
- </CoreButton>
59
- {isOpen && subMenu.length > 0 && <RenderSubMenu items={subMenu} />}
60
- </>
61
- );
62
- };
63
-
64
- const RenderSubMenu: React.FC<{ items: ContentfulButtonProps[] }> = ({
65
- items,
66
- }) => (
67
- <ul key={`submenu-${items.length}`} className="flex flex-col gap-2">
68
- {items.map((site, index) => {
69
- return (
70
- <li key={`submenu-link-${index}`} className="submenu-link">
71
- <Button
72
- {...site}
73
- linkVariant="unstyled"
74
- linkClassName="body3 pl-8 pr-4 flex items-center w-full h-11 text-text-link"
75
- />
76
- </li>
77
- );
78
- })}
79
- </ul>
80
- );
1
+ import React from "react";
2
+
3
+ import { Button as CoreButton } from "@shared/components/button";
4
+ import { MaterialIcon } from "@shared/components/material-icon";
5
+ import { Button } from "@shared/contentful/blocks/button";
6
+ import { ButtonProps as ContentfulButtonProps } from "@shared/contentful/blocks/button/types";
7
+
8
+ type ComponentButtonGroup = {
9
+ anchorId?: string | null;
10
+ title?: string | null;
11
+ items?: { items?: ContentfulButtonProps[] | null } | null;
12
+ };
13
+
14
+ type Link = ContentfulButtonProps | ComponentButtonGroup;
15
+
16
+ type LinkGroupsProps = {
17
+ link?: Link;
18
+ };
19
+
20
+ const isButton = (link: Link): link is ContentfulButtonProps => {
21
+ // If your group never has `href`, this is a simple and effective guard
22
+ return typeof (link as ContentfulButtonProps).href === "string";
23
+ };
24
+
25
+ export const MobileLinkGroups: React.FC<LinkGroupsProps> = ({ link }) => {
26
+ const [isOpen, setIsOpen] = React.useState(false);
27
+ if (!link) return null;
28
+
29
+ // Single button
30
+ if (isButton(link)) {
31
+ return (
32
+ <Button
33
+ key={`submenu-link-btn-${link.anchorId}`}
34
+ {...link}
35
+ linkClassName="label3 flex items-center w-full h-11 px-4 text-text-link"
36
+ linkVariant="unstyled"
37
+ />
38
+ );
39
+ }
40
+
41
+ // Group
42
+ const { anchorId, title, items } = link;
43
+ const subMenu = Array.isArray(items?.items) ? items!.items! : [];
44
+
45
+ return (
46
+ <>
47
+ <CoreButton
48
+ onClick={() => setIsOpen(prev => !prev)}
49
+ aria-expanded={isOpen}
50
+ className="label3 flex h-11 w-full items-center px-4"
51
+ key={anchorId}
52
+ >
53
+ {title ?? null}
54
+ <MaterialIcon
55
+ weight="700"
56
+ name={isOpen ? "keyboard_arrow_up" : "keyboard_arrow_down"}
57
+ />
58
+ </CoreButton>
59
+ {isOpen && subMenu.length > 0 && <RenderSubMenu items={subMenu} />}
60
+ </>
61
+ );
62
+ };
63
+
64
+ const RenderSubMenu: React.FC<{ items: ContentfulButtonProps[] }> = ({
65
+ items,
66
+ }) => (
67
+ <ul key={`submenu-${items.length}`} className="flex flex-col gap-2">
68
+ {items.map((site, index) => {
69
+ return (
70
+ <li key={`submenu-link-${index}`} className="submenu-link">
71
+ <Button
72
+ {...site}
73
+ linkVariant="unstyled"
74
+ linkClassName="body3 pl-8 pr-4 flex items-center w-full h-11 text-text-link"
75
+ />
76
+ </li>
77
+ );
78
+ })}
79
+ </ul>
80
+ );
@@ -1,39 +1,41 @@
1
- import React from "react";
2
-
3
- import { Asset, Button, ButtonGroup } from "@shared/types/micro-components";
4
-
5
- type Color = string;
6
-
7
- export interface Navigation {
8
- __typename?: "ComponentNavigation";
9
- primaryNavigationLogo?: Asset;
10
- anchorId?: string;
11
- primaryNavigationLinks?: (Button | ButtonGroup)[];
12
-
13
- supportNavigationLinks?: ButtonGroup[];
14
-
15
- utilityNavigationLinks?: (Button | ButtonGroup)[];
16
-
17
- accountNavigationLinks?: ButtonGroup[]; // limit: 1, but treat as array for consistency
18
-
19
- searchBarIcon?: Asset;
20
- searchBarPlaceholder?: string;
21
-
22
- navigationBackgroundColor?: Color;
23
- utilityNavBackgroundColor?: Color;
24
- utilityNavLinkColor?: Color;
25
-
26
- callNowCtaText?: string;
27
- callNowCtaIcon?: Asset;
28
-
29
- displaySearchBar?: boolean;
30
- displayCallNowCta?: boolean;
31
- displayUtilityNavigation?: boolean;
32
- showCallButton?: boolean;
33
- showMobileSliderMenu?: boolean;
34
- showCallNowCtaInMainNav?: boolean;
35
- checkPlansJSX?: React.ReactNode;
36
- onSearch?: (query: string) => void;
37
- }
38
-
39
- export type NavigationProps = Navigation;
1
+ import React from "react";
2
+
3
+ import { Asset, Button, ButtonGroup } from "@shared/types/micro-components";
4
+
5
+ type Color = string;
6
+
7
+ export interface Navigation {
8
+ __typename?: "ComponentNavigation";
9
+ primaryNavigationLogo?: Asset;
10
+ anchorId?: string;
11
+ primaryNavigationLinks?: (Button | ButtonGroup)[];
12
+
13
+ supportNavigationLinks?: ButtonGroup[];
14
+
15
+ utilityNavigationLinks?: (Button | ButtonGroup)[];
16
+
17
+ accountNavigationLinks?: ButtonGroup[]; // limit: 1, but treat as array for consistency
18
+
19
+ searchBarIcon?: Asset;
20
+ searchBarPlaceholder?: string;
21
+
22
+ navigationBackgroundColor?: Color;
23
+ utilityNavBackgroundColor?: Color;
24
+ utilityNavLinkColor?: Color;
25
+
26
+ callNowCtaText?: string;
27
+ callNowCtaIcon?: Asset;
28
+
29
+ displaySearchBar?: boolean;
30
+ displayCallNowCta?: boolean;
31
+ displayUtilityNavigation?: boolean;
32
+ showCallButton?: boolean;
33
+ showMobileSliderMenu?: boolean;
34
+ showCallNowCtaInMainNav?: boolean;
35
+ invocaPhoneNumberLink?: string;
36
+ invocaPhoneNumberDisplayText?: string;
37
+ checkPlansJSX?: React.ReactNode;
38
+ onSearch?: (query: string) => void;
39
+ }
40
+
41
+ export type NavigationProps = Navigation;
@@ -1,23 +1,23 @@
1
- import { PrimaryHero } from "./index";
2
-
3
- import { DocsPage } from "@shared/stories/DocsTemplate";
4
- import type { Meta, StoryObj } from "@storybook/react";
5
-
6
- const meta: Meta<typeof PrimaryHero> = {
7
- title: "Contentful Blocks/PrimaryHero",
8
- component: PrimaryHero,
9
- tags: ["autodocs"],
10
- parameters: {
11
- layout: "centered",
12
- docs: {
13
- page: DocsPage,
14
- description: {
15
- component: "Contentful primary hero block.",
16
- },
17
- },
18
- },
19
- args: {},
20
- };
21
- export default meta;
22
- type Story = StoryObj<typeof meta>;
23
- export const Default: Story = {};
1
+ import { PrimaryHero } from "./index";
2
+
3
+ import { DocsPage } from "@shared/stories/DocsTemplate";
4
+ import type { Meta, StoryObj } from "@storybook/react";
5
+
6
+ const meta: Meta<typeof PrimaryHero> = {
7
+ title: "Contentful Blocks/PrimaryHero",
8
+ component: PrimaryHero,
9
+ tags: ["autodocs"],
10
+ parameters: {
11
+ layout: "centered",
12
+ docs: {
13
+ page: DocsPage,
14
+ description: {
15
+ component: "Contentful primary hero block.",
16
+ },
17
+ },
18
+ },
19
+ args: {},
20
+ };
21
+ export default meta;
22
+ type Story = StoryObj<typeof meta>;
23
+ export const Default: Story = {};
@@ -1,160 +1,160 @@
1
- import React from "react";
2
- import { PrimaryHeroProps } from "./types";
3
-
4
- import { Checklist } from "@shared/components/checklist";
5
- import { NextImage } from "@shared/components/next-image";
6
- import { Text } from "@shared/components/text";
7
- import { Button as ContentfulButton } from "@shared/contentful/blocks/button";
8
- import { cx } from "@shared/utils";
9
-
10
- export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
11
- const {
12
- title,
13
- showAsHeading,
14
- subTitle,
15
- primaryCta1,
16
- carouselImages,
17
- bottomLink,
18
- price,
19
- priceCallout,
20
- priceSuffix,
21
- checklist,
22
- checkPlansJSX,
23
- } = props;
24
-
25
- const bottomLinkLabel = bottomLink?.buttonLabel ?? bottomLink?.label;
26
-
27
- return (
28
- <div className="component-container p-5 lg:h-[724px] lg:p-0">
29
- <div
30
- className={cx(
31
- "primary-hero-container mx-auto flex flex-col sm:items-center sm:text-center lg:h-full lg:max-w-120 lg:flex-row lg:items-center lg:justify-between lg:gap-4 lg:p-4 lg:text-left"
32
- )}
33
- >
34
- {/* Left column: navy background, headline, body, address, button, link */}
35
- <div className={cx("relative flex flex-col text-white sm:w-[485px]")}>
36
- <div className="flex flex-col gap-5 lg:gap-6">
37
- {title && (
38
- <Text
39
- as={showAsHeading ? "h1" : "h2"}
40
- className="heading2 font-bold lg:heading1"
41
- >
42
- {title}
43
- </Text>
44
- )}
45
- {subTitle && (
46
- <Text as="p" className="subheading3 lg:subheading1">
47
- {subTitle}
48
- </Text>
49
- )}
50
-
51
- {/* price callout */}
52
- {price ? (
53
- <div className="flex">
54
- <div className="mr-2">
55
- {priceCallout
56
- ? priceCallout.split("|").map((line, index) => (
57
- <Text key={index} as="p" className="body2">
58
- {line}
59
- </Text>
60
- ))
61
- : null}
62
- </div>
63
- <Text as="p" className="subheading1">
64
- $
65
- </Text>
66
- <Text as="p" className="subheading5">
67
- {price}
68
- </Text>
69
- {priceSuffix ? (
70
- <Text as="p" className="subheading1">
71
- {priceSuffix}
72
- </Text>
73
- ) : null}
74
- </div>
75
- ) : null}
76
-
77
- {/* checklist */}
78
- {checklist && (
79
- <Checklist
80
- listItemClassName="text-white body2"
81
- items={checklist.map(item => item.title)}
82
- />
83
- )}
84
-
85
- {/* desktop CTA */}
86
- {primaryCta1 && (
87
- <div className={cx("hidden flex-col gap-3 lg:flex")}>
88
- <ContentfulButton
89
- {...primaryCta1}
90
- checkPlansJSX={checkPlansJSX}
91
- />
92
-
93
- {bottomLink && (
94
- <div>
95
- <ContentfulButton
96
- {...bottomLink}
97
- linkClassName="text-footnote text-white"
98
- />
99
- </div>
100
- )}
101
- </div>
102
- )}
103
-
104
- {/* desktop bottom link */}
105
- {!primaryCta1 &&
106
- bottomLink &&
107
- (bottomLinkLabel || bottomLink?.href) && (
108
- <div className="hidden lg:block">
109
- <ContentfulButton
110
- {...bottomLink}
111
- linkClassName="text-footnote text-white"
112
- />
113
- </div>
114
- )}
115
- </div>
116
- </div>
117
-
118
- {/* mobile hero image and bottom link */}
119
- <div className="lg:hidden">
120
- <div className={"my-8"}>
121
- {carouselImages && carouselImages[0] ? (
122
- <NextImage
123
- src={carouselImages[0]}
124
- alt={"Hero"}
125
- className="aspect-[1.71:1] sm:aspect-[1.41:1] rounded-[40px] object-cover object-center sm:h-[420px]"
126
- width={350}
127
- height={205}
128
- loading="eager"
129
- />
130
- ) : null}
131
- </div>
132
- {bottomLink && (bottomLinkLabel || bottomLink?.href) && (
133
- <div>
134
- <ContentfulButton
135
- {...bottomLink}
136
- linkClassName="body3 text-white"
137
- />
138
- </div>
139
- )}
140
- </div>
141
-
142
- {/* Right column: bright blue background, diagonal top edge, hero image */}
143
- <div className={cx("relative hidden lg:block")}>
144
- {carouselImages && carouselImages[0] ? (
145
- <NextImage
146
- src={carouselImages[0]}
147
- alt={"Hero"}
148
- className="aspect-square rounded-[40px] object-cover object-center"
149
- width={600}
150
- height={600}
151
- loading="eager"
152
- />
153
- ) : null}
154
- </div>
155
- </div>
156
- </div>
157
- );
158
- };
159
-
160
- export default PrimaryHero;
1
+ import React from "react";
2
+ import { PrimaryHeroProps } from "./types";
3
+
4
+ import { Checklist } from "@shared/components/checklist";
5
+ import { NextImage } from "@shared/components/next-image";
6
+ import { Text } from "@shared/components/text";
7
+ import { Button as ContentfulButton } from "@shared/contentful/blocks/button";
8
+ import { cx } from "@shared/utils";
9
+
10
+ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
11
+ const {
12
+ title,
13
+ showAsHeading,
14
+ subTitle,
15
+ primaryCta1,
16
+ carouselImages,
17
+ bottomLink,
18
+ price,
19
+ priceCallout,
20
+ priceSuffix,
21
+ checklist,
22
+ checkPlansJSX,
23
+ } = props;
24
+
25
+ const bottomLinkLabel = bottomLink?.buttonLabel ?? bottomLink?.label;
26
+
27
+ return (
28
+ <div className="component-container p-5 lg:h-[724px] lg:p-0">
29
+ <div
30
+ className={cx(
31
+ "primary-hero-container mx-auto flex flex-col sm:items-center sm:text-center lg:h-full lg:max-w-120 lg:flex-row lg:items-center lg:justify-between lg:gap-4 lg:p-4 lg:text-left"
32
+ )}
33
+ >
34
+ {/* Left column: navy background, headline, body, address, button, link */}
35
+ <div className={cx("relative flex flex-col text-white sm:w-[485px]")}>
36
+ <div className="flex flex-col gap-5 lg:gap-6">
37
+ {title && (
38
+ <Text
39
+ as={showAsHeading ? "h1" : "h2"}
40
+ className="heading2 font-bold lg:heading1"
41
+ >
42
+ {title}
43
+ </Text>
44
+ )}
45
+ {subTitle && (
46
+ <Text as="p" className="subheading3 lg:subheading1">
47
+ {subTitle}
48
+ </Text>
49
+ )}
50
+
51
+ {/* price callout */}
52
+ {price ? (
53
+ <div className="flex">
54
+ <div className="mr-2">
55
+ {priceCallout
56
+ ? priceCallout.split("|").map((line, index) => (
57
+ <Text key={index} as="p" className="body2">
58
+ {line}
59
+ </Text>
60
+ ))
61
+ : null}
62
+ </div>
63
+ <Text as="p" className="subheading1">
64
+ $
65
+ </Text>
66
+ <Text as="p" className="subheading5">
67
+ {price}
68
+ </Text>
69
+ {priceSuffix ? (
70
+ <Text as="p" className="subheading1">
71
+ {priceSuffix}
72
+ </Text>
73
+ ) : null}
74
+ </div>
75
+ ) : null}
76
+
77
+ {/* checklist */}
78
+ {checklist && (
79
+ <Checklist
80
+ listItemClassName="text-white body2"
81
+ items={checklist.map(item => item.title)}
82
+ />
83
+ )}
84
+
85
+ {/* desktop CTA */}
86
+ {primaryCta1 && (
87
+ <div className={cx("hidden flex-col gap-3 lg:flex")}>
88
+ <ContentfulButton
89
+ {...primaryCta1}
90
+ checkPlansJSX={checkPlansJSX}
91
+ />
92
+
93
+ {bottomLink && (
94
+ <div>
95
+ <ContentfulButton
96
+ {...bottomLink}
97
+ linkClassName="text-footnote text-white"
98
+ />
99
+ </div>
100
+ )}
101
+ </div>
102
+ )}
103
+
104
+ {/* desktop bottom link */}
105
+ {!primaryCta1 &&
106
+ bottomLink &&
107
+ (bottomLinkLabel || bottomLink?.href) && (
108
+ <div className="hidden lg:block">
109
+ <ContentfulButton
110
+ {...bottomLink}
111
+ linkClassName="text-footnote text-white"
112
+ />
113
+ </div>
114
+ )}
115
+ </div>
116
+ </div>
117
+
118
+ {/* mobile hero image and bottom link */}
119
+ <div className="lg:hidden">
120
+ <div className={"my-8"}>
121
+ {carouselImages && carouselImages[0] ? (
122
+ <NextImage
123
+ src={carouselImages[0]}
124
+ alt={"Hero"}
125
+ className="aspect-[1.71:1] sm:aspect-[1.41:1] rounded-[40px] object-cover object-center sm:h-[420px]"
126
+ width={350}
127
+ height={205}
128
+ loading="eager"
129
+ />
130
+ ) : null}
131
+ </div>
132
+ {bottomLink && (bottomLinkLabel || bottomLink?.href) && (
133
+ <div>
134
+ <ContentfulButton
135
+ {...bottomLink}
136
+ linkClassName="body3 text-white"
137
+ />
138
+ </div>
139
+ )}
140
+ </div>
141
+
142
+ {/* Right column: bright blue background, diagonal top edge, hero image */}
143
+ <div className={cx("relative hidden lg:block")}>
144
+ {carouselImages && carouselImages[0] ? (
145
+ <NextImage
146
+ src={carouselImages[0]}
147
+ alt={"Hero"}
148
+ className="aspect-square rounded-[40px] object-cover object-center"
149
+ width={600}
150
+ height={600}
151
+ loading="eager"
152
+ />
153
+ ) : null}
154
+ </div>
155
+ </div>
156
+ </div>
157
+ );
158
+ };
159
+
160
+ export default PrimaryHero;
@@ -1,30 +1,30 @@
1
- export type PrimaryHeroProps = {
2
- title: string;
3
- showAsHeading?: boolean;
4
- subTitle?: string;
5
- price?: string;
6
- priceSuffix?: string;
7
- priceCallout?: string;
8
- pricingDescription?: string;
9
- pricingDescriptionDisclaimer?: string;
10
- checklist?: {
11
- title: string;
12
- iconUrl?: string;
13
- anchorId?: string;
14
- }[];
15
- logoLockup?: string;
16
- checkAvailabilityEyebrow?: string;
17
- primaryCtaPrefix1?: string;
18
- primaryCtaPrefix2?: string;
19
- primaryCta1?: any;
20
- primaryCta2?: any;
21
- secondaryCtaPrefix?: string;
22
- secondaryCta?: any;
23
- bottomLink?: any;
24
- carouselImages?: string[];
25
- squareImage?: boolean;
26
- badgeImage?: string;
27
- textColor?: string;
28
- maxWidth?: boolean;
29
- checkPlansJSX?: React.ReactNode;
30
- };
1
+ export type PrimaryHeroProps = {
2
+ title: string;
3
+ showAsHeading?: boolean;
4
+ subTitle?: string;
5
+ price?: string;
6
+ priceSuffix?: string;
7
+ priceCallout?: string;
8
+ pricingDescription?: string;
9
+ pricingDescriptionDisclaimer?: string;
10
+ checklist?: {
11
+ title: string;
12
+ iconUrl?: string;
13
+ anchorId?: string;
14
+ }[];
15
+ logoLockup?: string;
16
+ checkAvailabilityEyebrow?: string;
17
+ primaryCtaPrefix1?: string;
18
+ primaryCtaPrefix2?: string;
19
+ primaryCta1?: any;
20
+ primaryCta2?: any;
21
+ secondaryCtaPrefix?: string;
22
+ secondaryCta?: any;
23
+ bottomLink?: any;
24
+ carouselImages?: string[];
25
+ squareImage?: boolean;
26
+ badgeImage?: string;
27
+ textColor?: string;
28
+ maxWidth?: boolean;
29
+ checkPlansJSX?: React.ReactNode;
30
+ };