diff --git a/package-lock.json b/package-lock.json index 73fb8cf..d773301 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "@xsolla/pay-station-sdk", - "version": "0.0.17", + "version": "0.0.22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@xsolla/pay-station-sdk", - "version": "0.0.17", + "version": "0.0.22", "license": "ISC", "dependencies": { "currency-format": "^1.0.13", "i18next": "^23.4.6", + "lit": "^3.1.3", "tsyringe": "^4.8.0" }, "devDependencies": { @@ -1079,6 +1080,19 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz", + "integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==" + }, + "node_modules/@lit/reactive-element": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz", + "integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1257,6 +1271,11 @@ "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", "dev": true }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" + }, "node_modules/@types/yargs": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", @@ -6126,6 +6145,34 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/lit": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.3.tgz", + "integrity": "sha512-l4slfspEsnCcHVRTvaP7YnkTZEZggNFywLEIhQaGhYDczG+tu/vlgm/KaWIEjIp+ZyV20r2JnZctMb8LeLCG7Q==", + "dependencies": { + "@lit/reactive-element": "^2.0.4", + "lit-element": "^4.0.4", + "lit-html": "^3.1.2" + } + }, + "node_modules/lit-element": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.5.tgz", + "integrity": "sha512-iTWskWZEtn9SyEf4aBG6rKT8GABZMrTWop1+jopsEOgEcugcXJGKuX5bEbkq9qfzY+XB4MAgCaSPwnNpdsNQ3Q==", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.2.0", + "@lit/reactive-element": "^2.0.4", + "lit-html": "^3.1.2" + } + }, + "node_modules/lit-html": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.3.tgz", + "integrity": "sha512-FwIbqDD8O/8lM4vUZ4KvQZjPPNx7V1VhT7vmRB8RBAO0AU6wuTVdoXiu2CivVjEGdugvcbPNBLtPE1y0ifplHA==", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", diff --git a/package.json b/package.json index f169cad..75f4a0f 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "dependencies": { "currency-format": "^1.0.13", "i18next": "^23.4.6", + "lit": "^3.1.3", "tsyringe": "^4.8.0" } } diff --git a/src/core/form/form-loader.ts b/src/core/form/form-loader.ts index 71ee312..47af2bb 100644 --- a/src/core/form/form-loader.ts +++ b/src/core/form/form-loader.ts @@ -37,6 +37,10 @@ export class FormLoader { } public setFieldLoaded(name: string): void { + if (!this._fields) { + return; + } + if (name in this._fields) { this._fields[name] = true; } diff --git a/src/core/web-components/lit-web-component.abstract.ts b/src/core/web-components/lit-web-component.abstract.ts new file mode 100644 index 0000000..b8bffe5 --- /dev/null +++ b/src/core/web-components/lit-web-component.abstract.ts @@ -0,0 +1,77 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { FormLoader } from '../form/form-loader'; +import { container } from 'tsyringe'; +import { createFinishLoadingEvent } from '../../shared/loading-state/dispatch-finish-loading-event.function'; +import { isLoadingCssClassName } from '../../shared/loading-state/is-loading-css-class-name.const'; +import { html, LitElement, TemplateResult } from 'lit'; + +export abstract class LitWebComponentAbstract extends LitElement { + protected formLoader: FormLoader = container.resolve(FormLoader); + + protected eventListeners: Array<{ + element: Element; + eventType: string; + listener(event: Event): void; + }> = []; + + public disconnectedCallback(): void { + super.disconnectedCallback(); + this.removeAllEventListeners(); + } + + public createRenderRoot(): LitElement { + return this; + } + + protected abstract render(): void; + + protected renderByCondition( + condition: boolean, + template: TemplateResult<1>, + defaultValue: TemplateResult<1> = html``, + ): TemplateResult<1> { + return condition ? template : defaultValue; + } + + protected addEventListenerToElement( + element: Element, + eventType: string, + listener: (event: Event) => void, + ): void { + element.addEventListener(eventType, listener); + this.eventListeners.push({ element, eventType, listener }); + } + + protected removeAllEventListeners(): void { + this.eventListeners.forEach((item) => { + item.element.removeEventListener(item.eventType, item.listener); + }); + this.eventListeners = []; + } + + protected getJsonOrNull(data: string): unknown | null { + try { + return JSON.parse(data); + } catch (err: unknown) { + return null; + } + } + + protected finishLoadingFormControlHandler(componentName: string): void { + this.formLoader.setFieldLoaded(componentName); + } + + protected startLoadingComponentHandler(): void { + this.classList.add(isLoadingCssClassName); + } + + protected finishLoadingComponentHandler(componentName: string): void { + this.classList.remove(isLoadingCssClassName); + this.dispatchFinishLoadingEvent(componentName); + } + + protected dispatchFinishLoadingEvent(componentName: string): void { + this.dispatchEvent(createFinishLoadingEvent(componentName)); + this.formLoader.setFieldLoaded(componentName); + } +} diff --git a/src/core/web-components/secure-component/lit-secure-component.abstract.ts b/src/core/web-components/secure-component/lit-secure-component.abstract.ts new file mode 100644 index 0000000..1a22134 --- /dev/null +++ b/src/core/web-components/secure-component/lit-secure-component.abstract.ts @@ -0,0 +1,16 @@ +import { headlessCheckoutAppUrl } from '../../../features/headless-checkout/environment'; +import { LitWebComponentAbstract } from '../lit-web-component.abstract'; +import { property } from 'lit/decorators.js'; + +export abstract class LitSecureComponentAbstract extends LitWebComponentAbstract { + @property({ attribute: false }) + protected componentName: string | null = null; + + protected getSecureHtml(): string { + if (!this.componentName) { + throw new Error('Component name is required'); + } + + return ``; + } +} diff --git a/src/features/headless-checkout/web-components/card-number/card-number.component.scss b/src/features/headless-checkout/web-components/card-number/card-number.component.scss index f2cd694..c29ff89 100644 --- a/src/features/headless-checkout/web-components/card-number/card-number.component.scss +++ b/src/features/headless-checkout/web-components/card-number/card-number.component.scss @@ -1,4 +1,4 @@ -psdk-card-number { +psdk-card-number, psdk-lit-card-number { .wrapper { position: relative; } diff --git a/src/features/headless-checkout/web-components/card-number/card-number.component.ts b/src/features/headless-checkout/web-components/card-number/card-number.component.ts index 56d4ced..f9eff68 100644 --- a/src/features/headless-checkout/web-components/card-number/card-number.component.ts +++ b/src/features/headless-checkout/web-components/card-number/card-number.component.ts @@ -1,26 +1,22 @@ import { EventName } from '../../../../core/event-name.enum'; - -import { getCardNumberComponentTemplate } from './card-number.template'; import { updateCreditCardTypeHandler } from '../../post-messages-handlers/update-credit-card-type.handler'; import { cardIconsMap } from './card-icons.map'; import { CardType } from './card-type.enum'; import { CardNumberComponentAttributes } from './card-number-component-attributes.enum'; -import { TextComponent } from '../text-component/text.component'; import './card-number.component.scss'; +import { property, customElement } from 'lit/decorators.js'; +import { TextComponent } from '../text-component/text.component'; +import { html, TemplateResult } from 'lit'; +@customElement('psdk-card-number') export class CardNumberComponent extends TextComponent { + @property({ attribute: false }) private cardType = 'default'; - private isCardIconShown = true; - - public static get observedAttributes(): string[] { - return [ - CardNumberComponentAttributes.name, - CardNumberComponentAttributes.icon, - ]; - } + @property({ type: Boolean, attribute: CardNumberComponentAttributes.icon }) + private readonly isCardIconShown = false; - protected connectedCallback(): void { + public connectedCallback(): void { super.connectedCallback(); this.postMessagesClient.listen<{ cardType: string }>( @@ -29,65 +25,32 @@ export class CardNumberComponent extends TextComponent { (res) => { if (this.isCardIconShown && this.cardType !== res?.cardType) { this.cardType = res?.cardType ? res.cardType : 'default'; - this.updateCardIcon(this.cardType); } }, ); } - protected attributeChangedCallback(): void { - if (!this.formSpy.formWasInit) { - this.formSpy.listenFormInit(() => { - super.attributeChangedCallback(); - this.toggleCardIconVisibility(); - }); - return; - } - } - - protected getHtml(): string { - const secureHtml = this.getSecureHtml(); - return getCardNumberComponentTemplate({ - title: this.config?.title, - error: this.config?.error, - isCardIconShown: this.isCardIconShown, - secureHtml, - }); - } - - private updateCardIcon(iconName: string): void { - const rootElement = this.shadowRoot ?? this; - - const iconWrapperElement = rootElement.querySelector('.card-icon'); - - const iconElement = iconWrapperElement!.querySelector( - '.icon', - ) as HTMLImageElement | null; - - const cardIcon = - cardIconsMap[iconName as CardType] ?? cardIconsMap[CardType.DEFAULT_CARD]; - if (!iconElement) { - const newIconElement = this.window.document.createElement('img'); - newIconElement.width = 24; - newIconElement.height = 18; - newIconElement.classList.add('icon'); - newIconElement.src = cardIcon; - iconWrapperElement!.appendChild(newIconElement); - } else { - iconElement.src = cardIcon; + protected render(): TemplateResult<1> { + if (!this.formSpy.formWasInit || !this.componentName) { + return html``; } - } - private toggleCardIconVisibility(): void { - const isCardIconShownAttr = this.getAttribute( - CardNumberComponentAttributes.icon, + const textComponentTemplate = this.getTextComponentTemplate( + this.getCardIconTemplate(), ); - if (!isCardIconShownAttr) { - this.isCardIconShown = true; - return; - } + return html`${textComponentTemplate}`; + } - this.isCardIconShown = isCardIconShownAttr === 'true'; + private getCardIconTemplate(): TemplateResult<1> | null { + const cardIcon = + cardIconsMap[this.cardType as CardType] ?? + cardIconsMap[CardType.DEFAULT_CARD]; + + return this.isCardIconShown + ? html` + + ` + : null; } } diff --git a/src/features/headless-checkout/web-components/card-number/card-number.template.ts b/src/features/headless-checkout/web-components/card-number/card-number.template.ts deleted file mode 100644 index 68c4771..0000000 --- a/src/features/headless-checkout/web-components/card-number/card-number.template.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { getTextComponentTemplate } from '../text-component/text.compontent.template'; -import { TextComponentConfig } from '../text-component/text-component.config.interface'; - -export interface CardNumberComponentData extends TextComponentConfig { - secureHtml: string; - isCardIconShown: boolean; -} - -export const getCardNumberComponentTemplate = ({ - secureHtml, - title, - error, - tooltip, - isCardIconShown, -}: CardNumberComponentData): string => { - const additionalControls = isCardIconShown - ? '' - : ''; - return getTextComponentTemplate({ - secureHtml, - title, - error, - tooltip, - additionalControls, - }); -}; diff --git a/src/features/headless-checkout/web-components/phone-component/phone.component.ts b/src/features/headless-checkout/web-components/phone-component/phone.component.ts index 86c6499..49f12d9 100644 --- a/src/features/headless-checkout/web-components/phone-component/phone.component.ts +++ b/src/features/headless-checkout/web-components/phone-component/phone.component.ts @@ -1,18 +1,15 @@ import { PhoneComponentAttributes } from './phone-component-attributes.enum'; import { headlessCheckoutAppUrl } from '../../environment'; import { TextComponent } from '../text-component/text.component'; +import { property, customElement } from 'lit/decorators.js'; +@customElement('psdk-phone') export class PhoneComponent extends TextComponent { - public static get observedAttributes(): string[] { - return [PhoneComponentAttributes.showFlags]; - } + @property({ attribute: PhoneComponentAttributes.name }) + protected inputName = 'phone'; - protected connectedCallback(): void { - super.connectedCallback(); - if (!this.getAttribute(PhoneComponentAttributes.name)) { - this.setAttribute(PhoneComponentAttributes.name, 'phone'); - } - } + @property({ type: Boolean, attribute: PhoneComponentAttributes.showFlags }) + private readonly showFlags = false; protected getSecureHtml(): string { if (!this.componentName) { @@ -20,9 +17,7 @@ export class PhoneComponent extends TextComponent { } let src = `${headlessCheckoutAppUrl}/secure-components/${this.componentName}`; - const showFlags = this.getAttribute(PhoneComponentAttributes.showFlags); - - if (showFlags) { + if (this.showFlags) { src += '?showFlags=true'; } return ``; diff --git a/src/features/headless-checkout/web-components/text-component/text-component.config.interface.ts b/src/features/headless-checkout/web-components/text-component/text-component.config.interface.ts index d21237b..2835e74 100644 --- a/src/features/headless-checkout/web-components/text-component/text-component.config.interface.ts +++ b/src/features/headless-checkout/web-components/text-component/text-component.config.interface.ts @@ -1,8 +1,9 @@ import { ControlComponentConfig } from '../control-component-config.interface'; import { TextConfigTooltip } from './text-config-tooltip.interface'; +import { TemplateResult } from 'lit'; export interface TextComponentConfig extends ControlComponentConfig { secureHtml: string; - additionalControls?: string; + additionalControls?: TemplateResult<1>; tooltip?: TextConfigTooltip; } diff --git a/src/features/headless-checkout/web-components/text-component/text.component.template.spec.ts b/src/features/headless-checkout/web-components/text-component/text.component.template.spec.ts deleted file mode 100644 index 3f00173..0000000 --- a/src/features/headless-checkout/web-components/text-component/text.component.template.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { getTextComponentTemplate } from './text.compontent.template'; -import { TextComponentConfig } from './text-component.config.interface'; - -const mockedData: TextComponentConfig = { - secureHtml: 'secureHtml', - title: 'title', - tooltip: { text: 'tooltip' }, - error: 'error', -}; - -describe('getTextComponentTemplate', () => { - it('Should draw all blocks', () => { - const template = getTextComponentTemplate(mockedData); - - expect(template).toContain('secureHtml'); - expect(template).toContain('title'); - expect(template).toContain('tooltip'); - expect(template).toContain('error'); - }); - - it('Should draw only required parts', () => { - const template = getTextComponentTemplate({ - secureHtml: mockedData.secureHtml, - }); - expect(template).toContain('secureHtml'); - expect(template).not.toContain('title'); - expect(template).not.toContain('tooltip'); - expect(template).not.toContain('error'); - }); -}); diff --git a/src/features/headless-checkout/web-components/text-component/text.component.ts b/src/features/headless-checkout/web-components/text-component/text.component.ts index b1d8885..e0ea542 100644 --- a/src/features/headless-checkout/web-components/text-component/text.component.ts +++ b/src/features/headless-checkout/web-components/text-component/text.component.ts @@ -1,8 +1,6 @@ -import { SecureComponentAbstract } from '../../../../core/web-components/secure-component/secure-component.abstract'; import { TextComponentAttributes } from './text-component-attributes.enum'; import { container } from 'tsyringe'; import { FormSpy } from '../../../../core/spy/form-spy/form-spy'; -import { getTextComponentTemplate } from './text.compontent.template'; import { PostMessagesClient } from '../../../../core/post-messages-client/post-messages-client'; import { EventName } from '../../../../core/event-name.enum'; import { Message } from '../../../../core/message.interface'; @@ -11,25 +9,34 @@ import { getControlComponentConfigHandler } from '../get-control-component-confi import { HeadlessCheckout } from '../../headless-checkout'; import { ValidationErrors } from '../../../../core/form/validation-errors.interface'; import { TextComponentConfig } from './text-component.config.interface'; -import { FieldStatus } from '../../../../core/form/field-status.interface'; import { finishLoadComponentHandler } from '../../post-messages-handlers/finish-load-component.handler'; +import { LitSecureComponentAbstract } from '../../../../core/web-components/secure-component/lit-secure-component.abstract'; +import { html, TemplateResult } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; -export class TextComponent extends SecureComponentAbstract { +@customElement('psdk-text') +export class TextComponent extends LitSecureComponentAbstract { + @property({ attribute: TextComponentAttributes.name }) + protected inputName = ''; + + @property({ attribute: false }) protected config?: TextComponentConfig; - protected readonly postMessagesClient: PostMessagesClient; - protected readonly window: Window; - protected readonly formSpy: FormSpy; - private readonly headlessCheckout: HeadlessCheckout; + @property({ attribute: false }) + protected showError: boolean = false; + + protected readonly postMessagesClient: PostMessagesClient = + container.resolve(PostMessagesClient); + protected readonly window: Window = container.resolve(Window); + protected readonly formSpy: FormSpy = container.resolve(FormSpy); + + private readonly headlessCheckout: HeadlessCheckout = + container.resolve(HeadlessCheckout); private isListeningFieldStatusChange = false; - private inputName?: string | null; public constructor() { super(); - this.formSpy = container.resolve(FormSpy); - this.postMessagesClient = container.resolve(PostMessagesClient); - this.window = container.resolve(Window); - this.headlessCheckout = container.resolve(HeadlessCheckout); this.headlessCheckout.events.onCoreEvent( EventName.finishLoadComponent, @@ -42,11 +49,9 @@ export class TextComponent extends SecureComponentAbstract { ); } - public static get observedAttributes(): string[] { - return [TextComponentAttributes.name]; - } + public connectedCallback(): void { + super.connectedCallback(); - protected connectedCallback(): void { if (!this.formSpy.formWasInit) { this.formSpy.listenFormInit(() => this.getConfigFromInputName()); return; @@ -55,6 +60,36 @@ export class TextComponent extends SecureComponentAbstract { this.getConfigFromInputName(); } + protected render(): TemplateResult<1> { + if (!this.formSpy.formWasInit || !this.componentName) { + return html``; + } + + return this.getTextComponentTemplate(); + } + + protected getTextComponentTemplate( + additionalControls?: TemplateResult<1> | null, + ): TemplateResult<1> { + const { title, tooltip, error } = this.config ?? {}; + + return html` + ${this.renderByCondition( + !!title, + html`
${title}
`, + )} + ${this.renderByCondition( + !!tooltip?.text, + html`
${tooltip?.text}
`, + )} + ${this.renderSecureComponentWithWrapper(additionalControls)} + ${this.renderByCondition( + this.showError, + html`
${error}
`, + )} + `; + } + protected async getControlComponentConfig( inputName: string, ): Promise { @@ -81,29 +116,9 @@ export class TextComponent extends SecureComponentAbstract { ): void => { this.config = config; this.componentName = componentName; - super.render(); }; - protected attributeChangedCallback(): void { - if (!this.inputName) { - return; - } - - super.attributeChangedCallback(); - } - - protected getHtml(): string { - const secureHtml = this.getSecureHtml(); - return getTextComponentTemplate({ - title: this.config?.title, - tooltip: this.config?.tooltip, - error: this.config?.error, - secureHtml, - }); - } - private getConfigFromInputName(): void { - this.inputName = this.getAttribute(TextComponentAttributes.name); if (!this.inputName) { return; } @@ -128,29 +143,13 @@ export class TextComponent extends SecureComponentAbstract { return; } - this.config.error = this.getFirstError(fieldStatus.errors); - this.updateError(fieldStatus); - }); - } + this.showError = !!(fieldStatus.isTouched && !fieldStatus.isFocused); - private updateError(fieldStatus: FieldStatus): void { - const rootElement = this.shadowRoot ?? this; - const errorElement = rootElement.querySelector('.field-error'); - - if (this.config?.error && fieldStatus.isTouched && !fieldStatus.isFocused) { - if (!errorElement) { - const newErrorElement = this.window.document.createElement('div'); - newErrorElement.classList.add('field-error'); - newErrorElement.innerHTML = this.config.error; - rootElement.appendChild(newErrorElement); - } else { - errorElement.innerHTML = this.config.error; - } - } else { - if (errorElement) { - errorElement.remove(); - } - } + this.config = { + ...this.config, + error: this.getFirstError(fieldStatus.errors), + }; + }); } private getFirstError(errors: ValidationErrors | null): string | null { @@ -161,4 +160,21 @@ export class TextComponent extends SecureComponentAbstract { const firstErrorKey: string = Object.keys(errors)[0]; return errors[firstErrorKey]?.message ?? null; } + + private renderSecureComponentWithWrapper( + additionalControls?: TemplateResult<1> | null, + ): TemplateResult<1> { + const additionalClass = additionalControls + ? 'wrapper--additional-controls' + : ''; + return html` +
+ ${unsafeHTML(this.getSecureHtml())} + ${this.renderByCondition( + !!additionalControls, + html`${additionalControls}`, + )} +
+ `; + } } diff --git a/src/features/headless-checkout/web-components/text-component/text.compontent.template.ts b/src/features/headless-checkout/web-components/text-component/text.compontent.template.ts deleted file mode 100644 index 154e2f9..0000000 --- a/src/features/headless-checkout/web-components/text-component/text.compontent.template.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { TextConfigTooltip } from './text-config-tooltip.interface'; -import { TextComponentConfig } from './text-component.config.interface'; - -const getLabelTemplate = (title?: string): string => { - return title ? `
${title}
` : ''; -}; - -const getDescriptionTemplate = (tooltip?: TextConfigTooltip): string => { - return tooltip?.text ? `
${tooltip.text}
` : ''; -}; - -const getErrorsTemplate = (error?: string | null): string => { - return error ? `
${error}
` : ''; -}; - -export const getTextComponentTemplate = ({ - secureHtml, - title, - error, - tooltip, - additionalControls, -}: TextComponentConfig): string => { - return ` - ${getLabelTemplate(title)} - ${getDescriptionTemplate(tooltip)} -
- ${secureHtml} - ${additionalControls ? additionalControls : ''} -
- ${getErrorsTemplate(error)}`; -}; diff --git a/src/styles/style.scss b/src/styles/style.scss index ca8ace8..4c1b2dc 100644 --- a/src/styles/style.scss +++ b/src/styles/style.scss @@ -24,8 +24,10 @@ psdk-payment-form-messages { } psdk-text, +psdk-lit-text, psdk-phone, psdk-card-number, +psdk-lit-card-number, psdk-google-pay-button, psdk-apple-pay { @include psdk-typo; diff --git a/src/web-components.ts b/src/web-components.ts index bb326a7..5174fc1 100644 --- a/src/web-components.ts +++ b/src/web-components.ts @@ -22,12 +22,12 @@ import { TotalComponent } from './features/headless-checkout/web-components/fina export { SubmitButtonComponent, TextComponent, + CardNumberComponent, PaymentMethodsComponent, PriceTextComponent, FinanceDetailsComponent, LegalComponent, StatusComponent, - CardNumberComponent, ThreeDsComponent, PhoneComponent, SelectComponent,