@paypal/checkout-components 5.0.386 → 5.0.388

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.
@@ -491,6 +491,7 @@ export type RenderButtonProps = {|
491
491
  displayOnly?: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>,
492
492
  message?: ButtonMessage,
493
493
  messageMarkup?: string,
494
+ userAgent: string,
494
495
  |};
495
496
 
496
497
  export type PrerenderDetails = {|
@@ -633,6 +634,7 @@ export type ButtonProps = {|
633
634
  message?: ButtonMessage,
634
635
  messageMarkup?: string,
635
636
  hideSubmitButtonForCardForm?: boolean,
637
+ userAgent: string,
636
638
  |};
637
639
 
638
640
  // eslint-disable-next-line flowtype/require-exact-type
@@ -683,6 +685,7 @@ export type ButtonPropsInputs = {
683
685
  messageMarkup?: string | void,
684
686
  renderedButtons: $ReadOnlyArray<$Values<typeof FUNDING>>,
685
687
  buttonColor: ButtonColor,
688
+ userAgent: string,
686
689
  };
687
690
 
688
691
  export const DEFAULT_STYLE = {
@@ -754,6 +757,7 @@ export function hasInvalidScriptOptionsForFullRedesign({
754
757
  fundingSource?: ?$Values<typeof FUNDING>,
755
758
  |}): boolean {
756
759
  const validFundingSourcesForRedesign = [
760
+ undefined,
757
761
  FUNDING.PAYPAL,
758
762
  FUNDING.VENMO,
759
763
  FUNDING.PAYLATER,
@@ -882,7 +886,7 @@ export function getColorForFullRedesign({
882
886
  style,
883
887
  });
884
888
 
885
- buttonColor = rebrandColorMap[defaultButtonColor];
889
+ buttonColor = rebrandColorMap[defaultButtonColor] || defaultButtonColor;
886
890
  }
887
891
 
888
892
  return {
@@ -1262,6 +1266,7 @@ export function normalizeButtonProps(
1262
1266
  messageMarkup,
1263
1267
  renderedButtons,
1264
1268
  shopperSessionId,
1269
+ userAgent,
1265
1270
  } = props;
1266
1271
 
1267
1272
  const { country, lang } = locale;
@@ -1315,6 +1320,7 @@ export function normalizeButtonProps(
1315
1320
  supportsPopups,
1316
1321
  supportedNativeBrowser,
1317
1322
  displayOnly,
1323
+ userAgent,
1318
1324
  })
1319
1325
  ) {
1320
1326
  throw new Error(`Funding Source not eligible: ${fundingSource}`);
@@ -1366,5 +1372,6 @@ export function normalizeButtonProps(
1366
1372
  displayOnly,
1367
1373
  message,
1368
1374
  messageMarkup,
1375
+ userAgent,
1369
1376
  };
1370
1377
  }
@@ -160,12 +160,6 @@ describe("hasInvalidScriptOptionsForFullRedesign", () => {
160
160
  });
161
161
  });
162
162
 
163
- it("should return true when no funding source is provided", () => {
164
- const result = hasInvalidScriptOptionsForFullRedesign({});
165
-
166
- expect(result).toBe(true);
167
- });
168
-
169
163
  it("should return true when funding source is null", () => {
170
164
  const result = hasInvalidScriptOptionsForFullRedesign({
171
165
  fundingSource: null,
@@ -681,7 +675,7 @@ describe("getButtonColorExperience", () => {
681
675
  expect(result).toBe("fullRebrand");
682
676
  });
683
677
 
684
- it("should return legacy for smart stack (fundingSource is undefined)", () => {
678
+ it("should return fullRebrand for smart stack (fundingSource is undefined)", () => {
685
679
  const result = getButtonColorExperience({
686
680
  experiment: {
687
681
  isPaypalRebrandEnabled: true,
@@ -692,7 +686,7 @@ describe("getButtonColorExperience", () => {
692
686
  style: { color: BUTTON_COLOR.GOLD },
693
687
  });
694
688
 
695
- expect(result).toBe("legacy");
689
+ expect(result).toBe("fullRebrand");
696
690
  });
697
691
  });
698
692
 
@@ -199,10 +199,59 @@ export function getComponentScript(): () => void {
199
199
  }
200
200
  }
201
201
 
202
+ function toggleLogos() {
203
+ const LOGO_CLASS = {
204
+ PAYPAL_LOGO: ".paypal-logo-paypal-rebrand",
205
+ PP_LOGO: ".paypal-logo-pp-rebrand",
206
+ PAYPAL_BUTTON: ".paypal-button-rebrand",
207
+ BUTTON_LABEL: ".paypal-button-label-container",
208
+ };
209
+
210
+ const paylaterButtons = getElements(LOGO_CLASS.PAYPAL_BUTTON);
211
+
212
+ for (const button of paylaterButtons) {
213
+ const paypalLogo = button.querySelector(LOGO_CLASS.PAYPAL_LOGO);
214
+ const ppLogo = button.querySelector(LOGO_CLASS.PP_LOGO);
215
+ const buttonLabel = button.querySelector(LOGO_CLASS.BUTTON_LABEL);
216
+
217
+ if (!buttonLabel || !paypalLogo || !ppLogo) {
218
+ continue;
219
+ }
220
+
221
+ const buttonWidth = buttonLabel.offsetWidth;
222
+ const gap = calculateGap(buttonLabel);
223
+
224
+ // temporarily hide PayPal logos
225
+ hideElement(paypalLogo);
226
+ hideElement(ppLogo);
227
+
228
+ const allElements = getAllChildren(buttonLabel);
229
+ const textElements = allElements.filter(
230
+ (el) => !el.classList.contains("paypal-logo-pp-rebrand")
231
+ );
232
+
233
+ const totalWidth = getElementsTotalWidth(textElements) + gap;
234
+
235
+ if (totalWidth > buttonWidth) {
236
+ hideElement(paypalLogo);
237
+ showElement(ppLogo);
238
+ } else {
239
+ showElement(paypalLogo);
240
+ hideElement(ppLogo);
241
+ }
242
+ }
243
+ }
244
+
202
245
  const setDomReady = once(
203
246
  debounce(() => {
204
- window.addEventListener("resize", toggleOptionals);
205
- setTimeout(toggleOptionals);
247
+ window.addEventListener("resize", () => {
248
+ toggleOptionals();
249
+ toggleLogos();
250
+ });
251
+ setTimeout(() => {
252
+ toggleOptionals();
253
+ toggleLogos();
254
+ });
206
255
  if (document.body) {
207
256
  document.body.classList.add(CLASS.DOM_READY);
208
257
  }
@@ -211,10 +260,12 @@ export function getComponentScript(): () => void {
211
260
 
212
261
  const load = () => {
213
262
  toggleOptionals();
263
+ toggleLogos();
214
264
  setDomReady();
215
265
  };
216
266
 
217
267
  toggleOptionals();
268
+ toggleLogos();
218
269
  document.addEventListener("DOMContentLoaded", load);
219
270
  window.addEventListener("load", load);
220
271
  window.addEventListener("resize", load);
@@ -3,9 +3,7 @@
3
3
  import { ENV } from "@paypal/sdk-constants/src";
4
4
  import { LOGO_CLASS } from "@paypal/sdk-logos/src";
5
5
 
6
- import { CLASS, ATTRIBUTE } from "../../../constants";
7
-
8
- import { HIDDEN, VISIBLE } from "./labels";
6
+ import { CLASS } from "../../../constants";
9
7
 
10
8
  const MIN_VAULT_BUTTON_WIDTH = 250;
11
9
 
@@ -210,29 +208,4 @@ export const buttonRebrandStyle = `
210
208
  text-align: center;
211
209
  width: auto;
212
210
  }
213
-
214
- /* Hide/show credit/paylater logos based on button width */
215
- @media only screen and (min-width: 0px) and (max-width: 150px) {
216
- [${ATTRIBUTE.FUNDING_SOURCE}="credit"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_REBRAND},
217
- [${ATTRIBUTE.FUNDING_SOURCE}="paylater"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_REBRAND} {
218
- ${HIDDEN}
219
- }
220
-
221
- [${ATTRIBUTE.FUNDING_SOURCE}="credit"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_PP_REBRAND},
222
- [${ATTRIBUTE.FUNDING_SOURCE}="paylater"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_PP_REBRAND} {
223
- ${VISIBLE}
224
- }
225
- }
226
-
227
- @media only screen and (min-width: 150px) {
228
- [${ATTRIBUTE.FUNDING_SOURCE}="credit"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_REBRAND},
229
- [${ATTRIBUTE.FUNDING_SOURCE}="paylater"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_REBRAND} {
230
- ${VISIBLE}
231
- }
232
-
233
- [${ATTRIBUTE.FUNDING_SOURCE}="credit"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_PP_REBRAND},
234
- [${ATTRIBUTE.FUNDING_SOURCE}="paylater"].${CLASS.BUTTON_REBRAND} .${CLASS.BUTTON_LABEL} .${CLASS.LOGO_PP_REBRAND} {
235
- ${HIDDEN}
236
- }
237
- }
238
211
  `;
@@ -481,6 +481,29 @@ const generateDisableMaxHeightStyles = ({
481
481
  .join("\n");
482
482
  };
483
483
 
484
+ const generateRebrandedDisableMaxHeightStyles = (): string => {
485
+ return Object.keys(BUTTON_REDESIGN_STYLE)
486
+ .map((redesign_size) => {
487
+ const { gap, fontSize, minHeight, maxHeight } =
488
+ getResponsiveRebrandedStyleVariables({
489
+ redesign_size,
490
+ });
491
+
492
+ return `
493
+ @media (min-height: ${minHeight}px) and (max-height: ${maxHeight}px) {
494
+ .${CLASS.BUTTON_REBRAND} > .${CLASS.BUTTON_LABEL} {
495
+ gap: ${gap}px;
496
+ }
497
+ .${CLASS.CONTAINER} .${CLASS.BUTTON_ROW} .${CLASS.TEXT},
498
+ .${CLASS.CONTAINER} .${CLASS.BUTTON_ROW} .${CLASS.SPACE} {
499
+ font-size: ${fontSize}px;
500
+ position: relative;
501
+ }
502
+ `;
503
+ })
504
+ .join("\n");
505
+ };
506
+
484
507
  const generateRebrandedButtonSizeStyles = ({
485
508
  height,
486
509
  disableMaxWidth,
@@ -506,6 +529,7 @@ const generateRebrandedButtonSizeStyles = ({
506
529
  maxHeight,
507
530
  minWidth,
508
531
  maxWidth,
532
+ minDualWidth,
509
533
  } = getResponsiveRebrandedStyleVariables({
510
534
  height,
511
535
  redesign_size,
@@ -520,7 +544,11 @@ const generateRebrandedButtonSizeStyles = ({
520
544
  }
521
545
 
522
546
  .${CLASS.BUTTON_ROW} {
523
- ${disableMaxHeight ? "" : `height: ${height || defaultHeight}px;`}
547
+ ${
548
+ disableMaxHeight
549
+ ? "height: 100%;"
550
+ : `height: ${height || defaultHeight}px;`
551
+ }
524
552
  vertical-align: top;
525
553
  ${disableMaxHeight ? "" : `max-height: ${height || maxHeight}px;`}
526
554
  }
@@ -563,37 +591,86 @@ const generateRebrandedButtonSizeStyles = ({
563
591
  )}px;
564
592
  }
565
593
 
566
- // TO:DO no margin on last-child not getting applied
594
+ /* TO:DO no margin on last-child not getting applied */
567
595
  .${CLASS.BUTTON_ROW}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.VERTICAL}.${
568
596
  CLASS.NUMBER
569
597
  }-${BUTTON_NUMBER.MULTIPLE}:last-child {
570
598
  margin-bottom: 0;
571
599
  }
572
- }`;
600
+ }
601
+
602
+ @media only screen and (min-width: ${minWidth}px) and (max-width: ${minDualWidth}px) {
603
+ .${CLASS.BUTTON_ROW}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${
604
+ CLASS.NUMBER
605
+ }-${BUTTON_NUMBER.MULTIPLE}.${CLASS.NUMBER}-0 {
606
+ width: 100%;
607
+ margin-right: 0;
608
+ }
573
609
 
574
- const disableMaxHeightStyles = `
575
- @media only screen and (min-width: ${minWidth}px) {
576
- .${CLASS.CONTAINER} {
577
- min-width: ${minWidth}px;
578
- ${disableMaxWidth ? "" : `max-width: ${maxWidth}px;`};
579
- ${disableMaxHeight ? "height: 100%;" : ""};
610
+ .${CLASS.BUTTON_ROW}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${
611
+ CLASS.NUMBER
612
+ }-${BUTTON_NUMBER.MULTIPLE}.${CLASS.NUMBER}-1 {
613
+ display: none;
614
+ }
615
+
616
+ .${CLASS.CONTAINER}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${
617
+ CLASS.NUMBER
618
+ }-${BUTTON_NUMBER.MULTIPLE} .${CLASS.TAGLINE} {
619
+ display: none;
580
620
  }
581
621
  }
582
622
 
583
- @media only screen and (min-height: ${minHeight}px) and (max-height: ${maxHeight}px) {
584
- .${CLASS.BUTTON_ROW} {
585
- height: ${height || minHeight}px;
586
- vertical-align: top;
587
- min-height: ${height || minHeight}px;
588
- max-height: ${height || maxHeight}px;
623
+ @media only screen and (min-width: ${max(minWidth, minDualWidth)}px) {
624
+ .${CLASS.BUTTON_ROW}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${
625
+ CLASS.NUMBER
626
+ }-${BUTTON_NUMBER.MULTIPLE}.${CLASS.NUMBER}-0 {
627
+ display: inline-block;
628
+ width: calc(${FIRST_BUTTON_PERC}% - ${perc(buttonHeight, 7)}px);
629
+ margin-right: ${perc(buttonHeight, 7) * 2}px;
589
630
  }
590
631
 
591
- .${CLASS.BUTTON_REBRAND} > .${CLASS.BUTTON_LABEL} {
592
- margin: 0px 4vw;
593
- box-sizing: border-box;
594
- height: ${buttonHeight * 0.76}px;
632
+ .${CLASS.BUTTON_ROW}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${
633
+ CLASS.NUMBER
634
+ }-${BUTTON_NUMBER.MULTIPLE}.${CLASS.NUMBER}-1 {
635
+ display: inline-block;
636
+ width: calc(${100 - FIRST_BUTTON_PERC}% - ${perc(
637
+ buttonHeight,
638
+ 7
639
+ )}px);
595
640
  }
596
- }`;
641
+
642
+ .${CLASS.CONTAINER}.${CLASS.WALLET} .${CLASS.BUTTON_ROW}.${
643
+ CLASS.WALLET
644
+ }.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${CLASS.NUMBER}-${
645
+ BUTTON_NUMBER.MULTIPLE
646
+ } {
647
+ width: calc(${WALLET_BUTTON_PERC}% - ${perc(buttonHeight, 7)}px);
648
+ }
649
+
650
+ .${CLASS.CONTAINER}.${CLASS.WALLET} .${CLASS.BUTTON_ROW}:not(.${
651
+ CLASS.WALLET
652
+ }).${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${CLASS.NUMBER}-${
653
+ BUTTON_NUMBER.MULTIPLE
654
+ } {
655
+ width: calc(${100 - WALLET_BUTTON_PERC}% - ${perc(
656
+ buttonHeight,
657
+ 7
658
+ )}px);
659
+ }
660
+
661
+ .${CLASS.CONTAINER}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${
662
+ CLASS.NUMBER
663
+ }-${BUTTON_NUMBER.MULTIPLE} .${CLASS.TAGLINE} {
664
+ display: block;
665
+ }
666
+
667
+ .${CLASS.CONTAINER}.${CLASS.LAYOUT}-${BUTTON_LAYOUT.HORIZONTAL}.${
668
+ CLASS.NUMBER
669
+ }-${BUTTON_NUMBER.MULTIPLE} .${CLASS.TAGLINE} .${CLASS.TEXT} {
670
+ display: block;
671
+ }
672
+ }
673
+ `;
597
674
 
598
675
  const heightBasedStyles = `
599
676
  @media only screen and (min-height: ${minHeight}px) and (max-height: ${maxHeight}px) {
@@ -734,9 +811,8 @@ const generateRebrandedButtonSizeStyles = ({
734
811
  width: ${buttonHeight}px;
735
812
  }
736
813
  }`;
737
- return disableMaxHeight
738
- ? disableMaxHeightStyles + heightBasedStyles
739
- : widthBasedStyles + heightBasedStyles;
814
+
815
+ return widthBasedStyles + heightBasedStyles;
740
816
  })
741
817
  .join("\n");
742
818
  };
@@ -780,6 +856,10 @@ export function buttonResponsiveStyle({
780
856
  })
781
857
  : "";
782
858
 
859
+ const disableMaxHeightRebrandedStyles =
860
+ disableMaxHeightStyles +
861
+ (disableMaxHeight ? generateRebrandedDisableMaxHeightStyles() : "");
862
+
783
863
  const baseStyles = `
784
864
  .${CLASS.BUTTON} {
785
865
  display: inline-block;
@@ -827,7 +907,7 @@ export function buttonResponsiveStyle({
827
907
  }`;
828
908
 
829
909
  const rebrandedStyles = shouldApplyRebrandedStyles
830
- ? buttonRedesignSizeStyles
910
+ ? buttonRedesignSizeStyles + disableMaxHeightRebrandedStyles
831
911
  : buttonSizeStyles + disableMaxHeightStyles;
832
912
 
833
913
  return baseStyles + rebrandedStyles;
@@ -30,6 +30,7 @@ import {
30
30
  getAPIStageHost,
31
31
  getPayPalDomain,
32
32
  getUserIDToken,
33
+ getSDKIntegrationSource,
33
34
  getClientMetadataID,
34
35
  getAmount,
35
36
  getEnableFunding,
@@ -61,6 +62,7 @@ import {
61
62
  isApplePaySupported,
62
63
  supportsPopups as userAgentSupportsPopups,
63
64
  noop,
65
+ getUserAgent,
64
66
  } from "@krakenjs/belter/src";
65
67
  import {
66
68
  FUNDING,
@@ -89,6 +91,10 @@ import {
89
91
  type ButtonExtensions,
90
92
  } from "../../ui/buttons/props";
91
93
  import { isFundingEligible } from "../../funding";
94
+ import {
95
+ supportsVenmoPopups,
96
+ isSupportedNativeVenmoBrowser,
97
+ } from "../../funding/util";
92
98
  import { getPixelComponent } from "../pixel";
93
99
  import { CLASS } from "../../constants";
94
100
  import { PayPalAppSwitchOverlay } from "../../ui/overlay/paypal-app-switch/overlay";
@@ -251,6 +257,7 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
251
257
  createSubscription,
252
258
  createVaultSetupToken,
253
259
  displayOnly,
260
+ userAgent,
254
261
  } = props;
255
262
 
256
263
  const flow = determineFlow({
@@ -294,6 +301,7 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
294
301
  supportedNativeBrowser,
295
302
  experiment,
296
303
  displayOnly,
304
+ userAgent,
297
305
  })
298
306
  ) {
299
307
  return {
@@ -714,6 +722,7 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
714
722
  createSubscription,
715
723
  createVaultSetupToken,
716
724
  displayOnly,
725
+ userAgent = getUserAgent(),
717
726
  } = props;
718
727
 
719
728
  const flow = determineFlow({
@@ -744,6 +753,7 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
744
753
  supportsPopups,
745
754
  supportedNativeBrowser,
746
755
  displayOnly,
756
+ userAgent,
747
757
  })
748
758
  ) {
749
759
  throw new Error(`${fundingSource} is not eligible`);
@@ -1266,13 +1276,32 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
1266
1276
 
1267
1277
  supportedNativeBrowser: {
1268
1278
  type: "boolean",
1269
- value: isSupportedNativeBrowser,
1279
+ value: ({ props }) => {
1280
+ if (props.fundingSource === FUNDING.VENMO) {
1281
+ return isSupportedNativeVenmoBrowser(
1282
+ props.experiment,
1283
+ props.userAgent
1284
+ );
1285
+ }
1286
+
1287
+ return isSupportedNativeBrowser();
1288
+ },
1270
1289
  queryParam: true,
1271
1290
  },
1272
1291
 
1273
1292
  supportsPopups: {
1274
1293
  type: "boolean",
1275
- value: () => userAgentSupportsPopups(),
1294
+ value: ({ props }) => {
1295
+ if (props.fundingSource === FUNDING.VENMO) {
1296
+ return supportsVenmoPopups(
1297
+ props.experiment,
1298
+ userAgentSupportsPopups(),
1299
+ props.userAgent
1300
+ );
1301
+ }
1302
+
1303
+ return userAgentSupportsPopups();
1304
+ },
1276
1305
  queryParam: true,
1277
1306
  },
1278
1307
 
@@ -1299,6 +1328,14 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
1299
1328
  bodyParam: getEnv() === ENV.LOCAL || getEnv() === ENV.STAGE,
1300
1329
  },
1301
1330
 
1331
+ sdkSource: {
1332
+ type: "string",
1333
+ value: () => getSDKIntegrationSource(),
1334
+ required: false,
1335
+ queryParam: true,
1336
+ bodyParam: true,
1337
+ },
1338
+
1302
1339
  vault: {
1303
1340
  type: "boolean",
1304
1341
  queryParam: true,
@@ -1316,6 +1353,13 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
1316
1353
  required: false,
1317
1354
  queryParam: true,
1318
1355
  },
1356
+
1357
+ userAgent: {
1358
+ type: "string",
1359
+ required: false,
1360
+ queryParam: true,
1361
+ value: getUserAgent,
1362
+ },
1319
1363
  },
1320
1364
 
1321
1365
  exports: {