From 29775bf455e278cc82b560843380d5f8f91809c5 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Thu, 9 Apr 2026 16:44:21 +0100 Subject: [PATCH] feat: bump ShopifyCheckoutSheetKit dependency to 3.8.0 --- README.md | 172 ++++++++++++++++++ .../RNShopifyCheckoutSheetKit.podspec | 4 +- ...cceleratedCheckoutButtons+Extensions.swift | 20 ++ .../ios/AcceleratedCheckoutButtons.swift | 39 +++- .../ios/ShopifyCheckoutSheetKit.mm | 5 + .../@shopify/checkout-sheet-kit/package.json | 2 +- .../components/AcceleratedCheckoutButtons.tsx | 16 ++ .../@shopify/checkout-sheet-kit/src/index.ts | 3 +- sample/ios/Podfile.lock | 18 +- sample/src/context/Config.tsx | 4 +- sample/src/screens/CartScreen.tsx | 3 + sample/src/screens/ProductDetailsScreen.tsx | 3 + sample/src/screens/SettingsScreen.tsx | 53 +++++- 13 files changed, 316 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f06fc42b..31e10f04 100644 --- a/README.md +++ b/README.md @@ -841,6 +841,178 @@ shopify.addEventListener('geolocationRequest', async (event: GeolocationRequestE --- +## Accelerated Checkouts + +Accelerated checkout buttons surface Apple Pay and Shop Pay options earlier in the buyer journey so more orders complete without leaving your app. + +### Prerequisites + +- iOS 16 or later +- The `write_cart_wallet_payments` access scope ([request access](https://www.appsheet.com/start/1ff317b6-2da1-4f39-b041-c01cfada6098)) +- Apple Pay payment processing certificates ([setup guide](https://shopify.dev/docs/storefronts/mobile/create-apple-payment-processing-certificates)) +- A device configured for Apple Pay ([Apple setup instructions](https://developer.apple.com/documentation/passkit/setting-up-apple-pay)) + +### Configure the integration + +Pass an `acceleratedCheckouts` configuration when setting up the provider or `ShopifyCheckoutSheet` instance. This connects the accelerated checkout buttons to your storefront. + +```tsx +import {ShopifyCheckoutSheetProvider} from '@shopify/checkout-sheet-kit'; + +const config = { + acceleratedCheckouts: { + storefrontDomain: 'your-shop.myshopify.com', + storefrontAccessToken: 'your-storefront-access-token', + customer: { + // For authenticated customers + accessToken: 'customer-access-token', + // OR for guest customers + // email: 'customer@example.com', + // phoneNumber: '0123456789', + }, + wallets: { + applePay: { + merchantIdentifier: 'merchant.com.yourcompany', + contactFields: ['email', 'phone'], + // Optionally restrict shipping countries (ISO 3166-1 alpha-2) + // supportedShippingCountries: ['US', 'CA'], + }, + }, + }, +}; + +function App() { + return ( + + + + ); +} +``` + +> [!WARNING] +> Do not provide both `accessToken` and `email`/`phoneNumber` together. For authenticated customers, email and phone are fetched automatically from the Shopify account. + +### Render accelerated checkout buttons + +Use `AcceleratedCheckoutButtons` to attach accelerated checkout calls-to-action to product or cart surfaces once you have a valid cart ID or product variant ID from the Storefront API. + +```tsx +import { + AcceleratedCheckoutButtons, + AcceleratedCheckoutWallet, +} from '@shopify/checkout-sheet-kit'; + +function CartFooter({cartId}: {cartId: string}) { + return ( + + ); +} +``` + +You can also render buttons for a single product variant: + +```tsx + +``` + +#### Customize wallet options + +Accelerated checkout buttons display every available wallet by default. Use `wallets` to show a subset or adjust the order. + +```tsx +// Display only Shop Pay + + +// Display Shop Pay first, then Apple Pay + +``` + +#### Modify the Apple Pay button label + +Use `applePayLabel` to map to the native `PayWithApplePayButtonLabel` values. The default is `plain`. + +```tsx +import {ApplePayLabel} from '@shopify/checkout-sheet-kit'; + + +``` + +#### Customize the Apple Pay button style + +Use `applePayStyle` to set the color style of the Apple Pay button. The default is `automatic`, which adapts to the current appearance (light/dark mode). + +```tsx +import {ApplePayStyle} from '@shopify/checkout-sheet-kit'; + + +``` + +Available styles: `automatic`, `black`, `white`, `whiteOutline`. + +#### Customize button corners + +The `cornerRadius` prop lets you match the buttons to other calls-to-action in your app. Buttons default to an 8pt radius. + +```tsx +// Pill-shaped buttons + + +// Square buttons + +``` + +### Handle loading, errors, and lifecycle events + +Attach lifecycle handlers to respond when buyers finish, cancel, or encounter an error. + +```tsx + { + // Clear cart after successful checkout + clearCart(); + }} + onFail={(error) => { + console.error('Accelerated checkout failed:', error); + }} + onCancel={() => { + analytics.track('accelerated_checkout_cancelled'); + }} + onRenderStateChange={(event) => { + // event.state: 'loading' | 'rendered' | 'error' + setRenderState(event.state); + }} + onWebPixelEvent={(event) => { + analytics.track(event); + }} + onClickLink={(url) => { + Linking.openURL(url); + }} +/> +``` + +--- + ## Contributing See the [contributing documentation](CONTRIBUTING.md) for details on how to get started. diff --git a/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec b/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec index 99c25f14..092b4913 100644 --- a/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec +++ b/modules/@shopify/checkout-sheet-kit/RNShopifyCheckoutSheetKit.podspec @@ -20,8 +20,8 @@ Pod::Spec.new do |s| s.source_files = "ios/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency "ShopifyCheckoutSheetKit", "~> 3.7.0" - s.dependency "ShopifyCheckoutSheetKit/AcceleratedCheckouts", "~> 3.7.0" + s.dependency "ShopifyCheckoutSheetKit", "~> 3.8.0" + s.dependency "ShopifyCheckoutSheetKit/AcceleratedCheckouts", "~> 3.8.0" if fabric_enabled # Use React Native's helper if available, otherwise add dependencies directly diff --git a/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons+Extensions.swift b/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons+Extensions.swift index 9e4c4df4..cddc7f6c 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons+Extensions.swift +++ b/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons+Extensions.swift @@ -58,3 +58,23 @@ extension PayWithApplePayButtonLabel { "topUp": .topUp ] } + +// MARK: - Apple Pay Button Style + +@available(iOS 16.0, *) +extension PayWithApplePayButtonStyle { + static func from(_ string: String?, fallback: PayWithApplePayButtonStyle = .automatic) -> PayWithApplePayButtonStyle { + guard let string, let value = map[string] else { + return fallback + } + + return value + } + + private static let map: [String: PayWithApplePayButtonStyle] = [ + "automatic": .automatic, + "black": .black, + "white": .white, + "whiteOutline": .whiteOutline + ] +} diff --git a/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons.swift b/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons.swift index 75a78b72..fcefb67c 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons.swift +++ b/modules/@shopify/checkout-sheet-kit/ios/AcceleratedCheckoutButtons.swift @@ -120,6 +120,12 @@ class RCTAcceleratedCheckoutButtonsView: UIView { } } + @objc var applePayStyle: String? { + didSet { + updateView() + } + } + @objc var onFail: RCTBubblingEventBlock? @objc var onComplete: RCTBubblingEventBlock? @objc var onCancel: RCTBubblingEventBlock? @@ -156,6 +162,17 @@ class RCTAcceleratedCheckoutButtonsView: UIView { hostingController?.view.frame = bounds } + // Deprecated in iOS 17 — superseded by registerForTraitChanges in setupView(). + // Remove this override when dropping iOS 16 support. + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + if #unavailable(iOS 17.0) { + if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) { + updateView() + } + } + } + override var intrinsicContentSize: CGSize { let height = calculateRequiredHeight() return CGSize(width: UIView.noIntrinsicMetric, height: height) @@ -172,6 +189,14 @@ class RCTAcceleratedCheckoutButtonsView: UIView { updateView() + // Replaces traitCollectionDidChange for iOS 17+. + // When dropping iOS 16 support, remove the traitCollectionDidChange override above. + if #available(iOS 17.0, *) { + registerForTraitChanges([UITraitUserInterfaceStyle.self]) { [weak self] (_: RCTAcceleratedCheckoutButtonsView, _: UITraitCollection) in + self?.updateView() + } + } + // Listen for configuration updates NotificationCenter.default.addObserver( self, @@ -207,7 +232,7 @@ class RCTAcceleratedCheckoutButtonsView: UIView { updateView() } - private func attachModifiers(to buttons: AcceleratedCheckoutButtons, wallets: [Wallet]?, applePayLabel: PayWithApplePayButtonLabel?) -> AcceleratedCheckoutButtons { + private func attachModifiers(to buttons: AcceleratedCheckoutButtons, wallets: [Wallet]?, applePayLabel: PayWithApplePayButtonLabel?, applePayStyle: PayWithApplePayButtonStyle) -> AcceleratedCheckoutButtons { var modifiedButtons = buttons if let wallets { @@ -218,6 +243,8 @@ class RCTAcceleratedCheckoutButtonsView: UIView { modifiedButtons = modifiedButtons.applePayLabel(applePayLabel) } + modifiedButtons = modifiedButtons.applePayStyle(applePayStyle) + if let cornerRadius { modifiedButtons = modifiedButtons.cornerRadius(CGFloat(cornerRadius.doubleValue)) } @@ -276,18 +303,20 @@ class RCTAcceleratedCheckoutButtonsView: UIView { return } - // Attach modifiers (wallets, applePayLabel, cornerRadius) - buttons = attachModifiers(to: buttons, wallets: shopifyWallets, applePayLabel: PayWithApplePayButtonLabel.from(applePayLabel)) + // Attach modifiers (wallets, applePayLabel, applePayStyle, cornerRadius) + buttons = attachModifiers(to: buttons, wallets: shopifyWallets, applePayLabel: PayWithApplePayButtonLabel.from(applePayLabel), applePayStyle: PayWithApplePayButtonStyle.from(applePayStyle)) // Attach event handlers buttons = attachEventListeners(to: buttons) var view: AnyView + let colorScheme: SwiftUI.ColorScheme = traitCollection.userInterfaceStyle == .dark ? .dark : .light + // Attach config (and Apple Pay config if available) if let applePayConfig = AcceleratedCheckoutConfiguration.shared.applePayConfiguration { - view = AnyView(buttons.environmentObject(config).environmentObject(applePayConfig)) + view = AnyView(buttons.environmentObject(config).environmentObject(applePayConfig).environment(\.colorScheme, colorScheme)) } else { - view = AnyView(buttons.environmentObject(config)) + view = AnyView(buttons.environmentObject(config).environment(\.colorScheme, colorScheme)) } if let hostingController { diff --git a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm index 2971cd2c..5a3d7017 100644 --- a/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm +++ b/modules/@shopify/checkout-sheet-kit/ios/ShopifyCheckoutSheetKit.mm @@ -106,6 +106,11 @@ @interface RCT_EXTERN_MODULE (RCTAcceleratedCheckoutButtonsManager, RCTViewManag */ RCT_EXPORT_VIEW_PROPERTY(applePayLabel, NSString*) +/** + * Style variant for the Apple Pay button (e.g., "automatic", "black", "white", "whiteOutline"). + */ +RCT_EXPORT_VIEW_PROPERTY(applePayStyle, NSString*) + /** * Emitted when checkout fails. Payload contains a CheckoutException-like shape. */ diff --git a/modules/@shopify/checkout-sheet-kit/package.json b/modules/@shopify/checkout-sheet-kit/package.json index efd4b641..3ddaf0de 100644 --- a/modules/@shopify/checkout-sheet-kit/package.json +++ b/modules/@shopify/checkout-sheet-kit/package.json @@ -1,7 +1,7 @@ { "name": "@shopify/checkout-sheet-kit", "license": "MIT", - "version": "3.7.0", + "version": "3.8.0", "main": "lib/commonjs/index.js", "types": "src/index.ts", "source": "src/index.ts", diff --git a/modules/@shopify/checkout-sheet-kit/src/components/AcceleratedCheckoutButtons.tsx b/modules/@shopify/checkout-sheet-kit/src/components/AcceleratedCheckoutButtons.tsx index 7958fe85..ab8971f7 100644 --- a/modules/@shopify/checkout-sheet-kit/src/components/AcceleratedCheckoutButtons.tsx +++ b/modules/@shopify/checkout-sheet-kit/src/components/AcceleratedCheckoutButtons.tsx @@ -61,6 +61,13 @@ export enum ApplePayLabel { topUp = 'topUp', } +export enum ApplePayStyle { + automatic = 'automatic', + black = 'black', + white = 'white', + whiteOutline = 'whiteOutline', +} + type CheckoutIdentifier = | { cartId: string; @@ -87,6 +94,12 @@ interface CommonAcceleratedCheckoutButtonsProps { */ applePayLabel?: ApplePayLabel; + /** + * Style for the Apple Pay button color + * Defaults to 'automatic' which adapts to the current appearance (light/dark mode) + */ + applePayStyle?: ApplePayStyle; + /** * Called when checkout fails */ @@ -148,6 +161,7 @@ export type AcceleratedCheckoutButtonsProps = (CartProps | VariantProps) & interface NativeAcceleratedCheckoutButtonsProps { applePayLabel?: string; + applePayStyle?: string; style?: ViewStyle; checkoutIdentifier: CheckoutIdentifier; cornerRadius?: number; @@ -193,6 +207,7 @@ export const AcceleratedCheckoutButtons: React.FC< AcceleratedCheckoutButtonsProps > = ({ applePayLabel, + applePayStyle, cornerRadius, wallets, onFail, @@ -307,6 +322,7 @@ export const AcceleratedCheckoutButtons: React.FC< return ( 3.7.0) - - ShopifyCheckoutSheetKit/AcceleratedCheckouts (~> 3.7.0) + - ShopifyCheckoutSheetKit (~> 3.8.0) + - ShopifyCheckoutSheetKit/AcceleratedCheckouts (~> 3.8.0) - SocketRocket - Yoga - RNVectorIcons (10.3.0): @@ -2638,11 +2638,11 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ShopifyCheckoutSheetKit (3.7.0): - - ShopifyCheckoutSheetKit/Core (= 3.7.0) - - ShopifyCheckoutSheetKit/AcceleratedCheckouts (3.7.0): + - ShopifyCheckoutSheetKit (3.8.0): + - ShopifyCheckoutSheetKit/Core (= 3.8.0) + - ShopifyCheckoutSheetKit/AcceleratedCheckouts (3.8.0): - ShopifyCheckoutSheetKit/Core - - ShopifyCheckoutSheetKit/Core (3.7.0) + - ShopifyCheckoutSheetKit/Core (3.8.0) - SocketRocket (0.7.1) - Yoga (0.0.0) @@ -2996,9 +2996,9 @@ SPEC CHECKSUMS: RNGestureHandler: eeb622199ef1fb3a076243131095df1c797072f0 RNReanimated: 288616f9c66ff4b0911f3862ffcf4104482a2adc RNScreens: 3fc29af06302e1f1c18a7829fe57cbc2c0259912 - RNShopifyCheckoutSheetKit: 979ca69f1abbd0b38c3e996879e77a5b42a0103a + RNShopifyCheckoutSheetKit: 5587e0fc360607d832f7f10f8436883d1db4b5ef RNVectorIcons: be4d047a76ad307ffe54732208fb0498fcb8477f - ShopifyCheckoutSheetKit: 5bdc6c6c0dafc5ef15daa5963c03547bf6bfff6a + ShopifyCheckoutSheetKit: 5253ca4da4c4f31069286509693930d02b4150d8 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: a742cc68e8366fcfc681808162492bc0aa7a9498 diff --git a/sample/src/context/Config.tsx b/sample/src/context/Config.tsx index a92d6296..407fde01 100644 --- a/sample/src/context/Config.tsx +++ b/sample/src/context/Config.tsx @@ -6,7 +6,7 @@ import React, { useMemo, useState, } from 'react'; -import {ColorScheme} from '@shopify/checkout-sheet-kit'; +import {ColorScheme, ApplePayStyle} from '@shopify/checkout-sheet-kit'; import EncryptedStorage from 'react-native-encrypted-storage'; import {useTheme} from './Theme'; import {BuyerIdentityMode} from '../auth/types'; @@ -14,6 +14,7 @@ import {BuyerIdentityMode} from '../auth/types'; export interface AppConfig { colorScheme: ColorScheme; buyerIdentityMode: BuyerIdentityMode; + applePayStyle?: ApplePayStyle; } interface Context { @@ -26,6 +27,7 @@ const CONFIG_STORAGE_KEY = 'app_config'; const defaultAppConfig: AppConfig = { colorScheme: ColorScheme.automatic, buyerIdentityMode: BuyerIdentityMode.Guest, + applePayStyle: ApplePayStyle.automatic, }; const ConfigContext = createContext({ diff --git a/sample/src/screens/CartScreen.tsx b/sample/src/screens/CartScreen.tsx index 54e828bc..e5712df3 100644 --- a/sample/src/screens/CartScreen.tsx +++ b/sample/src/screens/CartScreen.tsx @@ -41,6 +41,7 @@ import { ApplePayLabel, AcceleratedCheckoutWallet, } from '@shopify/checkout-sheet-kit'; +import {useConfig} from '../context/Config'; import useShopify from '../hooks/useShopify'; import type {CartLineItem} from '../../@types'; import type {Colors} from '../context/Theme'; @@ -55,6 +56,7 @@ function CartScreen(): React.JSX.Element { const {cartId, checkoutURL, totalQuantity, removeFromCart, addingToCart} = useCart(); const {queries} = useShopify(); + const {appConfig} = useConfig(); const eventHandlers = useShopifyEventHandlers( 'Cart - AcceleratedCheckoutButtons', ); @@ -167,6 +169,7 @@ function CartScreen(): React.JSX.Element { ; @@ -90,6 +91,7 @@ function ProductDetails({ loading?: boolean; onAddToCart: (variantId: string) => void; }) { + const {appConfig} = useConfig(); const {colors, cornerRadius} = useTheme(); const styles = createStyles(colors, cornerRadius); const image = product.images?.edges[0]?.node; @@ -126,6 +128,7 @@ function ProductDetails({ { + setAppConfig({ + ...appConfig, + applePayStyle: item.value as ApplePayStyle, + }); + }, + [appConfig, setAppConfig], + ); + const handleBuyerIdentityModeChange = useCallback( (item: SingleSelectItem) => { const newMode = item.value as BuyerIdentityMode; @@ -200,6 +211,27 @@ function SettingsScreen() { [appConfig.colorScheme], ); + const applePayStyleDisplayNames: Record = useMemo( + () => ({ + [ApplePayStyle.automatic]: 'Automatic', + [ApplePayStyle.black]: 'Black', + [ApplePayStyle.white]: 'White', + [ApplePayStyle.whiteOutline]: 'White Outline', + }), + [], + ); + + const applePayStyleOptions: readonly SingleSelectItem[] = useMemo( + () => + Object.values(ApplePayStyle).map(style => ({ + title: applePayStyleDisplayNames[style], + type: SectionType.SingleSelect as const, + value: style, + selected: appConfig.applePayStyle === style, + })), + [appConfig.applePayStyle, applePayStyleDisplayNames], + ); + const informationalItems: readonly TextItem[] = useMemo( () => [ { @@ -237,6 +269,12 @@ function SettingsScreen() { title: 'Theme', data: themeOptions, }, + { + title: 'Apple Pay Style', + footer: + 'Configures the visual style of the Apple Pay button.', + data: applePayStyleOptions, + }, { title: 'Versions', data: informationalItems, @@ -246,6 +284,7 @@ function SettingsScreen() { themeOptions, configurationOptions, buyerIdentityOptions, + applePayStyleOptions, informationalItems, ], ); @@ -263,16 +302,16 @@ function SettingsScreen() { } if (isSingleSelectItem(item)) { - const isAuthSection = section.title === 'Authentication'; + const sectionHandlers: Record void> = { + Authentication: handleBuyerIdentityModeChange, + 'Apple Pay Style': handleApplePayStyleChange, + }; + const handler = sectionHandlers[section.title] ?? handleColorSchemeChange; return ( - isAuthSection - ? handleBuyerIdentityModeChange(item) - : handleColorSchemeChange(item) - } + onPress={() => handler(item)} /> ); }