@funnelsgrove/payments 0.11.24 → 0.11.26

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/README.md CHANGED
@@ -17,7 +17,8 @@ Render every visible wallet placement with `StripeSubscriptionWalletSurface` or
17
17
 
18
18
  - Each surface owns one private Checkout Session per simultaneously visible wallet placement, isolated by its own `surfaceId`.
19
19
  - Simultaneously visible placements may use the same plan and coupon; nothing is shared because each surface keeps its own session.
20
- - When the selected plan changes, the surface updates the existing Checkout Session in place without changing `surfaceId`, React `key`, `clientSecret`, `CheckoutProvider`, or the Express Checkout iframe.
20
+ - Changing the selected plan replaces the surface’s Checkout Session and `clientSecret`. A stable `surfaceId` identifies the placement; it does not guarantee that the Stripe iframe survives a plan change.
21
+ - If payment confirmation is already in flight when the selection changes, the success callback remains bound to the original confirmed Checkout Session.
21
22
 
22
23
  Use these for new subscription paywalls:
23
24
 
@@ -1,67 +1,3 @@
1
- import type { FunnelSdkRuntimeConfigOverrides, FunnelStepType, RuntimeMode } from '@funnelsgrove/runtime';
2
- import { type PrepareSolidgateCheckoutInput, type SolidgateCheckoutPreparation } from '../services/solidgate.service.js';
3
- export type SolidgateCheckoutDialogState = 'collecting_email' | 'loading' | 'ready' | 'submitting' | 'verifying' | 'success' | 'recoverable_error' | 'expired';
4
- export type SolidgateCheckoutDialogContent = {
5
- title: string;
6
- closeAriaLabel: string;
7
- loading: string;
8
- submitting: string;
9
- verifying: string;
10
- success: string;
11
- error: string;
12
- expired: string;
13
- retry: string;
14
- resumeVerification: string;
15
- customerEmailLabel: string;
16
- customerEmailPlaceholder: string;
17
- customerEmailInvalid: string;
18
- customerEmailUnavailable: string;
19
- customerEmailContinue: string;
20
- };
21
- export type SolidgateCheckoutDialogPresentation = {
22
- buttonColor: string;
23
- cardSubmitLabel: string;
24
- countdownLabel: string;
25
- discountAmountLabel: string;
26
- discountLabel: string;
27
- discountPercent: number;
28
- originalPriceLabel: string;
29
- originalPriceValue: string;
30
- promoActive: boolean;
31
- promoCode: string;
32
- promoCodeLabel: string;
33
- remainingSeconds: number;
34
- satisfactionLabel: string;
35
- satisfactionPercent: string;
36
- savedLabel: string;
37
- secureLabel: string;
38
- themeColor: string;
39
- title: string;
40
- totalLabel: string;
41
- totalValue: string;
42
- };
43
- export type SolidgateCheckoutDialogProps = {
44
- open: boolean;
45
- request: Omit<PrepareSolidgateCheckoutInput, 'signal'>;
46
- customerEmail?: string | null;
47
- checkoutAnalytics?: SolidgateCheckoutAnalyticsContext | null;
48
- content?: Partial<SolidgateCheckoutDialogContent>;
49
- presentation?: SolidgateCheckoutDialogPresentation;
50
- onClose: () => void;
51
- onCustomerEmailCommit?: (email: string) => Promise<string>;
52
- onSuccess?: (checkout: SolidgateCheckoutPreparation) => void | Promise<void>;
53
- onRetry?: () => void;
54
- onError?: (message: string) => void;
55
- onStateChange?: (state: SolidgateCheckoutDialogState) => void;
56
- };
57
- export type SolidgateCheckoutAnalyticsContext = {
58
- environment?: RuntimeMode;
59
- featureFlags?: Record<string, string | null | undefined>;
60
- metadata?: Record<string, unknown> | null;
61
- runtimeConfig?: FunnelSdkRuntimeConfigOverrides;
62
- stepId: string;
63
- stepName: string;
64
- stepType: Extract<FunnelStepType, 'checkout' | 'paywall_offer' | 'upsell_offer'>;
65
- stepContractVersion: number;
66
- };
1
+ import type { SolidgateCheckoutDialogProps } from './SolidgateCheckoutDialog.types.js';
2
+ export type { SolidgateCheckoutDialogState, SolidgateCheckoutDialogContent, SolidgateCheckoutDialogPresentation, SolidgateCheckoutDialogProps, SolidgateCheckoutAnalyticsContext, } from './SolidgateCheckoutDialog.types.js';
67
3
  export declare function SolidgateCheckoutDialog({ open, request, customerEmail, checkoutAnalytics, content, presentation, onClose, onCustomerEmailCommit, onSuccess, onRetry, onError, onStateChange, }: SolidgateCheckoutDialogProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1,12 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { publicAnalyticsSdk } from '@funnelsgrove/analytics';
4
- import { Suspense, lazy, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
4
+ import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
5
5
  import { pollSolidgateCheckoutStatus, prepareSolidgateCheckout, } from '../services/solidgate.service.js';
6
6
  import { trackCheckoutCanceled, trackCheckoutFailureShown, } from '../../../services/checkoutObservability.service.js';
7
- const SolidgatePayment = lazy(async () => ({
8
- default: (await import('@solidgate/react-sdk')).default,
9
- }));
7
+ import { SolidgateCheckoutSummary } from './SolidgateCheckoutSummary.js';
8
+ import { SolidgatePaymentForm } from './SolidgatePaymentForm.js';
9
+ import { solidgateCheckoutDialogStyles } from './SolidgateCheckoutDialog.styles.js';
10
10
  const defaultContent = {
11
11
  title: 'Secure checkout',
12
12
  closeAriaLabel: 'Close checkout',
@@ -35,14 +35,6 @@ const initialView = {
35
35
  checkout: null,
36
36
  canResumeVerification: false,
37
37
  };
38
- const formatCountdown = (remainingSeconds) => {
39
- const normalizedSeconds = Number.isFinite(remainingSeconds)
40
- ? Math.max(0, Math.floor(remainingSeconds))
41
- : 0;
42
- const minutes = Math.floor(normalizedSeconds / 60);
43
- const seconds = normalizedSeconds % 60;
44
- return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
45
- };
46
38
  const trackSolidgateCheckoutEvent = async (eventName, attemptId, context) => {
47
39
  var _a;
48
40
  if (!context) {
@@ -70,114 +62,6 @@ const trackSolidgateCheckoutEvent = async (eventName, attemptId, context) => {
70
62
  }
71
63
  };
72
64
  const isAbortError = (error) => (error instanceof DOMException && error.name === 'AbortError');
73
- const safeDestroyPaymentForm = (instance) => {
74
- var _a;
75
- try {
76
- instance === null || instance === void 0 ? void 0 : instance.unsubscribeAll();
77
- }
78
- catch (_b) {
79
- // The global destroy below is the final cleanup boundary.
80
- }
81
- try {
82
- (_a = window.PaymentFormSdk) === null || _a === void 0 ? void 0 : _a.destroy();
83
- }
84
- catch (_c) {
85
- // Cleanup must stay safe when the remote SDK is partially initialized.
86
- }
87
- };
88
- function SolidgatePaymentForm({ buttonColor, cardSubmitLabel, checkout, hidden, loadingLabel, onError, onMounted, onSubmit, onVerify, }) {
89
- const instanceRef = useRef(null);
90
- const submittedRef = useRef(false);
91
- const paymentBoundaryRef = useRef(null);
92
- const mountedReportedRef = useRef(false);
93
- const onMountedRef = useRef(onMounted);
94
- const applePayContainerRef = useRef(null);
95
- const googlePayContainerRef = useRef(null);
96
- useEffect(() => {
97
- onMountedRef.current = onMounted;
98
- }, [onMounted]);
99
- useEffect(() => {
100
- mountedReportedRef.current = false;
101
- const boundary = paymentBoundaryRef.current;
102
- if (!boundary) {
103
- return;
104
- }
105
- const reportIframeMounted = () => {
106
- if (!mountedReportedRef.current
107
- && boundary.querySelector('iframe#solid-payment-form-iframe, iframe[name="solid-payment-form-iframe"]')) {
108
- mountedReportedRef.current = true;
109
- onMountedRef.current();
110
- }
111
- };
112
- reportIframeMounted();
113
- const observer = new MutationObserver(reportIframeMounted);
114
- observer.observe(boundary, { childList: true, subtree: true });
115
- return () => observer.disconnect();
116
- }, [checkout.attemptId]);
117
- useEffect(() => {
118
- submittedRef.current = false;
119
- return () => {
120
- safeDestroyPaymentForm(instanceRef.current);
121
- instanceRef.current = null;
122
- };
123
- }, [checkout.attemptId]);
124
- const walletButtonType = checkout.display.billingInterval ? 'subscribe' : 'buy';
125
- return (_jsxs("div", { ref: paymentBoundaryRef, className: 'solidgate-checkout-payment', "data-solidgate-attempt-id": checkout.attemptId, hidden: hidden, "aria-hidden": hidden || undefined, children: [_jsxs("div", { className: 'solidgate-checkout-wallets', children: [_jsx("div", { ref: applePayContainerRef, "data-solidgate-wallet": 'apple-pay' }), _jsx("div", { ref: googlePayContainerRef, "data-solidgate-wallet": 'google-pay' })] }), _jsx(Suspense, { fallback: (_jsx("p", { role: 'status', className: 'solidgate-checkout-status-text', children: loadingLabel })), children: _jsx(SolidgatePayment, { merchantData: checkout.initialization.merchantData, width: '100%', formParams: {
126
- autoFocus: false,
127
- isSolidLogoVisible: true,
128
- submitButtonText: cardSubmitLabel,
129
- }, styles: {
130
- form_body: {
131
- 'font-family': 'Inter, Arial, sans-serif',
132
- },
133
- input_group: {
134
- input: {
135
- 'border-color': '#d8d9dd',
136
- 'border-radius': '10px',
137
- },
138
- },
139
- submit_button: {
140
- 'background-color': buttonColor,
141
- 'border-radius': '10px',
142
- 'font-size': '16px',
143
- 'font-weight': '800',
144
- height: '52px',
145
- },
146
- }, applePayButtonParams: {
147
- color: 'black',
148
- enabled: true,
149
- integrationType: 'js',
150
- type: walletButtonType,
151
- }, googlePayButtonParams: {
152
- color: 'black',
153
- enabled: true,
154
- type: walletButtonType,
155
- }, applePayContainerRef: applePayContainerRef, googlePayContainerRef: googlePayContainerRef, onReadyPaymentInstance: (instance) => {
156
- if (instanceRef.current && instanceRef.current !== instance) {
157
- try {
158
- instanceRef.current.unsubscribeAll();
159
- }
160
- catch (_a) {
161
- // The active instance remains usable even if stale-listener cleanup fails.
162
- }
163
- }
164
- instanceRef.current = instance;
165
- }, onMounted: () => {
166
- if (!mountedReportedRef.current) {
167
- mountedReportedRef.current = true;
168
- onMountedRef.current();
169
- }
170
- }, onSubmit: () => {
171
- submittedRef.current = true;
172
- onSubmit();
173
- }, onVerify: onVerify, onSuccess: onVerify, onFail: onVerify, onError: () => {
174
- if (submittedRef.current) {
175
- onVerify();
176
- return;
177
- }
178
- onError();
179
- } }, checkout.attemptId) })] }));
180
- }
181
65
  export function SolidgateCheckoutDialog({ open, request, customerEmail, checkoutAnalytics, content, presentation, onClose, onCustomerEmailCommit, onSuccess, onRetry, onError, onStateChange, }) {
182
66
  const copy = useMemo(() => (Object.assign(Object.assign({}, defaultContent), content)), [content]);
183
67
  const [view, setView] = useState(initialView);
@@ -474,9 +358,6 @@ export function SolidgateCheckoutDialog({ open, request, customerEmail, checkout
474
358
  : view.state === 'recoverable_error'
475
359
  ? copy.error
476
360
  : null;
477
- const showPromo = Boolean((presentation === null || presentation === void 0 ? void 0 : presentation.promoActive) &&
478
- presentation.discountPercent > 0 &&
479
- presentation.promoCode.trim());
480
361
  const presentationStyle = presentation
481
362
  ? {
482
363
  '--solidgate-checkout-theme-color': presentation.themeColor,
@@ -486,7 +367,7 @@ export function SolidgateCheckoutDialog({ open, request, customerEmail, checkout
486
367
  'solidgate-checkout-dialog',
487
368
  showPreparingLoader ? 'is-preparing' : '',
488
369
  presentation ? 'is-branded' : '',
489
- ].filter(Boolean).join(' '), children: [_jsxs("div", { className: 'solidgate-checkout-header', children: [_jsx("button", { ref: closeButtonRef, type: 'button', onClick: handleClose, "aria-label": copy.closeAriaLabel, className: 'solidgate-checkout-close', children: _jsx("span", { "aria-hidden": 'true' }) }), _jsx("h2", { id: 'solidgate-checkout-title', className: 'solidgate-checkout-title', children: (presentation === null || presentation === void 0 ? void 0 : presentation.title) || copy.title })] }), presentation ? (_jsxs("section", { className: 'solidgate-checkout-summary', children: [showPromo ? (_jsxs("p", { className: 'solidgate-checkout-countdown', children: [presentation.discountPercent, "% ", presentation.countdownLabel, ' ', formatCountdown(presentation.remainingSeconds), " min"] })) : null, _jsxs("p", { className: 'solidgate-checkout-satisfaction', children: [_jsx("strong", { children: presentation.satisfactionPercent }), ' ', presentation.satisfactionLabel] }), showPromo ? (_jsxs("div", { className: 'solidgate-checkout-price-stack', children: [_jsxs("div", { className: 'solidgate-checkout-price-row is-muted', children: [_jsx("span", { children: presentation.originalPriceLabel }), _jsx("span", { className: 'solidgate-checkout-strike', children: presentation.originalPriceValue })] }), _jsxs("div", { className: 'solidgate-checkout-price-row is-discount', children: [_jsx("strong", { children: presentation.discountLabel }), _jsx("strong", { children: presentation.discountAmountLabel })] }), _jsxs("div", { className: 'solidgate-checkout-promo', children: [_jsx("span", { children: presentation.promoCodeLabel }), _jsx("strong", { children: presentation.promoCode.trim() })] })] })) : null, _jsxs("div", { className: `solidgate-checkout-total${showPromo ? '' : ' is-plain'}`, children: [_jsx("span", { children: presentation.totalLabel }), _jsx("strong", { children: presentation.totalValue })] }), showPromo ? (_jsxs("p", { className: 'solidgate-checkout-saved', children: [_jsx("span", { "aria-hidden": 'true', children: "\uD83D\uDD25" }), presentation.savedLabel] })) : null] })) : null, view.state === 'collecting_email' ? (_jsxs("form", { className: 'solidgate-checkout-email-form', onSubmit: (event) => void commitCustomerEmail(event), children: [_jsxs("label", { className: 'solidgate-checkout-email-label', children: [copy.customerEmailLabel, _jsx("input", { type: 'email', autoComplete: 'email', inputMode: 'email', maxLength: 320, required: true, value: emailInput, onChange: (event) => {
370
+ ].filter(Boolean).join(' '), children: [_jsxs("div", { className: 'solidgate-checkout-header', children: [_jsx("button", { ref: closeButtonRef, type: 'button', onClick: handleClose, "aria-label": copy.closeAriaLabel, className: 'solidgate-checkout-close', children: _jsx("span", { "aria-hidden": 'true' }) }), _jsx("h2", { id: 'solidgate-checkout-title', className: 'solidgate-checkout-title', children: (presentation === null || presentation === void 0 ? void 0 : presentation.title) || copy.title })] }), presentation ? _jsx(SolidgateCheckoutSummary, { presentation: presentation }) : null, view.state === 'collecting_email' ? (_jsxs("form", { className: 'solidgate-checkout-email-form', onSubmit: (event) => void commitCustomerEmail(event), children: [_jsxs("label", { className: 'solidgate-checkout-email-label', children: [copy.customerEmailLabel, _jsx("input", { type: 'email', autoComplete: 'email', inputMode: 'email', maxLength: 320, required: true, value: emailInput, onChange: (event) => {
490
371
  setEmailInput(event.target.value);
491
372
  setEmailError(null);
492
373
  }, placeholder: copy.customerEmailPlaceholder, "aria-invalid": Boolean(emailError), className: 'solidgate-checkout-email-input' })] }), emailError ? (_jsx("p", { role: 'alert', className: 'solidgate-checkout-alert', children: emailError })) : null, _jsx("button", { type: 'submit', disabled: emailSubmitting, className: 'solidgate-checkout-action', children: copy.customerEmailContinue })] })) : null, view.checkout ? (_jsx(SolidgatePaymentForm, { buttonColor: (presentation === null || presentation === void 0 ? void 0 : presentation.buttonColor) || '#3f51b5', cardSubmitLabel: (presentation === null || presentation === void 0 ? void 0 : presentation.cardSubmitLabel) || 'Pay securely', checkout: view.checkout, hidden: !showForm, loadingLabel: copy.loading, onMounted: () => {
@@ -506,403 +387,3 @@ export function SolidgateCheckoutDialog({ open, request, customerEmail, checkout
506
387
  (_b = onErrorRef.current) === null || _b === void 0 ? void 0 : _b.call(onErrorRef, copyRef.current.error);
507
388
  } }, view.checkout.attemptId)) : null, presentation && view.checkout && showForm ? (_jsx("p", { className: 'solidgate-checkout-secure', children: presentation.secureLabel })) : null, statusMessage && view.state !== 'ready' ? (_jsx("div", { className: 'solidgate-checkout-status', children: _jsx("p", { role: 'status', "aria-live": 'polite', children: statusMessage }) })) : null, view.state === 'verifying' && view.canResumeVerification ? (_jsx("button", { type: 'button', onClick: () => void verifyCanonicalStatus(), className: 'solidgate-checkout-action solidgate-checkout-action--spaced', children: copy.resumeVerification })) : null, (view.state === 'recoverable_error' || view.state === 'expired') && onRetry ? (_jsx("button", { type: 'button', onClick: onRetry, className: 'solidgate-checkout-action solidgate-checkout-action--spaced', children: copy.retry })) : null] })) : null] }), _jsx("style", { children: solidgateCheckoutDialogStyles })] }));
508
389
  }
509
- const solidgateCheckoutDialogStyles = `
510
- .solidgate-checkout-overlay {
511
- position: fixed;
512
- inset: 0;
513
- z-index: 100;
514
- box-sizing: border-box;
515
- display: flex;
516
- align-items: center;
517
- justify-content: center;
518
- overflow: hidden;
519
- padding: 16px;
520
- background: rgb(17 24 39 / 60%);
521
- backdrop-filter: blur(4px);
522
- }
523
-
524
- .solidgate-checkout-overlay.is-branded {
525
- z-index: 110;
526
- align-items: stretch;
527
- padding: 0;
528
- background: #fff;
529
- backdrop-filter: none;
530
- }
531
-
532
- .solidgate-checkout-dialog {
533
- box-sizing: border-box;
534
- width: min(100%, 512px);
535
- max-height: calc(100svh - 32px);
536
- overflow-y: auto;
537
- border: 1px solid var(--color-border, #d1d5db);
538
- border-radius: 16px;
539
- background: var(--color-surface, #fff);
540
- padding: 20px;
541
- color: var(--color-text, #111827);
542
- box-shadow: 0 24px 80px rgb(17 24 39 / 22%);
543
- }
544
-
545
- .solidgate-checkout-dialog.is-branded {
546
- width: min(100%, 430px);
547
- height: 100svh;
548
- max-height: 100svh;
549
- border: 0;
550
- border-radius: 0;
551
- background: #fff;
552
- padding: 0 17px 28px;
553
- color: #303136;
554
- box-shadow: none;
555
- font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
556
- }
557
-
558
- .solidgate-checkout-dialog.is-preparing {
559
- position: absolute;
560
- opacity: 0;
561
- pointer-events: none;
562
- }
563
-
564
- .solidgate-checkout-loader {
565
- display: grid;
566
- place-items: center;
567
- }
568
-
569
- .solidgate-checkout-spinner {
570
- box-sizing: border-box;
571
- width: 44px;
572
- height: 44px;
573
- border: 4px solid var(--color-border, #d1d5db);
574
- border-top-color: var(--color-primary, #22c55e);
575
- border-radius: 50%;
576
- animation: solidgate-checkout-spin 720ms linear infinite;
577
- }
578
-
579
- .solidgate-checkout-visually-hidden {
580
- position: absolute;
581
- width: 1px;
582
- height: 1px;
583
- overflow: hidden;
584
- clip: rect(0 0 0 0);
585
- clip-path: inset(50%);
586
- white-space: nowrap;
587
- }
588
-
589
- @keyframes solidgate-checkout-spin {
590
- to {
591
- transform: rotate(360deg);
592
- }
593
- }
594
-
595
- @media (prefers-reduced-motion: reduce) {
596
- .solidgate-checkout-spinner {
597
- animation-duration: 1.6s;
598
- }
599
- }
600
-
601
- .solidgate-checkout-header {
602
- position: relative;
603
- display: flex;
604
- align-items: center;
605
- justify-content: center;
606
- gap: 16px;
607
- margin-bottom: 16px;
608
- }
609
-
610
- .solidgate-checkout-dialog.is-branded .solidgate-checkout-header {
611
- min-height: 70px;
612
- margin: 0 -17px;
613
- padding: 0 56px;
614
- }
615
-
616
- .solidgate-checkout-title {
617
- margin: 0;
618
- color: var(--color-text, #111827);
619
- font-size: 18px;
620
- font-weight: 600;
621
- line-height: 1.3;
622
- }
623
-
624
- .solidgate-checkout-dialog.is-branded .solidgate-checkout-title {
625
- color: #020203;
626
- font-size: 24px;
627
- font-weight: 900;
628
- line-height: 1.15;
629
- text-align: center;
630
- }
631
-
632
- .solidgate-checkout-close {
633
- position: absolute;
634
- left: 0;
635
- top: 50%;
636
- width: 36px;
637
- height: 36px;
638
- flex: none;
639
- border: 1px solid var(--color-border, #d1d5db);
640
- border-radius: 8px;
641
- background: var(--color-bg, #f9fafb);
642
- color: var(--color-text, #111827);
643
- font-size: 22px;
644
- transform: translateY(-50%);
645
- cursor: pointer;
646
- }
647
-
648
- .solidgate-checkout-dialog.is-branded .solidgate-checkout-close {
649
- left: 16px;
650
- width: 40px;
651
- height: 40px;
652
- border: 0;
653
- border-radius: 999px;
654
- background: #f2f2f3;
655
- color: #aaa;
656
- }
657
-
658
- .solidgate-checkout-close span,
659
- .solidgate-checkout-close span::after {
660
- position: absolute;
661
- left: 50%;
662
- top: 50%;
663
- width: 22px;
664
- height: 3px;
665
- border-radius: 999px;
666
- background: currentColor;
667
- content: '';
668
- }
669
-
670
- .solidgate-checkout-close span {
671
- transform: translate(-50%, -50%) rotate(45deg);
672
- }
673
-
674
- .solidgate-checkout-close span::after {
675
- transform: translate(-50%, -50%) rotate(90deg);
676
- }
677
-
678
- .solidgate-checkout-close:hover {
679
- background: var(--color-accent-soft, #eef2ff);
680
- }
681
-
682
- .solidgate-checkout-summary {
683
- color: #303136;
684
- }
685
-
686
- .solidgate-checkout-countdown {
687
- min-height: 37px;
688
- display: flex;
689
- align-items: center;
690
- justify-content: center;
691
- margin: 0;
692
- border-radius: 12px;
693
- background: color-mix(in srgb, var(--solidgate-checkout-theme-color) 10%, #fff);
694
- color: var(--solidgate-checkout-theme-color);
695
- font-size: 16px;
696
- font-weight: 900;
697
- text-align: center;
698
- }
699
-
700
- .solidgate-checkout-satisfaction {
701
- margin: 17px 0 21px;
702
- color: #2f3034;
703
- font-size: 19px;
704
- font-weight: 800;
705
- line-height: 1.15;
706
- text-align: center;
707
- }
708
-
709
- .solidgate-checkout-satisfaction strong {
710
- color: var(--solidgate-checkout-theme-color);
711
- }
712
-
713
- .solidgate-checkout-price-stack {
714
- display: flex;
715
- flex-direction: column;
716
- gap: 8px;
717
- }
718
-
719
- .solidgate-checkout-price-row,
720
- .solidgate-checkout-promo,
721
- .solidgate-checkout-total {
722
- display: flex;
723
- align-items: center;
724
- justify-content: space-between;
725
- gap: 12px;
726
- }
727
-
728
- .solidgate-checkout-price-row {
729
- font-size: 17px;
730
- }
731
-
732
- .solidgate-checkout-price-row.is-muted {
733
- color: #9d9d9f;
734
- font-weight: 500;
735
- }
736
-
737
- .solidgate-checkout-strike {
738
- text-decoration: line-through 2px;
739
- }
740
-
741
- .solidgate-checkout-price-row.is-discount {
742
- color: #040508;
743
- font-weight: 900;
744
- }
745
-
746
- .solidgate-checkout-price-row.is-discount strong:last-child {
747
- color: #ff2544;
748
- }
749
-
750
- .solidgate-checkout-promo {
751
- min-height: 42px;
752
- border-radius: 13px;
753
- background: #f0f0f0;
754
- padding: 0 14px;
755
- color: #8d8d90;
756
- font-size: 16px;
757
- }
758
-
759
- .solidgate-checkout-promo strong {
760
- color: #050609;
761
- font-weight: 900;
762
- }
763
-
764
- .solidgate-checkout-total {
765
- min-height: 76px;
766
- margin-top: 20px;
767
- border-top: 1px solid #dedede;
768
- font-size: 23px;
769
- font-weight: 800;
770
- }
771
-
772
- .solidgate-checkout-total.is-plain {
773
- margin-top: 0;
774
- }
775
-
776
- .solidgate-checkout-total strong {
777
- font-size: 25px;
778
- font-weight: 900;
779
- }
780
-
781
- .solidgate-checkout-saved {
782
- width: fit-content;
783
- min-height: 36px;
784
- display: flex;
785
- align-items: center;
786
- gap: 7px;
787
- margin: 0 auto 12px;
788
- border-radius: 999px;
789
- background: #fff3cf;
790
- padding: 0 13px;
791
- color: #2e3034;
792
- font-size: 14px;
793
- font-weight: 800;
794
- }
795
-
796
- .solidgate-checkout-email-form,
797
- .solidgate-checkout-email-label,
798
- .solidgate-checkout-wallets {
799
- display: grid;
800
- }
801
-
802
- .solidgate-checkout-email-form {
803
- gap: 16px;
804
- }
805
-
806
- .solidgate-checkout-email-label {
807
- gap: 8px;
808
- color: var(--color-text, #111827);
809
- font-size: 14px;
810
- font-weight: 500;
811
- }
812
-
813
- .solidgate-checkout-email-input {
814
- box-sizing: border-box;
815
- width: 100%;
816
- min-height: 44px;
817
- border: 1px solid var(--color-border, #d1d5db);
818
- border-radius: 8px;
819
- background: var(--color-bg, #fff);
820
- padding: 8px 12px;
821
- color: var(--color-text, #111827);
822
- font: inherit;
823
- }
824
-
825
- .solidgate-checkout-email-input::placeholder,
826
- .solidgate-checkout-status,
827
- .solidgate-checkout-status-text {
828
- color: var(--color-text-muted, #6b7280);
829
- }
830
-
831
- .solidgate-checkout-email-input:focus-visible,
832
- .solidgate-checkout-close:focus-visible,
833
- .solidgate-checkout-action:focus-visible {
834
- outline: 2px solid var(--color-accent, #3f51b5);
835
- outline-offset: 2px;
836
- }
837
-
838
- .solidgate-checkout-alert {
839
- margin: 0;
840
- color: var(--color-danger, #b91c1c);
841
- font-size: 14px;
842
- }
843
-
844
- .solidgate-checkout-action {
845
- box-sizing: border-box;
846
- width: 100%;
847
- min-height: 44px;
848
- border: 1px solid var(--color-accent, #3f51b5);
849
- border-radius: 8px;
850
- background: var(--color-accent, #3f51b5);
851
- padding: 8px 16px;
852
- color: var(--color-primary-text, #fff);
853
- font: inherit;
854
- font-weight: 600;
855
- cursor: pointer;
856
- }
857
-
858
- .solidgate-checkout-action:disabled {
859
- cursor: not-allowed;
860
- opacity: 0.6;
861
- }
862
-
863
- .solidgate-checkout-action--spaced {
864
- margin-top: 16px;
865
- }
866
-
867
- .solidgate-checkout-wallets {
868
- gap: 12px;
869
- margin-bottom: 12px;
870
- }
871
-
872
- .solidgate-checkout-dialog.is-branded .solidgate-checkout-wallets {
873
- margin-top: 4px;
874
- }
875
-
876
- .solidgate-checkout-dialog.is-branded .solidgate-checkout-wallets > div:not(:empty) {
877
- min-height: 48px;
878
- }
879
-
880
- .solidgate-checkout-secure {
881
- width: fit-content;
882
- margin: 14px auto 0;
883
- border-radius: 999px;
884
- background: #edfff4;
885
- padding: 8px 14px;
886
- color: #2b2d31;
887
- font-size: 13px;
888
- font-weight: 700;
889
- }
890
-
891
- .solidgate-checkout-payment[hidden] {
892
- display: none;
893
- }
894
-
895
- .solidgate-checkout-status {
896
- margin-top: 12px;
897
- border: 1px solid var(--color-border, #d1d5db);
898
- border-radius: 12px;
899
- background: var(--color-bg, #f9fafb);
900
- padding: 16px;
901
- font-size: 14px;
902
- }
903
-
904
- .solidgate-checkout-status p,
905
- .solidgate-checkout-status-text {
906
- margin: 0;
907
- }
908
- `;
@@ -0,0 +1 @@
1
+ export declare const solidgateCheckoutDialogStyles = "\n.solidgate-checkout-overlay {\n position: fixed;\n inset: 0;\n z-index: 100;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n padding: 16px;\n background: rgb(17 24 39 / 60%);\n backdrop-filter: blur(4px);\n}\n\n.solidgate-checkout-overlay.is-branded {\n z-index: 110;\n align-items: stretch;\n padding: 0;\n background: #fff;\n backdrop-filter: none;\n}\n\n.solidgate-checkout-dialog {\n box-sizing: border-box;\n width: min(100%, 512px);\n max-height: calc(100svh - 32px);\n overflow-y: auto;\n border: 1px solid var(--color-border, #d1d5db);\n border-radius: 16px;\n background: var(--color-surface, #fff);\n padding: 20px;\n color: var(--color-text, #111827);\n box-shadow: 0 24px 80px rgb(17 24 39 / 22%);\n}\n\n.solidgate-checkout-dialog.is-branded {\n width: min(100%, 430px);\n height: 100svh;\n max-height: 100svh;\n border: 0;\n border-radius: 0;\n background: #fff;\n padding: 0 17px 28px;\n color: #303136;\n box-shadow: none;\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}\n\n.solidgate-checkout-dialog.is-preparing {\n position: absolute;\n opacity: 0;\n pointer-events: none;\n}\n\n.solidgate-checkout-loader {\n display: grid;\n place-items: center;\n}\n\n.solidgate-checkout-spinner {\n box-sizing: border-box;\n width: 44px;\n height: 44px;\n border: 4px solid var(--color-border, #d1d5db);\n border-top-color: var(--color-primary, #22c55e);\n border-radius: 50%;\n animation: solidgate-checkout-spin 720ms linear infinite;\n}\n\n.solidgate-checkout-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n@keyframes solidgate-checkout-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .solidgate-checkout-spinner {\n animation-duration: 1.6s;\n }\n}\n\n.solidgate-checkout-header {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 16px;\n margin-bottom: 16px;\n}\n\n.solidgate-checkout-dialog.is-branded .solidgate-checkout-header {\n min-height: 70px;\n margin: 0 -17px;\n padding: 0 56px;\n}\n\n.solidgate-checkout-title {\n margin: 0;\n color: var(--color-text, #111827);\n font-size: 18px;\n font-weight: 600;\n line-height: 1.3;\n}\n\n.solidgate-checkout-dialog.is-branded .solidgate-checkout-title {\n color: #020203;\n font-size: 24px;\n font-weight: 900;\n line-height: 1.15;\n text-align: center;\n}\n\n.solidgate-checkout-close {\n position: absolute;\n left: 0;\n top: 50%;\n width: 36px;\n height: 36px;\n flex: none;\n border: 1px solid var(--color-border, #d1d5db);\n border-radius: 8px;\n background: var(--color-bg, #f9fafb);\n color: var(--color-text, #111827);\n font-size: 22px;\n transform: translateY(-50%);\n cursor: pointer;\n}\n\n.solidgate-checkout-dialog.is-branded .solidgate-checkout-close {\n left: 16px;\n width: 40px;\n height: 40px;\n border: 0;\n border-radius: 999px;\n background: #f2f2f3;\n color: #aaa;\n}\n\n.solidgate-checkout-close span,\n.solidgate-checkout-close span::after {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 22px;\n height: 3px;\n border-radius: 999px;\n background: currentColor;\n content: '';\n}\n\n.solidgate-checkout-close span {\n transform: translate(-50%, -50%) rotate(45deg);\n}\n\n.solidgate-checkout-close span::after {\n transform: translate(-50%, -50%) rotate(90deg);\n}\n\n.solidgate-checkout-close:hover {\n background: var(--color-accent-soft, #eef2ff);\n}\n\n.solidgate-checkout-summary {\n color: #303136;\n}\n\n.solidgate-checkout-countdown {\n min-height: 37px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0;\n border-radius: 12px;\n background: color-mix(in srgb, var(--solidgate-checkout-theme-color) 10%, #fff);\n color: var(--solidgate-checkout-theme-color);\n font-size: 16px;\n font-weight: 900;\n text-align: center;\n}\n\n.solidgate-checkout-satisfaction {\n margin: 17px 0 21px;\n color: #2f3034;\n font-size: 19px;\n font-weight: 800;\n line-height: 1.15;\n text-align: center;\n}\n\n.solidgate-checkout-satisfaction strong {\n color: var(--solidgate-checkout-theme-color);\n}\n\n.solidgate-checkout-price-stack {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.solidgate-checkout-price-row,\n.solidgate-checkout-promo,\n.solidgate-checkout-total {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n\n.solidgate-checkout-price-row {\n font-size: 17px;\n}\n\n.solidgate-checkout-price-row.is-muted {\n color: #9d9d9f;\n font-weight: 500;\n}\n\n.solidgate-checkout-strike {\n text-decoration: line-through 2px;\n}\n\n.solidgate-checkout-price-row.is-discount {\n color: #040508;\n font-weight: 900;\n}\n\n.solidgate-checkout-price-row.is-discount strong:last-child {\n color: #ff2544;\n}\n\n.solidgate-checkout-promo {\n min-height: 42px;\n border-radius: 13px;\n background: #f0f0f0;\n padding: 0 14px;\n color: #8d8d90;\n font-size: 16px;\n}\n\n.solidgate-checkout-promo strong {\n color: #050609;\n font-weight: 900;\n}\n\n.solidgate-checkout-total {\n min-height: 76px;\n margin-top: 20px;\n border-top: 1px solid #dedede;\n font-size: 23px;\n font-weight: 800;\n}\n\n.solidgate-checkout-total.is-plain {\n margin-top: 0;\n}\n\n.solidgate-checkout-total strong {\n font-size: 25px;\n font-weight: 900;\n}\n\n.solidgate-checkout-saved {\n width: fit-content;\n min-height: 36px;\n display: flex;\n align-items: center;\n gap: 7px;\n margin: 0 auto 12px;\n border-radius: 999px;\n background: #fff3cf;\n padding: 0 13px;\n color: #2e3034;\n font-size: 14px;\n font-weight: 800;\n}\n\n.solidgate-checkout-email-form,\n.solidgate-checkout-email-label,\n.solidgate-checkout-wallets {\n display: grid;\n}\n\n.solidgate-checkout-email-form {\n gap: 16px;\n}\n\n.solidgate-checkout-email-label {\n gap: 8px;\n color: var(--color-text, #111827);\n font-size: 14px;\n font-weight: 500;\n}\n\n.solidgate-checkout-email-input {\n box-sizing: border-box;\n width: 100%;\n min-height: 44px;\n border: 1px solid var(--color-border, #d1d5db);\n border-radius: 8px;\n background: var(--color-bg, #fff);\n padding: 8px 12px;\n color: var(--color-text, #111827);\n font: inherit;\n}\n\n.solidgate-checkout-email-input::placeholder,\n.solidgate-checkout-status,\n.solidgate-checkout-status-text {\n color: var(--color-text-muted, #6b7280);\n}\n\n.solidgate-checkout-email-input:focus-visible,\n.solidgate-checkout-close:focus-visible,\n.solidgate-checkout-action:focus-visible {\n outline: 2px solid var(--color-accent, #3f51b5);\n outline-offset: 2px;\n}\n\n.solidgate-checkout-alert {\n margin: 0;\n color: var(--color-danger, #b91c1c);\n font-size: 14px;\n}\n\n.solidgate-checkout-action {\n box-sizing: border-box;\n width: 100%;\n min-height: 44px;\n border: 1px solid var(--color-accent, #3f51b5);\n border-radius: 8px;\n background: var(--color-accent, #3f51b5);\n padding: 8px 16px;\n color: var(--color-primary-text, #fff);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n\n.solidgate-checkout-action:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.solidgate-checkout-action--spaced {\n margin-top: 16px;\n}\n\n.solidgate-checkout-wallets {\n gap: 12px;\n margin-bottom: 12px;\n}\n\n.solidgate-checkout-dialog.is-branded .solidgate-checkout-wallets {\n margin-top: 4px;\n}\n\n.solidgate-checkout-dialog.is-branded .solidgate-checkout-wallets > div:not(:empty) {\n min-height: 48px;\n}\n\n.solidgate-checkout-secure {\n width: fit-content;\n margin: 14px auto 0;\n border-radius: 999px;\n background: #edfff4;\n padding: 8px 14px;\n color: #2b2d31;\n font-size: 13px;\n font-weight: 700;\n}\n\n.solidgate-checkout-payment[hidden] {\n display: none;\n}\n\n.solidgate-checkout-status {\n margin-top: 12px;\n border: 1px solid var(--color-border, #d1d5db);\n border-radius: 12px;\n background: var(--color-bg, #f9fafb);\n padding: 16px;\n font-size: 14px;\n}\n\n.solidgate-checkout-status p,\n.solidgate-checkout-status-text {\n margin: 0;\n}\n";
@@ -0,0 +1,400 @@
1
+ export const solidgateCheckoutDialogStyles = `
2
+ .solidgate-checkout-overlay {
3
+ position: fixed;
4
+ inset: 0;
5
+ z-index: 100;
6
+ box-sizing: border-box;
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+ overflow: hidden;
11
+ padding: 16px;
12
+ background: rgb(17 24 39 / 60%);
13
+ backdrop-filter: blur(4px);
14
+ }
15
+
16
+ .solidgate-checkout-overlay.is-branded {
17
+ z-index: 110;
18
+ align-items: stretch;
19
+ padding: 0;
20
+ background: #fff;
21
+ backdrop-filter: none;
22
+ }
23
+
24
+ .solidgate-checkout-dialog {
25
+ box-sizing: border-box;
26
+ width: min(100%, 512px);
27
+ max-height: calc(100svh - 32px);
28
+ overflow-y: auto;
29
+ border: 1px solid var(--color-border, #d1d5db);
30
+ border-radius: 16px;
31
+ background: var(--color-surface, #fff);
32
+ padding: 20px;
33
+ color: var(--color-text, #111827);
34
+ box-shadow: 0 24px 80px rgb(17 24 39 / 22%);
35
+ }
36
+
37
+ .solidgate-checkout-dialog.is-branded {
38
+ width: min(100%, 430px);
39
+ height: 100svh;
40
+ max-height: 100svh;
41
+ border: 0;
42
+ border-radius: 0;
43
+ background: #fff;
44
+ padding: 0 17px 28px;
45
+ color: #303136;
46
+ box-shadow: none;
47
+ font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
48
+ }
49
+
50
+ .solidgate-checkout-dialog.is-preparing {
51
+ position: absolute;
52
+ opacity: 0;
53
+ pointer-events: none;
54
+ }
55
+
56
+ .solidgate-checkout-loader {
57
+ display: grid;
58
+ place-items: center;
59
+ }
60
+
61
+ .solidgate-checkout-spinner {
62
+ box-sizing: border-box;
63
+ width: 44px;
64
+ height: 44px;
65
+ border: 4px solid var(--color-border, #d1d5db);
66
+ border-top-color: var(--color-primary, #22c55e);
67
+ border-radius: 50%;
68
+ animation: solidgate-checkout-spin 720ms linear infinite;
69
+ }
70
+
71
+ .solidgate-checkout-visually-hidden {
72
+ position: absolute;
73
+ width: 1px;
74
+ height: 1px;
75
+ overflow: hidden;
76
+ clip: rect(0 0 0 0);
77
+ clip-path: inset(50%);
78
+ white-space: nowrap;
79
+ }
80
+
81
+ @keyframes solidgate-checkout-spin {
82
+ to {
83
+ transform: rotate(360deg);
84
+ }
85
+ }
86
+
87
+ @media (prefers-reduced-motion: reduce) {
88
+ .solidgate-checkout-spinner {
89
+ animation-duration: 1.6s;
90
+ }
91
+ }
92
+
93
+ .solidgate-checkout-header {
94
+ position: relative;
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ gap: 16px;
99
+ margin-bottom: 16px;
100
+ }
101
+
102
+ .solidgate-checkout-dialog.is-branded .solidgate-checkout-header {
103
+ min-height: 70px;
104
+ margin: 0 -17px;
105
+ padding: 0 56px;
106
+ }
107
+
108
+ .solidgate-checkout-title {
109
+ margin: 0;
110
+ color: var(--color-text, #111827);
111
+ font-size: 18px;
112
+ font-weight: 600;
113
+ line-height: 1.3;
114
+ }
115
+
116
+ .solidgate-checkout-dialog.is-branded .solidgate-checkout-title {
117
+ color: #020203;
118
+ font-size: 24px;
119
+ font-weight: 900;
120
+ line-height: 1.15;
121
+ text-align: center;
122
+ }
123
+
124
+ .solidgate-checkout-close {
125
+ position: absolute;
126
+ left: 0;
127
+ top: 50%;
128
+ width: 36px;
129
+ height: 36px;
130
+ flex: none;
131
+ border: 1px solid var(--color-border, #d1d5db);
132
+ border-radius: 8px;
133
+ background: var(--color-bg, #f9fafb);
134
+ color: var(--color-text, #111827);
135
+ font-size: 22px;
136
+ transform: translateY(-50%);
137
+ cursor: pointer;
138
+ }
139
+
140
+ .solidgate-checkout-dialog.is-branded .solidgate-checkout-close {
141
+ left: 16px;
142
+ width: 40px;
143
+ height: 40px;
144
+ border: 0;
145
+ border-radius: 999px;
146
+ background: #f2f2f3;
147
+ color: #aaa;
148
+ }
149
+
150
+ .solidgate-checkout-close span,
151
+ .solidgate-checkout-close span::after {
152
+ position: absolute;
153
+ left: 50%;
154
+ top: 50%;
155
+ width: 22px;
156
+ height: 3px;
157
+ border-radius: 999px;
158
+ background: currentColor;
159
+ content: '';
160
+ }
161
+
162
+ .solidgate-checkout-close span {
163
+ transform: translate(-50%, -50%) rotate(45deg);
164
+ }
165
+
166
+ .solidgate-checkout-close span::after {
167
+ transform: translate(-50%, -50%) rotate(90deg);
168
+ }
169
+
170
+ .solidgate-checkout-close:hover {
171
+ background: var(--color-accent-soft, #eef2ff);
172
+ }
173
+
174
+ .solidgate-checkout-summary {
175
+ color: #303136;
176
+ }
177
+
178
+ .solidgate-checkout-countdown {
179
+ min-height: 37px;
180
+ display: flex;
181
+ align-items: center;
182
+ justify-content: center;
183
+ margin: 0;
184
+ border-radius: 12px;
185
+ background: color-mix(in srgb, var(--solidgate-checkout-theme-color) 10%, #fff);
186
+ color: var(--solidgate-checkout-theme-color);
187
+ font-size: 16px;
188
+ font-weight: 900;
189
+ text-align: center;
190
+ }
191
+
192
+ .solidgate-checkout-satisfaction {
193
+ margin: 17px 0 21px;
194
+ color: #2f3034;
195
+ font-size: 19px;
196
+ font-weight: 800;
197
+ line-height: 1.15;
198
+ text-align: center;
199
+ }
200
+
201
+ .solidgate-checkout-satisfaction strong {
202
+ color: var(--solidgate-checkout-theme-color);
203
+ }
204
+
205
+ .solidgate-checkout-price-stack {
206
+ display: flex;
207
+ flex-direction: column;
208
+ gap: 8px;
209
+ }
210
+
211
+ .solidgate-checkout-price-row,
212
+ .solidgate-checkout-promo,
213
+ .solidgate-checkout-total {
214
+ display: flex;
215
+ align-items: center;
216
+ justify-content: space-between;
217
+ gap: 12px;
218
+ }
219
+
220
+ .solidgate-checkout-price-row {
221
+ font-size: 17px;
222
+ }
223
+
224
+ .solidgate-checkout-price-row.is-muted {
225
+ color: #9d9d9f;
226
+ font-weight: 500;
227
+ }
228
+
229
+ .solidgate-checkout-strike {
230
+ text-decoration: line-through 2px;
231
+ }
232
+
233
+ .solidgate-checkout-price-row.is-discount {
234
+ color: #040508;
235
+ font-weight: 900;
236
+ }
237
+
238
+ .solidgate-checkout-price-row.is-discount strong:last-child {
239
+ color: #ff2544;
240
+ }
241
+
242
+ .solidgate-checkout-promo {
243
+ min-height: 42px;
244
+ border-radius: 13px;
245
+ background: #f0f0f0;
246
+ padding: 0 14px;
247
+ color: #8d8d90;
248
+ font-size: 16px;
249
+ }
250
+
251
+ .solidgate-checkout-promo strong {
252
+ color: #050609;
253
+ font-weight: 900;
254
+ }
255
+
256
+ .solidgate-checkout-total {
257
+ min-height: 76px;
258
+ margin-top: 20px;
259
+ border-top: 1px solid #dedede;
260
+ font-size: 23px;
261
+ font-weight: 800;
262
+ }
263
+
264
+ .solidgate-checkout-total.is-plain {
265
+ margin-top: 0;
266
+ }
267
+
268
+ .solidgate-checkout-total strong {
269
+ font-size: 25px;
270
+ font-weight: 900;
271
+ }
272
+
273
+ .solidgate-checkout-saved {
274
+ width: fit-content;
275
+ min-height: 36px;
276
+ display: flex;
277
+ align-items: center;
278
+ gap: 7px;
279
+ margin: 0 auto 12px;
280
+ border-radius: 999px;
281
+ background: #fff3cf;
282
+ padding: 0 13px;
283
+ color: #2e3034;
284
+ font-size: 14px;
285
+ font-weight: 800;
286
+ }
287
+
288
+ .solidgate-checkout-email-form,
289
+ .solidgate-checkout-email-label,
290
+ .solidgate-checkout-wallets {
291
+ display: grid;
292
+ }
293
+
294
+ .solidgate-checkout-email-form {
295
+ gap: 16px;
296
+ }
297
+
298
+ .solidgate-checkout-email-label {
299
+ gap: 8px;
300
+ color: var(--color-text, #111827);
301
+ font-size: 14px;
302
+ font-weight: 500;
303
+ }
304
+
305
+ .solidgate-checkout-email-input {
306
+ box-sizing: border-box;
307
+ width: 100%;
308
+ min-height: 44px;
309
+ border: 1px solid var(--color-border, #d1d5db);
310
+ border-radius: 8px;
311
+ background: var(--color-bg, #fff);
312
+ padding: 8px 12px;
313
+ color: var(--color-text, #111827);
314
+ font: inherit;
315
+ }
316
+
317
+ .solidgate-checkout-email-input::placeholder,
318
+ .solidgate-checkout-status,
319
+ .solidgate-checkout-status-text {
320
+ color: var(--color-text-muted, #6b7280);
321
+ }
322
+
323
+ .solidgate-checkout-email-input:focus-visible,
324
+ .solidgate-checkout-close:focus-visible,
325
+ .solidgate-checkout-action:focus-visible {
326
+ outline: 2px solid var(--color-accent, #3f51b5);
327
+ outline-offset: 2px;
328
+ }
329
+
330
+ .solidgate-checkout-alert {
331
+ margin: 0;
332
+ color: var(--color-danger, #b91c1c);
333
+ font-size: 14px;
334
+ }
335
+
336
+ .solidgate-checkout-action {
337
+ box-sizing: border-box;
338
+ width: 100%;
339
+ min-height: 44px;
340
+ border: 1px solid var(--color-accent, #3f51b5);
341
+ border-radius: 8px;
342
+ background: var(--color-accent, #3f51b5);
343
+ padding: 8px 16px;
344
+ color: var(--color-primary-text, #fff);
345
+ font: inherit;
346
+ font-weight: 600;
347
+ cursor: pointer;
348
+ }
349
+
350
+ .solidgate-checkout-action:disabled {
351
+ cursor: not-allowed;
352
+ opacity: 0.6;
353
+ }
354
+
355
+ .solidgate-checkout-action--spaced {
356
+ margin-top: 16px;
357
+ }
358
+
359
+ .solidgate-checkout-wallets {
360
+ gap: 12px;
361
+ margin-bottom: 12px;
362
+ }
363
+
364
+ .solidgate-checkout-dialog.is-branded .solidgate-checkout-wallets {
365
+ margin-top: 4px;
366
+ }
367
+
368
+ .solidgate-checkout-dialog.is-branded .solidgate-checkout-wallets > div:not(:empty) {
369
+ min-height: 48px;
370
+ }
371
+
372
+ .solidgate-checkout-secure {
373
+ width: fit-content;
374
+ margin: 14px auto 0;
375
+ border-radius: 999px;
376
+ background: #edfff4;
377
+ padding: 8px 14px;
378
+ color: #2b2d31;
379
+ font-size: 13px;
380
+ font-weight: 700;
381
+ }
382
+
383
+ .solidgate-checkout-payment[hidden] {
384
+ display: none;
385
+ }
386
+
387
+ .solidgate-checkout-status {
388
+ margin-top: 12px;
389
+ border: 1px solid var(--color-border, #d1d5db);
390
+ border-radius: 12px;
391
+ background: var(--color-bg, #f9fafb);
392
+ padding: 16px;
393
+ font-size: 14px;
394
+ }
395
+
396
+ .solidgate-checkout-status p,
397
+ .solidgate-checkout-status-text {
398
+ margin: 0;
399
+ }
400
+ `;
@@ -0,0 +1,66 @@
1
+ import type { FunnelSdkRuntimeConfigOverrides, FunnelStepType, RuntimeMode } from '@funnelsgrove/runtime';
2
+ import type { PrepareSolidgateCheckoutInput, SolidgateCheckoutPreparation } from '../services/solidgate.service.js';
3
+ export type SolidgateCheckoutDialogState = 'collecting_email' | 'loading' | 'ready' | 'submitting' | 'verifying' | 'success' | 'recoverable_error' | 'expired';
4
+ export type SolidgateCheckoutDialogContent = {
5
+ title: string;
6
+ closeAriaLabel: string;
7
+ loading: string;
8
+ submitting: string;
9
+ verifying: string;
10
+ success: string;
11
+ error: string;
12
+ expired: string;
13
+ retry: string;
14
+ resumeVerification: string;
15
+ customerEmailLabel: string;
16
+ customerEmailPlaceholder: string;
17
+ customerEmailInvalid: string;
18
+ customerEmailUnavailable: string;
19
+ customerEmailContinue: string;
20
+ };
21
+ export type SolidgateCheckoutDialogPresentation = {
22
+ buttonColor: string;
23
+ cardSubmitLabel: string;
24
+ countdownLabel: string;
25
+ discountAmountLabel: string;
26
+ discountLabel: string;
27
+ discountPercent: number;
28
+ originalPriceLabel: string;
29
+ originalPriceValue: string;
30
+ promoActive: boolean;
31
+ promoCode: string;
32
+ promoCodeLabel: string;
33
+ remainingSeconds: number;
34
+ satisfactionLabel: string;
35
+ satisfactionPercent: string;
36
+ savedLabel: string;
37
+ secureLabel: string;
38
+ themeColor: string;
39
+ title: string;
40
+ totalLabel: string;
41
+ totalValue: string;
42
+ };
43
+ export type SolidgateCheckoutDialogProps = {
44
+ open: boolean;
45
+ request: Omit<PrepareSolidgateCheckoutInput, 'signal'>;
46
+ customerEmail?: string | null;
47
+ checkoutAnalytics?: SolidgateCheckoutAnalyticsContext | null;
48
+ content?: Partial<SolidgateCheckoutDialogContent>;
49
+ presentation?: SolidgateCheckoutDialogPresentation;
50
+ onClose: () => void;
51
+ onCustomerEmailCommit?: (email: string) => Promise<string>;
52
+ onSuccess?: (checkout: SolidgateCheckoutPreparation) => void | Promise<void>;
53
+ onRetry?: () => void;
54
+ onError?: (message: string) => void;
55
+ onStateChange?: (state: SolidgateCheckoutDialogState) => void;
56
+ };
57
+ export type SolidgateCheckoutAnalyticsContext = {
58
+ environment?: RuntimeMode;
59
+ featureFlags?: Record<string, string | null | undefined>;
60
+ metadata?: Record<string, unknown> | null;
61
+ runtimeConfig?: FunnelSdkRuntimeConfigOverrides;
62
+ stepId: string;
63
+ stepName: string;
64
+ stepType: Extract<FunnelStepType, 'checkout' | 'paywall_offer' | 'upsell_offer'>;
65
+ stepContractVersion: number;
66
+ };
@@ -0,0 +1,4 @@
1
+ import type { SolidgateCheckoutDialogPresentation } from './SolidgateCheckoutDialog.types.js';
2
+ export declare function SolidgateCheckoutSummary({ presentation }: {
3
+ presentation: SolidgateCheckoutDialogPresentation;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,15 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ const formatCountdown = (remainingSeconds) => {
3
+ const normalizedSeconds = Number.isFinite(remainingSeconds)
4
+ ? Math.max(0, Math.floor(remainingSeconds))
5
+ : 0;
6
+ const minutes = Math.floor(normalizedSeconds / 60);
7
+ const seconds = normalizedSeconds % 60;
8
+ return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
9
+ };
10
+ export function SolidgateCheckoutSummary({ presentation }) {
11
+ const showPromo = Boolean((presentation === null || presentation === void 0 ? void 0 : presentation.promoActive) &&
12
+ presentation.discountPercent > 0 &&
13
+ presentation.promoCode.trim());
14
+ return (_jsxs("section", { className: 'solidgate-checkout-summary', children: [showPromo ? (_jsxs("p", { className: 'solidgate-checkout-countdown', children: [presentation.discountPercent, "% ", presentation.countdownLabel, ' ', formatCountdown(presentation.remainingSeconds), " min"] })) : null, _jsxs("p", { className: 'solidgate-checkout-satisfaction', children: [_jsx("strong", { children: presentation.satisfactionPercent }), ' ', presentation.satisfactionLabel] }), showPromo ? (_jsxs("div", { className: 'solidgate-checkout-price-stack', children: [_jsxs("div", { className: 'solidgate-checkout-price-row is-muted', children: [_jsx("span", { children: presentation.originalPriceLabel }), _jsx("span", { className: 'solidgate-checkout-strike', children: presentation.originalPriceValue })] }), _jsxs("div", { className: 'solidgate-checkout-price-row is-discount', children: [_jsx("strong", { children: presentation.discountLabel }), _jsx("strong", { children: presentation.discountAmountLabel })] }), _jsxs("div", { className: 'solidgate-checkout-promo', children: [_jsx("span", { children: presentation.promoCodeLabel }), _jsx("strong", { children: presentation.promoCode.trim() })] })] })) : null, _jsxs("div", { className: `solidgate-checkout-total${showPromo ? '' : ' is-plain'}`, children: [_jsx("span", { children: presentation.totalLabel }), _jsx("strong", { children: presentation.totalValue })] }), showPromo ? (_jsxs("p", { className: 'solidgate-checkout-saved', children: [_jsx("span", { "aria-hidden": 'true', children: "\uD83D\uDD25" }), presentation.savedLabel] })) : null] }));
15
+ }
@@ -0,0 +1,12 @@
1
+ import type { SolidgateCheckoutPreparation } from '../services/solidgate.service.js';
2
+ export declare function SolidgatePaymentForm({ buttonColor, cardSubmitLabel, checkout, hidden, loadingLabel, onError, onMounted, onSubmit, onVerify, }: {
3
+ buttonColor: string;
4
+ cardSubmitLabel: string;
5
+ checkout: SolidgateCheckoutPreparation;
6
+ hidden: boolean;
7
+ loadingLabel: string;
8
+ onError: () => void;
9
+ onMounted: () => void;
10
+ onSubmit: () => void;
11
+ onVerify: () => void;
12
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,114 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Suspense, lazy, useEffect, useRef } from 'react';
4
+ const SolidgatePayment = lazy(async () => ({
5
+ default: (await import('@solidgate/react-sdk')).default,
6
+ }));
7
+ const safeDestroyPaymentForm = (instance) => {
8
+ var _a;
9
+ try {
10
+ instance === null || instance === void 0 ? void 0 : instance.unsubscribeAll();
11
+ }
12
+ catch (_b) {
13
+ // The global destroy below is the final cleanup boundary.
14
+ }
15
+ try {
16
+ (_a = window.PaymentFormSdk) === null || _a === void 0 ? void 0 : _a.destroy();
17
+ }
18
+ catch (_c) {
19
+ // Cleanup must stay safe when the remote SDK is partially initialized.
20
+ }
21
+ };
22
+ export function SolidgatePaymentForm({ buttonColor, cardSubmitLabel, checkout, hidden, loadingLabel, onError, onMounted, onSubmit, onVerify, }) {
23
+ const instanceRef = useRef(null);
24
+ const submittedRef = useRef(false);
25
+ const paymentBoundaryRef = useRef(null);
26
+ const mountedReportedRef = useRef(false);
27
+ const onMountedRef = useRef(onMounted);
28
+ const applePayContainerRef = useRef(null);
29
+ const googlePayContainerRef = useRef(null);
30
+ useEffect(() => {
31
+ onMountedRef.current = onMounted;
32
+ }, [onMounted]);
33
+ useEffect(() => {
34
+ mountedReportedRef.current = false;
35
+ const boundary = paymentBoundaryRef.current;
36
+ if (!boundary) {
37
+ return;
38
+ }
39
+ const reportIframeMounted = () => {
40
+ if (!mountedReportedRef.current
41
+ && boundary.querySelector('iframe#solid-payment-form-iframe, iframe[name="solid-payment-form-iframe"]')) {
42
+ mountedReportedRef.current = true;
43
+ onMountedRef.current();
44
+ }
45
+ };
46
+ reportIframeMounted();
47
+ const observer = new MutationObserver(reportIframeMounted);
48
+ observer.observe(boundary, { childList: true, subtree: true });
49
+ return () => observer.disconnect();
50
+ }, [checkout.attemptId]);
51
+ useEffect(() => {
52
+ submittedRef.current = false;
53
+ return () => {
54
+ safeDestroyPaymentForm(instanceRef.current);
55
+ instanceRef.current = null;
56
+ };
57
+ }, [checkout.attemptId]);
58
+ const walletButtonType = checkout.display.billingInterval ? 'subscribe' : 'buy';
59
+ return (_jsxs("div", { ref: paymentBoundaryRef, className: 'solidgate-checkout-payment', "data-solidgate-attempt-id": checkout.attemptId, hidden: hidden, "aria-hidden": hidden || undefined, children: [_jsxs("div", { className: 'solidgate-checkout-wallets', children: [_jsx("div", { ref: applePayContainerRef, "data-solidgate-wallet": 'apple-pay' }), _jsx("div", { ref: googlePayContainerRef, "data-solidgate-wallet": 'google-pay' })] }), _jsx(Suspense, { fallback: (_jsx("p", { role: 'status', className: 'solidgate-checkout-status-text', children: loadingLabel })), children: _jsx(SolidgatePayment, { merchantData: checkout.initialization.merchantData, width: '100%', formParams: {
60
+ autoFocus: false,
61
+ isSolidLogoVisible: true,
62
+ submitButtonText: cardSubmitLabel,
63
+ }, styles: {
64
+ form_body: {
65
+ 'font-family': 'Inter, Arial, sans-serif',
66
+ },
67
+ input_group: {
68
+ input: {
69
+ 'border-color': '#d8d9dd',
70
+ 'border-radius': '10px',
71
+ },
72
+ },
73
+ submit_button: {
74
+ 'background-color': buttonColor,
75
+ 'border-radius': '10px',
76
+ 'font-size': '16px',
77
+ 'font-weight': '800',
78
+ height: '52px',
79
+ },
80
+ }, applePayButtonParams: {
81
+ color: 'black',
82
+ enabled: true,
83
+ integrationType: 'js',
84
+ type: walletButtonType,
85
+ }, googlePayButtonParams: {
86
+ color: 'black',
87
+ enabled: true,
88
+ type: walletButtonType,
89
+ }, applePayContainerRef: applePayContainerRef, googlePayContainerRef: googlePayContainerRef, onReadyPaymentInstance: (instance) => {
90
+ if (instanceRef.current && instanceRef.current !== instance) {
91
+ try {
92
+ instanceRef.current.unsubscribeAll();
93
+ }
94
+ catch (_a) {
95
+ // The active instance remains usable even if stale-listener cleanup fails.
96
+ }
97
+ }
98
+ instanceRef.current = instance;
99
+ }, onMounted: () => {
100
+ if (!mountedReportedRef.current) {
101
+ mountedReportedRef.current = true;
102
+ onMountedRef.current();
103
+ }
104
+ }, onSubmit: () => {
105
+ submittedRef.current = true;
106
+ onSubmit();
107
+ }, onVerify: onVerify, onSuccess: onVerify, onFail: onVerify, onError: () => {
108
+ if (submittedRef.current) {
109
+ onVerify();
110
+ return;
111
+ }
112
+ onError();
113
+ } }, checkout.attemptId) })] }));
114
+ }
@@ -110,7 +110,7 @@ const parseStatus = (value) => {
110
110
  };
111
111
  };
112
112
  export const prepareSolidgateCheckout = async (input) => {
113
- var _a, _b, _c, _d;
113
+ var _a, _b, _c, _d, _e;
114
114
  const useV2 = ((_a = input.runtimeConfig) === null || _a === void 0 ? void 0 : _a.paymentsApiVersion) === 'v2';
115
115
  const paymentProfileId = ((_b = input.paymentProfileId) === null || _b === void 0 ? void 0 : _b.trim()) || null;
116
116
  const providerPlanId = ((_c = input.providerPlanId) === null || _c === void 0 ? void 0 : _c.trim()) || null;
@@ -121,7 +121,7 @@ export const prepareSolidgateCheckout = async (input) => {
121
121
  }
122
122
  return parsePreparation(await postJson(useV2
123
123
  ? '/sdk/public/v2/payments/checkout-sessions'
124
- : '/sdk/public/payments/solidgate/checkout', Object.assign(Object.assign({}, (useV2 ? {
124
+ : '/sdk/public/payments/solidgate/checkout', Object.assign(Object.assign(Object.assign(Object.assign({}, (useV2 ? {
125
125
  checkoutType,
126
126
  uiMode: 'custom',
127
127
  environment,
@@ -129,7 +129,9 @@ export const prepareSolidgateCheckout = async (input) => {
129
129
  provider: 'solidgate',
130
130
  providerPlanId,
131
131
  planKey: requiredString(input.funnelPlanKey, 'funnelPlanKey'),
132
- } : {})), { funnelId: resolveFunnelId(input.funnelId, input.runtimeConfig), funnelEndUserId: requiredString(input.funnelEndUserId, 'funnelEndUserId'), offerSetId: requiredString(input.offerSetId, 'offerSetId'), funnelPlanKey: requiredString(input.funnelPlanKey, 'funnelPlanKey'), idempotencyKey: requiredString(input.idempotencyKey, 'idempotencyKey'), discountKeyOrProviderId: ((_d = input.discountKeyOrProviderId) === null || _d === void 0 ? void 0 : _d.trim()) || null, returnUrl: requiredString(input.returnUrl, 'returnUrl'), successUrl: requiredString(input.successUrl, 'successUrl'), failUrl: requiredString(input.failUrl, 'failUrl') }), input.runtimeConfig, input.signal));
132
+ } : {})), { funnelId: resolveFunnelId(input.funnelId, input.runtimeConfig), funnelEndUserId: requiredString(input.funnelEndUserId, 'funnelEndUserId'), offerSetId: requiredString(input.offerSetId, 'offerSetId'), funnelPlanKey: requiredString(input.funnelPlanKey, 'funnelPlanKey'), idempotencyKey: requiredString(input.idempotencyKey, 'idempotencyKey') }), (useV2
133
+ ? { couponId: ((_d = input.discountKeyOrProviderId) === null || _d === void 0 ? void 0 : _d.trim()) || null }
134
+ : { discountKeyOrProviderId: ((_e = input.discountKeyOrProviderId) === null || _e === void 0 ? void 0 : _e.trim()) || null })), { returnUrl: requiredString(input.returnUrl, 'returnUrl'), successUrl: requiredString(input.successUrl, 'successUrl'), failUrl: requiredString(input.failUrl, 'failUrl') }), input.runtimeConfig, input.signal));
133
135
  };
134
136
  export const retrieveSolidgateCheckoutStatus = async (input) => {
135
137
  var _a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/payments",
3
- "version": "0.11.24",
3
+ "version": "0.11.26",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/The-Solid-Grove/funnelsgrove.git",