@daimo/pay 1.1.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/build/index.d.ts +37 -105
  2. package/build/package.json.js +3 -4
  3. package/build/package.json.js.map +1 -1
  4. package/build/src/assets/icons.js +2 -1
  5. package/build/src/assets/icons.js.map +1 -1
  6. package/build/src/components/Common/AmountInput/AmountInputField.js +59 -0
  7. package/build/src/components/Common/AmountInput/AmountInputField.js.map +1 -0
  8. package/build/src/components/Common/AmountInput/index.js +143 -0
  9. package/build/src/components/Common/AmountInput/index.js.map +1 -0
  10. package/build/src/components/Common/ChainSelectList/index.js +1 -1
  11. package/build/src/components/Common/Modal/index.js +9 -4
  12. package/build/src/components/Common/Modal/index.js.map +1 -1
  13. package/build/src/components/Common/Modal/styles.js +2 -1
  14. package/build/src/components/Common/Modal/styles.js.map +1 -1
  15. package/build/src/components/Common/OptionsList/styles.js +1 -1
  16. package/build/src/components/Common/OrderHeader/index.js +22 -111
  17. package/build/src/components/Common/OrderHeader/index.js.map +1 -1
  18. package/build/src/components/Common/PaymentBreakdown/index.js +48 -0
  19. package/build/src/components/{Pages/WaitingOther → Common/PaymentBreakdown}/index.js.map +1 -1
  20. package/build/src/components/Common/SwitchButton/index.js +39 -0
  21. package/build/src/components/Common/SwitchButton/index.js.map +1 -0
  22. package/build/src/components/Common/TokenChainLogo/index.js +24 -0
  23. package/build/src/components/Common/TokenChainLogo/index.js.map +1 -0
  24. package/build/src/components/DaimoPay.js +7 -2
  25. package/build/src/components/DaimoPay.js.map +1 -1
  26. package/build/src/components/DaimoPayButton/index.js +0 -1
  27. package/build/src/components/DaimoPayButton/index.js.map +1 -1
  28. package/build/src/components/DaimoPayModal/index.js +86 -26
  29. package/build/src/components/DaimoPayModal/index.js.map +1 -1
  30. package/build/src/components/Pages/PayWithToken/index.js +4 -109
  31. package/build/src/components/Pages/PayWithToken/index.js.map +1 -1
  32. package/build/src/components/Pages/SelectAmount/index.js +16 -0
  33. package/build/src/components/Pages/SelectAmount/index.js.map +1 -0
  34. package/build/src/components/Pages/SelectDepositAddressAmount/index.js +60 -0
  35. package/build/src/components/Pages/SelectDepositAddressAmount/index.js.map +1 -0
  36. package/build/src/components/Pages/SelectDepositAddressChain/index.js +7 -2
  37. package/build/src/components/Pages/SelectDepositAddressChain/index.js.map +1 -1
  38. package/build/src/components/Pages/SelectExternalAmount/index.js +62 -0
  39. package/build/src/components/Pages/SelectExternalAmount/index.js.map +1 -0
  40. package/build/src/components/Pages/SelectMethod/index.js +14 -7
  41. package/build/src/components/Pages/SelectMethod/index.js.map +1 -1
  42. package/build/src/components/Pages/SelectToken/index.js +36 -41
  43. package/build/src/components/Pages/SelectToken/index.js.map +1 -1
  44. package/build/src/components/Pages/Solana/ConnectorSolana/index.js +8 -2
  45. package/build/src/components/Pages/Solana/ConnectorSolana/index.js.map +1 -1
  46. package/build/src/components/Pages/Solana/PayWithSolanaToken/index.js +14 -8
  47. package/build/src/components/Pages/Solana/PayWithSolanaToken/index.js.map +1 -1
  48. package/build/src/components/Pages/Solana/SelectSolanaAmount/index.js +16 -0
  49. package/build/src/components/Pages/Solana/SelectSolanaAmount/index.js.map +1 -0
  50. package/build/src/components/Pages/Solana/SelectSolanaToken/index.js +37 -21
  51. package/build/src/components/Pages/Solana/SelectSolanaToken/index.js.map +1 -1
  52. package/build/src/components/Pages/WaitingExternal/index.js +53 -0
  53. package/build/src/components/Pages/WaitingExternal/index.js.map +1 -0
  54. package/build/src/components/Spinners/ExternalPaymentSpinner/index.js +20 -0
  55. package/build/src/components/Spinners/ExternalPaymentSpinner/index.js.map +1 -0
  56. package/build/src/components/Spinners/TokenLogoSpinner/index.js +13 -0
  57. package/build/src/components/Spinners/TokenLogoSpinner/index.js.map +1 -0
  58. package/build/src/components/Spinners/TokenLogoSpinner/styles.js +40 -0
  59. package/build/src/components/Spinners/TokenLogoSpinner/styles.js.map +1 -0
  60. package/build/src/components/Spinners/styles.js +32 -0
  61. package/build/src/components/Spinners/styles.js.map +1 -0
  62. package/build/src/hooks/useDepositAddressOptions.js +8 -5
  63. package/build/src/hooks/useDepositAddressOptions.js.map +1 -1
  64. package/build/src/hooks/useExternalPaymentOptions.js +7 -6
  65. package/build/src/hooks/useExternalPaymentOptions.js.map +1 -1
  66. package/build/src/hooks/useOrderUsdLimits.js +26 -0
  67. package/build/src/hooks/useOrderUsdLimits.js.map +1 -0
  68. package/build/src/hooks/usePaymentState.js +46 -14
  69. package/build/src/hooks/usePaymentState.js.map +1 -1
  70. package/build/src/hooks/useSolanaPaymentOptions.js +7 -5
  71. package/build/src/hooks/useSolanaPaymentOptions.js.map +1 -1
  72. package/build/src/hooks/useWalletPaymentOptions.js +9 -8
  73. package/build/src/hooks/useWalletPaymentOptions.js.map +1 -1
  74. package/build/src/index.js +1 -1
  75. package/build/src/utils/exports.js +4 -1
  76. package/build/src/utils/exports.js.map +1 -1
  77. package/build/src/utils/format.js +83 -0
  78. package/build/src/utils/format.js.map +1 -0
  79. package/build/src/utils/validateInput.js +36 -0
  80. package/build/src/utils/validateInput.js.map +1 -0
  81. package/package.json +4 -5
  82. package/build/src/components/Pages/WaitingOther/index.js +0 -91
package/build/index.d.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  import React$1, { ReactNode } from 'react';
2
2
  export { version } from '../package.json';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
- import * as _daimo_common from '@daimo/common';
5
- import { DepositAddressPaymentOptionMetadata, PlatformType, ExternalPaymentOptionMetadata, DaimoPayOrder, DaimoPayTokenAmount, ExternalPaymentOptions, DepositAddressPaymentOptions, DepositAddressPaymentOptionData, SolanaPublicKey, PaymentStartedEvent, PaymentCompletedEvent, PaymentBouncedEvent } from '@daimo/common';
4
+ import { DaimoPayOrderMode, DepositAddressPaymentOptionMetadata, PlatformType, ExternalPaymentOptionMetadata, WalletPaymentOption, DaimoPayOrder, DaimoPayTokenAmount, ExternalPaymentOptions, DepositAddressPaymentOptions, DepositAddressPaymentOptionData, SolanaPublicKey, PaymentStartedEvent, PaymentCompletedEvent, PaymentBouncedEvent } from '@daimo/common';
6
5
  import { Address, Hex } from 'viem';
7
6
  import { AppRouter } from '@daimo/pay-api';
8
7
  import { CreateTRPCClient } from '@trpc/client';
9
- import * as abitype from 'abitype';
10
8
  import { WalletName } from '@solana/wallet-adapter-base';
11
9
  import { CreateConfigParameters } from '@wagmi/core';
12
10
  import { CreateConnectorFn } from 'wagmi';
@@ -100,68 +98,39 @@ type useConnectCallbackProps = {
100
98
 
101
99
  type TrpcClient = CreateTRPCClient<AppRouter>;
102
100
 
103
- declare function useDepositAddressOptions({ trpc, usdRequired, }: {
101
+ declare function useDepositAddressOptions({ trpc, usdRequired, mode, }: {
104
102
  trpc: TrpcClient;
105
- usdRequired: number;
103
+ usdRequired: number | undefined;
104
+ mode: DaimoPayOrderMode | undefined;
106
105
  }): {
107
106
  options: DepositAddressPaymentOptionMetadata[];
108
107
  loading: boolean;
109
108
  };
110
109
 
111
- declare function useExternalPaymentOptions({ trpc, filterIds, usdRequired, platform, }: {
110
+ declare function useExternalPaymentOptions({ trpc, filterIds, platform, usdRequired, mode, }: {
112
111
  trpc: TrpcClient;
113
112
  filterIds: string[] | undefined;
114
- usdRequired: number | undefined;
115
113
  platform: PlatformType | undefined;
114
+ usdRequired: number | undefined;
115
+ mode: DaimoPayOrderMode | undefined;
116
116
  }): {
117
117
  options: ExternalPaymentOptionMetadata[];
118
118
  loading: boolean;
119
119
  };
120
120
 
121
- type SolanaPaymentOption = Awaited<ReturnType<TrpcClient["getSolanaPaymentOptions"]["query"]>>[0];
122
- declare function useSolanaPaymentOptions({ trpc, address, usdRequired, }: {
121
+ /** Wallet payment options. User picks one. */
122
+ declare function useSolanaPaymentOptions({ trpc, address, usdRequired, isDepositFlow, }: {
123
123
  trpc: TrpcClient;
124
124
  address: string | undefined;
125
125
  usdRequired: number | undefined;
126
+ isDepositFlow: boolean;
126
127
  }): {
127
- options: {
128
- required: {
129
- token: {
130
- symbol: string;
131
- chainId: number;
132
- token: abitype.Address | _daimo_common.SolanaPublicKey;
133
- usd: number;
134
- displayDecimals: number;
135
- decimals: number;
136
- name?: string;
137
- fiatSymbol?: string;
138
- logoURI?: string;
139
- };
140
- amount: _daimo_common.BigIntStr;
141
- usd: number;
142
- };
143
- balance: {
144
- token: {
145
- symbol: string;
146
- chainId: number;
147
- token: abitype.Address | _daimo_common.SolanaPublicKey;
148
- usd: number;
149
- displayDecimals: number;
150
- decimals: number;
151
- name?: string;
152
- fiatSymbol?: string;
153
- logoURI?: string;
154
- };
155
- amount: _daimo_common.BigIntStr;
156
- usd: number;
157
- };
158
- }[] | null;
128
+ options: WalletPaymentOption[] | null;
159
129
  isLoading: boolean;
160
130
  };
161
131
 
162
132
  /** Wallet payment options. User picks one. */
163
- type WalletPaymentOption = Awaited<ReturnType<TrpcClient["getWalletPaymentOptions"]["query"]>>[0];
164
- declare function useWalletPaymentOptions({ trpc, address, usdRequired, destChainId, preferredChains, preferredTokens, log, }: {
133
+ declare function useWalletPaymentOptions({ trpc, address, usdRequired, destChainId, preferredChains, preferredTokens, isDepositFlow, log, }: {
165
134
  trpc: TrpcClient;
166
135
  address: string | undefined;
167
136
  usdRequired: number | undefined;
@@ -171,55 +140,10 @@ declare function useWalletPaymentOptions({ trpc, address, usdRequired, destChain
171
140
  chain: number;
172
141
  address: string;
173
142
  }[] | undefined;
143
+ isDepositFlow: boolean;
174
144
  log: (msg: string) => void;
175
145
  }): {
176
- options: {
177
- fees: {
178
- token: {
179
- symbol: string;
180
- chainId: number;
181
- token: abitype.Address | _daimo_common.SolanaPublicKey;
182
- usd: number;
183
- displayDecimals: number;
184
- decimals: number;
185
- name?: string;
186
- fiatSymbol?: string;
187
- logoURI?: string;
188
- };
189
- amount: _daimo_common.BigIntStr;
190
- usd: number;
191
- };
192
- required: {
193
- token: {
194
- symbol: string;
195
- chainId: number;
196
- token: abitype.Address | _daimo_common.SolanaPublicKey;
197
- usd: number;
198
- displayDecimals: number;
199
- decimals: number;
200
- name?: string;
201
- fiatSymbol?: string;
202
- logoURI?: string;
203
- };
204
- amount: _daimo_common.BigIntStr;
205
- usd: number;
206
- };
207
- balance: {
208
- token: {
209
- symbol: string;
210
- chainId: number;
211
- token: abitype.Address | _daimo_common.SolanaPublicKey;
212
- usd: number;
213
- displayDecimals: number;
214
- decimals: number;
215
- name?: string;
216
- fiatSymbol?: string;
217
- logoURI?: string;
218
- };
219
- amount: _daimo_common.BigIntStr;
220
- usd: number;
221
- };
222
- }[] | null;
146
+ options: WalletPaymentOption[] | null;
223
147
  isLoading: boolean;
224
148
  };
225
149
 
@@ -231,14 +155,15 @@ interface PayParams {
231
155
  toChain: number;
232
156
  /** The destination token to send. */
233
157
  toToken: Address;
234
- /** The amount of the token to send. */
235
- toUnits: string;
158
+ /**
159
+ * The amount of the token to send.
160
+ * If not provided, the user will be prompted to enter an amount.
161
+ */
162
+ toUnits?: string;
236
163
  /** The final address to transfer to or contract to call. */
237
164
  toAddress: Address;
238
165
  /** Calldata for final call, or empty data for transfer. */
239
166
  toCallData?: Hex;
240
- /** Let the user edit the amount to send. */
241
- isAmountEditable: boolean;
242
167
  /** The intent verb, such as Pay, Deposit, or Purchase. Default: Pay */
243
168
  intent?: string;
244
169
  /** Payment options. By default, all are enabled. */
@@ -256,7 +181,9 @@ interface PaymentState {
256
181
  setPayId: (id: string | undefined) => void;
257
182
  setPayParams: (payParams: PayParams | undefined) => void;
258
183
  payParams: PayParams | undefined;
184
+ generatePreviewOrder: (payParams: PayParams) => void;
259
185
  daimoPayOrder: DaimoPayOrder | undefined;
186
+ isDepositFlow: boolean;
260
187
  modalOptions: DaimoPayModalOptions;
261
188
  setModalOptions: (modalOptions: DaimoPayModalOptions) => void;
262
189
  paymentWaitingMessage: string | undefined;
@@ -266,13 +193,15 @@ interface PaymentState {
266
193
  depositAddressOptions: ReturnType<typeof useDepositAddressOptions>;
267
194
  selectedExternalOption: ExternalPaymentOptionMetadata | undefined;
268
195
  selectedTokenOption: WalletPaymentOption | undefined;
269
- selectedSolanaTokenOption: SolanaPaymentOption | undefined;
196
+ selectedSolanaTokenOption: WalletPaymentOption | undefined;
270
197
  selectedDepositAddressOption: DepositAddressPaymentOptionMetadata | undefined;
271
- setSelectedDepositAddressOption: (option: DepositAddressPaymentOptionMetadata | undefined) => void;
198
+ getOrderUsdLimit: () => number;
199
+ setPaymentWaitingMessage: (message: string | undefined) => void;
272
200
  setSelectedExternalOption: (option: ExternalPaymentOptionMetadata | undefined) => void;
273
201
  setSelectedTokenOption: (option: WalletPaymentOption | undefined) => void;
274
- setSelectedSolanaTokenOption: (option: SolanaPaymentOption | undefined) => void;
275
- setChosenUsd: (amount: number) => void;
202
+ setSelectedSolanaTokenOption: (option: WalletPaymentOption | undefined) => void;
203
+ setSelectedDepositAddressOption: (option: DepositAddressPaymentOptionMetadata | undefined) => void;
204
+ setChosenUsd: (usd: number) => void;
276
205
  payWithToken: (tokenAmount: DaimoPayTokenAmount) => Promise<void>;
277
206
  payWithExternal: (option: ExternalPaymentOptions) => Promise<string>;
278
207
  payWithDepositAddress: (option: DepositAddressPaymentOptions) => Promise<DepositAddressPaymentOptionData | null>;
@@ -290,7 +219,10 @@ type SolanaWalletName = WalletName<string>;
290
219
  declare enum ROUTES {
291
220
  SELECT_METHOD = "daimoPaySelectMethod",
292
221
  SELECT_TOKEN = "daimoPaySelectToken",
293
- WAITING_OTHER = "daimoPayWaitingOther",
222
+ SELECT_AMOUNT = "daimoPaySelectAmount",
223
+ SELECT_EXTERNAL_AMOUNT = "daimoPaySelectExternalAmount",
224
+ SELECT_DEPOSIT_ADDRESS_AMOUNT = "daimoPaySelectDepositAddressAmount",
225
+ WAITING_EXTERNAL = "daimoPayWaitingExternal",
294
226
  SELECT_DEPOSIT_ADDRESS_CHAIN = "daimoPaySelectDepositAddressChain",
295
227
  WAITING_DEPOSIT_ADDRESS = "daimoPayWaitingDepositAddress",
296
228
  PAY_WITH_TOKEN = "daimoPayPayWithToken",
@@ -298,6 +230,7 @@ declare enum ROUTES {
298
230
  SOLANA_CONNECT = "daimoPaySolanaConnect",
299
231
  SOLANA_CONNECTOR = "daimoPaySolanaConnector",
300
232
  SOLANA_SELECT_TOKEN = "daimoPaySolanaSelectToken",
233
+ SOLANA_SELECT_AMOUNT = "daimoPaySolanaSelectAmount",
301
234
  SOLANA_PAY_WITH_TOKEN = "daimoPaySolanaPayWithToken",
302
235
  ONBOARDING = "onboarding",
303
236
  ABOUT = "about",
@@ -406,12 +339,9 @@ type PayButtonPaymentProps = {
406
339
  toToken: Address;
407
340
  /**
408
341
  * The amount of destination token to send (transfer or approve).
342
+ * If not provided, the user will be prompted to enter an amount.
409
343
  */
410
- toUnits: string;
411
- /**
412
- * Let the user edit the amount to send.
413
- */
414
- amountEditable?: boolean;
344
+ toUnits?: string;
415
345
  /**
416
346
  * The destination address to transfer to, or contract to call.
417
347
  */
@@ -526,5 +456,7 @@ declare const wallets: {
526
456
  declare const daimoPayVersion: string;
527
457
  /** Generates a globally-unique payId. */
528
458
  declare function generatePayId(): string;
459
+ /** Chain ids supported by Daimo Pay. */
460
+ declare const supportedChainIds: Set<number>;
529
461
 
530
- export { Avatar, Chain as ChainIcon, DaimoPayButton, Context as DaimoPayContext, DaimoPayProvider, types_d as Types, daimoPayVersion, generatePayId, defaultConfig as getDefaultConfig, useModal as useDaimoPayModal, useDaimoPayStatus, usePayContext, wallets };
462
+ export { Avatar, Chain as ChainIcon, DaimoPayButton, Context as DaimoPayContext, DaimoPayProvider, types_d as Types, daimoPayVersion, generatePayId, defaultConfig as getDefaultConfig, supportedChainIds, useModal as useDaimoPayModal, useDaimoPayStatus, usePayContext, wallets };
@@ -1,5 +1,5 @@
1
1
  var name = "@daimo/pay";
2
- var version = "1.1.5";
2
+ var version = "1.2.0";
3
3
  var author = "Daimo";
4
4
  var homepage = "https://pay.daimo.com";
5
5
  var license = "BSD-2-Clause license";
@@ -38,8 +38,8 @@ var keywords = [
38
38
  "crypto"
39
39
  ];
40
40
  var dependencies = {
41
- "@daimo/common": "1.1.0",
42
- "@daimo/contract": "1.1.0",
41
+ "@daimo/common": "1.1.1",
42
+ "@daimo/contract": "1.1.1",
43
43
  "@solana/wallet-adapter-base": "^0.9.23",
44
44
  "@solana/wallet-adapter-react": "^0.15.35",
45
45
  "@solana/web3.js": "^1.95.4",
@@ -65,7 +65,6 @@ var peerDependencies = {
65
65
  };
66
66
  var devDependencies = {
67
67
  "@rollup/plugin-json": "^6.1.0",
68
- "@rollup/plugin-node-resolve": "^13.1.3",
69
68
  "@types/node": "^20.14.12",
70
69
  "@types/qrcode": "^1.4.2",
71
70
  "@types/react": "^18.2.47",
@@ -1 +1 @@
1
- {"version":3,"file":"package.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"package.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -23,6 +23,7 @@ const RetryIconCircle = ({ ...props }) => {
23
23
  return (jsx("svg", { "aria-hidden": "true", width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M32 16C32 24.8366 24.8366 32 16 32C7.16344 32 0 24.8366 0 16C0 7.16344 7.16344 0 16 0C24.8366 0 32 7.16344 32 16ZM24.5001 8.74263C25.0834 8.74263 25.5563 9.21551 25.5563 9.79883V14.5997C25.5563 15.183 25.0834 15.6559 24.5001 15.6559H19.6992C19.1159 15.6559 18.643 15.183 18.643 14.5997C18.643 14.0164 19.1159 13.5435 19.6992 13.5435H21.8378L20.071 11.8798C20.0632 11.8724 20.0555 11.865 20.048 11.8574C19.1061 10.915 17.8835 10.3042 16.5643 10.1171C15.2452 9.92999 13.9009 10.1767 12.7341 10.82C11.5674 11.4634 10.6413 12.4685 10.0955 13.684C9.54968 14.8994 9.41368 16.2593 9.70801 17.5588C10.0023 18.8583 10.711 20.0269 11.7273 20.8885C12.7436 21.7502 14.0124 22.2582 15.3425 22.336C16.6726 22.4138 17.9919 22.0572 19.1017 21.3199C19.5088 21.0495 19.8795 20.7333 20.2078 20.3793C20.6043 19.9515 21.2726 19.9262 21.7004 20.3228C22.1282 20.7194 22.1534 21.3876 21.7569 21.8154C21.3158 22.2912 20.8176 22.7161 20.2706 23.0795C18.7793 24.0702 17.0064 24.5493 15.2191 24.4448C13.4318 24.3402 11.7268 23.6576 10.3612 22.4998C8.9956 21.3419 8.0433 19.7716 7.6478 18.0254C7.2523 16.2793 7.43504 14.4519 8.16848 12.8186C8.90192 11.1854 10.1463 9.83471 11.7142 8.97021C13.282 8.10572 15.0884 7.77421 16.861 8.02565C18.6282 8.27631 20.2664 9.09278 21.5304 10.3525L23.4439 12.1544V9.79883C23.4439 9.21551 23.9168 8.74263 24.5001 8.74263Z", fill: "currentColor" }) }));
24
24
  };
25
25
  const CopyToClipboardIcon = ({ ...props }) => (jsxs("svg", { "aria-hidden": "true", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [jsx("path", { d: "M14 9.5V7C14 5.89543 13.1046 5 12 5H7C5.89543 5 5 5.89543 5 7V12C5 13.1046 5.89543 14 7 14H9.5", stroke: "var(--ck-body-color-muted)", strokeWidth: "2" }), jsx("rect", { x: "10", y: "10", width: "9", height: "9", rx: "2", stroke: "var(--ck-body-color-muted)", strokeWidth: "2" }), jsx("path", { d: "M1 3L3 5L7 1", stroke: "var(--ck-body-color)", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" })] }));
26
+ const SwitchIcon = ({ ...props }) => (jsx("svg", { "aria-hidden": "true", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { stroke: "var(--ck-body-color-muted)", strokeWidth: 1.75, strokeLinecap: "round", strokeLinejoin: "round", d: "M3 7.5 7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5" }) }));
26
27
 
27
- export { AlertIcon, CopyToClipboardIcon, DisconnectIcon, ExternalLinkIcon, LoadingCircleIcon, RetryIconCircle, TickIcon };
28
+ export { AlertIcon, CopyToClipboardIcon, DisconnectIcon, ExternalLinkIcon, LoadingCircleIcon, RetryIconCircle, SwitchIcon, TickIcon };
28
29
  //# sourceMappingURL=icons.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"icons.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,59 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useRef, useEffect } from 'react';
3
+ import styled from '../../../styles/styled/index.js';
4
+ import { ModalBody } from '../Modal/styles.js';
5
+
6
+ const Container = styled.button `
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+ gap: 4px;
11
+ `;
12
+ const InputField = styled.input `
13
+ margin: 0;
14
+ padding: 0;
15
+ background: none;
16
+ border: none;
17
+ outline: none;
18
+ font-size: 30px;
19
+ font-weight: var(--ck-modal-h1-font-weight, 600);
20
+ color: var(--ck-body-color);
21
+ width: ${(props) => {
22
+ const length = props.value?.length ?? 0;
23
+ // Placeholder is "0.00", 3ch for digits + 0.55ch for decimal point
24
+ if (length === 0)
25
+ return "3.55ch";
26
+ // Reduce width when decimal or commas are present since they're smaller than normal chars
27
+ const numPunctuations = (props.value?.match(/[.,]/g) || []).length;
28
+ const adjustedLength = length - numPunctuations * 0.55;
29
+ return `${Math.min(adjustedLength, 10)}ch`;
30
+ }};
31
+ min-width: 1ch;
32
+ max-width: 10ch;
33
+ `;
34
+ const AnimatedCurrency = styled(ModalBody) `
35
+ @keyframes fadeInDown {
36
+ from {
37
+ opacity: 0;
38
+ transform: translateY(-8px);
39
+ }
40
+ to {
41
+ opacity: 1;
42
+ transform: translateY(0);
43
+ }
44
+ }
45
+
46
+ animation: fadeInDown 0.3s ease-out forwards;
47
+ font-size: ${(props) => (props.$small ? "16px" : "24px")};
48
+ `;
49
+ const AmountInputField = ({ value, onChange, currency = "$", onKeyDown }) => {
50
+ // Focus the input when the component mounts so the user can start typing immediately
51
+ const inputRef = useRef(null);
52
+ useEffect(() => {
53
+ inputRef.current?.focus();
54
+ }, [value]);
55
+ return (jsxs(Container, { children: [currency === "$" && jsx(AnimatedCurrency, { children: currency }), jsx(InputField, { ref: inputRef, type: "text", value: value, onChange: onChange, placeholder: "0.00", onKeyDown: onKeyDown }), currency !== "$" && (jsx(AnimatedCurrency, { "$small": true, children: currency }))] }));
56
+ };
57
+
58
+ export { AmountInputField as default };
59
+ //# sourceMappingURL=AmountInputField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AmountInputField.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,143 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import { usePayContext } from '../../DaimoPay.js';
4
+ import { PageContent, ModalContent, ModalBody } from '../Modal/styles.js';
5
+ import { parseUnits } from 'viem';
6
+ import styled from '../../../styles/styled/index.js';
7
+ import { formatUsd, usdToRoundedTokenAmount, USD_DECIMALS, tokenAmountToRoundedUsd, roundUsd, roundTokenAmount, roundTokenAmountUnits } from '../../../utils/format.js';
8
+ import { isValidNumber, sanitizeNumber } from '../../../utils/validateInput.js';
9
+ import Button from '../Button/index.js';
10
+ import SwitchButton from '../SwitchButton/index.js';
11
+ import TokenLogoSpinner from '../../Spinners/TokenLogoSpinner/index.js';
12
+ import AmountInputField from './AmountInputField.js';
13
+
14
+ const MultiCurrencySelectAmount = ({ selectedTokenOption, setSelectedTokenOption, nextPage }) => {
15
+ const { paymentState, setRoute, triggerResize } = usePayContext();
16
+ const maxUsdLimit = paymentState.getOrderUsdLimit();
17
+ const balanceToken = selectedTokenOption.balance.token;
18
+ const isUsdStablecoin = balanceToken.fiatSymbol === "$";
19
+ const minimumMessage = selectedTokenOption.minimumRequired.usd > 0
20
+ ? `Minimum
21
+ ${formatUsd(selectedTokenOption.minimumRequired.usd, "up")}`
22
+ : null;
23
+ const [usdValue, setUsdValue] = useState("");
24
+ const [tokenValue, setTokenValue] = useState(usdToRoundedTokenAmount(0, balanceToken));
25
+ const [isEditingUsd, setIsEditingUsd] = useState(true);
26
+ const [message, setMessage] = useState(minimumMessage);
27
+ const [continueDisabled, setContinueDisabled] = useState(true);
28
+ useEffect(() => {
29
+ triggerResize();
30
+ }, [message]);
31
+ /**
32
+ * Update the editable value and secondary value, taking into account whether
33
+ * the user is currently editing the USD value or the token value.
34
+ */
35
+ const updateValues = (newUsdValue, newTokenValue, newIsEditingUsd) => {
36
+ const sanitizedUsdValue = sanitizeNumber(newUsdValue);
37
+ const sanitizedTokenValue = sanitizeNumber(newTokenValue);
38
+ // Update the state. Don't sanitize the value if the user is editing it.
39
+ setUsdValue(newIsEditingUsd ? newUsdValue : roundUsd(Number(sanitizedUsdValue)));
40
+ setTokenValue(newIsEditingUsd
41
+ ? roundTokenAmountUnits(Number(sanitizedTokenValue), balanceToken)
42
+ : newTokenValue);
43
+ setIsEditingUsd(newIsEditingUsd);
44
+ setContinueDisabled(Number(sanitizedUsdValue) <= 0 ||
45
+ Number(sanitizedUsdValue) < selectedTokenOption.minimumRequired.usd ||
46
+ Number(sanitizedUsdValue) > selectedTokenOption.balance.usd ||
47
+ Number(sanitizedUsdValue) > maxUsdLimit);
48
+ if (Number(sanitizedUsdValue) > selectedTokenOption.balance.usd) {
49
+ setMessage(`Amount exceeds your balance:
50
+ ${formatUsd(selectedTokenOption.balance.usd)}`);
51
+ }
52
+ else if (Number(usdValue) > maxUsdLimit) {
53
+ setMessage(`Maximum ${formatUsd(maxUsdLimit)}`);
54
+ }
55
+ else {
56
+ setMessage(minimumMessage);
57
+ }
58
+ };
59
+ const handleAmountChange = (e) => {
60
+ const value = e.target.value;
61
+ const maxDecimals = isEditingUsd
62
+ ? USD_DECIMALS
63
+ : balanceToken.displayDecimals;
64
+ if (value !== "" && !isValidNumber(value, maxDecimals))
65
+ return;
66
+ const sanitizedValue = sanitizeNumber(value);
67
+ const newUsdValue = isEditingUsd
68
+ ? value
69
+ : tokenAmountToRoundedUsd(parseUnits(sanitizedValue, balanceToken.decimals), balanceToken);
70
+ const newTokenValue = isEditingUsd
71
+ ? usdToRoundedTokenAmount(Number(sanitizedValue), balanceToken)
72
+ : value;
73
+ updateValues(newUsdValue, newTokenValue, isEditingUsd);
74
+ };
75
+ const handleMax = () => {
76
+ const usdValue = roundUsd(Number(selectedTokenOption.balance.usd));
77
+ const tokenValue = roundTokenAmount(selectedTokenOption.balance.amount, balanceToken);
78
+ updateValues(usdValue, tokenValue, isEditingUsd);
79
+ };
80
+ const handleKeyDown = (e) => {
81
+ if (e.key === "Enter" && !continueDisabled) {
82
+ handleContinue();
83
+ }
84
+ };
85
+ const handleSwitchCurrency = () => {
86
+ updateValues(usdValue, tokenValue, !isEditingUsd);
87
+ };
88
+ const handleContinue = () => {
89
+ const usd = Number(sanitizeNumber(usdValue));
90
+ const amountUnits = usd / balanceToken.usd;
91
+ const amount = parseUnits(amountUnits.toString(), balanceToken.decimals);
92
+ setSelectedTokenOption({
93
+ ...selectedTokenOption,
94
+ required: {
95
+ token: balanceToken,
96
+ amount: amount.toString(),
97
+ usd,
98
+ },
99
+ });
100
+ paymentState.setChosenUsd(usd);
101
+ setRoute(nextPage);
102
+ };
103
+ return (jsxs(PageContent, { children: [jsx(TokenLogoSpinner, { token: balanceToken, showSpinner: false }), jsxs(ModalContent, { "$preserveDisplay": true, children: [jsxs(AmountInputContainer, { children: [jsx(MaxButton, { style: { visibility: "hidden" }, children: "Max" }), jsx(AmountInputField, { value: isEditingUsd ? usdValue : tokenValue, onChange: handleAmountChange, currency: isEditingUsd ? "$" : balanceToken.symbol, onKeyDown: handleKeyDown }), jsx(MaxButton, { onClick: handleMax, children: "Max" })] }), !isUsdStablecoin && (jsx(SwitchContainer, { children: jsx(SwitchButton, { onClick: handleSwitchCurrency, children: jsx(SecondaryAmount, { children: isEditingUsd
104
+ ? `${tokenValue} ${balanceToken.symbol}`
105
+ : `$${usdValue}` }) }) })), message && jsx(ModalBody, { children: message }), jsx(Button, { onClick: handleContinue, disabled: continueDisabled, children: "Continue" })] })] }));
106
+ };
107
+ const AmountInputContainer = styled.div `
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ gap: 6px;
112
+ `;
113
+ const SecondaryAmount = styled.div `
114
+ font-size: 16px;
115
+ font-weight: 400;
116
+ line-height: 21px;
117
+ color: var(--ck-body-color-muted);
118
+ strong {
119
+ font-weight: 500;
120
+ color: var(--ck-body-color);
121
+ }
122
+ `;
123
+ const MaxButton = styled.button `
124
+ display: inline-block;
125
+ padding: 3px 8px;
126
+ border-radius: var(--ck-primary-button-border-radius);
127
+ font-size: 14px;
128
+ font-weight: 400;
129
+ background: var(
130
+ --ck-secondary-button-background,
131
+ var(--ck-body-background-secondary)
132
+ );
133
+ color: var(--ck-body-color-muted);
134
+ cursor: pointer;
135
+ `;
136
+ const SwitchContainer = styled.div `
137
+ display: flex;
138
+ align-items: center;
139
+ justify-content: center;
140
+ `;
141
+
142
+ export { MultiCurrencySelectAmount as default };
143
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -57,7 +57,7 @@ const ChainSelectList = ({ variant, }) => {
57
57
  opacity: [1, 0],
58
58
  transition: { delay: 4, duration: 3 },
59
59
  }
60
- : { opacity: 1 }, children: Spinner }, `${ch?.id}-${ch?.name}`) }), jsx(ChainIcon, { children: ch.logo ?? jsx(Chains.UnknownChain, {}) })] }), ch.name] }), variant !== "secondary" && (jsx(ChainButtonStatus, { children: jsxs(AnimatePresence, { initial: false, exitBeforeEnter: true, children: [ch.id === chain?.id && (jsx(motion.span, { style: {
60
+ : { opacity: 1 }, children: Spinner }, `${ch?.id}-${ch?.name}`) }), jsx(ChainIcon, { children: ch.logo ?? jsx(Chains.UnknownChain, {}) })] }), ch.name] }), variant !== "secondary" && (jsx(ChainButtonStatus, { children: jsxs(AnimatePresence, { initial: false, mode: "wait", children: [ch.id === chain?.id && (jsx(motion.span, { style: {
61
61
  color: "var(--ck-dropdown-active-color, var(--ck-focus-color))",
62
62
  display: "block",
63
63
  position: "relative",
@@ -185,7 +185,7 @@ const Modal = ({ open, pages, pageId, positionInside, inline, demo, onClose, onB
185
185
  if (!selectedSolanaTokenOption)
186
186
  return undefined;
187
187
  return `Pay with ${selectedSolanaTokenOption.required.token.symbol}`;
188
- case ROUTES.WAITING_OTHER:
188
+ case ROUTES.WAITING_EXTERNAL:
189
189
  return selectedExternalOption?.cta;
190
190
  case ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN:
191
191
  return "Select Chain";
@@ -193,12 +193,17 @@ const Modal = ({ open, pages, pageId, positionInside, inline, demo, onClose, onB
193
193
  if (!selectedDepositAddressOption)
194
194
  return undefined;
195
195
  return `Pay with ${selectedDepositAddressOption.id}`;
196
+ case ROUTES.SELECT_AMOUNT:
197
+ case ROUTES.SELECT_EXTERNAL_AMOUNT:
198
+ case ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT:
199
+ case ROUTES.SOLANA_SELECT_AMOUNT:
200
+ return "Select Amount";
196
201
  case ROUTES.PAY_WITH_TOKEN:
197
- if (!selectedTokenOption)
202
+ if (selectedTokenOption == null)
198
203
  return undefined;
199
- const chainName = getChainName(selectedTokenOption.required.token.chainId ?? 0);
204
+ const chainName = getChainName(selectedTokenOption.balance.token.chainId);
200
205
  const capitalizedChainName = chainName.charAt(0).toUpperCase() + chainName.slice(1);
201
- return `Pay with ${capitalizedChainName} ${selectedTokenOption.required.token.symbol}`;
206
+ return `Pay with ${capitalizedChainName} ${selectedTokenOption.balance.token.symbol}`;
202
207
  case ROUTES.CONFIRMATION:
203
208
  return "Payment Successful";
204
209
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -131,7 +131,8 @@ const ModalContent = styled(motion.div) `
131
131
  padding: 0 0 16px;
132
132
 
133
133
  @media only screen and (max-width: ${defaultTheme.mobileWidth}px) {
134
- display: block;
134
+ display: ${(props) => (props.$preserveDisplay ? "flex" : "block")};
135
+ gap: ${(props) => (props.$preserveDisplay ? "4px" : undefined)};
135
136
  }
136
137
  `;
137
138
  const ModalH1 = styled(motion.h1) `
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"styles.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -5,7 +5,7 @@ import { motion } from 'framer-motion';
5
5
  const OptionButton = styled(motion.button) `
6
6
  display: block;
7
7
  text-decoration: none;
8
- cursor: pointer;
8
+ cursor: ${(props) => (props.disabled ? "default" : "pointer")};
9
9
  user-select: none;
10
10
  position: relative;
11
11
  display: flex;