@paypal/checkout-components 5.0.217 → 5.0.220
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/CHANGELOG.md +19 -0
- package/dist/button.js +1 -1
- package/package.json +7 -7
- package/src/funding/card/config.jsx +4 -3
- package/src/lib/index.js +1 -0
- package/src/lib/perceived-latency-instrumentation.js +61 -0
- package/src/types.js +2 -2
- package/src/ui/buttons/button.jsx +2 -2
- package/src/ui/buttons/buttons.jsx +1 -1
- package/src/ui/buttons/props.js +24 -2
- package/src/ui/buttons/style.jsx +1 -1
- package/src/ui/buttons/styles/base.js +1 -1
- package/src/ui/buttons/styles/custom.js +1 -1
- package/src/zoid/buttons/component.jsx +33 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paypal/checkout-components",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.220",
|
|
4
4
|
"description": "PayPal Checkout components, for integrating checkout products.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"engines": {
|
|
@@ -86,17 +86,17 @@
|
|
|
86
86
|
"serve": "^13.0.0"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@paypal/common-components": "^1.0.27",
|
|
90
|
-
"@paypal/funding-components": "^1.0.27",
|
|
91
|
-
"@paypal/sdk-client": "^4.0.166",
|
|
92
|
-
"@paypal/sdk-constants": "^1.0.107",
|
|
93
|
-
"@paypal/sdk-logos": "^1.0.45",
|
|
94
89
|
"@krakenjs/belter": "^2.0.0",
|
|
95
90
|
"@krakenjs/cross-domain-utils": "^3.0.0",
|
|
96
91
|
"@krakenjs/jsx-pragmatic": "^3",
|
|
97
92
|
"@krakenjs/post-robot": "^11.0.0",
|
|
98
93
|
"@krakenjs/zalgo-promise": "^2.0.0",
|
|
99
|
-
"@krakenjs/zoid": "^10.0.0"
|
|
94
|
+
"@krakenjs/zoid": "^10.0.0",
|
|
95
|
+
"@paypal/common-components": "^1.0.27",
|
|
96
|
+
"@paypal/funding-components": "^1.0.27",
|
|
97
|
+
"@paypal/sdk-client": "^4.0.166",
|
|
98
|
+
"@paypal/sdk-constants": "^1.0.119",
|
|
99
|
+
"@paypal/sdk-logos": "^1.0.45"
|
|
100
100
|
},
|
|
101
101
|
"lint-staged": {
|
|
102
102
|
"*.sh": "prettier --write"
|
|
@@ -122,15 +122,16 @@ export function getCardConfig() : FundingSourceConfig {
|
|
|
122
122
|
},
|
|
123
123
|
|
|
124
124
|
Label: ({ logo, locale, content, custom }) => {
|
|
125
|
-
if (custom) {
|
|
125
|
+
if (custom && custom.label && custom.label.length) {
|
|
126
126
|
const validLabels = {
|
|
127
127
|
checkout: 'Checkout'
|
|
128
128
|
};
|
|
129
129
|
|
|
130
130
|
let label = validLabels.checkout;
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
const lowerCaseLabel = custom.label.toLowerCase();
|
|
133
|
+
if (validLabels[lowerCaseLabel]) {
|
|
134
|
+
label = validLabels[lowerCaseLabel];
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
return (
|
package/src/lib/index.js
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
type LogLatencyInstrumentationPhaseParams = {|
|
|
4
|
+
buttonSessionID : string,
|
|
5
|
+
phase : string
|
|
6
|
+
|};
|
|
7
|
+
|
|
8
|
+
type InstrumentationPayload = {|
|
|
9
|
+
comp? : Object,
|
|
10
|
+
chunk? : Object,
|
|
11
|
+
query? : Object
|
|
12
|
+
|};
|
|
13
|
+
|
|
14
|
+
function getNavigationTimeOrigin() : number {
|
|
15
|
+
if (window.performance) {
|
|
16
|
+
const hrSyncPoint = performance.now();
|
|
17
|
+
const unixSyncPoint = new Date().getTime();
|
|
18
|
+
return window.performance.timeOrigin || window.performance.timing.navigationStart || (unixSyncPoint - hrSyncPoint);
|
|
19
|
+
} else {
|
|
20
|
+
throw new Error('window.performance not supported');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getStartTimeFromMark({ buttonSessionID, phase } : LogLatencyInstrumentationPhaseParams) : number {
|
|
25
|
+
if (window.performance) {
|
|
26
|
+
return performance.getEntriesByName(`${ buttonSessionID }_${ phase }`).pop().startTime;
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error('window.performance not supported');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* To Track time spent in each phase(cdn download, chunks download, etc)
|
|
33
|
+
logLatencyInstrumentationPhase({
|
|
34
|
+
buttonID: buttonId,
|
|
35
|
+
phase: 'html_body'
|
|
36
|
+
})
|
|
37
|
+
logLatencyInstrumentationPhase({
|
|
38
|
+
buttonID: buttonId,
|
|
39
|
+
phase: 'html_body'
|
|
40
|
+
})
|
|
41
|
+
*/
|
|
42
|
+
export const logLatencyInstrumentationPhase = ({ buttonSessionID, phase } : LogLatencyInstrumentationPhaseParams) => {
|
|
43
|
+
if (window.performance && window.performance.mark) {
|
|
44
|
+
window.performance.mark(`${ buttonSessionID }_${ phase }`);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const prepareInstrumentationPayload = (buttonSessionID : string) : InstrumentationPayload => {
|
|
49
|
+
const timeOrigin = getNavigationTimeOrigin();
|
|
50
|
+
const renderStartTime = getStartTimeFromMark({ buttonSessionID, phase: 'buttons-first-render' });
|
|
51
|
+
const renderEndTime = getStartTimeFromMark({ buttonSessionID, phase: 'buttons-first-render-end' });
|
|
52
|
+
return {
|
|
53
|
+
comp: {
|
|
54
|
+
'first-render': {
|
|
55
|
+
start: timeOrigin + renderStartTime,
|
|
56
|
+
tt: renderEndTime - renderStartTime
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
package/src/types.js
CHANGED
|
@@ -46,7 +46,7 @@ export function Button({ fundingSource, style, multiple, locale, env, fundingEli
|
|
|
46
46
|
userIDToken, personalization, onClick = noop, content, tagline, commit, experiment, instrument, experience } : IndividualButtonProps) : ElementNode {
|
|
47
47
|
|
|
48
48
|
const { custom, layout, shape } = style;
|
|
49
|
-
const inlineExperience = experience === EXPERIENCE.INLINE && custom;
|
|
49
|
+
const inlineExperience = experience === EXPERIENCE.INLINE && custom && custom.label;
|
|
50
50
|
const fundingConfig = getFundingConfig()[fundingSource];
|
|
51
51
|
|
|
52
52
|
if (!fundingConfig) {
|
|
@@ -130,7 +130,7 @@ export function Button({ fundingSource, style, multiple, locale, env, fundingEli
|
|
|
130
130
|
personalization={ personalization }
|
|
131
131
|
tagline={ tagline }
|
|
132
132
|
content={ content }
|
|
133
|
-
custom={ inlineExperience ? custom :
|
|
133
|
+
custom={ inlineExperience ? custom : undefined }
|
|
134
134
|
experiment={ experiment }
|
|
135
135
|
/>
|
|
136
136
|
);
|
|
@@ -102,7 +102,7 @@ export function Buttons(props : ButtonsProps) : ElementNode {
|
|
|
102
102
|
nonce, components, onShippingChange, personalization, userIDToken, content, flow, experiment, applePaySupport,
|
|
103
103
|
supportsPopups, supportedNativeBrowser, experience } = normalizeButtonProps(props);
|
|
104
104
|
const { custom, layout, shape, tagline } = style;
|
|
105
|
-
const inlineExperience = experience === EXPERIENCE.INLINE && custom;
|
|
105
|
+
const inlineExperience = experience === EXPERIENCE.INLINE && custom && custom.label;
|
|
106
106
|
|
|
107
107
|
let fundingSources = determineEligibleFunding({ fundingSource, layout, remembered, platform, fundingEligibility, components, onShippingChange, flow, wallet, applePaySupport, supportsPopups, supportedNativeBrowser, experiment });
|
|
108
108
|
const multiple = fundingSources.length > 1;
|
package/src/ui/buttons/props.js
CHANGED
|
@@ -138,7 +138,7 @@ export type ButtonStyle = {|
|
|
|
138
138
|
menuPlacement : $Values<typeof MENU_PLACEMENT>,
|
|
139
139
|
period? : number,
|
|
140
140
|
height? : number,
|
|
141
|
-
custom? : CustomStyle
|
|
141
|
+
custom? : ?CustomStyle
|
|
142
142
|
|};
|
|
143
143
|
|
|
144
144
|
export type ButtonStyleInputs = {|
|
|
@@ -149,7 +149,7 @@ export type ButtonStyleInputs = {|
|
|
|
149
149
|
layout? : $Values<typeof BUTTON_LAYOUT> | void,
|
|
150
150
|
period? : number | void,
|
|
151
151
|
height? : number | void,
|
|
152
|
-
custom? : CustomStyle
|
|
152
|
+
custom? : ?CustomStyle
|
|
153
153
|
|};
|
|
154
154
|
|
|
155
155
|
type PersonalizationComponentProps = {|
|
|
@@ -454,6 +454,28 @@ export function normalizeButtonStyle(props : ?ButtonPropsInputs, style : ButtonS
|
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
+
if (custom) {
|
|
458
|
+
if (custom.label && typeof custom.label !== 'string') {
|
|
459
|
+
throw new Error(`style.custom.label is expected to be a String.`);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (custom.css && typeof custom.css !== 'object') {
|
|
463
|
+
throw new Error(`style.custom.css is expected to be JSON.`);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (custom.css && custom.label && custom.label.length === 0) {
|
|
467
|
+
throw new Error(`Expected style.custom.label to be used with style.custom.css`);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (custom.label && custom.label.length > 0 && !custom.css) {
|
|
471
|
+
custom.css = {
|
|
472
|
+
'background-color': 'black',
|
|
473
|
+
'height': '48px',
|
|
474
|
+
'margin-bottom': '15px'
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
457
479
|
return { custom, label, layout, color, shape, tagline, height, period, menuPlacement };
|
|
458
480
|
}
|
|
459
481
|
|
package/src/ui/buttons/style.jsx
CHANGED
|
@@ -15,7 +15,7 @@ type StyleProps = {|
|
|
|
15
15
|
|
|
16
16
|
export function Style({ style, nonce, fundingEligibility } : StyleProps) : ElementNode {
|
|
17
17
|
|
|
18
|
-
const { custom, height } = style;
|
|
18
|
+
const { custom = { label: undefined, css: undefined }, height } = style;
|
|
19
19
|
const css = componentStyle({ custom, height, fundingEligibility });
|
|
20
20
|
|
|
21
21
|
return (
|
|
@@ -11,7 +11,7 @@ import { buttonResponsiveStyle } from './responsive';
|
|
|
11
11
|
import { buttonColorStyle } from './color';
|
|
12
12
|
import { customStyle } from './custom';
|
|
13
13
|
|
|
14
|
-
export function componentStyle({ custom, height, fundingEligibility } : {| custom? : CustomStyle, height? : ?number, fundingEligibility : FundingEligibilityType |}) : string {
|
|
14
|
+
export function componentStyle({ custom, height, fundingEligibility } : {| custom? : ?CustomStyle, height? : ?number, fundingEligibility : FundingEligibilityType |}) : string {
|
|
15
15
|
return `
|
|
16
16
|
${ pageStyle }
|
|
17
17
|
${ buttonStyle }
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { CustomStyle } from '../../../types';
|
|
4
4
|
import { CLASS } from '../../../constants';
|
|
5
5
|
|
|
6
|
-
export const customStyle = ({ custom } : {| custom? : CustomStyle |}) : string => {
|
|
6
|
+
export const customStyle = ({ custom } : {| custom? : ?CustomStyle |}) : string => {
|
|
7
7
|
const { css } = custom || {};
|
|
8
8
|
|
|
9
9
|
if (!css) {
|
|
@@ -8,12 +8,18 @@ import { getLogger, getLocale, getClientID, getEnv, getIntent, getCommit, getVau
|
|
|
8
8
|
getUserIDToken, getClientMetadataID, getAmount, getEnableFunding, getStorageID, getUserExperienceFlow, getMerchantRequestedPopupsDisabled, getVersion } from '@paypal/sdk-client/src';
|
|
9
9
|
import { rememberFunding, getRememberedFunding, getRefinedFundingEligibility } from '@paypal/funding-components/src';
|
|
10
10
|
import { ZalgoPromise } from '@krakenjs/zalgo-promise/src';
|
|
11
|
-
import { create, type ZoidComponent } from '@krakenjs/zoid/src';
|
|
11
|
+
import { create, EVENT, type ZoidComponent } from '@krakenjs/zoid/src';
|
|
12
12
|
import { uniqueID, memoize, isApplePaySupported, supportsPopups as userAgentSupportsPopups, noop, isLocalStorageEnabled } from '@krakenjs/belter/src';
|
|
13
13
|
import { FUNDING, FUNDING_BRAND_LABEL, QUERY_BOOL, ENV, FPTI_KEY } from '@paypal/sdk-constants/src';
|
|
14
14
|
import { node, dom } from '@krakenjs/jsx-pragmatic/src';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
getSessionID,
|
|
18
|
+
storageState,
|
|
19
|
+
sessionState,
|
|
20
|
+
logLatencyInstrumentationPhase,
|
|
21
|
+
prepareInstrumentationPayload
|
|
22
|
+
} from '../../lib';
|
|
17
23
|
import { normalizeButtonStyle, type ButtonProps } from '../../ui/buttons/props';
|
|
18
24
|
import { isFundingEligible } from '../../funding';
|
|
19
25
|
import { EXPERIENCE } from '../../constants';
|
|
@@ -44,7 +50,7 @@ export const getButtonsComponent : () => ButtonsComponent = memoize(() => {
|
|
|
44
50
|
|
|
45
51
|
logger: getLogger(),
|
|
46
52
|
|
|
47
|
-
prerenderTemplate: ({ state, props, doc }) => {
|
|
53
|
+
prerenderTemplate: ({ state, props, doc, event }) => {
|
|
48
54
|
const { buttonSessionID } = props;
|
|
49
55
|
|
|
50
56
|
if (!isLocalStorageEnabled()) {
|
|
@@ -56,6 +62,28 @@ export const getButtonsComponent : () => ButtonsComponent = memoize(() => {
|
|
|
56
62
|
});
|
|
57
63
|
}
|
|
58
64
|
|
|
65
|
+
event.on(EVENT.PRERENDERED, () => {
|
|
66
|
+
// CPL stands for Consumer Perceived Latency
|
|
67
|
+
logLatencyInstrumentationPhase({ buttonSessionID, phase: 'buttons-first-render-end' });
|
|
68
|
+
try {
|
|
69
|
+
const cplPhases = prepareInstrumentationPayload(buttonSessionID);
|
|
70
|
+
const cplLatencyMetrics = {
|
|
71
|
+
[FPTI_KEY.STATE]: 'CPL_LATENCY_METRICS',
|
|
72
|
+
[FPTI_KEY.TRANSITION]: 'process_client_metrics',
|
|
73
|
+
[FPTI_KEY.CONTEXT_ID]: buttonSessionID,
|
|
74
|
+
[FPTI_KEY.PAGE]: 'main:xo:paypal-components:smart-payment-buttons',
|
|
75
|
+
[FPTI_KEY.CPL_COMP_METRICS]: JSON.stringify(cplPhases?.comp || {})
|
|
76
|
+
};
|
|
77
|
+
getLogger().info('CPL_LATENCY_METRICS_FIRST_RENDER').track(cplLatencyMetrics);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
getLogger().info('button_render_CPL_instrumentation_log_error').track({
|
|
80
|
+
err: err.message || 'CPL_LOG_PHASE_ERROR',
|
|
81
|
+
details: err.details,
|
|
82
|
+
stack: JSON.stringify(err.stack || err)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
59
87
|
return (
|
|
60
88
|
<PrerenderedButtons
|
|
61
89
|
nonce={ props.nonce }
|
|
@@ -275,6 +303,8 @@ export const getButtonsComponent : () => ButtonsComponent = memoize(() => {
|
|
|
275
303
|
required: false,
|
|
276
304
|
default: () => noop,
|
|
277
305
|
decorate: ({ props, value = noop }) => {
|
|
306
|
+
logLatencyInstrumentationPhase({ buttonSessionID: props.buttonSessionID, phase: 'buttons-first-render' });
|
|
307
|
+
|
|
278
308
|
return (...args) => {
|
|
279
309
|
const { fundingSource } = props;
|
|
280
310
|
const venmoExperiment = createVenmoExperiment();
|