@paypal/checkout-components 5.0.296 → 5.0.297

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paypal/checkout-components",
3
- "version": "5.0.296",
3
+ "version": "5.0.297",
4
4
  "description": "PayPal Checkout components, for integrating checkout products.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -109,9 +109,9 @@
109
109
  "@krakenjs/zalgo-promise": "^2.0.0",
110
110
  "@krakenjs/zoid": "^10.3.1",
111
111
  "@paypal/common-components": "^1.0.35",
112
- "@paypal/funding-components": "^1.0.31",
113
112
  "@paypal/connect-loader-component": "1.1.1",
114
- "@paypal/sdk-client": "^4.0.179",
113
+ "@paypal/funding-components": "^1.0.31",
114
+ "@paypal/sdk-client": "^4.0.180",
115
115
  "@paypal/sdk-constants": "^1.0.133",
116
116
  "@paypal/sdk-logos": "^2.2.6"
117
117
  },
@@ -5,6 +5,7 @@ import {
5
5
  getClientID,
6
6
  getClientMetadataID,
7
7
  getUserIDToken,
8
+ getSDKToken,
8
9
  getLogger,
9
10
  getEnv,
10
11
  loadFraudnet,
@@ -52,7 +53,7 @@ export function getSdkVersion(version: string | null): string {
52
53
  export const getConnectComponent = async (merchantProps = {}) => {
53
54
  const cmid = getClientMetadataID() || getSessionID();
54
55
  const clientId = getClientID();
55
- const userIdToken = getUserIDToken();
56
+ const sdkToken = getSDKToken() || getUserIDToken();
56
57
  const env = getEnv();
57
58
  const cspNonce = getCSPNonce();
58
59
 
@@ -107,7 +108,7 @@ export const getConnectComponent = async (merchantProps = {}) => {
107
108
  ...merchantProps, // AXO specific props
108
109
  platformOptions: {
109
110
  platform: "PPCP",
110
- userIdToken,
111
+ userIdToken: sdkToken,
111
112
  clientId,
112
113
  fraudnet: collect,
113
114
  clientMetadataId: cmid,
@@ -1,10 +1,6 @@
1
1
  /* @flow */
2
2
 
3
- import {
4
- getClientID,
5
- getClientMetadataID,
6
- getUserIDToken,
7
- } from "@paypal/sdk-client/src";
3
+ import { getUserIDToken, getSDKToken } from "@paypal/sdk-client/src";
8
4
  import { loadAxo } from "@paypal/connect-loader-component";
9
5
  import { describe, expect, test, vi } from "vitest";
10
6
 
@@ -20,6 +16,7 @@ vi.mock("@paypal/sdk-client/src", () => {
20
16
  getClientID: vi.fn(() => "mock-client-id"),
21
17
  getClientMetadataID: vi.fn(() => "mock-cmid"),
22
18
  getUserIDToken: vi.fn(() => "mock-uid"),
19
+ getSDKToken: vi.fn().mockReturnValue("mock-sdk-token"),
23
20
  getDebug: vi.fn(() => false),
24
21
  getLogger: vi.fn(() => ({
25
22
  metric: vi.fn().mockReturnThis(),
@@ -27,7 +24,7 @@ vi.mock("@paypal/sdk-client/src", () => {
27
24
  track: vi.fn().mockReturnThis(),
28
25
  flush: vi.fn().mockReturnThis(),
29
26
  })),
30
- getEnv: vi.fn(),
27
+ getEnv: vi.fn().mockReturnValue("mock-env"),
31
28
  getCSPNonce: vi.fn(),
32
29
  loadFraudnet: vi.fn(() => ({ collect: vi.fn() })),
33
30
  };
@@ -59,13 +56,36 @@ describe("getConnectComponent: returns ConnectComponent", () => {
59
56
  loadAxo.mockResolvedValue({ metadata: mockAxoMetadata });
60
57
  });
61
58
 
62
- test("loadAxo and window.braintree.connect.create are called with proper data", async () => {
59
+ test("uses user id token if no sdk token is present", async () => {
60
+ // $FlowIssue
61
+ getUserIDToken.mockReturnValue("user-id-token");
62
+ // $FlowIssue
63
+ getSDKToken.mockReturnValue(undefined);
64
+
63
65
  await getConnectComponent(mockProps);
64
66
 
65
- expect(getClientID).toHaveBeenCalled();
66
- expect(getClientMetadataID).toHaveBeenCalled();
67
- expect(getUserIDToken).toHaveBeenCalled();
68
- expect(loadAxo).toHaveBeenCalled();
67
+ expect(window.braintree.connect.create).toHaveBeenCalledWith({
68
+ ...mockAxoMetadata,
69
+ ...mockProps,
70
+ platformOptions: {
71
+ platform: "PPCP",
72
+ clientId: "mock-client-id",
73
+ clientMetadataId: "mock-cmid",
74
+ userIdToken: "user-id-token",
75
+ fraudnet: expect.any(Function),
76
+ env: "mock-env",
77
+ },
78
+ });
79
+ expect(sendCountMetric).toBeCalledTimes(2);
80
+ });
81
+
82
+ test("uses sdk token if present", async () => {
83
+ // $FlowIssue
84
+ getUserIDToken.mockReturnValue("user-id-token");
85
+ // $FlowIssue
86
+ getSDKToken.mockReturnValue("sdk-client-token");
87
+
88
+ await getConnectComponent(mockProps);
69
89
 
70
90
  expect(window.braintree.connect.create).toHaveBeenCalledWith({
71
91
  ...mockAxoMetadata,
@@ -74,7 +94,7 @@ describe("getConnectComponent: returns ConnectComponent", () => {
74
94
  platform: "PPCP",
75
95
  clientId: "mock-client-id",
76
96
  clientMetadataId: "mock-cmid",
77
- userIdToken: "mock-uid",
97
+ userIdToken: "sdk-client-token",
78
98
  fraudnet: expect.any(Function),
79
99
  env: "mock-env",
80
100
  },
@@ -132,12 +152,8 @@ describe("getSdkVersion", () => {
132
152
  });
133
153
 
134
154
  test("throws error if the version passed is not supported for AXO and is not null", () => {
135
- const result1 = getSdkVersion("3.96.00");
136
- const result2 = getSdkVersion("2.87.alpha-test");
137
- const result3 = getSdkVersion("3.34.beta-test");
138
-
139
- expect(result1).toThrowError();
140
- expect(result2).toThrowError();
141
- expect(result3).toThrowError();
155
+ expect(() => getSdkVersion("3.96.00")).toThrowError();
156
+ expect(() => getSdkVersion("2.87.alpha-test")).toThrowError();
157
+ expect(() => getSdkVersion("3.34.beta-test")).toThrowError();
142
158
  });
143
159
  });
@@ -1,17 +1,24 @@
1
- /* eslint-disable flowtype/no-weak-types */
2
1
  /* @flow */
3
- // flow-disable
4
- import { memoize } from "@krakenjs/belter/src";
2
+ /* eslint-disable eslint-comments/disable-enable-pair */
3
+ /* eslint-disable no-restricted-globals, promise/no-native */
4
+
5
+ import { memoize, type Memoized } from "@krakenjs/belter/src";
5
6
 
6
7
  import { getConnectComponent } from "./component";
7
8
 
8
- type ConnectComponent = (merchantProps: any) => ConnectComponent;
9
+ type MerchantProps = {||};
10
+ // This needs to be typed, this is coming from the fastlane team i believe
11
+ type FastlaneExternalComponent = {||};
12
+
13
+ type ConnectComponent = (merchantProps: MerchantProps) => ConnectComponent;
9
14
  // $FlowFixMe
10
- export const Connect: (merchantProps: any) => ConnectComponent = memoize(
11
- async (merchantProps: any): ConnectComponent => {
15
+ export const Connect: (merchantProps: MerchantProps) => ConnectComponent =
16
+ memoize(async (merchantProps: MerchantProps): ConnectComponent => {
12
17
  // $FlowFixMe
13
18
  return await getConnectComponent(merchantProps);
14
- }
15
- );
19
+ });
16
20
 
17
- /* eslint-enable flowtype/no-weak-types */
21
+ export const Fastlane = (
22
+ merchantProps: MerchantProps
23
+ ): Memoized<() => Promise<FastlaneExternalComponent>> =>
24
+ memoize(() => getConnectComponent(merchantProps));
@@ -39,6 +39,7 @@ export const BUTTON_SIZE = {
39
39
  export const BUTTON_SHAPE = {
40
40
  PILL: ("pill": "pill"),
41
41
  RECT: ("rect": "rect"),
42
+ SHARP: ("sharp": "sharp"),
42
43
  };
43
44
 
44
45
  export const BUTTON_LAYOUT = {
@@ -12,6 +12,7 @@ export const CLASS = {
12
12
  COLOR: ("paypal-button-color": "paypal-button-color"),
13
13
  TEXT_COLOR: ("paypal-button-text-color": "paypal-button-text-color"),
14
14
  SHAPE: ("paypal-button-shape": "paypal-button-shape"),
15
+ BORDER_RADIUS: ("paypal-button-border-radius": "paypal-button-border-radius"),
15
16
  LAYOUT: ("paypal-button-layout": "paypal-button-layout"),
16
17
  NUMBER: ("paypal-button-number": "paypal-button-number"),
17
18
  ENV: ("paypal-button-env": "paypal-button-env"),
@@ -217,7 +217,7 @@ export const DEFAULT_FUNDING_CONFIG: FundingSourceConfig = {
217
217
  [BUTTON_COLOR.BLACK]: LOGO_COLOR.WHITE,
218
218
  },
219
219
 
220
- shapes: [BUTTON_SHAPE.RECT, BUTTON_SHAPE.PILL],
220
+ shapes: [BUTTON_SHAPE.RECT, BUTTON_SHAPE.PILL, BUTTON_SHAPE.SHARP],
221
221
 
222
222
  textColors: {
223
223
  [DEFAULT]: BUTTON_COLOR.BLACK,
@@ -39,6 +39,7 @@ import type {
39
39
  } from "./props";
40
40
  import { Spinner } from "./spinner";
41
41
  import { MenuButton } from "./menu-button";
42
+ import { isBorderRadiusNumber } from "./util";
42
43
 
43
44
  type IndividualButtonProps = {|
44
45
  style: ButtonStyle,
@@ -88,7 +89,7 @@ export function Button({
88
89
  instrument,
89
90
  showPayLabel,
90
91
  }: IndividualButtonProps): ElementNode {
91
- const { layout, shape } = style;
92
+ const { layout, shape, borderRadius } = style;
92
93
 
93
94
  const fundingConfig = getFundingConfig()[fundingSource];
94
95
 
@@ -261,6 +262,9 @@ export function Button({
261
262
 
262
263
  const shouldShowWalletMenu =
263
264
  isWallet && instrument && showWalletMenu({ instrument, userIDToken });
265
+ const borderRadiusClass = isBorderRadiusNumber(borderRadius)
266
+ ? CLASS.BORDER_RADIUS
267
+ : `${CLASS.SHAPE}-${shape}`;
264
268
 
265
269
  return (
266
270
  <div
@@ -268,7 +272,6 @@ export function Button({
268
272
  CLASS.BUTTON_ROW,
269
273
  `${CLASS.NUMBER}-${i}`,
270
274
  `${CLASS.LAYOUT}-${layout}`,
271
- `${CLASS.SHAPE}-${shape}`,
272
275
  `${CLASS.NUMBER}-${
273
276
  multiple ? BUTTON_NUMBER.MULTIPLE : BUTTON_NUMBER.SINGLE
274
277
  }`,
@@ -279,6 +282,7 @@ export function Button({
279
282
  `${isWallet ? CLASS.WALLET : ""}`,
280
283
  `${shouldShowWalletMenu ? CLASS.WALLET_MENU : ""}`,
281
284
  `${buttonDesignContainerClass}`,
285
+ `${borderRadiusClass}`,
282
286
  ].join(" ")}
283
287
  >
284
288
  <div
@@ -300,7 +304,6 @@ export function Button({
300
304
  CLASS.BUTTON,
301
305
  `${CLASS.NUMBER}-${i}`,
302
306
  `${CLASS.LAYOUT}-${layout}`,
303
- `${CLASS.SHAPE}-${shape}`,
304
307
  `${CLASS.NUMBER}-${
305
308
  multiple ? BUTTON_NUMBER.MULTIPLE : BUTTON_NUMBER.SINGLE
306
309
  }`,
@@ -309,6 +312,7 @@ export function Button({
309
312
  `${CLASS.TEXT_COLOR}-${textColor}`,
310
313
  `${LOGO_CLASS.LOGO_COLOR}-${logoColor}`,
311
314
  `${isWallet ? CLASS.WALLET : ""}`,
315
+ `${borderRadiusClass}`,
312
316
  ].join(" ")}
313
317
  onClick={clickHandler}
314
318
  onRender={onButtonRender}
@@ -44,6 +44,7 @@ import {
44
44
  import { getFundingConfig, isFundingEligible } from "../../funding";
45
45
 
46
46
  import { BUTTON_SIZE_STYLE } from "./config";
47
+ import { isBorderRadiusNumber } from "./util";
47
48
 
48
49
  export type CreateOrderData = {||} | {||};
49
50
 
@@ -319,6 +320,7 @@ export type ButtonStyle = {|
319
320
  period?: number,
320
321
  height?: number,
321
322
  disableMaxWidth?: boolean,
323
+ borderRadius?: number,
322
324
  |};
323
325
 
324
326
  export type ButtonStyleInputs = {|
@@ -330,6 +332,7 @@ export type ButtonStyleInputs = {|
330
332
  period?: number | void,
331
333
  height?: number | void,
332
334
  disableMaxWidth?: boolean | void,
335
+ borderRadius?: number | void,
333
336
  |};
334
337
 
335
338
  type PersonalizationComponentProps = {|
@@ -621,6 +624,7 @@ export function normalizeButtonStyle(
621
624
  period,
622
625
  menuPlacement = MENU_PLACEMENT.BELOW,
623
626
  disableMaxWidth,
627
+ borderRadius,
624
628
  } = style;
625
629
 
626
630
  // $FlowFixMe
@@ -675,6 +679,20 @@ export function normalizeButtonStyle(
675
679
  }
676
680
  }
677
681
 
682
+ if (borderRadius !== undefined) {
683
+ if (!isBorderRadiusNumber(borderRadius)) {
684
+ throw new TypeError(
685
+ `Expected style.borderRadius to be a number, got: ${borderRadius}`
686
+ );
687
+ }
688
+
689
+ if (borderRadius < 0) {
690
+ throw new Error(
691
+ `Expected style.borderRadius to be greater than or equal to 0, got: ${borderRadius}`
692
+ );
693
+ }
694
+ }
695
+
678
696
  if (layout === BUTTON_LAYOUT.VERTICAL) {
679
697
  if (tagline) {
680
698
  throw new Error(
@@ -693,6 +711,7 @@ export function normalizeButtonStyle(
693
711
  period,
694
712
  menuPlacement,
695
713
  disableMaxWidth,
714
+ borderRadius,
696
715
  };
697
716
  }
698
717
 
@@ -18,8 +18,13 @@ export function Style({
18
18
  nonce,
19
19
  fundingEligibility,
20
20
  }: StyleProps): ElementNode {
21
- const { height, disableMaxWidth } = style;
22
- const css = componentStyle({ height, fundingEligibility, disableMaxWidth });
21
+ const { height, disableMaxWidth, borderRadius } = style;
22
+ const css = componentStyle({
23
+ height,
24
+ fundingEligibility,
25
+ disableMaxWidth,
26
+ borderRadius,
27
+ });
23
28
 
24
29
  return <style nonce={nonce} innerHTML={css} />;
25
30
  }
@@ -12,10 +12,12 @@ export function componentStyle({
12
12
  height,
13
13
  fundingEligibility,
14
14
  disableMaxWidth,
15
+ borderRadius,
15
16
  }: {|
16
17
  height?: ?number,
17
18
  fundingEligibility: FundingEligibilityType,
18
19
  disableMaxWidth?: ?boolean,
20
+ borderRadius?: ?number,
19
21
  |}): string {
20
22
  return `
21
23
  ${pageStyle}
@@ -26,6 +28,7 @@ export function componentStyle({
26
28
  height,
27
29
  fundingEligibility,
28
30
  disableMaxWidth,
31
+ borderRadius,
29
32
  })}
30
33
  `;
31
34
  }
@@ -14,6 +14,7 @@ import {
14
14
  ATTRIBUTE,
15
15
  } from "../../../constants";
16
16
  import { BUTTON_SIZE_STYLE, BUTTON_RELATIVE_STYLE } from "../config";
17
+ import { isBorderRadiusNumber } from "../util";
17
18
 
18
19
  const BUTTON_MIN_ASPECT_RATIO = 2.2;
19
20
  const MIN_SPLIT_BUTTON_WIDTH = 300;
@@ -25,10 +26,12 @@ export function buttonResponsiveStyle({
25
26
  height,
26
27
  fundingEligibility,
27
28
  disableMaxWidth,
29
+ borderRadius,
28
30
  }: {|
29
31
  height?: ?number,
30
32
  fundingEligibility: FundingEligibilityType,
31
33
  disableMaxWidth?: ?boolean,
34
+ borderRadius?: ?number,
32
35
  |}): string {
33
36
  return Object.keys(BUTTON_SIZE_STYLE)
34
37
  .map((size) => {
@@ -56,6 +59,8 @@ export function buttonResponsiveStyle({
56
59
 
57
60
  const labelHeight = max(roundUp(perc(buttonHeight, 35) + 5, 2), 12);
58
61
 
62
+ const pillBorderRadius = Math.ceil(buttonHeight / 2);
63
+
59
64
  return `
60
65
  @media only screen and (min-width: ${style.minWidth}px) {
61
66
 
@@ -147,15 +152,42 @@ export function buttonResponsiveStyle({
147
152
  }] .${CLASS.BUTTON_LABEL} .${CLASS.SPACE} {
148
153
  line-height: ${perc(buttonHeight, 50) + 5}px;
149
154
  }
155
+
156
+ .${CLASS.BUTTON}.${CLASS.BORDER_RADIUS} {
157
+ ${
158
+ borderRadius && isBorderRadiusNumber(borderRadius)
159
+ ? `border-radius: ${borderRadius}px`
160
+ : ""
161
+ }
162
+ }
163
+
164
+ .${CLASS.BUTTON}.${CLASS.SHAPE}-${BUTTON_SHAPE.SHARP} {
165
+ border-radius: 0px;
166
+ }
150
167
 
151
168
  .${CLASS.BUTTON}.${CLASS.SHAPE}-${BUTTON_SHAPE.RECT} {
152
169
  border-radius: 4px;
153
170
  }
154
171
 
155
172
  .${CLASS.BUTTON}.${CLASS.SHAPE}-${BUTTON_SHAPE.PILL} {
156
- border-radius: ${Math.ceil(buttonHeight / 2)}px;
173
+ border-radius: ${pillBorderRadius}px;
174
+ }
175
+
176
+ .${CLASS.BUTTON_ROW}.${CLASS.BORDER_RADIUS} .menu-button {
177
+ ${
178
+ borderRadius && isBorderRadiusNumber(borderRadius)
179
+ ? `border-top-right-radius: ${borderRadius}px; border-bottom-right-radius: ${borderRadius}px`
180
+ : ""
181
+ }
157
182
  }
158
183
 
184
+ .${CLASS.BUTTON_ROW}.${CLASS.SHAPE}-${
185
+ BUTTON_SHAPE.SHARP
186
+ } .menu-button {
187
+ border-top-right-radius: 0px;
188
+ border-bottom-right-radius: 0px;
189
+ }
190
+
159
191
  .${CLASS.BUTTON_ROW}.${CLASS.SHAPE}-${
160
192
  BUTTON_SHAPE.RECT
161
193
  } .menu-button {
@@ -166,10 +198,8 @@ export function buttonResponsiveStyle({
166
198
  .${CLASS.BUTTON_ROW}.${CLASS.SHAPE}-${
167
199
  BUTTON_SHAPE.PILL
168
200
  } .menu-button {
169
- border-top-right-radius: ${Math.ceil(buttonHeight / 2)}px;
170
- border-bottom-right-radius: ${Math.ceil(
171
- buttonHeight / 2
172
- )}px;
201
+ border-top-right-radius: ${pillBorderRadius}px;
202
+ border-bottom-right-radius: ${pillBorderRadius}px;
173
203
  }
174
204
 
175
205
  .${CLASS.TAGLINE} .${CLASS.TEXT} {
@@ -0,0 +1,5 @@
1
+ /* @flow */
2
+
3
+ export function isBorderRadiusNumber(borderRadius?: number): boolean {
4
+ return typeof borderRadius === "number";
5
+ }