@b3dotfun/sdk 0.1.69-alpha.5 → 0.1.69-alpha.7

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.
Files changed (38) hide show
  1. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +5 -0
  2. package/dist/cjs/anyspend/react/components/common/OrderStatus.js +37 -6
  3. package/dist/cjs/anyspend/react/components/common/StepProgress.d.ts +2 -0
  4. package/dist/cjs/anyspend/react/components/common/StepProgress.js +7 -2
  5. package/dist/cjs/global-account/react/components/B3DynamicModal.js +2 -2
  6. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.native.js +2 -1
  7. package/dist/cjs/global-account/react/components/Toast/ToastContext.d.ts +3 -0
  8. package/dist/cjs/global-account/react/components/Toast/ToastContext.js +30 -7
  9. package/dist/cjs/global-account/react/hooks/useAuth.js +2 -4
  10. package/dist/cjs/global-account/react/hooks/useAuthentication.js +2 -4
  11. package/dist/cjs/global-account/react/utils/createWagmiConfig.d.ts +0 -18
  12. package/dist/cjs/global-account/react/utils/createWagmiConfig.js +0 -17
  13. package/dist/esm/anyspend/react/components/common/OrderDetails.js +6 -1
  14. package/dist/esm/anyspend/react/components/common/OrderStatus.js +34 -3
  15. package/dist/esm/anyspend/react/components/common/StepProgress.d.ts +2 -0
  16. package/dist/esm/anyspend/react/components/common/StepProgress.js +4 -2
  17. package/dist/esm/global-account/react/components/B3DynamicModal.js +2 -2
  18. package/dist/esm/global-account/react/components/B3Provider/B3Provider.native.js +2 -1
  19. package/dist/esm/global-account/react/components/Toast/ToastContext.d.ts +3 -0
  20. package/dist/esm/global-account/react/components/Toast/ToastContext.js +30 -7
  21. package/dist/esm/global-account/react/hooks/useAuth.js +4 -6
  22. package/dist/esm/global-account/react/hooks/useAuthentication.js +3 -5
  23. package/dist/esm/global-account/react/utils/createWagmiConfig.d.ts +0 -18
  24. package/dist/esm/global-account/react/utils/createWagmiConfig.js +0 -16
  25. package/dist/types/anyspend/react/components/common/StepProgress.d.ts +2 -0
  26. package/dist/types/global-account/react/components/Toast/ToastContext.d.ts +3 -0
  27. package/dist/types/global-account/react/utils/createWagmiConfig.d.ts +0 -18
  28. package/package.json +2 -1
  29. package/src/anyspend/react/components/common/OrderDetails.tsx +8 -0
  30. package/src/anyspend/react/components/common/OrderStatus.tsx +38 -3
  31. package/src/anyspend/react/components/common/StepProgress.tsx +15 -5
  32. package/src/global-account/react/components/B3DynamicModal.tsx +2 -2
  33. package/src/global-account/react/components/B3Provider/B3Provider.native.tsx +2 -1
  34. package/src/global-account/react/components/Toast/ToastContext.tsx +39 -7
  35. package/src/global-account/react/hooks/useAuth.ts +4 -6
  36. package/src/global-account/react/hooks/useAuthentication.ts +3 -5
  37. package/src/global-account/react/utils/createWagmiConfig.tsx +0 -18
  38. package/src/types/torph.d.ts +4 -0
@@ -140,6 +140,11 @@ function roundTokenAmount(amount) {
140
140
  exports.OrderDetails = (0, react_5.memo)(function OrderDetails({ mode = "modal", order, depositTxs, relayTxs, executeTx, refundTxs, cryptoPaymentMethod, selectedCryptoPaymentMethod, onPaymentMethodChange, onBack, disableUrlParamManagement = false, points, returnToHomeUrl, returnHomeLabel, classes, }) {
141
141
  const router = (0, hooks_1.useRouter)();
142
142
  const searchParams = (0, hooks_1.useSearchParams)();
143
+ const { setHeaderMode } = (0, react_1.useToastContext)();
144
+ (0, react_5.useEffect)(() => {
145
+ setHeaderMode(true);
146
+ return () => setHeaderMode(false);
147
+ }, [setHeaderMode]);
143
148
  // Get theme from B3Provider context
144
149
  const { theme } = (0, react_1.useB3Config)();
145
150
  const colorMode = theme || "light";
@@ -5,7 +5,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const anyspend_1 = require("../../../../anyspend");
6
6
  const react_1 = require("../../../../shared/react");
7
7
  const lucide_react_1 = require("lucide-react");
8
- const react_2 = require("react");
8
+ const react_2 = require("../../../../global-account/react");
9
+ const react_3 = require("react");
9
10
  const AnySpendCustomizationContext_1 = require("../context/AnySpendCustomizationContext");
10
11
  const AnimatedCheckmark_1 = require("../icons/AnimatedCheckmark");
11
12
  const StepProgress_1 = require("./StepProgress");
@@ -17,15 +18,28 @@ function getStepIndex(status) {
17
18
  return 1;
18
19
  return -1;
19
20
  }
20
- exports.OrderStatus = (0, react_2.memo)(function OrderStatus({ order, selectedCryptoPaymentMethod, }) {
21
+ function getToastIcon(type) {
22
+ const iconClass = "h-5 w-5";
23
+ switch (type) {
24
+ case "success":
25
+ return (0, jsx_runtime_1.jsx)(lucide_react_1.CheckCircle, { className: `${iconClass} text-green-500` });
26
+ case "error":
27
+ return (0, jsx_runtime_1.jsx)(lucide_react_1.AlertCircle, { className: `${iconClass} text-red-500` });
28
+ case "info":
29
+ return (0, jsx_runtime_1.jsx)(lucide_react_1.Info, { className: `${iconClass} text-blue-500` });
30
+ case "warning":
31
+ return (0, jsx_runtime_1.jsx)(lucide_react_1.AlertTriangle, { className: `${iconClass} text-amber-500` });
32
+ }
33
+ }
34
+ exports.OrderStatus = (0, react_3.memo)(function OrderStatus({ order, selectedCryptoPaymentMethod, }) {
21
35
  const { text: defaultText, description: defaultDescription } = (0, anyspend_1.getStatusDisplay)(order);
22
36
  const { content, slots } = (0, AnySpendCustomizationContext_1.useAnySpendCustomization)();
23
37
  const searchParams = (0, react_1.useSearchParams)();
24
38
  const cryptoPaymentMethod = selectedCryptoPaymentMethod || searchParams.get("cryptoPaymentMethod");
25
39
  const currentStepIndex = getStepIndex(order.status);
26
- const prevStepIndexRef = (0, react_2.useRef)(currentStepIndex);
40
+ const prevStepIndexRef = (0, react_3.useRef)(currentStepIndex);
27
41
  const shouldAnimateCheck = currentStepIndex > prevStepIndexRef.current;
28
- (0, react_2.useEffect)(() => {
42
+ (0, react_3.useEffect)(() => {
29
43
  prevStepIndexRef.current = currentStepIndex;
30
44
  }, [currentStepIndex]);
31
45
  // Resolve content overrides based on order status
@@ -61,9 +75,26 @@ exports.OrderStatus = (0, react_2.memo)(function OrderStatus({ order, selectedCr
61
75
  if (content.processingDescription)
62
76
  description = content.processingDescription;
63
77
  }
78
+ const { latestToast } = (0, react_2.useToastContext)();
79
+ // Override subtitle with toast notification when present (title stays unchanged)
80
+ let notificationIcon = undefined;
81
+ if (latestToast && currentStepIndex >= 0) {
82
+ description = latestToast.message;
83
+ notificationIcon = getToastIcon(latestToast.type);
84
+ }
64
85
  const paymentSteps = [
65
- { id: 1, title: text, description: typeof description === "string" ? description : defaultDescription || "" },
66
- { id: 2, title: text, description: typeof description === "string" ? description : defaultDescription || "" },
86
+ {
87
+ id: 1,
88
+ title: text,
89
+ description: typeof description === "string" ? description : defaultDescription || "",
90
+ icon: notificationIcon,
91
+ },
92
+ {
93
+ id: 2,
94
+ title: text,
95
+ description: typeof description === "string" ? description : defaultDescription || "",
96
+ icon: notificationIcon,
97
+ },
67
98
  ];
68
99
  if (currentStepIndex === 0) {
69
100
  if (!(order.status === "scanning_deposit_transaction" && cryptoPaymentMethod === "transfer_crypto")) {
@@ -1,7 +1,9 @@
1
+ import React from "react";
1
2
  export interface Step {
2
3
  id: string | number;
3
4
  title: string;
4
5
  description?: string;
6
+ icon?: React.ReactNode;
5
7
  }
6
8
  export interface StepProgressProps {
7
9
  steps: Step[];
@@ -1,17 +1,22 @@
1
1
  "use strict";
2
2
  "use client";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
3
6
  Object.defineProperty(exports, "__esModule", { value: true });
4
7
  exports.StepProgress = StepProgress;
5
8
  const jsx_runtime_1 = require("react/jsx-runtime");
9
+ const react_1 = __importDefault(require("react"));
6
10
  const framer_motion_1 = require("framer-motion");
11
+ const react_2 = require("torph/react");
7
12
  const AnimatedCheckmark_1 = require("../icons/AnimatedCheckmark");
8
13
  function StepProgress({ steps, currentStepIndex, className = "", animateCompletedSteps = true, }) {
9
14
  const currentStep = steps[currentStepIndex];
10
- return ((0, jsx_runtime_1.jsxs)("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: steps.map((_, index) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center", children: index < currentStepIndex ? (
15
+ return ((0, jsx_runtime_1.jsxs)("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: steps.map((_, index) => ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center", children: index < currentStepIndex ? (
11
16
  // Completed step - checkmark replaces the whole circle
12
17
  (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, children: (0, jsx_runtime_1.jsx)(AnimatedCheckmark_1.AnimatedCheckmark, { className: "h-10 w-10", strokeWidth: 2.5, static: !animateCompletedSteps }) })) : ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, className: `border-as-border-secondary relative flex h-10 w-10 items-center justify-center rounded-full border-[3px]`, children: index === currentStepIndex ? (
13
18
  // Current step - show spinning border and step number
14
19
  (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "border-t-as-primary absolute -inset-0.5 animate-spin rounded-full border-[3px] border-transparent" }), (0, jsx_runtime_1.jsx)("span", { className: "text-as-primary font-semibold", children: index + 1 })] })) : (
15
20
  // Future step - show step number with disabled styling
16
- (0, jsx_runtime_1.jsx)("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }, index), index < steps.length - 1 && ((0, jsx_runtime_1.jsx)("div", { className: "flex w-8 items-center justify-center gap-1", children: Array.from({ length: 6 }).map((_, dotIndex) => ((0, jsx_runtime_1.jsx)("div", { className: "bg-as-primary/30 h-[2px] w-[2px] rounded-full" }, dotIndex))) }))] }))) }), currentStep && ((0, jsx_runtime_1.jsxs)(framer_motion_1.motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.3 }, className: "text-center", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-xl font-semibold", children: currentStep.title }), currentStep.description && (0, jsx_runtime_1.jsx)("p", { className: "text-as-tertiary mt-1 text-sm", children: currentStep.description })] }))] }));
21
+ (0, jsx_runtime_1.jsx)("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }), index < steps.length - 1 && ((0, jsx_runtime_1.jsx)("div", { className: "flex w-8 items-center justify-center gap-1", children: Array.from({ length: 6 }).map((_, dotIndex) => ((0, jsx_runtime_1.jsx)("div", { className: "bg-as-primary/30 h-[2px] w-[2px] rounded-full" }, dotIndex))) }))] }, index))) }), currentStep && ((0, jsx_runtime_1.jsxs)(framer_motion_1.motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.3 }, className: "text-center", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-xl font-semibold", children: (0, jsx_runtime_1.jsx)(react_2.TextMorph, { children: currentStep.title }) }), currentStep.description && ((0, jsx_runtime_1.jsxs)("p", { className: "text-as-tertiary mt-1 flex items-center justify-center gap-1.5 text-sm", children: [currentStep.icon, (0, jsx_runtime_1.jsx)(react_2.TextMorph, { children: currentStep.description })] }))] }))] }));
17
22
  }
@@ -37,7 +37,7 @@ function B3DynamicModal() {
37
37
  const navigateBack = (0, react_2.useModalStore)(state => state.navigateBack);
38
38
  const { theme } = (0, react_2.useB3Config)();
39
39
  const isMobile = (0, react_2.useIsMobile)();
40
- const { toasts, removeToast } = (0, index_1.useToastContext)();
40
+ const { toasts, removeToast, headerMode } = (0, index_1.useToastContext)();
41
41
  // Define arrays for different modal type groups
42
42
  const fullWidthTypes = [
43
43
  "anySpend",
@@ -168,7 +168,7 @@ function B3DynamicModal() {
168
168
  contentType?.type === "send" ||
169
169
  contentType?.type === "avatarEditor" ||
170
170
  contentType?.type === "notifications") &&
171
- "p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), (0, jsx_runtime_1.jsx)("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: renderContent() }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: toasts.length > 0 && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: (0, jsx_runtime_1.jsx)(index_1.ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && ((0, jsx_runtime_1.jsx)("style", { children: `
171
+ "p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), (0, jsx_runtime_1.jsx)("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: renderContent() }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: !headerMode && toasts.length > 0 && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: (0, jsx_runtime_1.jsx)(index_1.ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && ((0, jsx_runtime_1.jsx)("style", { children: `
172
172
  .modal-inner-content {
173
173
  transition: margin-bottom 0.3s ease-in-out;
174
174
  margin-bottom: ${toasts.length > 0 ? "0px" : "23px"} !important;
@@ -8,6 +8,7 @@ exports.InnerProvider = InnerProvider;
8
8
  const jsx_runtime_1 = require("react/jsx-runtime");
9
9
  const react_query_1 = require("@tanstack/react-query");
10
10
  const react_1 = require("thirdweb/react");
11
+ const react_2 = require("react");
11
12
  const wagmi_1 = require("wagmi");
12
13
  const createWagmiConfig_1 = require("../../utils/createWagmiConfig");
13
14
  const AuthenticationProvider_1 = __importDefault(require("./AuthenticationProvider"));
@@ -25,6 +26,6 @@ function B3Provider({ theme = "light", children, accountOverride, environment, c
25
26
  * Inner provider component for native
26
27
  */
27
28
  function InnerProvider({ children, accountOverride, environment, defaultPermissions, theme = "light", clientType = "socket", partnerId, rpcUrls, }) {
28
- const wagmiConfig = (0, createWagmiConfig_1.createWagmiConfig)({ partnerId, rpcUrls });
29
+ const wagmiConfig = (0, react_2.useMemo)(() => (0, createWagmiConfig_1.createWagmiConfig)({ partnerId, rpcUrls }), [partnerId, rpcUrls]);
29
30
  return ((0, jsx_runtime_1.jsx)(wagmi_1.WagmiProvider, { config: wagmiConfig, children: (0, jsx_runtime_1.jsx)(react_query_1.QueryClientProvider, { client: queryClient, children: (0, jsx_runtime_1.jsx)(B3ConfigProvider_1.B3ConfigProvider, { accountOverride: accountOverride, environment: environment, automaticallySetFirstEoa: false, theme: theme, clientType: clientType, partnerId: partnerId, defaultPermissions: defaultPermissions, children: children }) }) }));
30
31
  }
@@ -11,6 +11,9 @@ interface ToastContextType {
11
11
  addToast: (type: ToastType, message: string, duration?: number) => string;
12
12
  removeToast: (id: string) => void;
13
13
  clearAll: () => void;
14
+ headerMode: boolean;
15
+ setHeaderMode: (enabled: boolean) => void;
16
+ latestToast: ToastItem | null;
14
17
  }
15
18
  export declare function ToastProvider({ children }: {
16
19
  children: React.ReactNode;
@@ -8,6 +8,9 @@ const ToastContext = (0, react_1.createContext)(undefined);
8
8
  let globalToastCounter = 0;
9
9
  function ToastProvider({ children }) {
10
10
  const [toasts, setToasts] = (0, react_1.useState)([]);
11
+ const [headerMode, setHeaderMode] = (0, react_1.useState)(false);
12
+ const headerModeRef = (0, react_1.useRef)(false);
13
+ const [latestToast, setLatestToast] = (0, react_1.useState)(null);
11
14
  const timeoutsRef = (0, react_1.useRef)(new Map());
12
15
  const removeToast = (0, react_1.useCallback)((id) => {
13
16
  setToasts(prev => prev.filter(toast => toast.id !== id));
@@ -26,12 +29,23 @@ function ToastProvider({ children }) {
26
29
  duration,
27
30
  createdAt: Date.now(),
28
31
  };
29
- setToasts(prev => [...prev, newToast]);
30
- if (duration > 0) {
31
- const timeout = setTimeout(() => {
32
- removeToast(id);
33
- }, duration);
34
- timeoutsRef.current.set(id, timeout);
32
+ if (headerModeRef.current) {
33
+ setLatestToast(newToast);
34
+ if (duration > 0) {
35
+ const timeout = setTimeout(() => {
36
+ setLatestToast(null);
37
+ }, duration);
38
+ timeoutsRef.current.set(id, timeout);
39
+ }
40
+ }
41
+ else {
42
+ setToasts(prev => [...prev, newToast]);
43
+ if (duration > 0) {
44
+ const timeout = setTimeout(() => {
45
+ removeToast(id);
46
+ }, duration);
47
+ timeoutsRef.current.set(id, timeout);
48
+ }
35
49
  }
36
50
  return id;
37
51
  }, [removeToast]);
@@ -40,6 +54,15 @@ function ToastProvider({ children }) {
40
54
  timeoutsRef.current.clear();
41
55
  setToasts([]);
42
56
  }, []);
57
+ const setHeaderModeCallback = (0, react_1.useCallback)((enabled) => {
58
+ setHeaderMode(enabled);
59
+ headerModeRef.current = enabled;
60
+ if (!enabled) {
61
+ setLatestToast(null);
62
+ timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
63
+ timeoutsRef.current.clear();
64
+ }
65
+ }, []);
43
66
  // Cleanup on unmount
44
67
  (0, react_1.useEffect)(() => {
45
68
  const timeouts = timeoutsRef.current;
@@ -48,7 +71,7 @@ function ToastProvider({ children }) {
48
71
  timeouts.clear();
49
72
  };
50
73
  }, []);
51
- return (0, jsx_runtime_1.jsx)(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll }, children: children });
74
+ return ((0, jsx_runtime_1.jsx)(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll, headerMode, setHeaderMode: setHeaderModeCallback, latestToast }, children: children }));
52
75
  }
53
76
  function useToastContext() {
54
77
  const context = (0, react_1.useContext)(ToastContext);
@@ -44,7 +44,7 @@ function useAuth() {
44
44
  const useAutoConnectLoadingPrevious = (0, react_2.useRef)(false);
45
45
  const referralCode = (0, useSearchParamsSSR_1.useSearchParam)("referralCode");
46
46
  const { partnerId } = (0, react_1.useB3Config)();
47
- const wagmiConfig = (0, createWagmiConfig_1.getCachedWagmiConfig)({ partnerId });
47
+ const wagmiConfig = (0, react_2.useMemo)(() => (0, createWagmiConfig_1.createWagmiConfig)({ partnerId }), [partnerId]);
48
48
  const { connect } = (0, wagmi_1.useConnect)();
49
49
  const activeWagmiAccount = (0, wagmi_1.useAccount)();
50
50
  const { switchAccount } = (0, wagmi_1.useSwitchAccount)();
@@ -126,9 +126,7 @@ function useAuth() {
126
126
  });
127
127
  }
128
128
  syncWagmiFunc();
129
- // wagmi config shouldn't change
130
- // eslint-disable-next-line react-hooks/exhaustive-deps
131
- }, [partnerId, wallets]);
129
+ }, [wagmiConfig, wallets, connect, switchAccount]);
132
130
  (0, react_2.useEffect)(() => {
133
131
  syncWagmi();
134
132
  }, [wallets, syncWagmi]);
@@ -54,7 +54,7 @@ function useAuthentication(partnerId, { skipAutoConnect = false } = {}) {
54
54
  const { authenticate } = (0, useTWAuth_1.useTWAuth)();
55
55
  const { user, setUser } = (0, useUserQuery_1.useUserQuery)();
56
56
  const useAutoConnectLoadingPrevious = (0, react_2.useRef)(false);
57
- const wagmiConfig = (0, createWagmiConfig_1.createWagmiConfig)({ partnerId });
57
+ const wagmiConfig = (0, react_2.useMemo)(() => (0, createWagmiConfig_1.createWagmiConfig)({ partnerId }), [partnerId]);
58
58
  const { connect } = (0, wagmi_1.useConnect)();
59
59
  const activeWagmiAccount = (0, wagmi_1.useAccount)();
60
60
  const { switchAccount } = (0, wagmi_1.useSwitchAccount)();
@@ -105,9 +105,7 @@ function useAuthentication(partnerId, { skipAutoConnect = false } = {}) {
105
105
  });
106
106
  }
107
107
  syncWagmiFunc();
108
- // wagmi config shouldn't change
109
- // eslint-disable-next-line react-hooks/exhaustive-deps
110
- }, [partnerId, wallets]);
108
+ }, [wagmiConfig, wallets, connect, switchAccount]);
111
109
  (0, react_2.useEffect)(() => {
112
110
  syncWagmi();
113
111
  }, [wallets, syncWagmi]);
@@ -25,21 +25,3 @@ export declare function createWagmiConfig(options: CreateWagmiConfigOptions): im
25
25
  }, {
26
26
  "thirdweb:lastChainId": number;
27
27
  }>)[]>;
28
- /**
29
- * Returns a cached wagmi config for the given partnerId.
30
- * Use this instead of calling createWagmiConfig() directly inside React components or hooks
31
- * to avoid registering duplicate EventEmitter listeners on every render.
32
- */
33
- export declare function getCachedWagmiConfig(options: CreateWagmiConfigOptions): import("wagmi").Config<readonly [import("viem").Chain, ...import("viem").Chain[]], {
34
- [k: string]: import("viem").HttpTransport<undefined, false>;
35
- }, (CreateConnectorFn | CreateConnectorFn<import("thirdweb/dist/types/adapters/eip1193").EIP1193Provider | undefined, {
36
- connect<withCapabilities extends boolean = false>(parameters?: import("@thirdweb-dev/wagmi-adapter").ConnectionOptions<withCapabilities> | undefined): Promise<{
37
- accounts: withCapabilities extends true ? readonly {
38
- address: `0x${string}`;
39
- capabilities: Record<string, unknown>;
40
- }[] : readonly `0x${string}`[];
41
- chainId: number;
42
- }>;
43
- }, {
44
- "thirdweb:lastChainId": number;
45
- }>)[]>;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createWagmiConfig = createWagmiConfig;
4
- exports.getCachedWagmiConfig = getCachedWagmiConfig;
5
4
  const constants_1 = require("../../../shared/constants");
6
5
  const supported_1 = require("../../../shared/constants/chains/supported");
7
6
  const thirdweb_1 = require("../../../shared/utils/thirdweb");
@@ -31,19 +30,3 @@ function createWagmiConfig(options) {
31
30
  connectors: finalConnectors,
32
31
  });
33
32
  }
34
- /** Module-level cache — wagmi configs must not be recreated on every render. */
35
- const wagmiConfigCache = new Map();
36
- /**
37
- * Returns a cached wagmi config for the given partnerId.
38
- * Use this instead of calling createWagmiConfig() directly inside React components or hooks
39
- * to avoid registering duplicate EventEmitter listeners on every render.
40
- */
41
- function getCachedWagmiConfig(options) {
42
- const key = options.partnerId;
43
- let config = wagmiConfigCache.get(key);
44
- if (!config) {
45
- config = createWagmiConfig(options);
46
- wagmiConfigCache.set(key, config);
47
- }
48
- return config;
49
- }
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { ALL_CHAINS, getChainName, getErrorDisplay, getExplorerTxUrl, getPaymentUrl, getStatusDisplay, isNativeToken, RELAY_SOLANA_MAINNET_CHAIN_ID, ZERO_ADDRESS, } from "../../../../anyspend/index.js";
4
- import { Badge, Button, CopyToClipboard, ShinyButton, Skeleton, TextLoop, TextShimmer, useAccountWallet, useB3Config, useModalStore, useProfile, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
4
+ import { Badge, Button, CopyToClipboard, ShinyButton, Skeleton, TextLoop, TextShimmer, useAccountWallet, useB3Config, useModalStore, useProfile, useToastContext, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
5
5
  import { useRouter, useSearchParams } from "../../../../shared/react/hooks/index.js";
6
6
  import { cn } from "../../../../shared/utils/index.js";
7
7
  import centerTruncate from "../../../../shared/utils/centerTruncate.js";
@@ -134,6 +134,11 @@ function roundTokenAmount(amount) {
134
134
  export const OrderDetails = memo(function OrderDetails({ mode = "modal", order, depositTxs, relayTxs, executeTx, refundTxs, cryptoPaymentMethod, selectedCryptoPaymentMethod, onPaymentMethodChange, onBack, disableUrlParamManagement = false, points, returnToHomeUrl, returnHomeLabel, classes, }) {
135
135
  const router = useRouter();
136
136
  const searchParams = useSearchParams();
137
+ const { setHeaderMode } = useToastContext();
138
+ useEffect(() => {
139
+ setHeaderMode(true);
140
+ return () => setHeaderMode(false);
141
+ }, [setHeaderMode]);
137
142
  // Get theme from B3Provider context
138
143
  const { theme } = useB3Config();
139
144
  const colorMode = theme || "light";
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { getStatusDisplay } from "../../../../anyspend/index.js";
3
3
  import { useSearchParams } from "../../../../shared/react/index.js";
4
- import { Clock, Loader2, RotateCcw, X } from "lucide-react";
4
+ import { AlertCircle, AlertTriangle, CheckCircle, Clock, Info, Loader2, RotateCcw, X } from "lucide-react";
5
+ import { useToastContext } from "../../../../global-account/react/index.js";
5
6
  import { memo, useEffect, useRef } from "react";
6
7
  import { useAnySpendCustomization } from "../context/AnySpendCustomizationContext.js";
7
8
  import { AnimatedCheckmark } from "../icons/AnimatedCheckmark.js";
@@ -14,6 +15,19 @@ function getStepIndex(status) {
14
15
  return 1;
15
16
  return -1;
16
17
  }
18
+ function getToastIcon(type) {
19
+ const iconClass = "h-5 w-5";
20
+ switch (type) {
21
+ case "success":
22
+ return _jsx(CheckCircle, { className: `${iconClass} text-green-500` });
23
+ case "error":
24
+ return _jsx(AlertCircle, { className: `${iconClass} text-red-500` });
25
+ case "info":
26
+ return _jsx(Info, { className: `${iconClass} text-blue-500` });
27
+ case "warning":
28
+ return _jsx(AlertTriangle, { className: `${iconClass} text-amber-500` });
29
+ }
30
+ }
17
31
  export const OrderStatus = memo(function OrderStatus({ order, selectedCryptoPaymentMethod, }) {
18
32
  const { text: defaultText, description: defaultDescription } = getStatusDisplay(order);
19
33
  const { content, slots } = useAnySpendCustomization();
@@ -58,9 +72,26 @@ export const OrderStatus = memo(function OrderStatus({ order, selectedCryptoPaym
58
72
  if (content.processingDescription)
59
73
  description = content.processingDescription;
60
74
  }
75
+ const { latestToast } = useToastContext();
76
+ // Override subtitle with toast notification when present (title stays unchanged)
77
+ let notificationIcon = undefined;
78
+ if (latestToast && currentStepIndex >= 0) {
79
+ description = latestToast.message;
80
+ notificationIcon = getToastIcon(latestToast.type);
81
+ }
61
82
  const paymentSteps = [
62
- { id: 1, title: text, description: typeof description === "string" ? description : defaultDescription || "" },
63
- { id: 2, title: text, description: typeof description === "string" ? description : defaultDescription || "" },
83
+ {
84
+ id: 1,
85
+ title: text,
86
+ description: typeof description === "string" ? description : defaultDescription || "",
87
+ icon: notificationIcon,
88
+ },
89
+ {
90
+ id: 2,
91
+ title: text,
92
+ description: typeof description === "string" ? description : defaultDescription || "",
93
+ icon: notificationIcon,
94
+ },
64
95
  ];
65
96
  if (currentStepIndex === 0) {
66
97
  if (!(order.status === "scanning_deposit_transaction" && cryptoPaymentMethod === "transfer_crypto")) {
@@ -1,7 +1,9 @@
1
+ import React from "react";
1
2
  export interface Step {
2
3
  id: string | number;
3
4
  title: string;
4
5
  description?: string;
6
+ icon?: React.ReactNode;
5
7
  }
6
8
  export interface StepProgressProps {
7
9
  steps: Step[];
@@ -1,14 +1,16 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React from "react";
3
4
  import { motion } from "framer-motion";
5
+ import { TextMorph } from "torph/react";
4
6
  import { AnimatedCheckmark } from "../icons/AnimatedCheckmark.js";
5
7
  export function StepProgress({ steps, currentStepIndex, className = "", animateCompletedSteps = true, }) {
6
8
  const currentStep = steps[currentStepIndex];
7
- return (_jsxs("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [_jsx("div", { className: "flex items-center gap-2", children: steps.map((_, index) => (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex items-center", children: index < currentStepIndex ? (
9
+ return (_jsxs("div", { className: `flex w-full flex-col items-center gap-4 ${className}`, children: [_jsx("div", { className: "flex items-center gap-2", children: steps.map((_, index) => (_jsxs(React.Fragment, { children: [_jsx("div", { className: "flex items-center", children: index < currentStepIndex ? (
8
10
  // Completed step - checkmark replaces the whole circle
9
11
  _jsx(motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, children: _jsx(AnimatedCheckmark, { className: "h-10 w-10", strokeWidth: 2.5, static: !animateCompletedSteps }) })) : (_jsx(motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, transition: { delay: index * 0.2 }, className: `border-as-border-secondary relative flex h-10 w-10 items-center justify-center rounded-full border-[3px]`, children: index === currentStepIndex ? (
10
12
  // Current step - show spinning border and step number
11
13
  _jsxs(_Fragment, { children: [_jsx("div", { className: "border-t-as-primary absolute -inset-0.5 animate-spin rounded-full border-[3px] border-transparent" }), _jsx("span", { className: "text-as-primary font-semibold", children: index + 1 })] })) : (
12
14
  // Future step - show step number with disabled styling
13
- _jsx("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }, index), index < steps.length - 1 && (_jsx("div", { className: "flex w-8 items-center justify-center gap-1", children: Array.from({ length: 6 }).map((_, dotIndex) => (_jsx("div", { className: "bg-as-primary/30 h-[2px] w-[2px] rounded-full" }, dotIndex))) }))] }))) }), currentStep && (_jsxs(motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.3 }, className: "text-center", children: [_jsx("h2", { className: "text-as-primary text-xl font-semibold", children: currentStep.title }), currentStep.description && _jsx("p", { className: "text-as-tertiary mt-1 text-sm", children: currentStep.description })] }))] }));
15
+ _jsx("span", { className: "text-as-content-disabled font-semibold", children: index + 1 })) })) }), index < steps.length - 1 && (_jsx("div", { className: "flex w-8 items-center justify-center gap-1", children: Array.from({ length: 6 }).map((_, dotIndex) => (_jsx("div", { className: "bg-as-primary/30 h-[2px] w-[2px] rounded-full" }, dotIndex))) }))] }, index))) }), currentStep && (_jsxs(motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { delay: 0.3 }, className: "text-center", children: [_jsx("h2", { className: "text-as-primary text-xl font-semibold", children: _jsx(TextMorph, { children: currentStep.title }) }), currentStep.description && (_jsxs("p", { className: "text-as-tertiary mt-1 flex items-center justify-center gap-1.5 text-sm", children: [currentStep.icon, _jsx(TextMorph, { children: currentStep.description })] }))] }))] }));
14
16
  }
@@ -31,7 +31,7 @@ export function B3DynamicModal() {
31
31
  const navigateBack = useModalStore(state => state.navigateBack);
32
32
  const { theme } = useB3Config();
33
33
  const isMobile = useIsMobile();
34
- const { toasts, removeToast } = useToastContext();
34
+ const { toasts, removeToast, headerMode } = useToastContext();
35
35
  // Define arrays for different modal type groups
36
36
  const fullWidthTypes = [
37
37
  "anySpend",
@@ -162,7 +162,7 @@ export function B3DynamicModal() {
162
162
  contentType?.type === "send" ||
163
163
  contentType?.type === "avatarEditor" ||
164
164
  contentType?.type === "notifications") &&
165
- "p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [_jsx(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), _jsx(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), _jsxs("div", { className: cn("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && (_jsxs("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), _jsx("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), _jsx("div", { className: "flex-1", children: renderContent() }), _jsx(AnimatePresence, { children: toasts.length > 0 && (_jsx(motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: _jsx(motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: _jsx(ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && (_jsx("style", { children: `
165
+ "p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, hideGABranding: isAnySpendType, onEscapeKeyDown: !isClosable ? e => e.preventDefault() : undefined, children: [_jsx(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), _jsx(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), _jsxs("div", { className: cn("b3-modal-content no-scrollbar dark:bg-b3-background flex max-h-[90dvh] flex-col overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && (_jsxs("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), _jsx("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), _jsx("div", { className: "flex-1", children: renderContent() }), _jsx(AnimatePresence, { children: !headerMode && toasts.length > 0 && (_jsx(motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, transition: { duration: 0.3, ease: "easeInOut" }, className: "toast-section relative z-10 overflow-hidden bg-white dark:border-neutral-800 dark:bg-neutral-900", children: _jsx(motion.div, { initial: { opacity: 0, y: -10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -10 }, transition: { duration: 0.2, delay: 0.1 }, className: "p-4 pt-0", children: _jsx(ToastContainer, { toasts: toasts, onDismiss: removeToast, theme: theme }) }) })) })] })] }), isOpen && !isAnySpendType && (_jsx("style", { children: `
166
166
  .modal-inner-content {
167
167
  transition: margin-bottom 0.3s ease-in-out;
168
168
  margin-bottom: ${toasts.length > 0 ? "0px" : "23px"} !important;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3
3
  import { ThirdwebProvider } from "thirdweb/react";
4
+ import { useMemo } from "react";
4
5
  import { WagmiProvider } from "wagmi";
5
6
  import { createWagmiConfig } from "../../utils/createWagmiConfig.js";
6
7
  import AuthenticationProvider from "./AuthenticationProvider.js";
@@ -18,6 +19,6 @@ export function B3Provider({ theme = "light", children, accountOverride, environ
18
19
  * Inner provider component for native
19
20
  */
20
21
  export function InnerProvider({ children, accountOverride, environment, defaultPermissions, theme = "light", clientType = "socket", partnerId, rpcUrls, }) {
21
- const wagmiConfig = createWagmiConfig({ partnerId, rpcUrls });
22
+ const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId, rpcUrls }), [partnerId, rpcUrls]);
22
23
  return (_jsx(WagmiProvider, { config: wagmiConfig, children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(B3ConfigProvider, { accountOverride: accountOverride, environment: environment, automaticallySetFirstEoa: false, theme: theme, clientType: clientType, partnerId: partnerId, defaultPermissions: defaultPermissions, children: children }) }) }));
23
24
  }
@@ -11,6 +11,9 @@ interface ToastContextType {
11
11
  addToast: (type: ToastType, message: string, duration?: number) => string;
12
12
  removeToast: (id: string) => void;
13
13
  clearAll: () => void;
14
+ headerMode: boolean;
15
+ setHeaderMode: (enabled: boolean) => void;
16
+ latestToast: ToastItem | null;
14
17
  }
15
18
  export declare function ToastProvider({ children }: {
16
19
  children: React.ReactNode;
@@ -4,6 +4,9 @@ const ToastContext = createContext(undefined);
4
4
  let globalToastCounter = 0;
5
5
  export function ToastProvider({ children }) {
6
6
  const [toasts, setToasts] = useState([]);
7
+ const [headerMode, setHeaderMode] = useState(false);
8
+ const headerModeRef = useRef(false);
9
+ const [latestToast, setLatestToast] = useState(null);
7
10
  const timeoutsRef = useRef(new Map());
8
11
  const removeToast = useCallback((id) => {
9
12
  setToasts(prev => prev.filter(toast => toast.id !== id));
@@ -22,12 +25,23 @@ export function ToastProvider({ children }) {
22
25
  duration,
23
26
  createdAt: Date.now(),
24
27
  };
25
- setToasts(prev => [...prev, newToast]);
26
- if (duration > 0) {
27
- const timeout = setTimeout(() => {
28
- removeToast(id);
29
- }, duration);
30
- timeoutsRef.current.set(id, timeout);
28
+ if (headerModeRef.current) {
29
+ setLatestToast(newToast);
30
+ if (duration > 0) {
31
+ const timeout = setTimeout(() => {
32
+ setLatestToast(null);
33
+ }, duration);
34
+ timeoutsRef.current.set(id, timeout);
35
+ }
36
+ }
37
+ else {
38
+ setToasts(prev => [...prev, newToast]);
39
+ if (duration > 0) {
40
+ const timeout = setTimeout(() => {
41
+ removeToast(id);
42
+ }, duration);
43
+ timeoutsRef.current.set(id, timeout);
44
+ }
31
45
  }
32
46
  return id;
33
47
  }, [removeToast]);
@@ -36,6 +50,15 @@ export function ToastProvider({ children }) {
36
50
  timeoutsRef.current.clear();
37
51
  setToasts([]);
38
52
  }, []);
53
+ const setHeaderModeCallback = useCallback((enabled) => {
54
+ setHeaderMode(enabled);
55
+ headerModeRef.current = enabled;
56
+ if (!enabled) {
57
+ setLatestToast(null);
58
+ timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
59
+ timeoutsRef.current.clear();
60
+ }
61
+ }, []);
39
62
  // Cleanup on unmount
40
63
  useEffect(() => {
41
64
  const timeouts = timeoutsRef.current;
@@ -44,7 +67,7 @@ export function ToastProvider({ children }) {
44
67
  timeouts.clear();
45
68
  };
46
69
  }, []);
47
- return _jsx(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll }, children: children });
70
+ return (_jsx(ToastContext.Provider, { value: { toasts, addToast, removeToast, clearAll, headerMode, setHeaderMode: setHeaderModeCallback, latestToast }, children: children }));
48
71
  }
49
72
  export function useToastContext() {
50
73
  const context = useContext(ToastContext);
@@ -5,13 +5,13 @@ import { ecosystemWalletId } from "../../../shared/constants/index.js";
5
5
  import { debugB3React } from "../../../shared/utils/debug.js";
6
6
  import { client } from "../../../shared/utils/thirdweb.js";
7
7
  import { getConnectors } from "@wagmi/core";
8
- import { useCallback, useContext, useEffect, useRef } from "react";
8
+ import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
9
9
  import { useActiveWallet, useAutoConnect, useConnectedWallets, useDisconnect, useSetActiveWallet, } from "thirdweb/react";
10
10
  import { ecosystemWallet } from "thirdweb/wallets";
11
11
  import { preAuthenticate } from "thirdweb/wallets/in-app";
12
12
  import { useAccount, useConnect, useSwitchAccount } from "wagmi";
13
13
  import { LocalSDKContext } from "../components/B3Provider/LocalSDKProvider.js";
14
- import { getCachedWagmiConfig } from "../utils/createWagmiConfig.js";
14
+ import { createWagmiConfig } from "../utils/createWagmiConfig.js";
15
15
  import { useSearchParam } from "./useSearchParamsSSR.js";
16
16
  import { useUserQuery } from "./useUserQuery.js";
17
17
  const debug = debugB3React("useAuth");
@@ -38,7 +38,7 @@ export function useAuth() {
38
38
  const useAutoConnectLoadingPrevious = useRef(false);
39
39
  const referralCode = useSearchParam("referralCode");
40
40
  const { partnerId } = useB3Config();
41
- const wagmiConfig = getCachedWagmiConfig({ partnerId });
41
+ const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId }), [partnerId]);
42
42
  const { connect } = useConnect();
43
43
  const activeWagmiAccount = useAccount();
44
44
  const { switchAccount } = useSwitchAccount();
@@ -120,9 +120,7 @@ export function useAuth() {
120
120
  });
121
121
  }
122
122
  syncWagmiFunc();
123
- // wagmi config shouldn't change
124
- // eslint-disable-next-line react-hooks/exhaustive-deps
125
- }, [partnerId, wallets]);
123
+ }, [wagmiConfig, wallets, connect, switchAccount]);
126
124
  useEffect(() => {
127
125
  syncWagmi();
128
126
  }, [wallets, syncWagmi]);
@@ -5,7 +5,7 @@ import { ecosystemWalletId } from "../../../shared/constants/index.js";
5
5
  import { debugB3React } from "../../../shared/utils/debug.js";
6
6
  import { client } from "../../../shared/utils/thirdweb.js";
7
7
  import { getConnectors } from "@wagmi/core";
8
- import { useCallback, useContext, useEffect, useRef } from "react";
8
+ import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
9
9
  import { useActiveWallet, useAutoConnect, useConnectedWallets, useDisconnect, useSetActiveWallet, } from "thirdweb/react";
10
10
  import { ecosystemWallet } from "thirdweb/wallets";
11
11
  import { preAuthenticate } from "thirdweb/wallets/in-app";
@@ -48,7 +48,7 @@ export function useAuthentication(partnerId, { skipAutoConnect = false } = {}) {
48
48
  const { authenticate } = useTWAuth();
49
49
  const { user, setUser } = useUserQuery();
50
50
  const useAutoConnectLoadingPrevious = useRef(false);
51
- const wagmiConfig = createWagmiConfig({ partnerId });
51
+ const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId }), [partnerId]);
52
52
  const { connect } = useConnect();
53
53
  const activeWagmiAccount = useAccount();
54
54
  const { switchAccount } = useSwitchAccount();
@@ -99,9 +99,7 @@ export function useAuthentication(partnerId, { skipAutoConnect = false } = {}) {
99
99
  });
100
100
  }
101
101
  syncWagmiFunc();
102
- // wagmi config shouldn't change
103
- // eslint-disable-next-line react-hooks/exhaustive-deps
104
- }, [partnerId, wallets]);
102
+ }, [wagmiConfig, wallets, connect, switchAccount]);
105
103
  useEffect(() => {
106
104
  syncWagmi();
107
105
  }, [wallets, syncWagmi]);
@@ -25,21 +25,3 @@ export declare function createWagmiConfig(options: CreateWagmiConfigOptions): im
25
25
  }, {
26
26
  "thirdweb:lastChainId": number;
27
27
  }>)[]>;
28
- /**
29
- * Returns a cached wagmi config for the given partnerId.
30
- * Use this instead of calling createWagmiConfig() directly inside React components or hooks
31
- * to avoid registering duplicate EventEmitter listeners on every render.
32
- */
33
- export declare function getCachedWagmiConfig(options: CreateWagmiConfigOptions): import("wagmi").Config<readonly [import("viem").Chain, ...import("viem").Chain[]], {
34
- [k: string]: import("viem").HttpTransport<undefined, false>;
35
- }, (CreateConnectorFn | CreateConnectorFn<import("thirdweb/dist/types/adapters/eip1193").EIP1193Provider | undefined, {
36
- connect<withCapabilities extends boolean = false>(parameters?: import("@thirdweb-dev/wagmi-adapter").ConnectionOptions<withCapabilities> | undefined): Promise<{
37
- accounts: withCapabilities extends true ? readonly {
38
- address: `0x${string}`;
39
- capabilities: Record<string, unknown>;
40
- }[] : readonly `0x${string}`[];
41
- chainId: number;
42
- }>;
43
- }, {
44
- "thirdweb:lastChainId": number;
45
- }>)[]>;
@@ -27,19 +27,3 @@ export function createWagmiConfig(options) {
27
27
  connectors: finalConnectors,
28
28
  });
29
29
  }
30
- /** Module-level cache — wagmi configs must not be recreated on every render. */
31
- const wagmiConfigCache = new Map();
32
- /**
33
- * Returns a cached wagmi config for the given partnerId.
34
- * Use this instead of calling createWagmiConfig() directly inside React components or hooks
35
- * to avoid registering duplicate EventEmitter listeners on every render.
36
- */
37
- export function getCachedWagmiConfig(options) {
38
- const key = options.partnerId;
39
- let config = wagmiConfigCache.get(key);
40
- if (!config) {
41
- config = createWagmiConfig(options);
42
- wagmiConfigCache.set(key, config);
43
- }
44
- return config;
45
- }
@@ -1,7 +1,9 @@
1
+ import React from "react";
1
2
  export interface Step {
2
3
  id: string | number;
3
4
  title: string;
4
5
  description?: string;
6
+ icon?: React.ReactNode;
5
7
  }
6
8
  export interface StepProgressProps {
7
9
  steps: Step[];
@@ -11,6 +11,9 @@ interface ToastContextType {
11
11
  addToast: (type: ToastType, message: string, duration?: number) => string;
12
12
  removeToast: (id: string) => void;
13
13
  clearAll: () => void;
14
+ headerMode: boolean;
15
+ setHeaderMode: (enabled: boolean) => void;
16
+ latestToast: ToastItem | null;
14
17
  }
15
18
  export declare function ToastProvider({ children }: {
16
19
  children: React.ReactNode;
@@ -25,21 +25,3 @@ export declare function createWagmiConfig(options: CreateWagmiConfigOptions): im
25
25
  }, {
26
26
  "thirdweb:lastChainId": number;
27
27
  }>)[]>;
28
- /**
29
- * Returns a cached wagmi config for the given partnerId.
30
- * Use this instead of calling createWagmiConfig() directly inside React components or hooks
31
- * to avoid registering duplicate EventEmitter listeners on every render.
32
- */
33
- export declare function getCachedWagmiConfig(options: CreateWagmiConfigOptions): import("wagmi").Config<readonly [import("viem").Chain, ...import("viem").Chain[]], {
34
- [k: string]: import("viem").HttpTransport<undefined, false>;
35
- }, (CreateConnectorFn | CreateConnectorFn<import("thirdweb/dist/types/adapters/eip1193").EIP1193Provider | undefined, {
36
- connect<withCapabilities extends boolean = false>(parameters?: import("@thirdweb-dev/wagmi-adapter").ConnectionOptions<withCapabilities> | undefined): Promise<{
37
- accounts: withCapabilities extends true ? readonly {
38
- address: `0x${string}`;
39
- capabilities: Record<string, unknown>;
40
- }[] : readonly `0x${string}`[];
41
- chainId: number;
42
- }>;
43
- }, {
44
- "thirdweb:lastChainId": number;
45
- }>)[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.1.69-alpha.5",
3
+ "version": "0.1.69-alpha.7",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -338,6 +338,7 @@
338
338
  "socket.io-client": "4.7.5",
339
339
  "sonner": "1.7.4",
340
340
  "tailwind-merge": "2.6.0",
341
+ "torph": "^0.0.9",
341
342
  "typescript": "5.8.2",
342
343
  "vaul": "^1.1.2",
343
344
  "zustand": "4.5.6"
@@ -24,6 +24,7 @@ import {
24
24
  useB3Config,
25
25
  useModalStore,
26
26
  useProfile,
27
+ useToastContext,
27
28
  useUnifiedChainSwitchAndExecute,
28
29
  } from "@b3dotfun/sdk/global-account/react";
29
30
  import { useRouter, useSearchParams } from "@b3dotfun/sdk/shared/react/hooks";
@@ -231,6 +232,13 @@ export const OrderDetails = memo(function OrderDetails({
231
232
  const router = useRouter();
232
233
  const searchParams = useSearchParams();
233
234
 
235
+ const { setHeaderMode } = useToastContext();
236
+
237
+ useEffect(() => {
238
+ setHeaderMode(true);
239
+ return () => setHeaderMode(false);
240
+ }, [setHeaderMode]);
241
+
234
242
  // Get theme from B3Provider context
235
243
  const { theme } = useB3Config();
236
244
  const colorMode = theme || "light";
@@ -1,7 +1,9 @@
1
1
  import { getStatusDisplay } from "@b3dotfun/sdk/anyspend";
2
2
  import { components } from "@b3dotfun/sdk/anyspend/types/api";
3
3
  import { useSearchParams } from "@b3dotfun/sdk/shared/react";
4
- import { Clock, Loader2, RotateCcw, X } from "lucide-react";
4
+ import { AlertCircle, AlertTriangle, CheckCircle, Clock, Info, Loader2, RotateCcw, X } from "lucide-react";
5
+ import { useToastContext } from "@b3dotfun/sdk/global-account/react";
6
+ import type { ToastType } from "@b3dotfun/sdk/global-account/react";
5
7
  import React, { memo, useEffect, useRef } from "react";
6
8
  import { useAnySpendCustomization } from "../context/AnySpendCustomizationContext";
7
9
  import { AnimatedCheckmark } from "../icons/AnimatedCheckmark";
@@ -15,6 +17,20 @@ function getStepIndex(status: string): number {
15
17
  return -1;
16
18
  }
17
19
 
20
+ function getToastIcon(type: ToastType): React.ReactNode {
21
+ const iconClass = "h-5 w-5";
22
+ switch (type) {
23
+ case "success":
24
+ return <CheckCircle className={`${iconClass} text-green-500`} />;
25
+ case "error":
26
+ return <AlertCircle className={`${iconClass} text-red-500`} />;
27
+ case "info":
28
+ return <Info className={`${iconClass} text-blue-500`} />;
29
+ case "warning":
30
+ return <AlertTriangle className={`${iconClass} text-amber-500`} />;
31
+ }
32
+ }
33
+
18
34
  export const OrderStatus = memo(function OrderStatus({
19
35
  order,
20
36
  selectedCryptoPaymentMethod,
@@ -56,9 +72,28 @@ export const OrderStatus = memo(function OrderStatus({
56
72
  if (content.processingDescription) description = content.processingDescription;
57
73
  }
58
74
 
75
+ const { latestToast } = useToastContext();
76
+
77
+ // Override subtitle with toast notification when present (title stays unchanged)
78
+ let notificationIcon: React.ReactNode = undefined;
79
+ if (latestToast && currentStepIndex >= 0) {
80
+ description = latestToast.message;
81
+ notificationIcon = getToastIcon(latestToast.type);
82
+ }
83
+
59
84
  const paymentSteps: Step[] = [
60
- { id: 1, title: text, description: typeof description === "string" ? description : defaultDescription || "" },
61
- { id: 2, title: text, description: typeof description === "string" ? description : defaultDescription || "" },
85
+ {
86
+ id: 1,
87
+ title: text,
88
+ description: typeof description === "string" ? description : defaultDescription || "",
89
+ icon: notificationIcon,
90
+ },
91
+ {
92
+ id: 2,
93
+ title: text,
94
+ description: typeof description === "string" ? description : defaultDescription || "",
95
+ icon: notificationIcon,
96
+ },
62
97
  ];
63
98
 
64
99
  if (currentStepIndex === 0) {
@@ -1,12 +1,15 @@
1
1
  "use client";
2
2
 
3
+ import React from "react";
3
4
  import { motion } from "framer-motion";
5
+ import { TextMorph } from "torph/react";
4
6
  import { AnimatedCheckmark } from "../icons/AnimatedCheckmark";
5
7
 
6
8
  export interface Step {
7
9
  id: string | number;
8
10
  title: string;
9
11
  description?: string;
12
+ icon?: React.ReactNode;
10
13
  }
11
14
 
12
15
  export interface StepProgressProps {
@@ -32,8 +35,8 @@ export function StepProgress({
32
35
  {/* Step Progress Indicator */}
33
36
  <div className="flex items-center gap-2">
34
37
  {steps.map((_, index) => (
35
- <>
36
- <div key={index} className="flex items-center">
38
+ <React.Fragment key={index}>
39
+ <div className="flex items-center">
37
40
  {index < currentStepIndex ? (
38
41
  // Completed step - checkmark replaces the whole circle
39
42
  <motion.div
@@ -71,7 +74,7 @@ export function StepProgress({
71
74
  ))}
72
75
  </div>
73
76
  )}
74
- </>
77
+ </React.Fragment>
75
78
  ))}
76
79
  </div>
77
80
 
@@ -83,8 +86,15 @@ export function StepProgress({
83
86
  transition={{ delay: 0.3 }}
84
87
  className="text-center"
85
88
  >
86
- <h2 className="text-as-primary text-xl font-semibold">{currentStep.title}</h2>
87
- {currentStep.description && <p className="text-as-tertiary mt-1 text-sm">{currentStep.description}</p>}
89
+ <h2 className="text-as-primary text-xl font-semibold">
90
+ <TextMorph>{currentStep.title}</TextMorph>
91
+ </h2>
92
+ {currentStep.description && (
93
+ <p className="text-as-tertiary mt-1 flex items-center justify-center gap-1.5 text-sm">
94
+ {currentStep.icon}
95
+ <TextMorph>{currentStep.description}</TextMorph>
96
+ </p>
97
+ )}
88
98
  </motion.div>
89
99
  )}
90
100
  </div>
@@ -43,7 +43,7 @@ export function B3DynamicModal() {
43
43
  const navigateBack = useModalStore(state => state.navigateBack);
44
44
  const { theme } = useB3Config();
45
45
  const isMobile = useIsMobile();
46
- const { toasts, removeToast } = useToastContext();
46
+ const { toasts, removeToast, headerMode } = useToastContext();
47
47
 
48
48
  // Define arrays for different modal type groups
49
49
  const fullWidthTypes = [
@@ -247,7 +247,7 @@ export function B3DynamicModal() {
247
247
 
248
248
  {/* Toast Container - Part of modal-inner-content layer */}
249
249
  <AnimatePresence>
250
- {toasts.length > 0 && (
250
+ {!headerMode && toasts.length > 0 && (
251
251
  <motion.div
252
252
  initial={{ height: 0 }}
253
253
  animate={{ height: "auto" }}
@@ -5,6 +5,7 @@ import { Account, Wallet } from "thirdweb/wallets";
5
5
 
6
6
  import { ClientType } from "../../../client-manager";
7
7
 
8
+ import { useMemo } from "react";
8
9
  import { WagmiProvider } from "wagmi";
9
10
  import { createWagmiConfig } from "../../utils/createWagmiConfig";
10
11
  import AuthenticationProvider from "./AuthenticationProvider";
@@ -82,7 +83,7 @@ export function InnerProvider({
82
83
  partnerId: string;
83
84
  rpcUrls?: Record<number, string>;
84
85
  }) {
85
- const wagmiConfig = createWagmiConfig({ partnerId, rpcUrls });
86
+ const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId, rpcUrls }), [partnerId, rpcUrls]);
86
87
 
87
88
  return (
88
89
  <WagmiProvider config={wagmiConfig}>
@@ -15,6 +15,9 @@ interface ToastContextType {
15
15
  addToast: (type: ToastType, message: string, duration?: number) => string;
16
16
  removeToast: (id: string) => void;
17
17
  clearAll: () => void;
18
+ headerMode: boolean;
19
+ setHeaderMode: (enabled: boolean) => void;
20
+ latestToast: ToastItem | null;
18
21
  }
19
22
 
20
23
  const ToastContext = createContext<ToastContextType | undefined>(undefined);
@@ -23,6 +26,9 @@ let globalToastCounter = 0;
23
26
 
24
27
  export function ToastProvider({ children }: { children: React.ReactNode }) {
25
28
  const [toasts, setToasts] = useState<ToastItem[]>([]);
29
+ const [headerMode, setHeaderMode] = useState(false);
30
+ const headerModeRef = useRef(false);
31
+ const [latestToast, setLatestToast] = useState<ToastItem | null>(null);
26
32
  const timeoutsRef = useRef<Map<string, NodeJS.Timeout>>(new Map());
27
33
 
28
34
  const removeToast = useCallback((id: string) => {
@@ -45,13 +51,23 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
45
51
  createdAt: Date.now(),
46
52
  };
47
53
 
48
- setToasts(prev => [...prev, newToast]);
54
+ if (headerModeRef.current) {
55
+ setLatestToast(newToast);
56
+ if (duration > 0) {
57
+ const timeout = setTimeout(() => {
58
+ setLatestToast(null);
59
+ }, duration);
60
+ timeoutsRef.current.set(id, timeout);
61
+ }
62
+ } else {
63
+ setToasts(prev => [...prev, newToast]);
49
64
 
50
- if (duration > 0) {
51
- const timeout = setTimeout(() => {
52
- removeToast(id);
53
- }, duration);
54
- timeoutsRef.current.set(id, timeout);
65
+ if (duration > 0) {
66
+ const timeout = setTimeout(() => {
67
+ removeToast(id);
68
+ }, duration);
69
+ timeoutsRef.current.set(id, timeout);
70
+ }
55
71
  }
56
72
 
57
73
  return id;
@@ -65,6 +81,16 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
65
81
  setToasts([]);
66
82
  }, []);
67
83
 
84
+ const setHeaderModeCallback = useCallback((enabled: boolean) => {
85
+ setHeaderMode(enabled);
86
+ headerModeRef.current = enabled;
87
+ if (!enabled) {
88
+ setLatestToast(null);
89
+ timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
90
+ timeoutsRef.current.clear();
91
+ }
92
+ }, []);
93
+
68
94
  // Cleanup on unmount
69
95
  useEffect(() => {
70
96
  const timeouts = timeoutsRef.current;
@@ -74,7 +100,13 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
74
100
  };
75
101
  }, []);
76
102
 
77
- return <ToastContext.Provider value={{ toasts, addToast, removeToast, clearAll }}>{children}</ToastContext.Provider>;
103
+ return (
104
+ <ToastContext.Provider
105
+ value={{ toasts, addToast, removeToast, clearAll, headerMode, setHeaderMode: setHeaderModeCallback, latestToast }}
106
+ >
107
+ {children}
108
+ </ToastContext.Provider>
109
+ );
78
110
  }
79
111
 
80
112
  export function useToastContext() {
@@ -6,7 +6,7 @@ import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
6
6
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
7
7
  import { ConnectionOptions } from "@thirdweb-dev/wagmi-adapter";
8
8
  import { getConnectors } from "@wagmi/core";
9
- import { useCallback, useContext, useEffect, useRef } from "react";
9
+ import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
10
10
  import {
11
11
  useActiveWallet,
12
12
  useAutoConnect,
@@ -18,7 +18,7 @@ import { Wallet, ecosystemWallet } from "thirdweb/wallets";
18
18
  import { preAuthenticate } from "thirdweb/wallets/in-app";
19
19
  import { useAccount, useConnect, useSwitchAccount } from "wagmi";
20
20
  import { LocalSDKContext } from "../components/B3Provider/LocalSDKProvider";
21
- import { getCachedWagmiConfig } from "../utils/createWagmiConfig";
21
+ import { createWagmiConfig } from "../utils/createWagmiConfig";
22
22
  import { useSearchParam } from "./useSearchParamsSSR";
23
23
  import { useUserQuery } from "./useUserQuery";
24
24
 
@@ -47,7 +47,7 @@ export function useAuth() {
47
47
  const useAutoConnectLoadingPrevious = useRef(false);
48
48
  const referralCode = useSearchParam("referralCode");
49
49
  const { partnerId } = useB3Config();
50
- const wagmiConfig = getCachedWagmiConfig({ partnerId });
50
+ const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId }), [partnerId]);
51
51
  const { connect } = useConnect();
52
52
  const activeWagmiAccount = useAccount();
53
53
  const { switchAccount } = useSwitchAccount();
@@ -136,9 +136,7 @@ export function useAuth() {
136
136
  });
137
137
  }
138
138
  syncWagmiFunc();
139
- // wagmi config shouldn't change
140
- // eslint-disable-next-line react-hooks/exhaustive-deps
141
- }, [partnerId, wallets]);
139
+ }, [wagmiConfig, wallets, connect, switchAccount]);
142
140
 
143
141
  useEffect(() => {
144
142
  syncWagmi();
@@ -6,7 +6,7 @@ import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
6
6
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
7
7
  import { ConnectionOptions } from "@thirdweb-dev/wagmi-adapter";
8
8
  import { getConnectors } from "@wagmi/core";
9
- import { useCallback, useContext, useEffect, useRef } from "react";
9
+ import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
10
10
  import {
11
11
  useActiveWallet,
12
12
  useAutoConnect,
@@ -57,7 +57,7 @@ export function useAuthentication(partnerId: string, { skipAutoConnect = false }
57
57
  const { authenticate } = useTWAuth();
58
58
  const { user, setUser } = useUserQuery();
59
59
  const useAutoConnectLoadingPrevious = useRef(false);
60
- const wagmiConfig = createWagmiConfig({ partnerId });
60
+ const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId }), [partnerId]);
61
61
  const { connect } = useConnect();
62
62
  const activeWagmiAccount = useAccount();
63
63
  const { switchAccount } = useSwitchAccount();
@@ -113,9 +113,7 @@ export function useAuthentication(partnerId: string, { skipAutoConnect = false }
113
113
  });
114
114
  }
115
115
  syncWagmiFunc();
116
- // wagmi config shouldn't change
117
- // eslint-disable-next-line react-hooks/exhaustive-deps
118
- }, [partnerId, wallets]);
116
+ }, [wagmiConfig, wallets, connect, switchAccount]);
119
117
 
120
118
  useEffect(() => {
121
119
  syncWagmi();
@@ -38,21 +38,3 @@ export function createWagmiConfig(options: CreateWagmiConfigOptions) {
38
38
  connectors: finalConnectors,
39
39
  });
40
40
  }
41
-
42
- /** Module-level cache — wagmi configs must not be recreated on every render. */
43
- const wagmiConfigCache = new Map<string, ReturnType<typeof createWagmiConfig>>();
44
-
45
- /**
46
- * Returns a cached wagmi config for the given partnerId.
47
- * Use this instead of calling createWagmiConfig() directly inside React components or hooks
48
- * to avoid registering duplicate EventEmitter listeners on every render.
49
- */
50
- export function getCachedWagmiConfig(options: CreateWagmiConfigOptions) {
51
- const key = options.partnerId;
52
- let config = wagmiConfigCache.get(key);
53
- if (!config) {
54
- config = createWagmiConfig(options);
55
- wagmiConfigCache.set(key, config);
56
- }
57
- return config;
58
- }
@@ -0,0 +1,4 @@
1
+ declare module "torph/react" {
2
+ import type { JSX } from "react";
3
+ export function TextMorph(props: { children: string; className?: string }): JSX.Element;
4
+ }