@paypal/checkout-components
Advanced tools
Comparing version 5.0.306 to 5.0.307-alpha-de2b1cd.0
@@ -35,4 +35,5 @@ /* eslint import/no-commonjs: off, flowtype/require-valid-file-annotation: off, flowtype/require-return-type: off */ | ||
__PAYMENT_FIELDS__: "/altpayfields", | ||
__MESSAGE_MODAL__: "https://www.paypalobjects.com/upstream/bizcomponents/js/modal.js", | ||
}, | ||
}, | ||
}; |
{ | ||
"name": "@paypal/checkout-components", | ||
"version": "5.0.306", | ||
"version": "5.0.307-alpha-de2b1cd.0", | ||
"description": "PayPal Checkout components, for integrating checkout products.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -66,1 +66,22 @@ /* @flow */ | ||
}; | ||
export const MESSAGE_OFFER = { | ||
PAY_LATER_LONG_TERM: ("pay_later_long_term": "pay_later_long_term"), | ||
PAY_LATER_SHORT_TERM: ("pay_later_short_term": "pay_later_short_term"), | ||
}; | ||
export const MESSAGE_COLOR = { | ||
BLACK: ("black": "black"), | ||
WHITE: ("white": "white"), | ||
}; | ||
export const MESSAGE_POSITION = { | ||
TOP: ("top": "top"), | ||
BOTTOM: ("bottom": "bottom"), | ||
}; | ||
export const MESSAGE_ALIGN = { | ||
CENTER: ("center": "center"), | ||
LEFT: ("left": "left"), | ||
RIGHT: ("right": "right"), | ||
}; |
@@ -45,2 +45,7 @@ /* @flow */ | ||
IMMEDIATE: ("immediate": "immediate"), | ||
BUTTON_MESSAGE: ("paypal-button-message": "paypal-button-message"), | ||
BUTTON_MESSAGE_RESERVE: | ||
("paypal-button-message-reserved": "paypal-button-message-reserved"), | ||
}; |
@@ -21,2 +21,3 @@ /* @flow */ | ||
__PAYMENT_FIELDS__: string, | ||
__MESSAGE_MODAL__: string, | ||
|}, | ||
@@ -23,0 +24,0 @@ |}; |
@@ -75,22 +75,2 @@ /* @flow */ | ||
export type DesignExperimentLabelOptions = {| | ||
i: number, | ||
logo: ChildType, | ||
label: ?$Values<typeof BUTTON_LABEL>, | ||
locale: LocaleType, | ||
logoColor: $Values<typeof LOGO_COLOR>, | ||
multiple: boolean, | ||
period?: number, | ||
fundingEligibility: FundingEligibilityType, | ||
optional?: boolean, | ||
onClick: (event: Event, ...args: $ReadOnlyArray<mixed>) => void, | ||
onKeyPress?: (event: KeyboardEvent, ...args: $ReadOnlyArray<mixed>) => void, | ||
layout: $Values<typeof BUTTON_LAYOUT>, | ||
personalization: ?Personalization, | ||
nonce: ?string, | ||
tagline: ?boolean, | ||
content: ?ContentType, | ||
buttonDesignComponent: ?ChildType, | ||
|}; | ||
export type WalletLabelOptions = {| | ||
@@ -119,3 +99,6 @@ locale: LocaleType, | ||
shippingChange?: boolean, | ||
requires?: ({| experiment?: ?Experiment, platform?: $Values<typeof PLATFORM> |}) => Requires, | ||
requires?: ({| | ||
experiment?: ?Experiment, | ||
platform?: $Values<typeof PLATFORM>, | ||
|}) => Requires, | ||
platforms: $ReadOnlyArray<$Values<typeof PLATFORM>>, | ||
@@ -122,0 +105,0 @@ layouts: $ReadOnlyArray<$Values<typeof BUTTON_LAYOUT>>, |
@@ -32,3 +32,2 @@ /* @flow */ | ||
type LabelOptions, | ||
type DesignExperimentLabelOptions, | ||
type WalletLabelOptions, | ||
@@ -221,17 +220,2 @@ type TagOptions, | ||
export function DesignExperimentLabel( | ||
opts: DesignExperimentLabelOptions | ||
): ChildType { | ||
const { buttonDesignComponent, ...updatedOpts } = opts; | ||
const basicLabel = <BasicLabel {...updatedOpts} />; | ||
const buttonPersonalization = <ButtonPersonalization {...updatedOpts} />; | ||
return ( | ||
<Fragment> | ||
{basicLabel} | ||
{buttonDesignComponent} | ||
{buttonPersonalization} | ||
</Fragment> | ||
); | ||
} | ||
export function WalletLabelOld(opts: WalletLabelOptions): ?ChildType { | ||
@@ -238,0 +222,0 @@ const { logoColor, instrument, locale, content, commit } = opts; |
@@ -30,5 +30,3 @@ /* @flow */ | ||
import { getFundingConfig } from "../../funding"; | ||
import { DesignExperimentLabel } from "../../funding/paypal/template"; | ||
import { getButtonDesign } from "./buttonDesigns"; | ||
import type { | ||
@@ -203,32 +201,2 @@ ButtonStyle, | ||
// Only apply animation to the paypal button | ||
const buttonDesign = | ||
fundingSource === FUNDING.PAYPAL ? getButtonDesign(personalization) : {}; | ||
const { buttonDesignContainerClass = "", buttonDesignComponent = null } = | ||
buttonDesign; | ||
if (buttonDesignComponent) { | ||
labelNode = ( | ||
<DesignExperimentLabel | ||
i={i} | ||
logo={logoNode} | ||
label={label} | ||
nonce={nonce} | ||
locale={locale} | ||
logoColor={logoColor} | ||
period={period} | ||
layout={layout} | ||
multiple={multiple} | ||
fundingEligibility={fundingEligibility} | ||
onClick={clickHandler} | ||
onKeyPress={keypressHandler} | ||
personalization={personalization} | ||
tagline={tagline} | ||
content={content} | ||
buttonDesignComponent={buttonDesignComponent} | ||
/> | ||
); | ||
} | ||
let isWallet = false; | ||
@@ -286,3 +254,2 @@ | ||
`${shouldShowWalletMenu ? CLASS.WALLET_MENU : ""}`, | ||
`${buttonDesignContainerClass}`, | ||
`${borderRadiusClass}`, | ||
@@ -289,0 +256,0 @@ ].join(" ")} |
@@ -18,2 +18,3 @@ /* @flow */ | ||
BUTTON_FLOW, | ||
MESSAGE_POSITION, | ||
} from "../../constants"; | ||
@@ -26,4 +27,2 @@ import { | ||
import { getButtonDesign } from "./buttonDesigns"; | ||
import { ButtonDesignExperimentScriptWrapper } from "./buttonDesigns/script"; | ||
import { | ||
@@ -41,2 +40,4 @@ normalizeButtonProps, | ||
import { PoweredByPayPal } from "./poweredBy"; | ||
import { Message } from "./message"; | ||
import { calculateShowPoweredBy } from "./util"; | ||
@@ -185,2 +186,4 @@ type GetWalletInstrumentOptions = {| | ||
displayOnly, | ||
message, | ||
messageMarkup, | ||
} = normalizeButtonProps(props); | ||
@@ -242,3 +245,2 @@ const { layout, shape, tagline } = style; | ||
const { buttonDesignScript = "" } = getButtonDesign(personalization); | ||
const index = (i) => { | ||
@@ -248,2 +250,10 @@ return i; | ||
const showTagline = | ||
tagline && | ||
layout === BUTTON_LAYOUT.HORIZONTAL && | ||
!fundingSource && | ||
!message; | ||
const showPoweredBy = calculateShowPoweredBy(layout, fundingSources); | ||
return ( | ||
@@ -268,2 +278,6 @@ <div | ||
{message && message.position === MESSAGE_POSITION.TOP ? ( | ||
<Message markup={messageMarkup} position={message.position} /> | ||
) : null} | ||
{fundingSources.map((source, i) => ( | ||
@@ -298,3 +312,3 @@ <Button | ||
{tagline && layout === BUTTON_LAYOUT.HORIZONTAL && !fundingSource ? ( | ||
{showTagline ? ( | ||
<TagLine | ||
@@ -321,15 +335,9 @@ fundingSource={fundingSources[0]} | ||
{layout === BUTTON_LAYOUT.VERTICAL && | ||
fundingSources.indexOf(FUNDING.CARD) !== -1 ? ( | ||
<PoweredByPayPal locale={locale} nonce={nonce} /> | ||
{showPoweredBy ? <PoweredByPayPal locale={locale} nonce={nonce} /> : null} | ||
{message && message.position === MESSAGE_POSITION.BOTTOM ? ( | ||
<Message markup={messageMarkup} position={message.position} /> | ||
) : null} | ||
{buttonDesignScript ? ( | ||
<ButtonDesignExperimentScriptWrapper | ||
nonce={nonce} | ||
buttonDesignScript={buttonDesignScript} | ||
/> | ||
) : ( | ||
<Script nonce={nonce} /> | ||
)} | ||
<Script nonce={nonce} /> | ||
</div> | ||
@@ -336,0 +344,0 @@ ); |
@@ -43,2 +43,6 @@ /* eslint-disable eslint-comments/disable-enable-pair */ | ||
MENU_PLACEMENT, | ||
MESSAGE_OFFER, | ||
MESSAGE_COLOR, | ||
MESSAGE_POSITION, | ||
MESSAGE_ALIGN, | ||
} from "../../constants"; | ||
@@ -48,3 +52,3 @@ import { getFundingConfig, isFundingEligible } from "../../funding"; | ||
import { BUTTON_SIZE_STYLE } from "./config"; | ||
import { isBorderRadiusNumber } from "./util"; | ||
import { isBorderRadiusNumber, calculateMessagePosition } from "./util"; | ||
@@ -362,10 +366,2 @@ export type CreateOrderData = {||} | {||}; | ||
|}, | ||
buttonDesign?: {| | ||
id: string, | ||
text: string, | ||
tracking: {| | ||
impression: string, | ||
click: string, | ||
|}, | ||
|}, | ||
|}; | ||
@@ -438,2 +434,18 @@ | ||
export type ButtonMessage = {| | ||
amount?: number, | ||
offer?: $ReadOnlyArray<$Values<typeof MESSAGE_OFFER>>, | ||
color: $Values<typeof MESSAGE_COLOR>, | ||
position: $Values<typeof MESSAGE_POSITION>, | ||
align: $Values<typeof MESSAGE_ALIGN>, | ||
|}; | ||
export type ButtonMessageInputs = {| | ||
amount?: number | void, | ||
offer?: $ReadOnlyArray<$Values<typeof MESSAGE_OFFER>> | void, | ||
color?: $Values<typeof MESSAGE_COLOR> | void, | ||
position?: $Values<typeof MESSAGE_POSITION> | void, | ||
align?: $Values<typeof MESSAGE_ALIGN> | void, | ||
|}; | ||
export type RenderButtonProps = {| | ||
@@ -473,2 +485,4 @@ style: ButtonStyle, | ||
displayOnly?: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>, | ||
message?: ButtonMessage, | ||
messageMarkup?: string, | ||
|}; | ||
@@ -533,2 +547,4 @@ | ||
hostedButtonId?: string, | ||
message?: ButtonMessage, | ||
messageMarkup?: string, | ||
|}; | ||
@@ -576,2 +592,5 @@ | ||
displayOnly: $ReadOnlyArray<$Values<typeof DISPLAY_ONLY_VALUES>>, | ||
message?: ButtonMessageInputs | void, | ||
messageMarkup?: string | void, | ||
renderedButtons: $ReadOnlyArray<$Values<typeof FUNDING>>, | ||
}; | ||
@@ -725,2 +744,68 @@ | ||
export function normalizeButtonMessage( | ||
message: ButtonMessageInputs, | ||
layout: $Values<typeof BUTTON_LAYOUT>, | ||
fundingSources: $ReadOnlyArray<$Values<typeof FUNDING>> | ||
): ButtonMessage { | ||
const { | ||
amount, | ||
offer, | ||
color = MESSAGE_COLOR.BLACK, | ||
position, | ||
align = MESSAGE_ALIGN.CENTER, | ||
} = message; | ||
if (typeof amount !== "undefined") { | ||
if (typeof amount !== "number") { | ||
throw new TypeError( | ||
`Expected message.amount to be a number, got: ${amount}` | ||
); | ||
} | ||
if (amount < 0) { | ||
throw new Error( | ||
`Expected message.amount to be a positive number, got: ${amount}` | ||
); | ||
} | ||
} | ||
if (typeof offer !== "undefined") { | ||
if (!Array.isArray(offer)) { | ||
throw new TypeError( | ||
`Expected message.offer to be an array of strings, got: ${String( | ||
offer | ||
)}` | ||
); | ||
} | ||
const invalidOffers = offer.filter( | ||
(o) => !values(MESSAGE_OFFER).includes(o) | ||
); | ||
if (invalidOffers.length > 0) { | ||
throw new Error(`Invalid offer(s): ${invalidOffers.join(",")}`); | ||
} | ||
} | ||
if (typeof color !== "undefined" && !values(MESSAGE_COLOR).includes(color)) { | ||
throw new Error(`Invalid color: ${color}`); | ||
} | ||
if ( | ||
typeof position !== "undefined" && | ||
!values(MESSAGE_POSITION).includes(position) | ||
) { | ||
throw new Error(`Invalid position: ${position}`); | ||
} | ||
if (typeof align !== "undefined" && !values(MESSAGE_ALIGN).includes(align)) { | ||
throw new Error(`Invalid align: ${align}`); | ||
} | ||
return { | ||
amount, | ||
offer, | ||
color, | ||
position: calculateMessagePosition(fundingSources, layout, position), | ||
align, | ||
}; | ||
} | ||
const COUNTRIES = values(COUNTRY); | ||
@@ -780,2 +865,5 @@ const FUNDING_SOURCES = values(FUNDING); | ||
displayOnly = [], | ||
message, | ||
messageMarkup, | ||
renderedButtons, | ||
} = props; | ||
@@ -839,3 +927,8 @@ | ||
style = normalizeButtonStyle(props, style); | ||
const { layout } = style; | ||
message = message | ||
? normalizeButtonMessage(message, layout, renderedButtons) | ||
: undefined; | ||
return { | ||
@@ -873,3 +966,5 @@ clientID, | ||
displayOnly, | ||
message, | ||
messageMarkup, | ||
}; | ||
} |
/* @flow */ | ||
import { FUNDING } from "@paypal/sdk-constants/src"; | ||
import { BUTTON_LAYOUT, MESSAGE_POSITION } from "../../constants"; | ||
import { ValidationError } from "../../lib"; | ||
export function isBorderRadiusNumber(borderRadius?: number): boolean { | ||
return typeof borderRadius === "number"; | ||
} | ||
export function calculateShowPoweredBy( | ||
layout: $Values<typeof BUTTON_LAYOUT>, | ||
fundingSources: $ReadOnlyArray<$Values<typeof FUNDING>> | ||
): boolean { | ||
return ( | ||
layout === BUTTON_LAYOUT.VERTICAL && fundingSources.includes(FUNDING.CARD) | ||
); | ||
} | ||
export function calculateMessagePosition( | ||
fundingSources: $ReadOnlyArray<$Values<typeof FUNDING>>, | ||
layout: $Values<typeof BUTTON_LAYOUT>, | ||
position?: $Values<typeof MESSAGE_POSITION> | ||
): $Values<typeof MESSAGE_POSITION> { | ||
const showPoweredBy = calculateShowPoweredBy(layout, fundingSources); | ||
if (showPoweredBy && position === MESSAGE_POSITION.BOTTOM) { | ||
throw new ValidationError( | ||
"Message position must be 'top' when Debit and/or Credit Card button is present" | ||
); | ||
} | ||
if ( | ||
showPoweredBy || | ||
position === MESSAGE_POSITION.TOP || | ||
(layout === BUTTON_LAYOUT.VERTICAL && !position) | ||
) { | ||
return MESSAGE_POSITION.TOP; | ||
} | ||
return MESSAGE_POSITION.BOTTOM; | ||
} |
@@ -76,3 +76,7 @@ /* @flow */ | ||
} from "../../lib"; | ||
import { normalizeButtonStyle, type ButtonProps } from "../../ui/buttons/props"; | ||
import { | ||
normalizeButtonStyle, | ||
normalizeButtonMessage, | ||
type ButtonProps, | ||
} from "../../ui/buttons/props"; | ||
import { isFundingEligible } from "../../funding"; | ||
@@ -90,2 +94,3 @@ | ||
getButtonExperiments, | ||
getModal, | ||
} from "./util"; | ||
@@ -640,2 +645,20 @@ | ||
message: { | ||
type: "object", | ||
queryParam: true, | ||
required: false, | ||
decorate: ({ props, value }) => { | ||
const { | ||
style: { layout }, | ||
renderedButtons: fundingSources, | ||
} = props; | ||
return normalizeButtonMessage( | ||
// $FlowFixMe | ||
value, | ||
layout, | ||
fundingSources | ||
); | ||
}, | ||
}, | ||
nonce: { | ||
@@ -690,2 +713,97 @@ type: "string", | ||
onMessageClick: { | ||
type: "function", | ||
required: false, | ||
value: ({ props }) => { | ||
return async ({ | ||
offerType, | ||
messageType, | ||
offerCountryCode, | ||
creditProductIdentifier, | ||
}) => { | ||
const { message, clientID, merchantID, currency, buttonSessionID } = | ||
props; | ||
const amount = message?.amount; | ||
getLogger() | ||
.info("button_message_click") | ||
.track({ | ||
[FPTI_KEY.TRANSITION]: "button_message_click", | ||
[FPTI_KEY.STATE]: "BUTTON_MESSAGE", | ||
[FPTI_KEY.CONTEXT_ID]: buttonSessionID, | ||
[FPTI_KEY.CONTEXT_TYPE]: "button_session_id", | ||
[FPTI_KEY.EVENT_NAME]: "message_click", | ||
// adding temp string here for our sdk constants | ||
button_message_offer_type: offerType, | ||
button_message_credit_product_identifier: | ||
creditProductIdentifier, | ||
button_message_type: messageType, | ||
button_message_position: message?.position, | ||
button_message_align: message?.align, | ||
button_message_color: message?.color, | ||
button_message_offer_country: offerCountryCode, | ||
button_message_amount: amount, | ||
[FPTI_KEY.BUTTON_SESSION_UID]: buttonSessionID, | ||
}); | ||
const modalInstance = await getModal(clientID, merchantID); | ||
return modalInstance?.show({ | ||
amount, | ||
offer: offerType, | ||
currency, | ||
}); | ||
}; | ||
}, | ||
}, | ||
onMessageHover: { | ||
type: "function", | ||
required: false, | ||
value: ({ props }) => { | ||
return () => { | ||
// offerType, messageType, offerCountryCode, and creditProductIdentifier are passed in and may be used in an upcoming message hover logging feature | ||
// lazy loads the modal, to be memoized and executed onMessageClick | ||
const { clientID, merchantID } = props; | ||
return getModal(clientID, merchantID); | ||
}; | ||
}, | ||
}, | ||
onMessageReady: { | ||
type: "function", | ||
required: false, | ||
value: ({ props }) => { | ||
return ({ | ||
offerType, | ||
messageType, | ||
offerCountryCode, | ||
creditProductIdentifier, | ||
}) => { | ||
const { message, buttonSessionID } = props; | ||
getLogger() | ||
.info("button_message_render") | ||
.track({ | ||
[FPTI_KEY.TRANSITION]: "button_message_render", | ||
[FPTI_KEY.STATE]: "BUTTON_MESSAGE", | ||
[FPTI_KEY.CONTEXT_ID]: buttonSessionID, | ||
[FPTI_KEY.CONTEXT_TYPE]: "button_session_id", | ||
[FPTI_KEY.EVENT_NAME]: "message_render", | ||
// adding temp string here for our sdk constants | ||
button_message_offer_type: offerType, | ||
button_message_credit_product_identifier: | ||
creditProductIdentifier, | ||
button_message_type: messageType, | ||
button_message_posiiton: message?.position, | ||
button_message_align: message?.align, | ||
button_message_color: message?.color, | ||
button_message_offer_country: offerCountryCode, | ||
button_message_amount: message?.amount, | ||
[FPTI_KEY.BUTTON_SESSION_UID]: buttonSessionID, | ||
}); | ||
}; | ||
}, | ||
}, | ||
onShippingAddressChange: { | ||
@@ -692,0 +810,0 @@ type: "function", |
@@ -16,2 +16,3 @@ /* @flow */ | ||
once, | ||
memoize, | ||
} from "@krakenjs/belter/src"; | ||
@@ -26,2 +27,4 @@ import { FUNDING } from "@paypal/sdk-constants/src"; | ||
getComponents, | ||
getEnv, | ||
getNamespace, | ||
} from "@paypal/sdk-client/src"; | ||
@@ -362,1 +365,51 @@ import { getRefinedFundingEligibility } from "@paypal/funding-components/src"; | ||
} | ||
function buildModalBundleUrl(): string { | ||
let url = __PAYPAL_CHECKOUT__.__URI__.__MESSAGE_MODAL__; | ||
if (getEnv() === "sandbox") { | ||
url = url.replace("/js/", "/sandbox/"); | ||
} else if (getEnv() === "stage" || getEnv() === "local") { | ||
url = url.replace("/js/", "/stage/"); | ||
} | ||
return url; | ||
} | ||
export const getModal: ( | ||
clientID: string, | ||
merchantID: $ReadOnlyArray<string> | void | ||
) => Object = memoize(async (clientID, merchantID) => { | ||
try { | ||
const namespace = getNamespace(); | ||
if (!window[namespace].MessagesModal) { | ||
// eslint-disable-next-line no-restricted-globals, promise/no-native | ||
await new Promise((resolve, reject) => { | ||
const script = document.createElement("script"); | ||
script.setAttribute("data-pp-namespace", namespace); | ||
script.src = buildModalBundleUrl(); | ||
script.addEventListener("error", (err: Event) => { | ||
reject(err); | ||
}); | ||
script.addEventListener("load", () => { | ||
document.body?.removeChild(script); | ||
resolve(); | ||
}); | ||
document.body?.appendChild(script); | ||
}); | ||
} | ||
return window[namespace].MessagesModal({ | ||
account: `client-id:${clientID}`, | ||
merchantId: merchantID?.join(",") || undefined, | ||
}); | ||
} catch (err) { | ||
// $FlowFixMe flow doesn't seem to understand that the reset function property exists on the function object itself | ||
getModal.reset(); | ||
getLogger() | ||
.error("button_message_modal_fetch_error", { err }) | ||
.track({ | ||
err: err.message || "BUTTON_MESSAGE_MODAL_FETCH_ERROR", | ||
details: err.details, | ||
stack: JSON.stringify(err.stack || err), | ||
}); | ||
} | ||
}); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1156768
195
15099
1