diff --git a/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.styles.ts b/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.styles.ts index df5fea79316..fd6bf4dd51d 100644 --- a/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.styles.ts +++ b/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.styles.ts @@ -1,13 +1,16 @@ import { StyleSheet } from 'react-native'; import { Theme } from '../../../../../../util/theme/models'; -const styleSheet = (params: { theme: Theme }) => +const styleSheet = (params: { theme: Theme; vars: { providerBg: string } }) => StyleSheet.create({ headerWithoutPadding: { paddingVertical: 0, }, webview: { - backgroundColor: params.theme.colors.background.default, + // Matches the provider iframe background to suppress the native white + // flash before content loads. Unknown providers receive the BottomSheet + // default surface color from getProviderWebviewColors. + backgroundColor: params.vars.providerBg, }, }); diff --git a/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.tsx b/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.tsx index 1d2253510e8..588ffc0fdf4 100644 --- a/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.tsx +++ b/app/components/UI/Ramp/Aggregator/Views/Checkout/Checkout.tsx @@ -38,6 +38,9 @@ import { } from '../../../../../../component-library/components/Icons/Icon'; import { useStyles } from '../../../../../../component-library/hooks'; import styleSheet from './Checkout.styles'; +import { useTheme } from '../../../../../../util/theme'; +import { AppThemeKey } from '../../../../../../util/theme/models'; +import { getProviderWebviewColors } from '../../../utils/getProviderWebviewColors'; import Device from '../../../../../../util/device'; import { shouldStartLoadWithRequest } from '../../../../../../util/browser'; import { CHECKOUT_TEST_IDS } from './Checkout.testIds'; @@ -66,10 +69,18 @@ const CheckoutWebView = () => { const params = useParams(); const handleSuccessfulOrder = useHandleSuccessfulOrder(); - const { styles } = useStyles(styleSheet, {}); - const { url: uri, customOrderId, provider } = params; + // Resolve the provider's iframe background color for the current theme. + // Applied to both the component-library BottomSheet (via providerBgStyle) and + // the WebView (via styles.webview) so the native chrome matches the embedded + // checkout seamlessly. Unknown providers fall back to the BottomSheet default surface. + const { themeAppearance } = useTheme(); + const isDark = themeAppearance === AppThemeKey.dark; + const providerBg = getProviderWebviewColors(provider?.id, isDark); + const { styles } = useStyles(styleSheet, { providerBg }); + const providerBgStyle = { backgroundColor: providerBg }; + const handleCancelPress = useCallback(() => { const chainId = selectedAsset?.network?.chainId || ''; if (isBuy) { @@ -252,6 +263,7 @@ const CheckoutWebView = () => { isFullscreen isInteractable={!Device.isAndroid()} keyboardAvoidingViewEnabled={false} + style={providerBgStyle} > +const styleSheet = (params: { theme: Theme; vars: { providerBg: string } }) => StyleSheet.create({ headerWithoutPadding: { paddingVertical: 0, }, webview: { - backgroundColor: params.theme.colors.background.default, + // Matches the provider iframe background to suppress the native white + // flash before content loads. Unknown providers receive the BottomSheet + // default surface color from getProviderWebviewColors. + backgroundColor: params.vars.providerBg, }, }); diff --git a/app/components/UI/Ramp/Views/Checkout/Checkout.tsx b/app/components/UI/Ramp/Views/Checkout/Checkout.tsx index 36112af360f..156f7711895 100644 --- a/app/components/UI/Ramp/Views/Checkout/Checkout.tsx +++ b/app/components/UI/Ramp/Views/Checkout/Checkout.tsx @@ -44,6 +44,9 @@ import { } from '../../headless/headlessEntryNavigation'; import { useStyles } from '../../../../hooks/useStyles'; import styleSheet from './Checkout.styles'; +import { useTheme } from '../../../../../util/theme'; +import { AppThemeKey } from '../../../../../util/theme/models'; +import { getProviderWebviewColors } from '../../utils/getProviderWebviewColors'; import Device from '../../../../../util/device'; import { shouldStartLoadWithRequest } from '../../../../../util/browser'; import { CHECKOUT_TEST_IDS } from './Checkout.testIds'; @@ -98,7 +101,7 @@ const Checkout = () => { const [key, setKey] = useState(0); const navigation = useNavigation(); const params = useParams(); - const { styles } = useStyles(styleSheet, {}); + const { themeAppearance } = useTheme(); const { addOrder, addPrecreatedOrder, getOrderFromCallback } = useRampsOrders(); const { trackEvent, createEventBuilder } = useAnalytics(); @@ -116,6 +119,16 @@ const Checkout = () => { cryptocurrency, headlessSessionId, } = params ?? {}; + + // Resolve the provider's iframe background color for the current theme. + // Applied to both the MMDS BottomSheet (via twClassName) and the WebView + // (via styles.webview) so the native chrome matches the embedded checkout + // seamlessly. Unknown providers fall back to the BottomSheet default surface. + const isDark = themeAppearance === AppThemeKey.dark; + const providerBg = getProviderWebviewColors(providerCode, isDark); + const { styles } = useStyles(styleSheet, { providerBg }); + const providerBgTwClassName = `bg-[${providerBg}]`; + const effectiveOrderId = (orderIdParam ?? customOrderId)?.trim() || null; // Headless deposit (TRAM-3623): when a headless session drives this Checkout, @@ -695,6 +708,7 @@ const Checkout = () => { isFullscreen isInteractable={!Device.isAndroid()} keyboardAvoidingViewEnabled={false} + twClassName={providerBgTwClassName} > {sharedHeader} = { + // Defaults to MMDS BottomSheet surface colors when no provider-specific + // color is known, ensuring the WebView background always matches the sheet. + default: { + dark: darkTheme.colors.background.alternative, + light: lightTheme.colors.background.default, + }, + transak: { dark: colors.transakCheckoutDark, light: brandColor.white }, + moonpay: { dark: colors.moonpayCheckoutDark, light: brandColor.white }, + banxa: { dark: colors.banxaCheckoutDark, light: brandColor.white }, +}; + +/** + * Returns the provider's iframe background color for the current theme. + * Falls back to the MMDS BottomSheet default surface for unknown providers. + */ +export function getProviderWebviewColors( + providerCode: string | undefined, + isDark: boolean, +): string { + const key = + providerCode && + Object.keys(PROVIDER_WEBVIEW_COLORS).find( + (k) => k !== 'default' && providerCode.toLowerCase().includes(k), + ); + const entry = PROVIDER_WEBVIEW_COLORS[key || 'default']; + return isDark ? entry.dark : entry.light; +} diff --git a/app/styles/common.ts b/app/styles/common.ts index 13de042dbbe..a6b7035547b 100644 --- a/app/styles/common.ts +++ b/app/styles/common.ts @@ -27,6 +27,13 @@ export const colors = { gettingStartedPageBackgroundColor: '#EAC2FF', gettingStartedTextColor: '#3D065F', gettingStartedPageBackgroundColorLightMode: '#FFF2EB', + // Provider iframe backgrounds — these colors are set by each provider and + // outside our control. We match them in the checkout BottomSheet so the + // native chrome feels seamless with the embedded webview. Update only if + // a provider changes their iframe theme colors. + transakCheckoutDark: '#1a1a1a', + moonpayCheckoutDark: '#131416', + banxaCheckoutDark: '#0D0D0F', }; export const onboardingCarouselColors: Record<