@b3dotfun/sdk 0.0.42 → 0.0.43

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 (114) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.d.ts +1 -0
  2. package/dist/cjs/anyspend/react/components/AnySpend.js +11 -4
  3. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +43 -3
  4. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.d.ts +1 -0
  5. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +2 -2
  6. package/dist/cjs/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
  7. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +5 -3
  8. package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +1 -1
  9. package/dist/cjs/global-account/react/components/index.d.ts +8 -7
  10. package/dist/cjs/global-account/react/components/index.js +29 -23
  11. package/dist/cjs/global-account/react/components/ui/dropdown-menu.d.ts +27 -0
  12. package/dist/cjs/global-account/react/components/ui/dropdown-menu.js +100 -0
  13. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +5 -1
  14. package/dist/cjs/shared/constants/currency.d.ts +1 -0
  15. package/dist/cjs/shared/constants/currency.js +5 -0
  16. package/dist/cjs/shared/constants/index.d.ts +1 -0
  17. package/dist/cjs/shared/constants/index.js +15 -0
  18. package/dist/cjs/shared/react/components/CurrencySelector.d.ts +7 -0
  19. package/dist/cjs/shared/react/components/CurrencySelector.js +14 -0
  20. package/dist/cjs/shared/react/components/FormattedCurrency.d.ts +12 -0
  21. package/dist/cjs/shared/react/components/FormattedCurrency.js +60 -0
  22. package/dist/cjs/shared/react/components/index.d.ts +2 -0
  23. package/dist/cjs/shared/react/components/index.js +18 -0
  24. package/dist/cjs/shared/react/hooks/__tests__/useCurrencyConversion.test.d.ts +1 -0
  25. package/dist/cjs/shared/react/hooks/__tests__/useCurrencyConversion.test.js +245 -0
  26. package/dist/cjs/shared/react/hooks/index.d.ts +1 -0
  27. package/dist/cjs/shared/react/hooks/index.js +1 -0
  28. package/dist/cjs/shared/react/hooks/useCurrencyConversion.d.ts +35 -0
  29. package/dist/cjs/shared/react/hooks/useCurrencyConversion.js +200 -0
  30. package/dist/cjs/shared/react/index.d.ts +2 -0
  31. package/dist/cjs/shared/react/index.js +2 -0
  32. package/dist/cjs/shared/react/stores/currencyModalStore.d.ts +7 -0
  33. package/dist/cjs/shared/react/stores/currencyModalStore.js +9 -0
  34. package/dist/cjs/shared/react/stores/currencyStore.d.ts +51 -0
  35. package/dist/cjs/shared/react/stores/currencyStore.js +57 -0
  36. package/dist/cjs/shared/react/stores/index.d.ts +2 -0
  37. package/dist/cjs/shared/react/stores/index.js +18 -0
  38. package/dist/esm/anyspend/react/components/AnySpend.d.ts +1 -0
  39. package/dist/esm/anyspend/react/components/AnySpend.js +11 -4
  40. package/dist/esm/anyspend/react/components/AnySpendCustom.js +10 -3
  41. package/dist/esm/anyspend/react/components/AnyspendDepositHype.d.ts +1 -0
  42. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +2 -2
  43. package/dist/esm/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
  44. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +5 -3
  45. package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +1 -1
  46. package/dist/esm/global-account/react/components/index.d.ts +8 -7
  47. package/dist/esm/global-account/react/components/index.js +8 -7
  48. package/dist/esm/global-account/react/components/ui/dropdown-menu.d.ts +27 -0
  49. package/dist/esm/global-account/react/components/ui/dropdown-menu.js +60 -0
  50. package/dist/esm/global-account/react/stores/useModalStore.d.ts +5 -1
  51. package/dist/esm/shared/constants/currency.d.ts +1 -0
  52. package/dist/esm/shared/constants/currency.js +2 -0
  53. package/dist/esm/shared/constants/index.d.ts +1 -0
  54. package/dist/esm/shared/constants/index.js +1 -0
  55. package/dist/esm/shared/react/components/CurrencySelector.d.ts +7 -0
  56. package/dist/esm/shared/react/components/CurrencySelector.js +11 -0
  57. package/dist/esm/shared/react/components/FormattedCurrency.d.ts +12 -0
  58. package/dist/esm/shared/react/components/FormattedCurrency.js +57 -0
  59. package/dist/esm/shared/react/components/index.d.ts +2 -0
  60. package/dist/esm/shared/react/components/index.js +2 -0
  61. package/dist/esm/shared/react/hooks/__tests__/useCurrencyConversion.test.d.ts +1 -0
  62. package/dist/esm/shared/react/hooks/__tests__/useCurrencyConversion.test.js +243 -0
  63. package/dist/esm/shared/react/hooks/index.d.ts +1 -0
  64. package/dist/esm/shared/react/hooks/index.js +1 -0
  65. package/dist/esm/shared/react/hooks/useCurrencyConversion.d.ts +35 -0
  66. package/dist/esm/shared/react/hooks/useCurrencyConversion.js +197 -0
  67. package/dist/esm/shared/react/index.d.ts +2 -0
  68. package/dist/esm/shared/react/index.js +2 -0
  69. package/dist/esm/shared/react/stores/currencyModalStore.d.ts +7 -0
  70. package/dist/esm/shared/react/stores/currencyModalStore.js +6 -0
  71. package/dist/esm/shared/react/stores/currencyStore.d.ts +51 -0
  72. package/dist/esm/shared/react/stores/currencyStore.js +54 -0
  73. package/dist/esm/shared/react/stores/index.d.ts +2 -0
  74. package/dist/esm/shared/react/stores/index.js +2 -0
  75. package/dist/styles/index.css +1 -1
  76. package/dist/types/anyspend/react/components/AnySpend.d.ts +1 -0
  77. package/dist/types/anyspend/react/components/AnyspendDepositHype.d.ts +1 -0
  78. package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
  79. package/dist/types/global-account/react/components/index.d.ts +8 -7
  80. package/dist/types/global-account/react/components/ui/dropdown-menu.d.ts +27 -0
  81. package/dist/types/global-account/react/stores/useModalStore.d.ts +5 -1
  82. package/dist/types/shared/constants/currency.d.ts +1 -0
  83. package/dist/types/shared/constants/index.d.ts +1 -0
  84. package/dist/types/shared/react/components/CurrencySelector.d.ts +7 -0
  85. package/dist/types/shared/react/components/FormattedCurrency.d.ts +12 -0
  86. package/dist/types/shared/react/components/index.d.ts +2 -0
  87. package/dist/types/shared/react/hooks/__tests__/useCurrencyConversion.test.d.ts +1 -0
  88. package/dist/types/shared/react/hooks/index.d.ts +1 -0
  89. package/dist/types/shared/react/hooks/useCurrencyConversion.d.ts +35 -0
  90. package/dist/types/shared/react/index.d.ts +2 -0
  91. package/dist/types/shared/react/stores/currencyModalStore.d.ts +7 -0
  92. package/dist/types/shared/react/stores/currencyStore.d.ts +51 -0
  93. package/dist/types/shared/react/stores/index.d.ts +2 -0
  94. package/package.json +29 -3
  95. package/src/anyspend/react/components/AnySpend.tsx +15 -2
  96. package/src/anyspend/react/components/AnySpendCustom.tsx +11 -2
  97. package/src/anyspend/react/components/AnyspendDepositHype.tsx +3 -0
  98. package/src/anyspend/react/components/common/PanelOnramp.tsx +19 -15
  99. package/src/global-account/react/components/SignInWithB3/SignIn.tsx +2 -7
  100. package/src/global-account/react/components/index.ts +19 -12
  101. package/src/global-account/react/components/ui/dropdown-menu.tsx +132 -0
  102. package/src/global-account/react/stores/useModalStore.ts +5 -1
  103. package/src/shared/constants/currency.ts +2 -0
  104. package/src/shared/constants/index.ts +2 -0
  105. package/src/shared/react/components/CurrencySelector.tsx +71 -0
  106. package/src/shared/react/components/FormattedCurrency.tsx +106 -0
  107. package/src/shared/react/components/index.ts +2 -0
  108. package/src/shared/react/hooks/__tests__/useCurrencyConversion.test.ts +308 -0
  109. package/src/shared/react/hooks/index.ts +1 -0
  110. package/src/shared/react/hooks/useCurrencyConversion.ts +211 -0
  111. package/src/shared/react/index.ts +2 -0
  112. package/src/shared/react/stores/currencyModalStore.ts +13 -0
  113. package/src/shared/react/stores/currencyStore.ts +82 -0
  114. package/src/shared/react/stores/index.ts +2 -0
@@ -0,0 +1,7 @@
1
+ interface CurrencySelectorProps {
2
+ labelClassName?: string;
3
+ buttonVariant?: "dark" | "primary" | "ghost" | "gold";
4
+ label?: string;
5
+ }
6
+ export declare function CurrencySelector({ labelClassName, buttonVariant, label }: CurrencySelectorProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,12 @@
1
+ interface FormattedCurrencyProps {
2
+ amount: number;
3
+ showChange?: boolean;
4
+ showColor?: boolean;
5
+ className?: string;
6
+ subB3Icon?: boolean;
7
+ clickable?: boolean;
8
+ decimals?: number;
9
+ currency?: string;
10
+ }
11
+ export declare function FormattedCurrency({ amount, showChange, showColor, className, subB3Icon, clickable, decimals, currency, }: FormattedCurrencyProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./CurrencySelector";
2
+ export * from "./FormattedCurrency";
@@ -1 +1,2 @@
1
+ export * from "./useCurrencyConversion";
1
2
  export * from "./useNavigation";
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Hook for currency conversion and formatting with real-time exchange rates.
3
+ *
4
+ * This hook provides currency conversion functionality using live exchange rates
5
+ * and formats values according to currency-specific rules (decimals, symbols, etc.).
6
+ *
7
+ * @returns Currency conversion utilities and state
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * function PriceDisplay({ amount }: { amount: number }) {
12
+ * const { formatCurrencyValue, selectedCurrency } = useCurrencyConversion();
13
+ * return <div>{formatCurrencyValue(amount)}</div>;
14
+ * }
15
+ * ```
16
+ */
17
+ export declare function useCurrencyConversion(): {
18
+ /** Currently selected display currency */
19
+ selectedCurrency: import("../stores/currencyStore").SupportedCurrency;
20
+ /** Base currency used for conversion (typically B3) */
21
+ baseCurrency: import("../stores/currencyStore").SupportedCurrency;
22
+ /** Current exchange rate from base to selected currency (undefined while loading) */
23
+ exchangeRate: number;
24
+ /** Format a value with currency conversion and proper symbol/decimal handling */
25
+ formatCurrencyValue: (value: number, options?: {
26
+ decimals?: number;
27
+ currency?: string;
28
+ }) => string;
29
+ /** Format a tooltip value showing alternate currency representation */
30
+ formatTooltipValue: (value: number, customCurrency?: string) => string;
31
+ /** Symbol for the currently selected currency (e.g., "$", "€", "ETH") */
32
+ selectedCurrencySymbol: string;
33
+ /** Symbol for the base currency */
34
+ baseCurrencySymbol: string;
35
+ };
@@ -1 +1,3 @@
1
+ export * from "./components";
1
2
  export * from "./hooks";
3
+ export * from "./stores";
@@ -0,0 +1,7 @@
1
+ interface CurrencyModalState {
2
+ isOpen: boolean;
3
+ openModal: () => void;
4
+ closeModal: () => void;
5
+ }
6
+ export declare const useCurrencyModalStore: import("zustand").UseBoundStore<import("zustand").StoreApi<CurrencyModalState>>;
7
+ export {};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Supported currencies for display and conversion.
3
+ * Includes fiat currencies (USD, EUR, GBP, JPY, CAD, AUD, KRW) and crypto (ETH, SOL, B3).
4
+ */
5
+ export type SupportedCurrency = "ETH" | "USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD" | "B3" | "SOL" | "KRW";
6
+ /**
7
+ * Currency symbols used for display formatting.
8
+ * Prefix currencies (USD, EUR, GBP, CAD, AUD) show symbol before the amount.
9
+ * Suffix currencies (JPY, KRW, ETH, SOL, B3) show symbol after the amount.
10
+ */
11
+ export declare const CURRENCY_SYMBOLS: Record<SupportedCurrency, string>;
12
+ /**
13
+ * Human-readable currency names for display in selectors and labels.
14
+ */
15
+ export declare const CURRENCY_NAMES: Record<SupportedCurrency, string>;
16
+ /**
17
+ * Currency store state interface.
18
+ * @property selectedCurrency - The currency currently selected for display
19
+ * @property baseCurrency - The base currency for conversion (typically B3)
20
+ * @property setSelectedCurrency - Update the selected display currency
21
+ * @property setBaseCurrency - Update the base currency for conversions
22
+ */
23
+ interface CurrencyState {
24
+ selectedCurrency: SupportedCurrency;
25
+ baseCurrency: SupportedCurrency;
26
+ setSelectedCurrency: (currency: SupportedCurrency) => void;
27
+ setBaseCurrency: (currency: SupportedCurrency) => void;
28
+ }
29
+ /**
30
+ * Zustand store for managing currency selection and conversion.
31
+ * Persists user's selected currency preference in localStorage.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * const { selectedCurrency, setSelectedCurrency } = useCurrencyStore();
36
+ * // Change display currency to USD
37
+ * setSelectedCurrency('USD');
38
+ * ```
39
+ */
40
+ export declare const useCurrencyStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<CurrencyState>, "persist"> & {
41
+ persist: {
42
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<CurrencyState, CurrencyState>>) => void;
43
+ clearStorage: () => void;
44
+ rehydrate: () => Promise<void> | void;
45
+ hasHydrated: () => boolean;
46
+ onHydrate: (fn: (state: CurrencyState) => void) => () => void;
47
+ onFinishHydration: (fn: (state: CurrencyState) => void) => () => void;
48
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<CurrencyState, CurrencyState>>;
49
+ };
50
+ }>;
51
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./currencyModalStore";
2
+ export * from "./currencyStore";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.0.42",
3
+ "version": "0.0.43",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -205,6 +205,26 @@
205
205
  "import": "./dist/esm/shared/thirdweb/*.js",
206
206
  "require": "./dist/cjs/shared/thirdweb/*.js"
207
207
  },
208
+ "./shared/react": {
209
+ "types": "./dist/types/shared/react/index.d.ts",
210
+ "import": "./dist/esm/shared/react/index.js",
211
+ "require": "./dist/cjs/shared/react/index.js"
212
+ },
213
+ "./shared/react/components": {
214
+ "types": "./dist/types/shared/react/components/index.d.ts",
215
+ "import": "./dist/esm/shared/react/components/index.js",
216
+ "require": "./dist/cjs/shared/react/components/index.js"
217
+ },
218
+ "./shared/react/hooks": {
219
+ "types": "./dist/types/shared/react/hooks/index.d.ts",
220
+ "import": "./dist/esm/shared/react/hooks/index.js",
221
+ "require": "./dist/cjs/shared/react/hooks/index.js"
222
+ },
223
+ "./shared/react/stores": {
224
+ "types": "./dist/types/shared/react/stores/index.d.ts",
225
+ "import": "./dist/esm/shared/react/stores/index.js",
226
+ "require": "./dist/cjs/shared/react/stores/index.js"
227
+ },
208
228
  "./types/chain-networks": {
209
229
  "types": "./dist/types/generated/chain-networks.d.ts",
210
230
  "import": "./dist/esm/generated/chain-networks.js",
@@ -289,6 +309,8 @@
289
309
  "@feathersjs/feathers": "5.0.33",
290
310
  "@feathersjs/socketio-client": "5.0.33",
291
311
  "@feathersjs/typebox": "5.0.33",
312
+ "@testing-library/react": "^16.3.0",
313
+ "@testing-library/react-hooks": "^8.0.1",
292
314
  "@types/big.js": "^6.2.2",
293
315
  "@types/invariant": "2.2.37",
294
316
  "@types/js-cookie": "3.0.6",
@@ -304,6 +326,7 @@
304
326
  "eslint-plugin-import": "2.x.x",
305
327
  "eslint-plugin-react-hooks": "4.6.2",
306
328
  "eslint-plugin-tailwindcss": "3.18.0",
329
+ "happy-dom": "^19.0.2",
307
330
  "postcss": "8.5.3",
308
331
  "postcss-cli": "11.0.1",
309
332
  "postcss-nesting": "^13.0.2",
@@ -311,7 +334,8 @@
311
334
  "tailwindcss": "3.4.1",
312
335
  "tailwindcss-animate": "^1.0.7",
313
336
  "tsc-alias": "^1.8.16",
314
- "tsc-watch": "^7.1.1"
337
+ "tsc-watch": "^7.1.1",
338
+ "vitest": "^3.2.4"
315
339
  },
316
340
  "typesVersions": {
317
341
  "*": {
@@ -367,6 +391,8 @@
367
391
  "typecheck": "tsc --noEmit",
368
392
  "generate:thirdweb": "npx @hey-api/openapi-ts --file src/thirdweb/openapi-ts.config.ts --input src/thirdweb/insight-service.json",
369
393
  "lint": "eslint 'src/**/*.{ts,tsx}'",
370
- "lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix"
394
+ "lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix",
395
+ "test": "vitest run",
396
+ "test:ui": "vitest --ui"
371
397
  }
372
398
  }
@@ -79,6 +79,7 @@ export function AnySpend(props: {
79
79
  */
80
80
  onTokenSelect?: (token: components["schemas"]["Token"], event: { preventDefault: () => void }) => void;
81
81
  onSuccess?: (txHash?: string) => void;
82
+ customUsdInputValues?: string[];
82
83
  }) {
83
84
  const fingerprintConfig = getFingerprintConfig();
84
85
 
@@ -99,6 +100,7 @@ function AnySpendInner({
99
100
  recipientAddress: recipientAddressFromProps,
100
101
  onTokenSelect,
101
102
  onSuccess,
103
+ customUsdInputValues,
102
104
  }: {
103
105
  destinationTokenAddress?: string;
104
106
  destinationTokenChainId?: number;
@@ -109,6 +111,7 @@ function AnySpendInner({
109
111
  recipientAddress?: string;
110
112
  onTokenSelect?: (token: components["schemas"]["Token"], event: { preventDefault: () => void }) => void;
111
113
  onSuccess?: (txHash?: string) => void;
114
+ customUsdInputValues?: string[];
112
115
  }) {
113
116
  const searchParams = useSearchParamsSSR();
114
117
  const router = useRouter();
@@ -134,6 +137,9 @@ function AnySpendInner({
134
137
  toAmount?: string;
135
138
  } | null>(null);
136
139
 
140
+ // Track if onSuccess has been called for the current order
141
+ const onSuccessCalled = useRef(false);
142
+
137
143
  const [activeTab, setActiveTab] = useState<"crypto" | "fiat">(defaultActiveTab);
138
144
 
139
145
  const [orderId, setOrderId] = useState<string | undefined>(loadOrder);
@@ -520,12 +526,18 @@ function AnySpendInner({
520
526
  }, [anyspendQuote, isSrcInputDirty]);
521
527
 
522
528
  useEffect(() => {
523
- if (oat?.data?.order.status === "executed") {
529
+ if (oat?.data?.order.status === "executed" && !onSuccessCalled.current) {
524
530
  console.log("Calling onSuccess");
525
531
  const txHash = oat?.data?.executeTx?.txHash;
526
532
  onSuccess?.(txHash);
533
+ onSuccessCalled.current = true;
527
534
  }
528
- }, [oat?.data?.executeTx?.txHash, oat?.data?.order.status, onSuccess]);
535
+ }, [oat?.data?.order.status, oat?.data?.executeTx?.txHash, onSuccess]);
536
+
537
+ // Reset flag when orderId changes
538
+ useEffect(() => {
539
+ onSuccessCalled.current = false;
540
+ }, [orderId]);
529
541
 
530
542
  const { createOrder, isCreatingOrder } = useAnyspendCreateOrder({
531
543
  onSuccess: data => {
@@ -915,6 +927,7 @@ function AnySpendInner({
915
927
  hideDstToken={isBuyMode}
916
928
  anyspendQuote={anyspendQuote}
917
929
  onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
930
+ customUsdInputValues={customUsdInputValues}
918
931
  />
919
932
  </motion.div>
920
933
  )}
@@ -255,6 +255,9 @@ function AnySpendCustomInner({
255
255
 
256
256
  const [orderId, setOrderId] = useState<string | undefined>(loadOrder);
257
257
 
258
+ // Track if onSuccess has been called for the current order
259
+ const onSuccessCalled = React.useRef(false);
260
+
258
261
  const [srcChainId, setSrcChainId] = useState<number>(base.id);
259
262
 
260
263
  // Get token list for token balance check
@@ -390,12 +393,18 @@ function AnySpendCustomInner({
390
393
  useGeoOnrampOptions(srcFiatAmount);
391
394
 
392
395
  useEffect(() => {
393
- if (oat?.data?.order.status === "executed") {
396
+ if (oat?.data?.order.status === "executed" && !onSuccessCalled.current) {
394
397
  console.log("Calling onSuccess");
395
398
  const txHash = oat?.data?.executeTx?.txHash;
396
399
  onSuccess?.(txHash);
400
+ onSuccessCalled.current = true;
397
401
  }
398
- }, [oat?.data?.executeTx?.txHash, oat?.data?.order.status, onSuccess]);
402
+ }, [oat?.data?.order.status, oat?.data?.executeTx?.txHash, onSuccess]);
403
+
404
+ // Reset flag when orderId changes
405
+ useEffect(() => {
406
+ onSuccessCalled.current = false;
407
+ }, [orderId]);
399
408
 
400
409
  const { createOrder: createRegularOrder, isCreatingOrder: isCreatingRegularOrder } = useAnyspendCreateOrder({
401
410
  onSuccess: data => {
@@ -42,6 +42,7 @@ export interface AnySpendDepositHypeProps {
42
42
  * Useful for handling special cases like B3 token selection.
43
43
  */
44
44
  onTokenSelect?: (token: components["schemas"]["Token"], event: { preventDefault: () => void }) => void;
45
+ customUsdInputValues?: string[];
45
46
  }
46
47
 
47
48
  export function AnySpendDepositHype(props: AnySpendDepositHypeProps) {
@@ -64,6 +65,7 @@ function AnySpendDepositHypeInner({
64
65
  onSuccess,
65
66
  mainFooter,
66
67
  onTokenSelect,
68
+ customUsdInputValues,
67
69
  }: AnySpendDepositHypeProps) {
68
70
  // Use shared flow hook
69
71
  const {
@@ -234,6 +236,7 @@ function AnySpendDepositHypeInner({
234
236
  recipientSelectionPanelIndex={PanelView.RECIPIENT_SELECTION}
235
237
  anyspendQuote={anyspendQuote}
236
238
  onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
239
+ customUsdInputValues={customUsdInputValues}
237
240
  />
238
241
  </motion.div>
239
242
  )}
@@ -30,6 +30,7 @@ export function PanelOnramp({
30
30
  hideDstToken = false,
31
31
  anyspendQuote,
32
32
  onShowPointsDetail,
33
+ customUsdInputValues = ["5", "10", "20", "25"],
33
34
  }: {
34
35
  srcAmountOnRamp: string;
35
36
  setSrcAmountOnRamp: (amount: string) => void;
@@ -47,6 +48,7 @@ export function PanelOnramp({
47
48
  hideDstToken?: boolean;
48
49
  anyspendQuote?: GetQuoteResponse;
49
50
  onShowPointsDetail?: () => void;
51
+ customUsdInputValues?: string[];
50
52
  }) {
51
53
  const featureFlags = useFeatureFlags();
52
54
  // Get geo-based onramp options to access fee information
@@ -166,7 +168,7 @@ export function PanelOnramp({
166
168
  value={srcAmountOnRamp}
167
169
  onChange={handleAmountChange}
168
170
  placeholder="5"
169
- className="text-as-primary placeholder:text-as-primary/50 h-auto min-w-[70px] border-0 bg-transparent p-0 px-3 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0"
171
+ className="text-as-primary placeholder:text-as-primary/50 h-auto min-w-[70px] border-0 bg-transparent p-0 px-1 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0"
170
172
  style={{
171
173
  width: `${Math.max(50, srcAmountOnRamp.length * 34)}px`,
172
174
  }}
@@ -175,20 +177,22 @@ export function PanelOnramp({
175
177
  </div>
176
178
 
177
179
  {/* Quick Amount Buttons */}
178
- <div className={cn("mx-auto mb-6 inline-grid grid-cols-4 gap-2", hideDstToken && "mb-0")}>
179
- {["5", "10", "20", "25"].map(value => (
180
- <button
181
- key={value}
182
- onClick={() => handleQuickAmount(value)}
183
- className={`bg-as-surface-secondary border-as-border-secondary hover:border-as-border-secondary h-7 w-14 rounded-lg border text-sm font-medium transition-all duration-200 ${
184
- srcAmountOnRamp === value
185
- ? "border-as-border-secondary bg-as-surface-secondary"
186
- : "bg-as-surface-secondary hover:bg-as-surface-secondary"
187
- }`}
188
- >
189
- ${value}
190
- </button>
191
- ))}
180
+ <div className={cn("mx-auto mb-6 flex justify-center gap-2", hideDstToken && "mb-0")}>
181
+ {customUsdInputValues
182
+ .filter(v => !isNaN(Number(v)))
183
+ .map(value => (
184
+ <button
185
+ key={value}
186
+ onClick={() => handleQuickAmount(value)}
187
+ className={`bg-as-surface-secondary border-as-border-secondary hover:border-as-border-secondary h-7 w-14 rounded-lg border text-sm font-medium transition-all duration-200 ${
188
+ srcAmountOnRamp === value
189
+ ? "border-as-border-secondary bg-as-surface-secondary"
190
+ : "bg-as-surface-secondary hover:bg-as-surface-secondary"
191
+ }`}
192
+ >
193
+ ${value}
194
+ </button>
195
+ ))}
192
196
  </div>
193
197
 
194
198
  {/* Token Display */}
@@ -159,13 +159,8 @@ export function SignIn(props: SignInWithB3Props) {
159
159
 
160
160
  <button className="mb-2 w-full space-y-1" onClick={onDisconnect}>
161
161
  <div className="hover:bg-b3-react-background group flex h-12 items-center rounded-xl px-4 transition-colors">
162
- <Icon
163
- className="fill-b3-react-background group-hover:fill-b3-react-primary mr-4 shrink-0 transition-colors"
164
- name="logout"
165
- />
166
- <div className="text-b3-react-background group-hover:text-b3-react-primary mr-auto transition-colors">
167
- Disconnect
168
- </div>
162
+ <Icon className="fill-b3-react-primary mr-4 shrink-0 transition-colors" name="logout" />
163
+ <div className="text-b3-react-primary mr-auto transition-colors">Disconnect</div>
169
164
  </div>
170
165
  </button>
171
166
  </div>
@@ -7,12 +7,12 @@ export { useB3 } from "./B3Provider/useB3";
7
7
  export { StyleRoot } from "./StyleRoot";
8
8
 
9
9
  // SignInWithB3 Components
10
- export { SignInWithB3 } from "./SignInWithB3/SignInWithB3";
11
- export { SignInWithB3Flow } from "./SignInWithB3/SignInWithB3Flow";
12
- export { SignInWithB3Privy } from "./SignInWithB3/SignInWithB3Privy";
13
10
  export { AuthButton } from "./SignInWithB3/components/AuthButton";
14
11
  export { PermissionItem } from "./SignInWithB3/components/PermissionItem";
15
12
  export { WalletRow } from "./SignInWithB3/components/WalletRow";
13
+ export { SignInWithB3 } from "./SignInWithB3/SignInWithB3";
14
+ export { SignInWithB3Flow } from "./SignInWithB3/SignInWithB3Flow";
15
+ export { SignInWithB3Privy } from "./SignInWithB3/SignInWithB3Privy";
16
16
  export { LoginStepContainer } from "./SignInWithB3/steps/LoginStep";
17
17
  export { getConnectOptionsFromStrategy, isWalletType, type AllowedStrategy } from "./SignInWithB3/utils/signInUtils";
18
18
 
@@ -43,15 +43,6 @@ export { StaggeredFadeLoader } from "./custom/StaggeredFadeLoader";
43
43
  export { WalletConnectorIcon } from "./custom/WalletConnectorIcon";
44
44
 
45
45
  // UI Components
46
- export { Loading } from "./ui/Loading";
47
- export { ShinyButton } from "./ui/ShinyButton";
48
- export { TabTrigger, Tabs, TabsContent, TabsList, TabsTransitionWrapper } from "./ui/TabSystem";
49
- export {
50
- TabTrigger as TabTriggerPrimitive,
51
- TabsContent as TabsContentPrimitive,
52
- TabsList as TabsListPrimitive,
53
- Tabs as TabsPrimitive,
54
- } from "./ui/Tabs";
55
46
  export { Badge, badgeVariants } from "./ui/badge";
56
47
  export { Button, buttonVariants } from "./ui/button";
57
48
  export {
@@ -89,12 +80,28 @@ export {
89
80
  DrawerTitle,
90
81
  DrawerTrigger,
91
82
  } from "./ui/drawer";
83
+ export {
84
+ DropdownMenu,
85
+ DropdownMenuContent,
86
+ DropdownMenuItem,
87
+ DropdownMenuSeparator,
88
+ DropdownMenuTrigger,
89
+ } from "./ui/dropdown-menu";
92
90
  export { GlareCard } from "./ui/glare-card";
93
91
  export { GlareCardRounded } from "./ui/glare-card-rounded";
94
92
  export { Input } from "./ui/input";
93
+ export { Loading } from "./ui/Loading";
95
94
  export { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
96
95
  export { ScrollArea, ScrollBar } from "./ui/scroll-area";
96
+ export { ShinyButton } from "./ui/ShinyButton";
97
97
  export { Skeleton } from "./ui/skeleton";
98
+ export {
99
+ TabTrigger as TabTriggerPrimitive,
100
+ TabsContent as TabsContentPrimitive,
101
+ TabsList as TabsListPrimitive,
102
+ Tabs as TabsPrimitive,
103
+ } from "./ui/Tabs";
104
+ export { TabTrigger, Tabs, TabsContent, TabsList, TabsTransitionWrapper } from "./ui/TabSystem";
98
105
  export { TextLoop } from "./ui/text-loop";
99
106
  export { TextShimmer } from "./ui/text-shimmer";
100
107
  export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip";
@@ -0,0 +1,132 @@
1
+ "use client";
2
+
3
+ import { cn } from "@b3dotfun/sdk/shared/utils";
4
+ import * as React from "react";
5
+
6
+ interface DropdownMenuProps {
7
+ children: React.ReactNode;
8
+ }
9
+
10
+ interface DropdownMenuContentProps {
11
+ children: React.ReactNode;
12
+ align?: "start" | "center" | "end";
13
+ className?: string;
14
+ }
15
+
16
+ interface DropdownMenuItemProps {
17
+ children: React.ReactNode;
18
+ onClick?: () => void;
19
+ className?: string;
20
+ }
21
+
22
+ interface DropdownMenuSeparatorProps {
23
+ className?: string;
24
+ }
25
+
26
+ interface DropdownMenuTriggerProps {
27
+ children: React.ReactNode;
28
+ asChild?: boolean;
29
+ }
30
+
31
+ const DropdownMenuContext = React.createContext<{
32
+ isOpen: boolean;
33
+ setIsOpen: (open: boolean) => void;
34
+ }>({
35
+ isOpen: false,
36
+ setIsOpen: () => {},
37
+ });
38
+
39
+ export function DropdownMenu({ children }: DropdownMenuProps) {
40
+ const [isOpen, setIsOpen] = React.useState(false);
41
+
42
+ React.useEffect(() => {
43
+ const handleClickOutside = (event: MouseEvent) => {
44
+ const target = event.target as Element;
45
+ if (!target.closest("[data-dropdown-menu]")) {
46
+ setIsOpen(false);
47
+ }
48
+ };
49
+
50
+ if (isOpen) {
51
+ document.addEventListener("click", handleClickOutside);
52
+ return () => document.removeEventListener("click", handleClickOutside);
53
+ }
54
+ }, [isOpen]);
55
+
56
+ return (
57
+ <DropdownMenuContext.Provider value={{ isOpen, setIsOpen }}>
58
+ <div className="relative" data-dropdown-menu>
59
+ {children}
60
+ </div>
61
+ </DropdownMenuContext.Provider>
62
+ );
63
+ }
64
+
65
+ export function DropdownMenuTrigger({ children, asChild }: DropdownMenuTriggerProps) {
66
+ const { isOpen, setIsOpen } = React.useContext(DropdownMenuContext);
67
+
68
+ const handleClick = () => {
69
+ setIsOpen(!isOpen);
70
+ };
71
+
72
+ if (asChild) {
73
+ if (React.isValidElement(children)) {
74
+ return React.cloneElement(children as React.ReactElement<{ onClick?: () => void }>, {
75
+ onClick: handleClick,
76
+ });
77
+ }
78
+ }
79
+
80
+ return <button onClick={handleClick}>{children}</button>;
81
+ }
82
+
83
+ export function DropdownMenuContent({ children, align = "start", className }: DropdownMenuContentProps) {
84
+ const { isOpen } = React.useContext(DropdownMenuContext);
85
+
86
+ if (!isOpen) return null;
87
+
88
+ const alignmentClasses = {
89
+ start: "left-0",
90
+ center: "left-1/2 -translate-x-1/2",
91
+ end: "right-0",
92
+ };
93
+
94
+ return (
95
+ <div
96
+ className={cn(
97
+ "bg-popover text-popover-foreground absolute top-full z-50 mt-1 min-w-32 overflow-hidden rounded-md border p-1 shadow-md",
98
+ "border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800",
99
+ alignmentClasses[align],
100
+ className,
101
+ )}
102
+ >
103
+ {children}
104
+ </div>
105
+ );
106
+ }
107
+
108
+ export function DropdownMenuItem({ children, onClick, className }: DropdownMenuItemProps) {
109
+ const { setIsOpen } = React.useContext(DropdownMenuContext);
110
+
111
+ const handleClick = () => {
112
+ onClick?.();
113
+ setIsOpen(false);
114
+ };
115
+
116
+ return (
117
+ <div
118
+ className={cn(
119
+ "hover:bg-accent hover:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
120
+ "hover:bg-gray-100 dark:hover:bg-gray-700",
121
+ className,
122
+ )}
123
+ onClick={handleClick}
124
+ >
125
+ {children}
126
+ </div>
127
+ );
128
+ }
129
+
130
+ export function DropdownMenuSeparator({ className }: DropdownMenuSeparatorProps) {
131
+ return <div className={cn("bg-muted -mx-1 my-1 h-px", "bg-gray-200 dark:bg-gray-600", className)} />;
132
+ }
@@ -123,11 +123,13 @@ export interface AnySpendModalProps extends BaseModalProps {
123
123
  /** Whether to hide the transaction history button */
124
124
  hideTransactionHistoryButton?: boolean;
125
125
  /** Callback function called when the transaction is successful */
126
- onSuccess?: () => void;
126
+ onSuccess?: (txHash?: string) => void;
127
127
  /** Token address of the destination token to buy (enables buy mode) */
128
128
  destinationTokenAddress?: string;
129
129
  /** Chain ID where the destination token exists (enables buy mode) */
130
130
  destinationTokenChainId?: number;
131
+ /** Custom USD input values for quick amount buttons in fiat onramp */
132
+ customUsdInputValues?: string[];
131
133
  }
132
134
 
133
135
  /**
@@ -307,6 +309,8 @@ export interface AnySpendDepositHypeProps extends BaseModalProps {
307
309
  mainFooter?: React.ReactNode;
308
310
  /** Callback function called when the deposit is successful */
309
311
  onSuccess?: (amount?: string) => void;
312
+ /** Custom USD input values for quick amount buttons in fiat onramp */
313
+ customUsdInputValues?: string[];
310
314
  }
311
315
 
312
316
  export interface AvatarEditorModalProps extends BaseModalProps {
@@ -0,0 +1,2 @@
1
+ // B3 Token image URL
2
+ export const B3_COIN_IMAGE_URL = "https://cdn.b3.fun/b3-coin-3d.png";
@@ -1,3 +1,5 @@
1
+ export * from "./currency";
2
+
1
3
  export const siteURL = "https://basement.fun";
2
4
 
3
5
  export const b3CoinIcon = "https://cdn.b3.fun/b3-coin-3d.png";