@paypal/checkout-components 5.0.297 → 5.0.298-alpha.2

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.
@@ -15,6 +15,7 @@ import {
15
15
  BUTTON_NUMBER,
16
16
  BUTTON_LAYOUT,
17
17
  BUTTON_FLOW,
18
+ MESSAGE_POSITION,
18
19
  } from "../../constants";
19
20
  import {
20
21
  determineEligibleFunding,
@@ -36,6 +37,8 @@ import { Button } from "./button";
36
37
  import { TagLine } from "./tagline";
37
38
  import { Script } from "./script";
38
39
  import { PoweredByPayPal } from "./poweredBy";
40
+ import { Message } from "./message";
41
+ import { calculateMessagePosition } from "./util";
39
42
 
40
43
  type GetWalletInstrumentOptions = {|
41
44
  wallet: ?Wallet,
@@ -179,6 +182,8 @@ export function Buttons(props: ButtonsProps): ElementNode {
179
182
  supportedNativeBrowser,
180
183
  showPayLabel,
181
184
  displayOnly,
185
+ message,
186
+ messageMarkup,
182
187
  } = normalizeButtonProps(props);
183
188
  const { layout, shape, tagline } = style;
184
189
 
@@ -240,6 +245,20 @@ export function Buttons(props: ButtonsProps): ElementNode {
240
245
  return i;
241
246
  };
242
247
 
248
+ const showTagline =
249
+ tagline &&
250
+ layout === BUTTON_LAYOUT.HORIZONTAL &&
251
+ !fundingSource &&
252
+ !message;
253
+ const showPoweredBy =
254
+ layout === BUTTON_LAYOUT.VERTICAL && fundingSources.includes(FUNDING.CARD);
255
+
256
+ const calculatedMessagePosition = calculateMessagePosition({
257
+ message,
258
+ showPoweredBy,
259
+ layout,
260
+ });
261
+
243
262
  return (
244
263
  <div
245
264
  class={[
@@ -259,6 +278,10 @@ export function Buttons(props: ButtonsProps): ElementNode {
259
278
  fundingEligibility={fundingEligibility}
260
279
  />
261
280
 
281
+ {message && calculatedMessagePosition === MESSAGE_POSITION.TOP ? (
282
+ <Message markup={messageMarkup} position={calculatedMessagePosition} />
283
+ ) : null}
284
+
262
285
  {fundingSources.map((source, i) => (
263
286
  <Button
264
287
  content={content}
@@ -288,7 +311,7 @@ export function Buttons(props: ButtonsProps): ElementNode {
288
311
  />
289
312
  ))}
290
313
 
291
- {tagline && layout === BUTTON_LAYOUT.HORIZONTAL && !fundingSource ? (
314
+ {showTagline ? (
292
315
  <TagLine
293
316
  fundingSource={fundingSources[0]}
294
317
  style={style}
@@ -310,9 +333,10 @@ export function Buttons(props: ButtonsProps): ElementNode {
310
333
  />
311
334
  ) : null}
312
335
 
313
- {layout === BUTTON_LAYOUT.VERTICAL &&
314
- fundingSources.indexOf(FUNDING.CARD) !== -1 ? (
315
- <PoweredByPayPal locale={locale} nonce={nonce} />
336
+ {showPoweredBy ? <PoweredByPayPal locale={locale} nonce={nonce} /> : null}
337
+
338
+ {message && calculatedMessagePosition === MESSAGE_POSITION.BOTTOM ? (
339
+ <Message markup={messageMarkup} position={calculatedMessagePosition} />
316
340
  ) : null}
317
341
 
318
342
  {buttonDesignScript ? (
@@ -0,0 +1,31 @@
1
+ /* @flow */
2
+ /** @jsx node */
3
+
4
+ import { node, type ChildType } from "@krakenjs/jsx-pragmatic/src";
5
+
6
+ import { CLASS } from "../../constants";
7
+
8
+ const INITIAL_RESERVED_HEIGHT = "36px";
9
+
10
+ type MessageProps = {|
11
+ markup: ?string,
12
+ position: string,
13
+ |};
14
+
15
+ export function Message({ markup, position }: MessageProps): ChildType {
16
+ const messageClassNames = [
17
+ CLASS.BUTTON_MESSAGE,
18
+ `${CLASS.BUTTON_MESSAGE}-${position}`,
19
+ ].join(" ");
20
+
21
+ if (typeof markup !== "string") {
22
+ return (
23
+ <div
24
+ className={`${messageClassNames} ${CLASS.BUTTON_MESSAGE_RESERVE}`}
25
+ style={`height:${INITIAL_RESERVED_HEIGHT}`}
26
+ />
27
+ );
28
+ }
29
+
30
+ return <div class={messageClassNames} innerHTML={markup} />;
31
+ }
@@ -40,6 +40,10 @@ import {
40
40
  BUTTON_SIZE,
41
41
  BUTTON_FLOW,
42
42
  MENU_PLACEMENT,
43
+ MESSAGE_OFFER,
44
+ MESSAGE_COLOR,
45
+ MESSAGE_POSITION,
46
+ MESSAGE_ALIGN,
43
47
  } from "../../constants";
44
48
  import { getFundingConfig, isFundingEligible } from "../../funding";
45
49
 
@@ -432,6 +436,22 @@ export type ApplePaySessionConfigRequest = (
432
436
  request: Object
433
437
  ) => ApplePaySessionConfig;
434
438
 
439
+ export type ButtonMessage = {|
440
+ amount?: number,
441
+ offer?: $ReadOnlyArray<$Values<typeof MESSAGE_OFFER>>,
442
+ color?: $Values<typeof MESSAGE_COLOR>,
443
+ position?: $Values<typeof MESSAGE_POSITION>,
444
+ align?: $Values<typeof MESSAGE_ALIGN>,
445
+ |};
446
+
447
+ export type ButtonMessageInputs = {|
448
+ amount?: number | void,
449
+ offer?: $ReadOnlyArray<$Values<typeof MESSAGE_OFFER>> | void,
450
+ color?: $Values<typeof MESSAGE_COLOR> | void,
451
+ position?: $Values<typeof MESSAGE_POSITION> | void,
452
+ align?: $Values<typeof MESSAGE_ALIGN> | void,
453
+ |};
454
+
435
455
  export type RenderButtonProps = {|
436
456
  style: ButtonStyle,
437
457
  locale: LocaleType,
@@ -466,6 +486,8 @@ export type RenderButtonProps = {|
466
486
  supportedNativeBrowser: boolean,
467
487
  showPayLabel: boolean,
468
488
  displayOnly?: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>,
489
+ message?: ButtonMessage,
490
+ messageMarkup?: string,
469
491
  |};
470
492
 
471
493
  export type PrerenderDetails = {|
@@ -525,6 +547,8 @@ export type ButtonProps = {|
525
547
  createVaultSetupToken: CreateVaultSetupToken,
526
548
  displayOnly?: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>,
527
549
  hostedButtonId?: string,
550
+ message?: ButtonMessage,
551
+ messageMarkup?: string,
528
552
  |};
529
553
 
530
554
  // eslint-disable-next-line flowtype/require-exact-type
@@ -567,6 +591,8 @@ export type ButtonPropsInputs = {
567
591
  supportedNativeBrowser: boolean,
568
592
  showPayLabel: boolean,
569
593
  displayOnly: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>,
594
+ message?: ButtonMessageInputs | void,
595
+ messageMarkup?: string | void,
570
596
  };
571
597
 
572
598
  export const DEFAULT_STYLE = {
@@ -715,6 +741,62 @@ export function normalizeButtonStyle(
715
741
  };
716
742
  }
717
743
 
744
+ export function normalizeButtonMessage(
745
+ props: ?ButtonPropsInputs,
746
+ message: ButtonMessageInputs
747
+ ): ButtonMessage {
748
+ const { amount, offer, color, position, align } = message;
749
+
750
+ if (typeof amount !== "undefined") {
751
+ if (typeof amount !== "number") {
752
+ throw new TypeError(
753
+ `Expected message.amount to be a number, got: ${amount}`
754
+ );
755
+ }
756
+ if (amount < 0) {
757
+ throw new Error(
758
+ `Expected message.amount to be a positive number, got: ${amount}`
759
+ );
760
+ }
761
+ }
762
+
763
+ if (offer) {
764
+ if (!Array.isArray(offer)) {
765
+ throw new TypeError(
766
+ `Expected message.offer to be an array of strings, got: ${String(
767
+ offer
768
+ )}`
769
+ );
770
+ }
771
+ const invalidOffers = offer.filter(
772
+ (o) => !values(MESSAGE_OFFER).includes(o)
773
+ );
774
+ if (invalidOffers.length > 0) {
775
+ throw new Error(`Invalid offer(s): ${invalidOffers.join(",")}`);
776
+ }
777
+ }
778
+
779
+ if (color && !values(MESSAGE_COLOR).includes(color)) {
780
+ throw new Error(`Invalid color: ${color}`);
781
+ }
782
+
783
+ if (position && !values(MESSAGE_POSITION).includes(position)) {
784
+ throw new Error(`Invalid position: ${position}`);
785
+ }
786
+
787
+ if (align && !values(MESSAGE_ALIGN).includes(align)) {
788
+ throw new Error(`Invalid align: ${align}`);
789
+ }
790
+
791
+ return {
792
+ amount,
793
+ offer,
794
+ color,
795
+ position,
796
+ align,
797
+ };
798
+ }
799
+
718
800
  const COUNTRIES = values(COUNTRY);
719
801
  const FUNDING_SOURCES = values(FUNDING);
720
802
  const ENVS = values(ENV);
@@ -769,6 +851,8 @@ export function normalizeButtonProps(
769
851
  supportedNativeBrowser = false,
770
852
  showPayLabel = true,
771
853
  displayOnly = [],
854
+ message,
855
+ messageMarkup,
772
856
  } = props;
773
857
 
774
858
  const { country, lang } = locale;
@@ -860,5 +944,7 @@ export function normalizeButtonProps(
860
944
  supportedNativeBrowser,
861
945
  showPayLabel,
862
946
  displayOnly,
947
+ message: message ? normalizeButtonMessage(props, message) : undefined,
948
+ messageMarkup,
863
949
  };
864
950
  }
@@ -1,5 +1,41 @@
1
1
  /* @flow */
2
+ import { BUTTON_LAYOUT, MESSAGE_POSITION } from "../../constants";
3
+ import { ValidationError } from "../../lib";
4
+
5
+ import type { ButtonMessage } from "./props";
2
6
 
3
7
  export function isBorderRadiusNumber(borderRadius?: number): boolean {
4
8
  return typeof borderRadius === "number";
5
9
  }
10
+
11
+ type calculateMessagePositionProps = {|
12
+ message: ButtonMessage | void,
13
+ showPoweredBy: boolean,
14
+ layout: string,
15
+ |};
16
+
17
+ export function calculateMessagePosition({
18
+ message,
19
+ showPoweredBy,
20
+ layout,
21
+ }: calculateMessagePositionProps): string {
22
+ if (!message) {
23
+ return "none";
24
+ }
25
+ const { position } = message;
26
+
27
+ if (showPoweredBy && position === MESSAGE_POSITION.BOTTOM) {
28
+ throw new ValidationError(
29
+ "Message position must be 'top' when Debit and/or Credit Card button is present"
30
+ );
31
+ }
32
+
33
+ if (
34
+ showPoweredBy ||
35
+ position === MESSAGE_POSITION.TOP ||
36
+ (layout === BUTTON_LAYOUT.VERTICAL && !position)
37
+ ) {
38
+ return MESSAGE_POSITION.TOP;
39
+ }
40
+ return MESSAGE_POSITION.BOTTOM;
41
+ }
@@ -73,7 +73,11 @@ import {
73
73
  logLatencyInstrumentationPhase,
74
74
  prepareInstrumentationPayload,
75
75
  } from "../../lib";
76
- import { normalizeButtonStyle, type ButtonProps } from "../../ui/buttons/props";
76
+ import {
77
+ normalizeButtonStyle,
78
+ normalizeButtonMessage,
79
+ type ButtonProps,
80
+ } from "../../ui/buttons/props";
77
81
  import { isFundingEligible } from "../../funding";
78
82
 
79
83
  import { containerTemplate } from "./container";
@@ -887,6 +891,16 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
887
891
  required: false,
888
892
  default: () => window.__TEST_WALLET__,
889
893
  },
894
+
895
+ message: {
896
+ type: "object",
897
+ queryParam: true,
898
+ required: false,
899
+ decorate: ({ props, value }) => {
900
+ // $FlowFixMe
901
+ return normalizeButtonMessage(props, value);
902
+ },
903
+ },
890
904
  },
891
905
  });
892
906
  });
@@ -1,25 +0,0 @@
1
- /* @flow */
2
- import { getLogger } from "@paypal/sdk-client/src";
3
-
4
- // TODO: This will be pulled in to a shared sdk-client util
5
- export const sendCountMetric = ({
6
- dimensions,
7
- event = "unused",
8
- name,
9
- value = 1,
10
- }: {|
11
- event?: string,
12
- name: string,
13
- value?: number,
14
- dimensions: {
15
- [string]: mixed,
16
- },
17
- // $FlowIssue return type
18
- |}) =>
19
- getLogger().metric({
20
- dimensions,
21
- metricEventName: event,
22
- metricNamespace: name,
23
- metricValue: value,
24
- metricType: "counter",
25
- });