@windstream/react-shared-components 0.1.94 → 0.1.95
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 +4 -4
- package/dist/index.esm.js +5 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +5 -13
- 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 -191
- package/src/components/accordion/Accordion.stories.tsx +230 -230
- package/src/components/accordion/index.test.tsx +270 -270
- 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 -152
- 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 -424
- 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 -292
- 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 -91
- 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 -260
- 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 -252
- 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 -231
- package/src/components/checklist/index.tsx +96 -96
- package/src/components/checklist/types.ts +23 -23
- package/src/components/collapse/Collapse.stories.tsx +255 -255
- package/src/components/collapse/index.test.tsx +277 -277
- package/src/components/collapse/index.tsx +47 -47
- 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 -53
- 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 -174
- 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 -348
- 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 -199
- 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 -166
- 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 -130
- 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 -310
- 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 -406
- 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 -521
- 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 -151
- 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 -96
- 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 -256
- 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 -173
- 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 -74
- 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 -76
- 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 -65
- 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 -50
- 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 -57
- 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 -218
- package/src/contentful/blocks/accordion/index.tsx +114 -114
- package/src/contentful/blocks/accordion/types.ts +34 -34
- package/src/contentful/blocks/address-input-banner/index.test.tsx +132 -132
- 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 -287
- 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 -157
- package/src/contentful/blocks/blogs-grid/index.test.tsx +355 -355
- 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 -274
- 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 -281
- 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 -339
- 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 -539
- 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 -218
- 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 -201
- 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 -216
- 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 -39
- package/src/contentful/blocks/cards/index.tsx +13 -13
- package/src/contentful/blocks/cards/product-card/index.test.tsx +263 -263
- 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 -364
- 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 -180
- 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 -539
- package/src/contentful/blocks/carousel/helper.tsx +494 -494
- package/src/contentful/blocks/carousel/index.test.tsx +308 -308
- package/src/contentful/blocks/carousel/index.tsx +87 -87
- package/src/contentful/blocks/carousel/types.test.ts +16 -16
- package/src/contentful/blocks/carousel/types.ts +145 -145
- package/src/contentful/blocks/cart-retention-banner/index.test.tsx +409 -409
- 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 -114
- 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 -277
- 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 -244
- 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 -240
- 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 -213
- package/src/contentful/blocks/email-input-block/index.tsx +121 -121
- 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 -269
- 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 -246
- 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 -302
- 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 -61
- package/src/contentful/blocks/image-promo-bar/helper.tsx +28 -28
- package/src/contentful/blocks/image-promo-bar/index.test.tsx +467 -467
- package/src/contentful/blocks/image-promo-bar/index.tsx +8 -6
- package/src/contentful/blocks/image-promo-bar/types.ts +44 -44
- package/src/contentful/blocks/image-promo-bar/vimeo-embed.test.tsx +142 -142
- package/src/contentful/blocks/image-promo-bar/vimeo-embed.tsx +93 -93
- package/src/contentful/blocks/image-promo-bar/youtube-embed.test.tsx +104 -104
- 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 -209
- 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 -208
- package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.tsx +141 -141
- package/src/contentful/blocks/navigation/index.test.tsx +924 -924
- package/src/contentful/blocks/navigation/index.tsx +569 -569
- package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.test.tsx +131 -131
- 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 -286
- package/src/contentful/blocks/primary-hero/index.tsx +239 -239
- package/src/contentful/blocks/primary-hero/types.ts +37 -37
- package/src/contentful/blocks/search-block/index.test.tsx +268 -268
- 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 -284
- 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 -36
- 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 -45
- package/src/contentful/index.ts +105 -105
- package/src/global-mocks/contentful/to-document.ts +25 -25
- package/src/global-mocks/cookie.ts +48 -48
- package/src/global-mocks/cx.ts +37 -37
- package/src/global-mocks/index.ts +89 -89
- package/src/global-mocks/speed-card-bg.ts +27 -27
- package/src/global-mocks/utm.ts +49 -49
- package/src/hooks/contentful/use-contentful-rich-text.test.tsx +1758 -1758
- package/src/hooks/contentful/use-contentful-rich-text.tsx +309 -309
- package/src/hooks/contentful/use-processed-check-list.test.tsx +277 -277
- package/src/hooks/contentful/use-processed-check-list.ts +63 -63
- package/src/hooks/use-body-scroll-lock.test.ts +134 -134
- package/src/hooks/use-body-scroll-lock.ts +34 -34
- package/src/hooks/use-carousel-swipe.test.ts +393 -393
- package/src/hooks/use-carousel-swipe.ts +264 -264
- package/src/hooks/use-outside-click.test.ts +142 -142
- package/src/hooks/use-outside-click.ts +17 -17
- package/src/index.ts +107 -107
- package/src/next/index.test.ts +7 -7
- package/src/next/index.ts +5 -5
- package/src/setupTests.ts +52 -52
- 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 -85
- package/src/utils/contentful/to-document.ts +24 -24
- package/src/utils/cookie.test.ts +180 -180
- package/src/utils/cookie.ts +84 -84
- package/src/utils/cx.test.ts +90 -90
- package/src/utils/cx.ts +49 -49
- package/src/utils/index.test.ts +115 -115
- package/src/utils/index.ts +41 -41
- package/src/utils/speed-card-bg.test.ts +46 -46
- package/src/utils/speed-card-bg.ts +24 -24
- package/src/utils/utm.test.ts +359 -359
- package/src/utils/utm.ts +221 -221
|
@@ -61,15 +61,15 @@ export const ImagePromoBar: React.FC<ImagePromoBarProps> = ({
|
|
|
61
61
|
const contentVideo = videoLink && videoImage ? embedSelector() : null;
|
|
62
62
|
|
|
63
63
|
return (
|
|
64
|
-
<div className="component-container">
|
|
64
|
+
<div className="component-container shared-component-ipb">
|
|
65
65
|
<div
|
|
66
|
-
className={`image-promo-bar-content ${maxWidth ? "max-w-120
|
|
66
|
+
className={`image-promo-bar-content ${maxWidth ? "max-w-120 xl:mx-auto" : ""} mx-5 mb-8 mt-16 md:mx-10`}
|
|
67
67
|
>
|
|
68
68
|
<div
|
|
69
|
-
className={`flex shrink-0 flex-col items-center gap-8
|
|
69
|
+
className={`flex shrink-0 flex-col items-center gap-8 xl:items-stretch xl:gap-10 xl:gap-[126px] ${mediaPosition ? "xl:flex-row-reverse" : "xl:flex-row"}`}
|
|
70
70
|
>
|
|
71
71
|
<div
|
|
72
|
-
className={`flex flex-[1_0_0] flex-col items-start justify-center gap-8
|
|
72
|
+
className={`flex flex-[1_0_0] flex-col items-start justify-center gap-8 xl:gap-10 ${color == "dark" ? "text-text" : "text-white"}`}
|
|
73
73
|
>
|
|
74
74
|
<div className="heading holder">
|
|
75
75
|
{brow && (
|
|
@@ -160,7 +160,6 @@ export const ImagePromoBar: React.FC<ImagePromoBarProps> = ({
|
|
|
160
160
|
</div>
|
|
161
161
|
)}
|
|
162
162
|
{ctaDisclaimer && <div>{ctaDisclaimer}</div>}
|
|
163
|
-
{disclaimer && <div>{disclaimer}</div>}
|
|
164
163
|
</div>
|
|
165
164
|
<aside className="flex w-full shrink-0 items-center justify-center lg:w-auto">
|
|
166
165
|
{/* Media Section */}
|
|
@@ -169,7 +168,7 @@ export const ImagePromoBar: React.FC<ImagePromoBarProps> = ({
|
|
|
169
168
|
<NextImage
|
|
170
169
|
src={image}
|
|
171
170
|
alt="section-image"
|
|
172
|
-
fill
|
|
171
|
+
fill={true}
|
|
173
172
|
sizes="(min-width: 768px) 486px, 334px"
|
|
174
173
|
className="object-cover"
|
|
175
174
|
/>
|
|
@@ -239,6 +238,9 @@ export const ImagePromoBar: React.FC<ImagePromoBarProps> = ({
|
|
|
239
238
|
</div>
|
|
240
239
|
</div>
|
|
241
240
|
)}
|
|
241
|
+
{disclaimer && (
|
|
242
|
+
<div className="mt-10 flex justify-center xl:mt-18">{disclaimer}</div>
|
|
243
|
+
)}
|
|
242
244
|
</div>
|
|
243
245
|
);
|
|
244
246
|
};
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import { CheckPlansProps } from "@shared/types/micro-components";
|
|
4
|
-
|
|
5
|
-
export type VideoLinkProps = {
|
|
6
|
-
image?: string;
|
|
7
|
-
videoPopup?: boolean;
|
|
8
|
-
link?: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type VideoEmbedProps = {
|
|
12
|
-
containerClassName?: string;
|
|
13
|
-
autoplay?: boolean;
|
|
14
|
-
debug?: boolean;
|
|
15
|
-
} & VideoLinkProps;
|
|
16
|
-
|
|
17
|
-
export type ImagePromoBarProps = {
|
|
18
|
-
brow: string;
|
|
19
|
-
enableHeading: boolean;
|
|
20
|
-
title: string;
|
|
21
|
-
subTitle: string;
|
|
22
|
-
image: string;
|
|
23
|
-
imageWidth: number;
|
|
24
|
-
imageHeight: number;
|
|
25
|
-
mediaPosition: boolean;
|
|
26
|
-
description: React.ReactNode;
|
|
27
|
-
openDescriptionLinksOnANewTab: boolean;
|
|
28
|
-
checklist: string[];
|
|
29
|
-
disclaimer: React.ReactNode;
|
|
30
|
-
imageLinks: { url: string; image: string }[];
|
|
31
|
-
cta: any;
|
|
32
|
-
secondaryCta: any;
|
|
33
|
-
ctaDisclaimer: React.ReactNode;
|
|
34
|
-
videoLink: VideoLinkProps;
|
|
35
|
-
maxWidth?: boolean;
|
|
36
|
-
color: "light" | "dark";
|
|
37
|
-
onModalButtonClick?: (id?: string) => void;
|
|
38
|
-
renderCheckPlans?: (overrides?: CheckPlansProps) => React.ReactNode;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export type PlayButtonProps = {
|
|
42
|
-
isHovered?: boolean;
|
|
43
|
-
containerClassName?: string;
|
|
44
|
-
};
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { CheckPlansProps } from "@shared/types/micro-components";
|
|
4
|
+
|
|
5
|
+
export type VideoLinkProps = {
|
|
6
|
+
image?: string;
|
|
7
|
+
videoPopup?: boolean;
|
|
8
|
+
link?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type VideoEmbedProps = {
|
|
12
|
+
containerClassName?: string;
|
|
13
|
+
autoplay?: boolean;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
} & VideoLinkProps;
|
|
16
|
+
|
|
17
|
+
export type ImagePromoBarProps = {
|
|
18
|
+
brow: string;
|
|
19
|
+
enableHeading: boolean;
|
|
20
|
+
title: string;
|
|
21
|
+
subTitle: string;
|
|
22
|
+
image: string;
|
|
23
|
+
imageWidth: number;
|
|
24
|
+
imageHeight: number;
|
|
25
|
+
mediaPosition: boolean;
|
|
26
|
+
description: React.ReactNode;
|
|
27
|
+
openDescriptionLinksOnANewTab: boolean;
|
|
28
|
+
checklist: string[];
|
|
29
|
+
disclaimer: React.ReactNode;
|
|
30
|
+
imageLinks: { url: string; image: string }[];
|
|
31
|
+
cta: any;
|
|
32
|
+
secondaryCta: any;
|
|
33
|
+
ctaDisclaimer: React.ReactNode;
|
|
34
|
+
videoLink: VideoLinkProps;
|
|
35
|
+
maxWidth?: boolean;
|
|
36
|
+
color: "light" | "dark";
|
|
37
|
+
onModalButtonClick?: (id?: string) => void;
|
|
38
|
+
renderCheckPlans?: (overrides?: CheckPlansProps) => React.ReactNode;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type PlayButtonProps = {
|
|
42
|
+
isHovered?: boolean;
|
|
43
|
+
containerClassName?: string;
|
|
44
|
+
};
|
|
@@ -1,142 +1,142 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { VimeoEmbed } from "./vimeo-embed";
|
|
3
|
-
|
|
4
|
-
import { render, screen } from "@testing-library/react";
|
|
5
|
-
|
|
6
|
-
jest.mock("@shared/utils", () => ({
|
|
7
|
-
cx: (...args: any[]) => args.filter(Boolean).join(" "),
|
|
8
|
-
}));
|
|
9
|
-
|
|
10
|
-
describe("VimeoEmbed", () => {
|
|
11
|
-
describe("Rendering", () => {
|
|
12
|
-
it("renders iframe with correct src for standard vimeo link", () => {
|
|
13
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
14
|
-
const iframe = screen.getByTitle("Embedded vimeo");
|
|
15
|
-
expect(iframe).toBeInTheDocument();
|
|
16
|
-
expect(iframe.getAttribute("src")).toContain(
|
|
17
|
-
"player.vimeo.com/video/123456789"
|
|
18
|
-
);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("renders null when link is empty", () => {
|
|
22
|
-
const { container } = render(<VimeoEmbed link="" />);
|
|
23
|
-
expect(container.innerHTML).toBe("");
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("renders null when link is undefined", () => {
|
|
27
|
-
const { container } = render(<VimeoEmbed link={undefined} />);
|
|
28
|
-
expect(container.innerHTML).toBe("");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("renders null when link has no valid vimeo id", () => {
|
|
32
|
-
const { container } = render(
|
|
33
|
-
<VimeoEmbed link="https://example.com/notavideo" />
|
|
34
|
-
);
|
|
35
|
-
expect(container.innerHTML).toBe("");
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("applies containerClassName", () => {
|
|
39
|
-
const { container } = render(
|
|
40
|
-
<VimeoEmbed
|
|
41
|
-
link="https://vimeo.com/123456789"
|
|
42
|
-
containerClassName="custom"
|
|
43
|
-
/>
|
|
44
|
-
);
|
|
45
|
-
expect(container.firstElementChild?.className).toContain("custom");
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("sets autoplay=1 when autoplay is true", () => {
|
|
49
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789" autoplay={true} />);
|
|
50
|
-
const iframe = screen.getByTitle("Embedded vimeo");
|
|
51
|
-
expect(iframe.getAttribute("src")).toContain("autoplay=1");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("sets autoplay=0 when autoplay is false", () => {
|
|
55
|
-
render(
|
|
56
|
-
<VimeoEmbed link="https://vimeo.com/123456789" autoplay={false} />
|
|
57
|
-
);
|
|
58
|
-
const iframe = screen.getByTitle("Embedded vimeo");
|
|
59
|
-
expect(iframe.getAttribute("src")).toContain("autoplay=0");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("has correct iframe attributes", () => {
|
|
63
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
64
|
-
const iframe = screen.getByTitle("Embedded vimeo");
|
|
65
|
-
expect(iframe).toHaveAttribute(
|
|
66
|
-
"allow",
|
|
67
|
-
"autoplay; fullscreen; picture-in-picture"
|
|
68
|
-
);
|
|
69
|
-
expect(iframe).toHaveAttribute(
|
|
70
|
-
"referrerPolicy",
|
|
71
|
-
"strict-origin-when-cross-origin"
|
|
72
|
-
);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
describe("extractVimeoIdandHash", () => {
|
|
77
|
-
it("extracts id from standard vimeo.com URL", () => {
|
|
78
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
79
|
-
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
80
|
-
"/video/123456789"
|
|
81
|
-
);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("extracts id and hash from vimeo URL with hash path", () => {
|
|
85
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789/abc123def" />);
|
|
86
|
-
const src = screen.getByTitle("Embedded vimeo").getAttribute("src")!;
|
|
87
|
-
expect(src).toContain("/video/123456789");
|
|
88
|
-
expect(src).toContain("h=abc123def");
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("extracts id from player.vimeo.com URL", () => {
|
|
92
|
-
render(<VimeoEmbed link="https://player.vimeo.com/video/987654321" />);
|
|
93
|
-
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
94
|
-
"/video/987654321"
|
|
95
|
-
);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("strips query params from link before extracting", () => {
|
|
99
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789?autoplay=1" />);
|
|
100
|
-
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
101
|
-
"/video/123456789"
|
|
102
|
-
);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("strips trailing slashes from link", () => {
|
|
106
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789/" />);
|
|
107
|
-
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
108
|
-
"/video/123456789"
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("handles vimeo URL with nested path", () => {
|
|
113
|
-
render(
|
|
114
|
-
<VimeoEmbed link="https://vimeo.com/channels/staffpicks/123456789" />
|
|
115
|
-
);
|
|
116
|
-
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
117
|
-
"/video/123456789"
|
|
118
|
-
);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe("debug mode", () => {
|
|
123
|
-
it("logs to console when debug is true", () => {
|
|
124
|
-
const consoleSpy = jest.spyOn(console, "log").mockImplementation();
|
|
125
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789" debug={true} />);
|
|
126
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
127
|
-
"[VimeoEmbed] href:",
|
|
128
|
-
"https://vimeo.com/123456789",
|
|
129
|
-
"id:",
|
|
130
|
-
expect.any(String)
|
|
131
|
-
);
|
|
132
|
-
consoleSpy.mockRestore();
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("does not log when debug is false", () => {
|
|
136
|
-
const consoleSpy = jest.spyOn(console, "log").mockImplementation();
|
|
137
|
-
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
138
|
-
expect(consoleSpy).not.toHaveBeenCalled();
|
|
139
|
-
consoleSpy.mockRestore();
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
});
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { VimeoEmbed } from "./vimeo-embed";
|
|
3
|
+
|
|
4
|
+
import { render, screen } from "@testing-library/react";
|
|
5
|
+
|
|
6
|
+
jest.mock("@shared/utils", () => ({
|
|
7
|
+
cx: (...args: any[]) => args.filter(Boolean).join(" "),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
describe("VimeoEmbed", () => {
|
|
11
|
+
describe("Rendering", () => {
|
|
12
|
+
it("renders iframe with correct src for standard vimeo link", () => {
|
|
13
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
14
|
+
const iframe = screen.getByTitle("Embedded vimeo");
|
|
15
|
+
expect(iframe).toBeInTheDocument();
|
|
16
|
+
expect(iframe.getAttribute("src")).toContain(
|
|
17
|
+
"player.vimeo.com/video/123456789"
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("renders null when link is empty", () => {
|
|
22
|
+
const { container } = render(<VimeoEmbed link="" />);
|
|
23
|
+
expect(container.innerHTML).toBe("");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("renders null when link is undefined", () => {
|
|
27
|
+
const { container } = render(<VimeoEmbed link={undefined} />);
|
|
28
|
+
expect(container.innerHTML).toBe("");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("renders null when link has no valid vimeo id", () => {
|
|
32
|
+
const { container } = render(
|
|
33
|
+
<VimeoEmbed link="https://example.com/notavideo" />
|
|
34
|
+
);
|
|
35
|
+
expect(container.innerHTML).toBe("");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("applies containerClassName", () => {
|
|
39
|
+
const { container } = render(
|
|
40
|
+
<VimeoEmbed
|
|
41
|
+
link="https://vimeo.com/123456789"
|
|
42
|
+
containerClassName="custom"
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
expect(container.firstElementChild?.className).toContain("custom");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("sets autoplay=1 when autoplay is true", () => {
|
|
49
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789" autoplay={true} />);
|
|
50
|
+
const iframe = screen.getByTitle("Embedded vimeo");
|
|
51
|
+
expect(iframe.getAttribute("src")).toContain("autoplay=1");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("sets autoplay=0 when autoplay is false", () => {
|
|
55
|
+
render(
|
|
56
|
+
<VimeoEmbed link="https://vimeo.com/123456789" autoplay={false} />
|
|
57
|
+
);
|
|
58
|
+
const iframe = screen.getByTitle("Embedded vimeo");
|
|
59
|
+
expect(iframe.getAttribute("src")).toContain("autoplay=0");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("has correct iframe attributes", () => {
|
|
63
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
64
|
+
const iframe = screen.getByTitle("Embedded vimeo");
|
|
65
|
+
expect(iframe).toHaveAttribute(
|
|
66
|
+
"allow",
|
|
67
|
+
"autoplay; fullscreen; picture-in-picture"
|
|
68
|
+
);
|
|
69
|
+
expect(iframe).toHaveAttribute(
|
|
70
|
+
"referrerPolicy",
|
|
71
|
+
"strict-origin-when-cross-origin"
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("extractVimeoIdandHash", () => {
|
|
77
|
+
it("extracts id from standard vimeo.com URL", () => {
|
|
78
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
79
|
+
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
80
|
+
"/video/123456789"
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("extracts id and hash from vimeo URL with hash path", () => {
|
|
85
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789/abc123def" />);
|
|
86
|
+
const src = screen.getByTitle("Embedded vimeo").getAttribute("src")!;
|
|
87
|
+
expect(src).toContain("/video/123456789");
|
|
88
|
+
expect(src).toContain("h=abc123def");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("extracts id from player.vimeo.com URL", () => {
|
|
92
|
+
render(<VimeoEmbed link="https://player.vimeo.com/video/987654321" />);
|
|
93
|
+
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
94
|
+
"/video/987654321"
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("strips query params from link before extracting", () => {
|
|
99
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789?autoplay=1" />);
|
|
100
|
+
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
101
|
+
"/video/123456789"
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("strips trailing slashes from link", () => {
|
|
106
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789/" />);
|
|
107
|
+
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
108
|
+
"/video/123456789"
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("handles vimeo URL with nested path", () => {
|
|
113
|
+
render(
|
|
114
|
+
<VimeoEmbed link="https://vimeo.com/channels/staffpicks/123456789" />
|
|
115
|
+
);
|
|
116
|
+
expect(screen.getByTitle("Embedded vimeo").getAttribute("src")).toContain(
|
|
117
|
+
"/video/123456789"
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("debug mode", () => {
|
|
123
|
+
it("logs to console when debug is true", () => {
|
|
124
|
+
const consoleSpy = jest.spyOn(console, "log").mockImplementation();
|
|
125
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789" debug={true} />);
|
|
126
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
127
|
+
"[VimeoEmbed] href:",
|
|
128
|
+
"https://vimeo.com/123456789",
|
|
129
|
+
"id:",
|
|
130
|
+
expect.any(String)
|
|
131
|
+
);
|
|
132
|
+
consoleSpy.mockRestore();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("does not log when debug is false", () => {
|
|
136
|
+
const consoleSpy = jest.spyOn(console, "log").mockImplementation();
|
|
137
|
+
render(<VimeoEmbed link="https://vimeo.com/123456789" />);
|
|
138
|
+
expect(consoleSpy).not.toHaveBeenCalled();
|
|
139
|
+
consoleSpy.mockRestore();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
import React, { useMemo } from "react";
|
|
2
|
-
import { VideoEmbedProps } from "./types";
|
|
3
|
-
|
|
4
|
-
import { cx } from "@shared/utils";
|
|
5
|
-
|
|
6
|
-
const extractVimeoIdandHash = (href: string) => {
|
|
7
|
-
// Strip query parameters and fragments
|
|
8
|
-
const cleanHref = href.split(/[?#]/)[0].replace(/\/+$/, "");
|
|
9
|
-
const match =
|
|
10
|
-
cleanHref.match(/vimeo\.com\/(?:.*\/)?(\d{6,})/) ||
|
|
11
|
-
cleanHref.match(/player\.vimeo\.com\/video\/(\d{6,})/);
|
|
12
|
-
|
|
13
|
-
const parts = cleanHref.split("/");
|
|
14
|
-
const hash = parts[parts.length - 1];
|
|
15
|
-
|
|
16
|
-
if (!match?.[1]) return "";
|
|
17
|
-
if (match[1] === hash) return match[1];
|
|
18
|
-
return `${match[1]}/${hash}`;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const VimeoEmbed: React.FC<VideoEmbedProps> = props => {
|
|
22
|
-
const { link, containerClassName, autoplay = false, debug = false } = props;
|
|
23
|
-
|
|
24
|
-
const { href, embedId } = useMemo(() => {
|
|
25
|
-
if (!link) return { href: "", embedId: "" };
|
|
26
|
-
const resolved = link.toString();
|
|
27
|
-
const id = extractVimeoIdandHash(resolved);
|
|
28
|
-
return { href: resolved, embedId: id };
|
|
29
|
-
}, [link]);
|
|
30
|
-
|
|
31
|
-
if (debug) {
|
|
32
|
-
// eslint-disable-next-line no-console
|
|
33
|
-
console.log("[VimeoEmbed] href:", href, "id:", embedId);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!embedId) {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const params = new URLSearchParams({
|
|
41
|
-
autoplay: autoplay ? "1" : "0",
|
|
42
|
-
muted: "0",
|
|
43
|
-
playsinline: "1",
|
|
44
|
-
dnt: "1",
|
|
45
|
-
title: "0",
|
|
46
|
-
byline: "0",
|
|
47
|
-
portrait: "0",
|
|
48
|
-
autopause: "1",
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const o_src = `https://player.vimeo.com/video/${embedId}?${params.toString()}`;
|
|
52
|
-
const src = normalizeVimeoPlayerSrc(o_src);
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<div
|
|
56
|
-
className={cx(
|
|
57
|
-
"relative h-0 w-full overflow-hidden pb-[56.25%]",
|
|
58
|
-
containerClassName
|
|
59
|
-
)}
|
|
60
|
-
>
|
|
61
|
-
<iframe
|
|
62
|
-
className="absolute left-0 top-0 h-full w-full"
|
|
63
|
-
src={src}
|
|
64
|
-
allow="autoplay; fullscreen; picture-in-picture"
|
|
65
|
-
allowFullScreen={true}
|
|
66
|
-
referrerPolicy="strict-origin-when-cross-origin"
|
|
67
|
-
title="Embedded vimeo"
|
|
68
|
-
/>
|
|
69
|
-
</div>
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
function normalizeVimeoPlayerSrc(src: string): string {
|
|
74
|
-
try {
|
|
75
|
-
const u = new URL(src);
|
|
76
|
-
// Expect path like /video/{id}
|
|
77
|
-
const parts = u.pathname.split("/").filter(Boolean);
|
|
78
|
-
// Handle /video/{id}/{hash} -> move {hash} to ?h=...
|
|
79
|
-
if (parts[0] === "video" && parts.length >= 2) {
|
|
80
|
-
const id = parts[1];
|
|
81
|
-
const maybeHash = parts[2];
|
|
82
|
-
// Rebuild base
|
|
83
|
-
const base = `https://player.vimeo.com/video/${id}`;
|
|
84
|
-
if (maybeHash && /^[a-f0-9]+$/i.test(maybeHash)) {
|
|
85
|
-
u.searchParams.set("h", maybeHash);
|
|
86
|
-
}
|
|
87
|
-
return `${base}?${u.searchParams.toString()}`;
|
|
88
|
-
}
|
|
89
|
-
return src;
|
|
90
|
-
} catch {
|
|
91
|
-
return src;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { VideoEmbedProps } from "./types";
|
|
3
|
+
|
|
4
|
+
import { cx } from "@shared/utils";
|
|
5
|
+
|
|
6
|
+
const extractVimeoIdandHash = (href: string) => {
|
|
7
|
+
// Strip query parameters and fragments
|
|
8
|
+
const cleanHref = href.split(/[?#]/)[0].replace(/\/+$/, "");
|
|
9
|
+
const match =
|
|
10
|
+
cleanHref.match(/vimeo\.com\/(?:.*\/)?(\d{6,})/) ||
|
|
11
|
+
cleanHref.match(/player\.vimeo\.com\/video\/(\d{6,})/);
|
|
12
|
+
|
|
13
|
+
const parts = cleanHref.split("/");
|
|
14
|
+
const hash = parts[parts.length - 1];
|
|
15
|
+
|
|
16
|
+
if (!match?.[1]) return "";
|
|
17
|
+
if (match[1] === hash) return match[1];
|
|
18
|
+
return `${match[1]}/${hash}`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const VimeoEmbed: React.FC<VideoEmbedProps> = props => {
|
|
22
|
+
const { link, containerClassName, autoplay = false, debug = false } = props;
|
|
23
|
+
|
|
24
|
+
const { href, embedId } = useMemo(() => {
|
|
25
|
+
if (!link) return { href: "", embedId: "" };
|
|
26
|
+
const resolved = link.toString();
|
|
27
|
+
const id = extractVimeoIdandHash(resolved);
|
|
28
|
+
return { href: resolved, embedId: id };
|
|
29
|
+
}, [link]);
|
|
30
|
+
|
|
31
|
+
if (debug) {
|
|
32
|
+
// eslint-disable-next-line no-console
|
|
33
|
+
console.log("[VimeoEmbed] href:", href, "id:", embedId);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!embedId) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const params = new URLSearchParams({
|
|
41
|
+
autoplay: autoplay ? "1" : "0",
|
|
42
|
+
muted: "0",
|
|
43
|
+
playsinline: "1",
|
|
44
|
+
dnt: "1",
|
|
45
|
+
title: "0",
|
|
46
|
+
byline: "0",
|
|
47
|
+
portrait: "0",
|
|
48
|
+
autopause: "1",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const o_src = `https://player.vimeo.com/video/${embedId}?${params.toString()}`;
|
|
52
|
+
const src = normalizeVimeoPlayerSrc(o_src);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
className={cx(
|
|
57
|
+
"relative h-0 w-full overflow-hidden pb-[56.25%]",
|
|
58
|
+
containerClassName
|
|
59
|
+
)}
|
|
60
|
+
>
|
|
61
|
+
<iframe
|
|
62
|
+
className="absolute left-0 top-0 h-full w-full"
|
|
63
|
+
src={src}
|
|
64
|
+
allow="autoplay; fullscreen; picture-in-picture"
|
|
65
|
+
allowFullScreen={true}
|
|
66
|
+
referrerPolicy="strict-origin-when-cross-origin"
|
|
67
|
+
title="Embedded vimeo"
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function normalizeVimeoPlayerSrc(src: string): string {
|
|
74
|
+
try {
|
|
75
|
+
const u = new URL(src);
|
|
76
|
+
// Expect path like /video/{id}
|
|
77
|
+
const parts = u.pathname.split("/").filter(Boolean);
|
|
78
|
+
// Handle /video/{id}/{hash} -> move {hash} to ?h=...
|
|
79
|
+
if (parts[0] === "video" && parts.length >= 2) {
|
|
80
|
+
const id = parts[1];
|
|
81
|
+
const maybeHash = parts[2];
|
|
82
|
+
// Rebuild base
|
|
83
|
+
const base = `https://player.vimeo.com/video/${id}`;
|
|
84
|
+
if (maybeHash && /^[a-f0-9]+$/i.test(maybeHash)) {
|
|
85
|
+
u.searchParams.set("h", maybeHash);
|
|
86
|
+
}
|
|
87
|
+
return `${base}?${u.searchParams.toString()}`;
|
|
88
|
+
}
|
|
89
|
+
return src;
|
|
90
|
+
} catch {
|
|
91
|
+
return src;
|
|
92
|
+
}
|
|
93
|
+
}
|