@moonpay/platform-sdk-react-native 1.1.0 → 1.2.0

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/dist/index.d.cts CHANGED
@@ -24,10 +24,11 @@ import * as GooglePaySdk from '@moonpay/platform-protocol/sdks/google-pay';
24
24
  export { Event as GooglePayEvent, SetupError as SetupGooglePayError } from '@moonpay/platform-protocol/sdks/google-pay';
25
25
  import * as WidgetSdk from '@moonpay/platform-protocol/sdks/widget';
26
26
  export { SetupError as SetupWidgetError, Event as WidgetEvent } from '@moonpay/platform-protocol/sdks/widget';
27
+ import { FrameTransport, FrameOptions, ThemeOptions, ListTransactionsParams } from '@moonpay/platform-sdk-core';
28
+ export { ThemeOptions } from '@moonpay/platform-sdk-core';
27
29
  import { GetPaymentMethodsError, GetQuoteError, GetTransactionsError, DevPlatformApiError, CreateIdentityError, GetIdentityError, UpdateIdentityError, VerifyIdentityError, GetIdentityUploadUrlError, SubmitIdentityFilesError } from '@moonpay/platform-protocol/api/errors';
28
30
  import { CreateIdentityRequestBody, Identity, UpdateIdentityRequestBody, IdentityVerificationResponse, IdentityFileUploadUrlRequestBody, IdentityFileUploadUrl, SubmitIdentityFilesRequestBody } from '@moonpay/platform-protocol/api/identity';
29
31
  import { ResetConnectionError } from '@moonpay/platform-protocol/sdks/reset';
30
- import { FrameTransport, FrameOptions, ListTransactionsParams } from '@moonpay/platform-sdk-core';
31
32
  import { ViewStyle } from 'react-native';
32
33
  import { ProtocolMessage } from '@moonpay/platform-protocol/protocol';
33
34
  import { RefObject, ReactNode } from 'react';
@@ -132,10 +133,8 @@ interface ChallengeFrame {
132
133
  }
133
134
 
134
135
  interface ConnectOptions {
135
- /** Theme options for the connect frame. */
136
- theme?: {
137
- appearance?: 'light' | 'dark';
138
- };
136
+ /** Theme for this connect frame. Overrides the provider-level `theme`. */
137
+ theme?: ThemeOptions;
139
138
  /** Callback for connect lifecycle events. */
140
139
  onEvent?: (event: ConnectSdk.Event) => void;
141
140
  }
@@ -306,10 +305,8 @@ interface MoonPayChallengeProps {
306
305
  declare function MoonPayChallenge({ url, onEvent, style }: MoonPayChallengeProps): JSX.Element;
307
306
 
308
307
  interface MoonPayConnectProps {
309
- /** Theme options for the connect frame. Mount-time only. */
310
- theme?: {
311
- appearance?: 'light' | 'dark';
312
- };
308
+ /** Theme for this connect frame. Overrides the provider-level `theme`. Mount-time only. */
309
+ theme?: ThemeOptions;
313
310
  /** Callback for connect lifecycle events. */
314
311
  onEvent?: (event: ConnectSdk.Event) => void;
315
312
  /** Container style. Defaults to flex: 1. */
@@ -398,9 +395,11 @@ interface MoonPayProviderProps {
398
395
  sessionToken: string;
399
396
  apiBaseUrl?: string;
400
397
  frameBaseUrl?: string;
398
+ /** Theme applied to every visible MoonPay frame (connect, widget, Apple/Google Pay, …). */
399
+ theme?: ThemeOptions;
401
400
  children: ReactNode;
402
401
  }
403
- declare function MoonPayProvider({ sessionToken, apiBaseUrl, frameBaseUrl, children, }: MoonPayProviderProps): JSX.Element;
402
+ declare function MoonPayProvider({ sessionToken, apiBaseUrl, frameBaseUrl, theme, children, }: MoonPayProviderProps): JSX.Element;
404
403
  declare function useMoonPay(): {
405
404
  client: RNClient;
406
405
  };
package/dist/index.d.ts CHANGED
@@ -24,10 +24,11 @@ import * as GooglePaySdk from '@moonpay/platform-protocol/sdks/google-pay';
24
24
  export { Event as GooglePayEvent, SetupError as SetupGooglePayError } from '@moonpay/platform-protocol/sdks/google-pay';
25
25
  import * as WidgetSdk from '@moonpay/platform-protocol/sdks/widget';
26
26
  export { SetupError as SetupWidgetError, Event as WidgetEvent } from '@moonpay/platform-protocol/sdks/widget';
27
+ import { FrameTransport, FrameOptions, ThemeOptions, ListTransactionsParams } from '@moonpay/platform-sdk-core';
28
+ export { ThemeOptions } from '@moonpay/platform-sdk-core';
27
29
  import { GetPaymentMethodsError, GetQuoteError, GetTransactionsError, DevPlatformApiError, CreateIdentityError, GetIdentityError, UpdateIdentityError, VerifyIdentityError, GetIdentityUploadUrlError, SubmitIdentityFilesError } from '@moonpay/platform-protocol/api/errors';
28
30
  import { CreateIdentityRequestBody, Identity, UpdateIdentityRequestBody, IdentityVerificationResponse, IdentityFileUploadUrlRequestBody, IdentityFileUploadUrl, SubmitIdentityFilesRequestBody } from '@moonpay/platform-protocol/api/identity';
29
31
  import { ResetConnectionError } from '@moonpay/platform-protocol/sdks/reset';
30
- import { FrameTransport, FrameOptions, ListTransactionsParams } from '@moonpay/platform-sdk-core';
31
32
  import { ViewStyle } from 'react-native';
32
33
  import { ProtocolMessage } from '@moonpay/platform-protocol/protocol';
33
34
  import { RefObject, ReactNode } from 'react';
@@ -132,10 +133,8 @@ interface ChallengeFrame {
132
133
  }
133
134
 
134
135
  interface ConnectOptions {
135
- /** Theme options for the connect frame. */
136
- theme?: {
137
- appearance?: 'light' | 'dark';
138
- };
136
+ /** Theme for this connect frame. Overrides the provider-level `theme`. */
137
+ theme?: ThemeOptions;
139
138
  /** Callback for connect lifecycle events. */
140
139
  onEvent?: (event: ConnectSdk.Event) => void;
141
140
  }
@@ -306,10 +305,8 @@ interface MoonPayChallengeProps {
306
305
  declare function MoonPayChallenge({ url, onEvent, style }: MoonPayChallengeProps): JSX.Element;
307
306
 
308
307
  interface MoonPayConnectProps {
309
- /** Theme options for the connect frame. Mount-time only. */
310
- theme?: {
311
- appearance?: 'light' | 'dark';
312
- };
308
+ /** Theme for this connect frame. Overrides the provider-level `theme`. Mount-time only. */
309
+ theme?: ThemeOptions;
313
310
  /** Callback for connect lifecycle events. */
314
311
  onEvent?: (event: ConnectSdk.Event) => void;
315
312
  /** Container style. Defaults to flex: 1. */
@@ -398,9 +395,11 @@ interface MoonPayProviderProps {
398
395
  sessionToken: string;
399
396
  apiBaseUrl?: string;
400
397
  frameBaseUrl?: string;
398
+ /** Theme applied to every visible MoonPay frame (connect, widget, Apple/Google Pay, …). */
399
+ theme?: ThemeOptions;
401
400
  children: ReactNode;
402
401
  }
403
- declare function MoonPayProvider({ sessionToken, apiBaseUrl, frameBaseUrl, children, }: MoonPayProviderProps): JSX.Element;
402
+ declare function MoonPayProvider({ sessionToken, apiBaseUrl, frameBaseUrl, theme, children, }: MoonPayProviderProps): JSX.Element;
404
403
  declare function useMoonPay(): {
405
404
  client: RNClient;
406
405
  };
package/dist/index.js CHANGED
@@ -6,7 +6,11 @@ import {
6
6
  ConnectionErrorCode,
7
7
  ConnectionStatus
8
8
  } from "@moonpay/platform-protocol/models/connection";
9
- import { decryptCredentials, FRAME_PATHS } from "@moonpay/platform-sdk-core";
9
+ import {
10
+ decryptCredentials,
11
+ FRAME_PATHS,
12
+ themeParams
13
+ } from "@moonpay/platform-sdk-core";
10
14
  function createQuoteCommands(send, channelId) {
11
15
  return {
12
16
  setQuote: (signature) => send({
@@ -174,7 +178,9 @@ var connectSpec = {
174
178
  buildParams: (ctx, props, publicKey) => ({
175
179
  sessionToken: ctx.sessionToken,
176
180
  publicKey,
177
- ...props.theme?.appearance && { appearance: props.theme.appearance }
181
+ // Per-call override; `applyThemeParam` in the engine fills the client
182
+ // default for connect (and every other visible frame) when this is absent.
183
+ ...themeParams(props.theme)
178
184
  }),
179
185
  onMessageEffect: applyCredentialsOnComplete,
180
186
  mapMessage: (msg) => {
@@ -408,6 +414,7 @@ function MoonPayFrame({ transport, hidden, style }) {
408
414
 
409
415
  // src/frame-engine.ts
410
416
  import {
417
+ applyThemeParam,
411
418
  buildFrameUrl,
412
419
  createFrameOrchestrator,
413
420
  generateKeyPair
@@ -479,11 +486,12 @@ function createFrameSession(spec, ctx, props, overrides = {}) {
479
486
  const generated = `${spec.channelPrefix}-${Date.now()}`;
480
487
  const channelId = spec.resolveChannelId ? spec.resolveChannelId(props, generated) : generated;
481
488
  const keyPair = spec.needsKeyPair ? generateKeyPair() : void 0;
482
- const url = spec.buildUrl ? spec.buildUrl(ctx, props, channelId, keyPair?.publicKey) : buildFrameUrl(
489
+ const builtUrl = spec.buildUrl ? spec.buildUrl(ctx, props, channelId, keyPair?.publicKey) : buildFrameUrl(
483
490
  spec.path,
484
491
  { ...spec.buildParams?.(ctx, props, keyPair?.publicKey), channelId },
485
492
  { frameBaseUrl: ctx.frameBaseUrl }
486
493
  );
494
+ const url = spec.hidden ? builtUrl : applyThemeParam(builtUrl, ctx.theme);
487
495
  const transport = (overrides.createTransport ?? (() => new WebViewTransport()))();
488
496
  let resolvedHandle = null;
489
497
  let rejectDisposed;
@@ -579,7 +587,7 @@ import {
579
587
  createContext,
580
588
  useCallback as useCallback2,
581
589
  useContext,
582
- useMemo,
590
+ useMemo as useMemo2,
583
591
  useRef as useRef3,
584
592
  useState as useState2
585
593
  } from "react";
@@ -872,16 +880,16 @@ function createMountSession(specCtx, host) {
872
880
  }
873
881
 
874
882
  // src/VisibleFrameSlotSheet.tsx
875
- import { useCallback, useEffect as useEffect2, useRef as useRef2, useState } from "react";
883
+ import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState } from "react";
876
884
  import {
877
885
  ActivityIndicator,
878
886
  Animated,
879
887
  Easing,
880
888
  Modal,
889
+ PanResponder,
881
890
  Platform,
882
891
  Pressable,
883
892
  StyleSheet,
884
- Text,
885
893
  useWindowDimensions,
886
894
  View as View2
887
895
  } from "react-native";
@@ -924,6 +932,38 @@ function VisibleFrameSlotSheet({
924
932
  onCloseRef.current();
925
933
  });
926
934
  }, [translateY, sheetHeight]);
935
+ const panResponder = useMemo(
936
+ () => PanResponder.create({
937
+ // Claim the gesture only for a clearly downward drag — never on a tap
938
+ // (so the handle's onPress still fires) or a mostly-horizontal swipe.
939
+ onMoveShouldSetPanResponder: (_evt, { dy, dx }) => dy > 5 && dy > Math.abs(dx),
940
+ onPanResponderGrant: () => {
941
+ translateY.stopAnimation(() => {
942
+ translateY.extractOffset();
943
+ });
944
+ },
945
+ // Track the finger downward; clamp upward travel to the open position.
946
+ onPanResponderMove: (_evt, { dy }) => {
947
+ translateY.setValue(Math.max(0, dy));
948
+ },
949
+ onPanResponderRelease: (_evt, { dy, vy }) => {
950
+ translateY.flattenOffset();
951
+ const draggedPastThreshold = dy > sheetHeight * 0.35;
952
+ const flungDownFast = vy > 0.5;
953
+ if (draggedPastThreshold || flungDownFast) {
954
+ close();
955
+ } else {
956
+ animateSheet(translateY, 0);
957
+ }
958
+ },
959
+ // Another responder stole the gesture: settle to a known state.
960
+ onPanResponderTerminate: () => {
961
+ translateY.flattenOffset();
962
+ animateSheet(translateY, 0);
963
+ }
964
+ }),
965
+ [translateY, sheetHeight, close]
966
+ );
927
967
  useEffect2(() => {
928
968
  animateSheet(translateY, 0);
929
969
  }, [translateY]);
@@ -954,17 +994,16 @@ function VisibleFrameSlotSheet({
954
994
  /* @__PURE__ */ jsxs(Animated.View, { style: [styles.sheet, { height: sheetHeight, transform: [{ translateY }] }], children: [
955
995
  /* @__PURE__ */ jsx2(MoonPayFrame, { transport: slot.transport }),
956
996
  !frameReady && /* @__PURE__ */ jsx2(View2, { style: styles.loading, children: /* @__PURE__ */ jsx2(ActivityIndicator, { size: "large", color: "#000" }) }),
957
- /* @__PURE__ */ jsx2(
997
+ /* @__PURE__ */ jsx2(View2, { style: styles.handleArea, ...panResponder.panHandlers, children: /* @__PURE__ */ jsx2(
958
998
  Pressable,
959
999
  {
960
1000
  onPress: close,
961
1001
  accessibilityRole: "button",
962
1002
  accessibilityLabel: "Close",
963
- hitSlop: 8,
964
- style: styles.closeButton,
965
- children: /* @__PURE__ */ jsx2(Text, { style: styles.closeButtonText, children: "\u2715" })
1003
+ hitSlop: 12,
1004
+ children: /* @__PURE__ */ jsx2(View2, { style: styles.handleBar })
966
1005
  }
967
- )
1006
+ ) })
968
1007
  ] })
969
1008
  ] }) });
970
1009
  }
@@ -994,25 +1033,25 @@ var styles = StyleSheet.create({
994
1033
  alignItems: "center",
995
1034
  justifyContent: "center"
996
1035
  },
997
- // Floating X in the top-right corner, over the frame.
998
- closeButton: {
1036
+ // Drag-to-dismiss strip pinned across the top of the sheet, floating over the
1037
+ // frame. Tall enough to be an easy grab target without eating much of the UI.
1038
+ handleArea: {
999
1039
  position: "absolute",
1000
- top: 12,
1001
- right: 12,
1002
- width: 32,
1003
- height: 32,
1004
- borderRadius: 16,
1005
- backgroundColor: "rgba(0, 0, 0, 0.06)",
1040
+ top: 0,
1041
+ left: 0,
1042
+ right: 0,
1043
+ height: 28,
1006
1044
  alignItems: "center",
1007
1045
  justifyContent: "center",
1008
1046
  zIndex: 1,
1009
1047
  elevation: 2
1010
1048
  },
1011
- closeButtonText: {
1012
- fontSize: 17,
1013
- lineHeight: 20,
1014
- color: "#000",
1015
- fontWeight: "500"
1049
+ // The visible pill.
1050
+ handleBar: {
1051
+ width: 36,
1052
+ height: 5,
1053
+ borderRadius: 3,
1054
+ backgroundColor: "rgba(0, 0, 0, 0.2)"
1016
1055
  }
1017
1056
  });
1018
1057
 
@@ -1023,6 +1062,7 @@ function MoonPayProvider({
1023
1062
  sessionToken,
1024
1063
  apiBaseUrl,
1025
1064
  frameBaseUrl,
1065
+ theme,
1026
1066
  children
1027
1067
  }) {
1028
1068
  const [frameSlots, setFrameSlots] = useState2([]);
@@ -1041,14 +1081,14 @@ function MoonPayProvider({
1041
1081
  });
1042
1082
  }
1043
1083
  const core = coreRef.current;
1044
- const client = useMemo(() => {
1045
- const specCtx = { sessionToken, core, frameBaseUrl };
1084
+ const client = useMemo2(() => {
1085
+ const specCtx = { sessionToken, core, frameBaseUrl, theme };
1046
1086
  return createRNClient({
1047
1087
  mountSession: createMountSession(specCtx, { addSlot, removeSlot }),
1048
1088
  core
1049
1089
  });
1050
- }, [sessionToken, frameBaseUrl, core, addSlot, removeSlot]);
1051
- return /* @__PURE__ */ jsxs2(MoonPayContext.Provider, { value: { client, sessionToken, core, frameBaseUrl }, children: [
1090
+ }, [sessionToken, frameBaseUrl, core, addSlot, removeSlot, theme?.appearance]);
1091
+ return /* @__PURE__ */ jsxs2(MoonPayContext.Provider, { value: { client, sessionToken, core, frameBaseUrl, theme }, children: [
1052
1092
  children,
1053
1093
  frameSlots.filter((slot) => slot.hidden).map((slot) => /* @__PURE__ */ jsx3(MoonPayFrame, { transport: slot.transport, hidden: true }, slot.id)),
1054
1094
  frameSlots.filter((slot) => !slot.hidden).map((slot) => /* @__PURE__ */ jsx3(
@@ -1093,7 +1133,7 @@ function MoonPayFrameView({
1093
1133
  defaultStyle,
1094
1134
  onEvent
1095
1135
  }) {
1096
- const { sessionToken, core, frameBaseUrl } = useMoonPayContext();
1136
+ const { sessionToken, core, frameBaseUrl, theme } = useMoonPayContext();
1097
1137
  const [transport, setTransport] = useState3(null);
1098
1138
  const handleRef = useRef4(null);
1099
1139
  const onEventRef = useRef4(onEvent);
@@ -1119,7 +1159,11 @@ function MoonPayFrameView({
1119
1159
  }
1120
1160
  appliedRef.current = applied;
1121
1161
  try {
1122
- session = createFrameSession(spec, { sessionToken, core, frameBaseUrl }, propsRef.current);
1162
+ session = createFrameSession(
1163
+ spec,
1164
+ { sessionToken, core, frameBaseUrl, theme },
1165
+ propsRef.current
1166
+ );
1123
1167
  } catch (e) {
1124
1168
  onEventRef.current?.(
1125
1169
  spec.errorEvent(e instanceof Error ? e.message : "Failed to create frame")