@rango-dev/widget-embedded 0.30.1 → 0.31.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 (128) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts +1 -653
  3. package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts.map +1 -1
  4. package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.d.ts.map +1 -1
  5. package/dist/components/ConfirmWalletsModal/WalletList.d.ts.map +1 -1
  6. package/dist/components/CustomDestination/CustomDestination.d.ts +4 -0
  7. package/dist/components/CustomDestination/CustomDestination.d.ts.map +1 -0
  8. package/dist/components/CustomDestination/CustomDestination.styles.d.ts +495 -0
  9. package/dist/components/CustomDestination/CustomDestination.styles.d.ts.map +1 -0
  10. package/dist/components/CustomDestination/CustomDestination.types.d.ts +7 -0
  11. package/dist/components/CustomDestination/CustomDestination.types.d.ts.map +1 -0
  12. package/dist/components/FilterSelector/FilterSelector.d.ts +4 -0
  13. package/dist/components/FilterSelector/FilterSelector.d.ts.map +1 -0
  14. package/dist/components/FilterSelector/FilterSelector.style.d.ts +962 -0
  15. package/dist/components/FilterSelector/FilterSelector.style.d.ts.map +1 -0
  16. package/dist/components/FilterSelector/FilterSelector.type.d.ts +14 -0
  17. package/dist/components/FilterSelector/FilterSelector.type.d.ts.map +1 -0
  18. package/dist/components/FilterSelector/FilterSelectorContent.d.ts +4 -0
  19. package/dist/components/FilterSelector/FilterSelectorContent.d.ts.map +1 -0
  20. package/dist/components/FilterSelector/index.d.ts +2 -0
  21. package/dist/components/FilterSelector/index.d.ts.map +1 -0
  22. package/dist/components/Quote/Quote.styles.d.ts +3 -3
  23. package/dist/components/RefreshModal/RefreshModal.styles.d.ts +3 -3
  24. package/dist/components/SearchInput/SearchInput.d.ts.map +1 -1
  25. package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
  26. package/dist/components/SwapDetails/SwapDetails.styles.d.ts.map +1 -1
  27. package/dist/components/SwapDetailsModal/SwapDetailsModal.WalletState.d.ts.map +1 -1
  28. package/dist/components/TokenList/TokenList.d.ts.map +1 -1
  29. package/dist/containers/Inputs/Inputs.d.ts.map +1 -1
  30. package/dist/containers/Wallets/Wallets.d.ts.map +1 -1
  31. package/dist/containers/WidgetInfo/WidgetInfo.d.ts.map +1 -1
  32. package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts +5 -1
  33. package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts.map +1 -1
  34. package/dist/hooks/useObserveBalanceChanges/index.d.ts +2 -0
  35. package/dist/hooks/useObserveBalanceChanges/index.d.ts.map +1 -0
  36. package/dist/hooks/useObserveBalanceChanges/useObserveBalanceChanges.d.ts +4 -0
  37. package/dist/hooks/useObserveBalanceChanges/useObserveBalanceChanges.d.ts.map +1 -0
  38. package/dist/hooks/usePrepareBlockchainList/usePrepareBlockchainList.helpers.d.ts +2 -2
  39. package/dist/hooks/useTheme.d.ts.map +1 -1
  40. package/dist/hooks/useUpdateQuoteInputs/index.d.ts +2 -0
  41. package/dist/hooks/useUpdateQuoteInputs/index.d.ts.map +1 -0
  42. package/dist/hooks/useUpdateQuoteInputs/useUpdateQuoteInputs.d.ts +3 -0
  43. package/dist/hooks/useUpdateQuoteInputs/useUpdateQuoteInputs.d.ts.map +1 -0
  44. package/dist/index.d.ts +4 -4
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +2 -2
  47. package/dist/index.js.map +4 -4
  48. package/dist/pages/HistoryPage.d.ts.map +1 -1
  49. package/dist/pages/Home.d.ts.map +1 -1
  50. package/dist/pages/WalletsPage.d.ts.map +1 -1
  51. package/dist/services/cacheService.d.ts +21 -0
  52. package/dist/services/cacheService.d.ts.map +1 -0
  53. package/dist/store/notification.d.ts.map +1 -1
  54. package/dist/store/slices/config.d.ts +2 -1
  55. package/dist/store/slices/config.d.ts.map +1 -1
  56. package/dist/store/slices/data.d.ts +2 -1
  57. package/dist/store/slices/data.d.ts.map +1 -1
  58. package/dist/store/utils/data.d.ts +20 -0
  59. package/dist/store/utils/data.d.ts.map +1 -0
  60. package/dist/store/utils/data.test.d.ts +2 -0
  61. package/dist/store/utils/data.test.d.ts.map +1 -0
  62. package/dist/store/utils/index.d.ts +2 -0
  63. package/dist/store/utils/index.d.ts.map +1 -0
  64. package/dist/test-utils/fixtures.d.ts +1 -0
  65. package/dist/test-utils/fixtures.d.ts.map +1 -1
  66. package/dist/types/config.d.ts +5 -0
  67. package/dist/types/config.d.ts.map +1 -1
  68. package/dist/types/event.d.ts +21 -15
  69. package/dist/types/event.d.ts.map +1 -1
  70. package/dist/types/notification.d.ts +1 -0
  71. package/dist/types/notification.d.ts.map +1 -1
  72. package/dist/types/quote.d.ts +9 -1
  73. package/dist/types/quote.d.ts.map +1 -1
  74. package/dist/types/wallets.d.ts +1 -1
  75. package/dist/types/wallets.d.ts.map +1 -1
  76. package/dist/utils/events.d.ts +8 -0
  77. package/dist/utils/events.d.ts.map +1 -0
  78. package/dist/utils/settings.d.ts +1 -1
  79. package/dist/utils/swap.d.ts +1 -1
  80. package/dist/utils/swap.d.ts.map +1 -1
  81. package/dist/widget-embedded.build.json +1 -1
  82. package/package.json +10 -10
  83. package/src/components/ConfirmWalletsModal/ConfirmWallets.styles.ts +1 -49
  84. package/src/components/ConfirmWalletsModal/ConfirmWalletsModal.tsx +61 -179
  85. package/src/components/ConfirmWalletsModal/WalletList.tsx +16 -4
  86. package/src/components/CustomDestination/CustomDestination.styles.ts +45 -0
  87. package/src/components/CustomDestination/CustomDestination.tsx +148 -0
  88. package/src/components/CustomDestination/CustomDestination.types.ts +7 -0
  89. package/src/components/FilterSelector/FilterSelector.style.ts +95 -0
  90. package/src/components/FilterSelector/FilterSelector.tsx +42 -0
  91. package/src/components/FilterSelector/FilterSelector.type.ts +15 -0
  92. package/src/components/FilterSelector/FilterSelectorContent.tsx +60 -0
  93. package/src/components/FilterSelector/index.ts +1 -0
  94. package/src/components/SearchInput/SearchInput.tsx +2 -0
  95. package/src/components/SwapDetails/SwapDetails.styles.ts +10 -0
  96. package/src/components/SwapDetails/SwapDetails.tsx +25 -13
  97. package/src/components/SwapDetailsModal/SwapDetailsModal.WalletState.tsx +28 -13
  98. package/src/components/TokenList/TokenList.tsx +8 -2
  99. package/src/containers/Inputs/Inputs.tsx +1 -0
  100. package/src/containers/Wallets/Wallets.tsx +7 -2
  101. package/src/containers/WidgetInfo/WidgetInfo.tsx +26 -0
  102. package/src/containers/WidgetInfo/WidgetInfo.types.ts +5 -1
  103. package/src/hooks/useObserveBalanceChanges/index.ts +1 -0
  104. package/src/hooks/useObserveBalanceChanges/useObserveBalanceChanges.ts +68 -0
  105. package/src/hooks/useTheme.ts +11 -5
  106. package/src/hooks/useUpdateQuoteInputs/index.ts +1 -0
  107. package/src/hooks/useUpdateQuoteInputs/useUpdateQuoteInputs.ts +50 -0
  108. package/src/index.ts +4 -0
  109. package/src/pages/HistoryPage.tsx +180 -26
  110. package/src/pages/Home.tsx +6 -3
  111. package/src/pages/WalletsPage.tsx +29 -13
  112. package/src/services/cacheService.ts +35 -0
  113. package/src/store/notification.ts +13 -1
  114. package/src/store/quote.ts +1 -1
  115. package/src/store/slices/config.ts +39 -1
  116. package/src/store/slices/data.test.ts +84 -0
  117. package/src/store/slices/data.ts +44 -24
  118. package/src/store/utils/data.test.ts +175 -0
  119. package/src/store/utils/data.ts +117 -0
  120. package/src/store/utils/index.ts +1 -0
  121. package/src/test-utils/fixtures.ts +14 -7
  122. package/src/types/config.ts +3 -1
  123. package/src/types/event.ts +32 -16
  124. package/src/types/notification.ts +1 -0
  125. package/src/types/quote.ts +11 -0
  126. package/src/types/wallets.ts +1 -1
  127. package/src/utils/events.ts +27 -0
  128. package/src/utils/swap.ts +4 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rango-dev/widget-embedded",
3
- "version": "0.30.1",
3
+ "version": "0.31.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "source": "./src/index.ts",
@@ -24,15 +24,15 @@
24
24
  "dependencies": {
25
25
  "@lingui/core": "4.2.1",
26
26
  "@lingui/react": "4.2.1",
27
- "@rango-dev/logging-core": "^0.5.0",
28
- "@rango-dev/provider-all": "^0.35.1",
29
- "@rango-dev/queue-manager-core": "^0.26.0",
30
- "@rango-dev/queue-manager-rango-preset": "^0.35.1",
31
- "@rango-dev/queue-manager-react": "^0.26.0",
32
- "@rango-dev/signer-solana": "^0.30.0",
33
- "@rango-dev/ui": "^0.36.1",
34
- "@rango-dev/wallets-react": "^0.21.1",
35
- "@rango-dev/wallets-shared": "^0.35.1",
27
+ "@rango-dev/logging-core": "^0.6.0",
28
+ "@rango-dev/provider-all": "^0.36.0",
29
+ "@rango-dev/queue-manager-core": "^0.27.0",
30
+ "@rango-dev/queue-manager-rango-preset": "^0.36.0",
31
+ "@rango-dev/queue-manager-react": "^0.27.0",
32
+ "@rango-dev/signer-solana": "^0.31.0",
33
+ "@rango-dev/ui": "^0.37.0",
34
+ "@rango-dev/wallets-react": "^0.22.0",
35
+ "@rango-dev/wallets-shared": "^0.36.0",
36
36
  "bignumber.js": "^9.1.1",
37
37
  "copy-to-clipboard": "^3.3.3",
38
38
  "dayjs": "^1.11.7",
@@ -1,4 +1,4 @@
1
- import { css, darkTheme, IconButton, styled, TextField } from '@rango-dev/ui';
1
+ import { css, darkTheme, IconButton, styled } from '@rango-dev/ui';
2
2
 
3
3
  export const Title = styled('div', {
4
4
  display: 'flex',
@@ -93,56 +93,8 @@ export const walletsListStyles = css({
93
93
  height: '100%',
94
94
  });
95
95
 
96
- export const CustomDestination = styled('div', {
97
- padding: '$10 $0',
98
- '& .button__content': {
99
- display: 'flex',
100
- alignItems: 'center',
101
- },
102
- '& .alarms': { paddingTop: '$5' },
103
- '& .collapsible_content': {
104
- backgroundColor: '$neutral100',
105
- },
106
- '& .collapsible_root': {
107
- backgroundColor: '$neutral100',
108
- },
109
- });
110
-
111
- export const alarmsStyles = css({
112
- paddingTop: '$5',
113
- });
114
-
115
96
  export const ConfirmButton = styled('div', {
116
97
  display: 'flex',
117
98
  });
118
99
 
119
- export const StyledTextField = styled(TextField, {
120
- backgroundColor: '$neutral100',
121
- padding: '$15',
122
- });
123
-
124
100
  export const Wallets = styled('div', { overflow: 'visible', width: '100%' });
125
-
126
- export const CustomDestinationButton = styled('div', {
127
- width: '100%',
128
- borderRadius: '$sm',
129
- display: 'flex',
130
- padding: '$15',
131
- justifyContent: 'space-between',
132
- alignItems: 'center',
133
- $$color: '$colors$neutral100',
134
- [`.${darkTheme} &`]: {
135
- $$color: '$colors$neutral300',
136
- },
137
- backgroundColor: '$$color',
138
- borderBottomRightRadius: '0',
139
- borderBottomLeftRadius: '0',
140
- '&:focus-visible': {
141
- $$background: '$colors$secondary100',
142
- [`.${darkTheme} &`]: {
143
- $$background: '$colors$info700',
144
- },
145
- backgroundColor: '$$background',
146
- outline: 0,
147
- },
148
- });
@@ -1,30 +1,18 @@
1
1
  import type { PropTypes } from './ConfirmWalletsModal.types';
2
2
  import type { ConnectedWallet } from '../../store/wallets';
3
3
  import type { ConfirmSwapWarnings, Wallet } from '../../types';
4
- import type { MouseEvent } from 'react';
5
4
 
6
5
  import { i18n } from '@lingui/core';
7
6
  import {
8
7
  Alert,
9
8
  BalanceErrors,
10
9
  Button,
11
- ChevronDownIcon,
12
10
  ChevronLeftIcon,
13
- CloseIcon,
14
11
  Divider,
15
- IconButton,
16
12
  MessageBox,
17
- PasteIcon,
18
13
  Typography,
19
- WalletIcon,
20
14
  } from '@rango-dev/ui';
21
- import React, {
22
- useCallback,
23
- useEffect,
24
- useMemo,
25
- useRef,
26
- useState,
27
- } from 'react';
15
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
28
16
  import { useNavigate } from 'react-router-dom';
29
17
 
30
18
  import { WIDGET_UI_ID } from '../../constants';
@@ -33,26 +21,17 @@ import { getQuoteUpdateWarningMessage } from '../../constants/warnings';
33
21
  import { useAppStore } from '../../store/AppStore';
34
22
  import { useQuoteStore } from '../../store/quote';
35
23
  import { useWalletsStore } from '../../store/wallets';
36
- import {
37
- getBlockchainDisplayNameFor,
38
- getBlockchainShortNameFor,
39
- } from '../../utils/meta';
24
+ import { getBlockchainShortNameFor } from '../../utils/meta';
40
25
  import { isConfirmSwapDisabled } from '../../utils/swap';
41
26
  import { getQuoteWallets } from '../../utils/wallets';
42
27
  import { WatermarkedModal } from '../common/WatermarkedModal';
43
- import { CustomCollapsible } from '../CustomCollapsible/CustomCollapsible';
44
- import { ExpandedIcon } from '../CustomCollapsible/CustomCollapsible.styles';
28
+ import { CustomDestination } from '../CustomDestination/CustomDestination';
45
29
 
46
- import { isValidAddress } from './ConfirmWallets.helpers';
47
30
  import {
48
- alarmsStyles,
49
31
  ConfirmButton,
50
- CustomDestination,
51
- CustomDestinationButton,
52
32
  ListContainer,
53
33
  NavigateBack,
54
34
  ShowMoreHeader,
55
- StyledTextField,
56
35
  Title,
57
36
  Wallets,
58
37
  WalletsContainer,
@@ -66,10 +45,6 @@ export function ConfirmWalletsModal(props: PropTypes) {
66
45
  //TODO: move component's logics to a custom hook
67
46
  const { open, onClose, onCancel, onCheckBalance, loading } = props;
68
47
  const navigate = useNavigate();
69
- const config = useAppStore().config;
70
-
71
- const customDestinationInputRef = useRef<HTMLInputElement | null>(null);
72
-
73
48
  const blockchains = useAppStore().blockchains();
74
49
  const {
75
50
  selectedQuote,
@@ -80,6 +55,7 @@ export function ConfirmWalletsModal(props: PropTypes) {
80
55
  setCustomDestination,
81
56
  } = useQuoteStore();
82
57
  const { connectedWallets, selectWallets } = useWalletsStore();
58
+ const { config } = useAppStore();
83
59
 
84
60
  const [showMoreWalletFor, setShowMoreWalletFor] = useState('');
85
61
  const [balanceWarnings, setBalanceWarnings] = useState<string[]>([]);
@@ -87,12 +63,11 @@ export function ConfirmWalletsModal(props: PropTypes) {
87
63
  const [quoteWarning, setQuoteWarning] = useState<
88
64
  ConfirmSwapWarnings['quoteUpdate'] | null
89
65
  >(null);
90
- const [showCustomDestination, setShowCustomDestination] = useState(
66
+
67
+ const [isCustomDestinationOpen, setCustomDestinationOpen] = useState(
91
68
  !!customDestination
92
69
  );
93
70
 
94
- const isFirefox = navigator?.userAgent.includes('Firefox');
95
-
96
71
  const quoteWallets = useMemo(
97
72
  () =>
98
73
  getQuoteWallets({
@@ -156,62 +131,50 @@ export function ConfirmWalletsModal(props: PropTypes) {
156
131
  (!isWalletRequiredFor(chain) && !customDestination))
157
132
  );
158
133
 
159
- const isAddressMatched =
160
- !!customDestination &&
161
- showCustomDestination &&
162
- lastStepToBlockchain &&
163
- !isValidAddress(lastStepToBlockchain, customDestination);
164
-
165
- const resetCustomDestination = () => {
166
- setShowCustomDestination(false);
167
- setCustomDestination(null);
168
- setSelectableWallets((selectableWallets) => {
169
- let anyWalletSelected = false;
170
- return selectableWallets.map((selectableWallet) => {
171
- if (
172
- !anyWalletSelected &&
173
- selectableWallet.chain === lastStepToBlockchain?.name
174
- ) {
175
- anyWalletSelected = true;
176
- return {
177
- ...selectableWallet,
178
- selected: true,
179
- };
134
+ const updateSelectableWallets = (
135
+ wallets: ConnectedWallet[],
136
+ chainName: string,
137
+ shouldSelect: boolean
138
+ ) => {
139
+ let isAnyWalletSelected = false;
140
+ return wallets.map((wallet) => {
141
+ if (wallet.chain === chainName) {
142
+ let selected = wallet.selected;
143
+ if (!isAnyWalletSelected && shouldSelect) {
144
+ isAnyWalletSelected = true;
145
+ selected = true;
146
+ } else if (!shouldSelect) {
147
+ selected = false;
180
148
  }
181
- return selectableWallet;
182
- });
149
+ return {
150
+ ...wallet,
151
+ selected,
152
+ };
153
+ }
154
+ return wallet;
183
155
  });
184
156
  };
185
157
 
186
- const handleClearCustomDestination = () => setCustomDestination('');
187
-
188
- const handlePasteCustomDestination = async (
189
- event: MouseEvent<HTMLButtonElement>
190
- ) => {
191
- event.preventDefault();
192
- if (navigator.clipboard !== undefined) {
193
- const pastedText = await navigator.clipboard.readText();
194
- setCustomDestination(pastedText);
195
- customDestinationInputRef?.current?.focus();
196
- }
197
- };
198
-
199
- const handleCustomDestinationCollapsibleOpenChange = (checked: boolean) => {
200
- if (!checked) {
201
- resetCustomDestination();
158
+ const handleCustomDestinationCollapsibleOpenChange = (open: boolean) => {
159
+ setCustomDestinationOpen(open);
160
+ if (!open) {
161
+ setCustomDestination('');
162
+ setSelectableWallets((selectableWallets) => {
163
+ return updateSelectableWallets(
164
+ selectableWallets,
165
+ lastStepToBlockchain?.name || '',
166
+ true
167
+ );
168
+ });
202
169
  } else {
203
170
  if (!isWalletRequiredFor(lastStepToBlockchain?.name ?? '')) {
204
- setSelectableWallets((selectableWallets) =>
205
- selectableWallets.map((selectableWallet) => {
206
- if (selectableWallet.chain === lastStepToBlockchain?.name) {
207
- return {
208
- ...selectableWallet,
209
- selected: false,
210
- };
211
- }
212
- return selectableWallet;
213
- })
214
- );
171
+ setSelectableWallets((selectableWallets) => {
172
+ return updateSelectableWallets(
173
+ selectableWallets,
174
+ lastStepToBlockchain?.name || '',
175
+ false
176
+ );
177
+ });
215
178
  }
216
179
  }
217
180
  };
@@ -237,10 +200,10 @@ export function ConfirmWalletsModal(props: PropTypes) {
237
200
  onCancel();
238
201
  if (
239
202
  wallet.chain === lastStepToBlockchain?.name &&
240
- showCustomDestination &&
203
+ isCustomDestinationOpen &&
241
204
  !isWalletRequiredFor(lastStepToBlockchain.name)
242
205
  ) {
243
- setShowCustomDestination(false);
206
+ setCustomDestinationOpen(false);
244
207
  setCustomDestination(null);
245
208
  }
246
209
  setSelectableWallets((selectableWallets) =>
@@ -287,24 +250,6 @@ export function ConfirmWalletsModal(props: PropTypes) {
287
250
  }
288
251
  };
289
252
 
290
- const renderCustomDestinationSuffix = () => {
291
- if (customDestination) {
292
- return (
293
- <IconButton onClick={handleClearCustomDestination} variant="ghost">
294
- <CloseIcon size={12} color="gray" />
295
- </IconButton>
296
- );
297
- } else if (!isFirefox) {
298
- return (
299
- <IconButton onClick={handlePasteCustomDestination} variant="ghost">
300
- <PasteIcon size={16} />
301
- </IconButton>
302
- );
303
- }
304
-
305
- return null;
306
- };
307
-
308
253
  useEffect(() => {
309
254
  setSelectableWallets((selectableWallets) => {
310
255
  let nextState: typeof selectableWallets = [];
@@ -382,13 +327,14 @@ export function ConfirmWalletsModal(props: PropTypes) {
382
327
  dismissible={!showMoreWalletFor}
383
328
  container={modalContainer}
384
329
  {...(!showMoreWalletFor && {
330
+ styles: { container: { height: '100%' } },
385
331
  footer: (
386
332
  <ConfirmButton>
387
333
  <Button
388
334
  loading={loading}
389
335
  disabled={isConfirmSwapDisabled(
390
336
  loading,
391
- showCustomDestination,
337
+ isCustomDestinationOpen,
392
338
  customDestination,
393
339
  selectedQuote,
394
340
  selectableWallets,
@@ -405,7 +351,7 @@ export function ConfirmWalletsModal(props: PropTypes) {
405
351
  ),
406
352
  })}
407
353
  {...(showMoreWalletFor && {
408
- styles: { container: { padding: '$0' } },
354
+ styles: { container: { height: '100%', padding: '$0' } },
409
355
  header: (
410
356
  <ShowMoreHeader>
411
357
  <NavigateBack
@@ -487,7 +433,10 @@ export function ConfirmWalletsModal(props: PropTypes) {
487
433
 
488
434
  const key = `wallet-${index}`;
489
435
  const isLastWallet = index === quoteWallets.length - 1;
490
-
436
+ const showCustomDestination =
437
+ isLastWallet &&
438
+ lastStepToBlockchain &&
439
+ config?.customDestination !== false;
491
440
  return (
492
441
  <div key={key}>
493
442
  <Title>
@@ -523,81 +472,14 @@ export function ConfirmWalletsModal(props: PropTypes) {
523
472
  />
524
473
  </ListContainer>
525
474
  {!isLastWallet && <Divider size={32} />}
526
- {isLastWallet && config?.customDestination !== false && (
527
- <CustomDestination>
528
- <CustomCollapsible
529
- onOpenChange={
530
- handleCustomDestinationCollapsibleOpenChange
531
- }
532
- hasSelected
533
- open={showCustomDestination}
534
- triggerAnchor="top"
535
- trigger={
536
- <CustomDestinationButton>
537
- <div className="button__content">
538
- <WalletIcon size={18} color="info" />
539
- <Divider size={4} direction="horizontal" />
540
- <Typography
541
- variant="label"
542
- size="medium"
543
- color={
544
- showCustomDestination
545
- ? '$neutral600'
546
- : undefined
547
- }>
548
- {i18n.t('Send to a different address')}
549
- </Typography>
550
- </div>
551
- <ExpandedIcon
552
- orientation={
553
- showCustomDestination ? 'up' : 'down'
554
- }>
555
- <ChevronDownIcon size={10} color="secondary" />
556
- </ExpandedIcon>
557
- </CustomDestinationButton>
558
- }
559
- onClickTrigger={() =>
560
- setShowCustomDestination((prev) => !prev)
561
- }>
562
- <StyledTextField
563
- ref={customDestinationInputRef}
564
- style={{
565
- padding: 0,
566
- paddingRight: customDestination ? '8px' : '5px',
567
- }}
568
- autoFocus
569
- placeholder={i18n.t(
570
- 'Enter {blockchainName} address',
571
- {
572
- blockchainName: getBlockchainDisplayNameFor(
573
- requiredWallet,
574
- blockchains
575
- ),
576
- }
577
- )}
578
- value={customDestination || ''}
579
- suffix={renderCustomDestinationSuffix()}
580
- onChange={(e) => {
581
- const value = e.target.value;
582
- setCustomDestination(value);
583
- }}
584
- {...(!customDestination && { autoFocus: true })}
585
- />
586
- </CustomCollapsible>
587
-
588
- {isAddressMatched && (
589
- <div className={alarmsStyles()}>
590
- <Alert
591
- variant="alarm"
592
- type="error"
593
- title={i18n.t({
594
- values: { destination: customDestination },
595
- id: "Address {destination} doesn't match the blockchain address pattern.",
596
- })}
597
- />
598
- </div>
599
- )}
600
- </CustomDestination>
475
+ {showCustomDestination && (
476
+ <CustomDestination
477
+ blockchain={lastStepToBlockchain}
478
+ open={isCustomDestinationOpen}
479
+ handleOpenChange={
480
+ handleCustomDestinationCollapsibleOpenChange
481
+ }
482
+ />
601
483
  )}
602
484
  </div>
603
485
  );
@@ -260,14 +260,26 @@ export function WalletList(props: PropTypes) {
260
260
  })
261
261
  : conciseAddress;
262
262
 
263
- const onClick = async () => {
263
+ const onSelectableWalletClick = async () => {
264
264
  if (wallet.state === WalletState.DISCONNECTED) {
265
- if (!!wallet.namespaces) {
266
- handleOpenNamespacesModal(wallet);
265
+ if (!!wallet.namespaces?.length) {
266
+ if (wallet.namespaces.length > 1) {
267
+ handleOpenNamespacesModal(wallet);
268
+ } else if (wallet.needsDerivationPath) {
269
+ setDerivationPathModalState({
270
+ open: true,
271
+ providerType: wallet.type,
272
+ providerImage: wallet.image,
273
+ namespace: wallet.namespaces[0],
274
+ });
275
+ } else {
276
+ void handleClick(wallet.type);
277
+ }
267
278
  } else {
268
279
  void handleClick(wallet.type);
269
280
  }
270
281
  } else if (!!wallet.namespaces && !conciseAddress) {
282
+ // wallet is connected on a different namespace
271
283
  await disconnectWallet(wallet.type);
272
284
  handleOpenNamespacesModal(wallet);
273
285
  } else if (couldAddExperimentalChain) {
@@ -409,7 +421,7 @@ export function WalletList(props: PropTypes) {
409
421
  <SelectableWallet
410
422
  key={wallet.type}
411
423
  description={connectedWalletDescription}
412
- onClick={onClick}
424
+ onClick={onSelectableWalletClick}
413
425
  selected={isSelected(wallet.type, chain)}
414
426
  disabled={!isActiveTab}
415
427
  {...wallet}
@@ -0,0 +1,45 @@
1
+ import { darkTheme, styled, TextField } from '@rango-dev/ui';
2
+
3
+ export const Container = styled('div', {
4
+ padding: '$10 $0',
5
+ '& .button__content': {
6
+ display: 'flex',
7
+ alignItems: 'center',
8
+ },
9
+ '& .alarms': { paddingTop: '$5' },
10
+ '& .collapsible_content': {
11
+ backgroundColor: '$neutral100',
12
+ },
13
+ '& .collapsible_root': {
14
+ backgroundColor: '$neutral100',
15
+ },
16
+ });
17
+
18
+ export const StyledTextField = styled(TextField, {
19
+ backgroundColor: '$neutral100',
20
+ padding: '$15',
21
+ });
22
+
23
+ export const CustomDestinationButton = styled('div', {
24
+ width: '100%',
25
+ borderRadius: '$sm',
26
+ display: 'flex',
27
+ padding: '$15',
28
+ justifyContent: 'space-between',
29
+ alignItems: 'center',
30
+ $$color: '$colors$neutral100',
31
+ [`.${darkTheme} &`]: {
32
+ $$color: '$colors$neutral300',
33
+ },
34
+ backgroundColor: '$$color',
35
+ borderBottomRightRadius: '0',
36
+ borderBottomLeftRadius: '0',
37
+ '&:focus-visible': {
38
+ $$background: '$colors$secondary100',
39
+ [`.${darkTheme} &`]: {
40
+ $$background: '$colors$info700',
41
+ },
42
+ backgroundColor: '$$background',
43
+ outline: 0,
44
+ },
45
+ });
@@ -0,0 +1,148 @@
1
+ import type { PropTypes } from './CustomDestination.types';
2
+ import type { MouseEvent } from 'react';
3
+
4
+ import { i18n } from '@lingui/core';
5
+ import {
6
+ Alert,
7
+ ChevronDownIcon,
8
+ CloseIcon,
9
+ Divider,
10
+ IconButton,
11
+ PasteIcon,
12
+ Typography,
13
+ WalletIcon,
14
+ } from '@rango-dev/ui';
15
+ import React, { useEffect, useRef } from 'react';
16
+
17
+ import { useAppStore } from '../../store/AppStore';
18
+ import { useQuoteStore } from '../../store/quote';
19
+ import { getBlockchainDisplayNameFor } from '../../utils/meta';
20
+ import { isValidAddress } from '../ConfirmWalletsModal/ConfirmWallets.helpers';
21
+ import { CustomCollapsible } from '../CustomCollapsible/CustomCollapsible';
22
+ import { ExpandedIcon } from '../CustomCollapsible/CustomCollapsible.styles';
23
+
24
+ import {
25
+ Container,
26
+ CustomDestinationButton,
27
+ StyledTextField,
28
+ } from './CustomDestination.styles';
29
+
30
+ export function CustomDestination(props: PropTypes) {
31
+ const { blockchain, handleOpenChange, open } = props;
32
+
33
+ const { customDestination, setCustomDestination } = useQuoteStore();
34
+ const { config } = useAppStore();
35
+ const blockchains = useAppStore().blockchains();
36
+ const blockchainName = getBlockchainDisplayNameFor(
37
+ blockchain.name,
38
+ blockchains
39
+ );
40
+ const inputRef = useRef<HTMLInputElement | null>(null);
41
+ const configDestination =
42
+ config?.defaultCustomDestinations?.[blockchain.name];
43
+
44
+ const isFirefox = navigator?.userAgent.includes('Firefox');
45
+ const isAddressChecked = open && !!customDestination && blockchain;
46
+ const isAddressInvalid =
47
+ isAddressChecked && !isValidAddress(blockchain, customDestination);
48
+ const handleClear = () => {
49
+ setCustomDestination('');
50
+ };
51
+
52
+ const handlePaste = async (event: MouseEvent<HTMLButtonElement>) => {
53
+ event.preventDefault();
54
+ if (navigator.clipboard !== undefined) {
55
+ const pastedText = await navigator.clipboard.readText();
56
+ setCustomDestination(pastedText);
57
+ inputRef?.current?.focus();
58
+ }
59
+ };
60
+
61
+ const renderSuffix = () => {
62
+ if (customDestination) {
63
+ return (
64
+ <IconButton onClick={handleClear} variant="ghost">
65
+ <CloseIcon size={12} color="gray" />
66
+ </IconButton>
67
+ );
68
+ } else if (!isFirefox) {
69
+ return (
70
+ <IconButton onClick={handlePaste} variant="ghost">
71
+ <PasteIcon size={16} />
72
+ </IconButton>
73
+ );
74
+ }
75
+
76
+ return null;
77
+ };
78
+
79
+ useEffect(() => {
80
+ const shouldUseConfigDestination =
81
+ !!configDestination && customDestination === null;
82
+
83
+ if (shouldUseConfigDestination) {
84
+ setCustomDestination(configDestination);
85
+ handleOpenChange(true);
86
+ }
87
+ }, [configDestination]);
88
+
89
+ return (
90
+ <Container>
91
+ <CustomCollapsible
92
+ onOpenChange={handleOpenChange}
93
+ hasSelected
94
+ open={open}
95
+ triggerAnchor="top"
96
+ trigger={
97
+ <CustomDestinationButton>
98
+ <div className="button__content">
99
+ <WalletIcon size={18} color="info" />
100
+ <Divider size={4} direction="horizontal" />
101
+ <Typography
102
+ variant="label"
103
+ size="medium"
104
+ color={open ? '$neutral600' : undefined}>
105
+ {i18n.t('Send to a different address')}
106
+ </Typography>
107
+ </div>
108
+ <ExpandedIcon orientation={open ? 'up' : 'down'}>
109
+ <ChevronDownIcon size={10} color="secondary" />
110
+ </ExpandedIcon>
111
+ </CustomDestinationButton>
112
+ }
113
+ onClickTrigger={() => handleOpenChange(!open)}>
114
+ <StyledTextField
115
+ ref={inputRef}
116
+ style={{
117
+ padding: 0,
118
+ paddingRight: customDestination ? '8px' : '5px',
119
+ }}
120
+ autoFocus={!customDestination}
121
+ placeholder={i18n.t('Enter {blockchainName} address', {
122
+ blockchainName,
123
+ })}
124
+ value={customDestination || ''}
125
+ suffix={renderSuffix()}
126
+ onChange={(e) => {
127
+ const customDestination = e.target.value;
128
+ setCustomDestination(customDestination);
129
+ }}
130
+ />
131
+ </CustomCollapsible>
132
+
133
+ {isAddressInvalid && (
134
+ <>
135
+ <Divider size={4} />
136
+ <Alert
137
+ variant="alarm"
138
+ type="error"
139
+ title={i18n.t({
140
+ values: { destination: customDestination },
141
+ id: "Address {destination} doesn't match the blockchain address pattern.",
142
+ })}
143
+ />
144
+ </>
145
+ )}
146
+ </Container>
147
+ );
148
+ }