@rango-dev/ui 0.1.10-next.81 → 0.1.10-next.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TokenList/TokenItem.d.ts +11 -0
- package/dist/components/VirtualizedList/VirtualizedList.d.ts +0 -1
- package/dist/ui.cjs.development.js +75 -85
- package/dist/ui.cjs.development.js.map +1 -1
- package/dist/ui.cjs.production.min.js +1 -1
- package/dist/ui.cjs.production.min.js.map +1 -1
- package/dist/ui.esm.js +76 -86
- package/dist/ui.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/TokenList/TokenItem.tsx +70 -0
- package/src/components/TokenList/TokenList.tsx +14 -108
- package/src/components/TokenSelector/TokenSelector.tsx +10 -1
- package/src/components/VirtualizedList/VirtualizedList.tsx +19 -35
package/package.json
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Token } from 'rango-sdk';
|
|
2
|
+
import React, { CSSProperties } from 'react';
|
|
3
|
+
import { styled } from '../../theme';
|
|
4
|
+
import { Button } from '../Button';
|
|
5
|
+
import { Typography } from '../Typography';
|
|
6
|
+
import { TokenWithAmount } from './TokenList';
|
|
7
|
+
|
|
8
|
+
const TokenImage = styled('img', {
|
|
9
|
+
width: '$32',
|
|
10
|
+
maxHeight: '$32',
|
|
11
|
+
marginRight: '$16',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const TokenNameContainer = styled('div', {
|
|
15
|
+
display: 'flex',
|
|
16
|
+
flexDirection: 'column',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const TokenAmountContainer = styled('div', {
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexDirection: 'column',
|
|
22
|
+
alignItems: 'flex-end',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
interface PropTypes {
|
|
26
|
+
token: TokenWithAmount;
|
|
27
|
+
selected: boolean;
|
|
28
|
+
onClick: (token: Token) => void;
|
|
29
|
+
style?: CSSProperties;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function TokenItem(props: PropTypes) {
|
|
33
|
+
const { token, style, onClick, selected } = props;
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
style={{
|
|
37
|
+
display: 'flex',
|
|
38
|
+
alignItems: 'center',
|
|
39
|
+
width: '100%',
|
|
40
|
+
...style,
|
|
41
|
+
height: '48px',
|
|
42
|
+
top: `${parseFloat(style?.top as string) + 0}px`,
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
<Button
|
|
46
|
+
variant="outlined"
|
|
47
|
+
size="large"
|
|
48
|
+
align="start"
|
|
49
|
+
onClick={onClick.bind(null, token)}
|
|
50
|
+
type={selected ? 'primary' : undefined}
|
|
51
|
+
prefix={<TokenImage src={token.image} />}
|
|
52
|
+
suffix={
|
|
53
|
+
token.balance?.amount && (
|
|
54
|
+
<TokenAmountContainer>
|
|
55
|
+
<Typography variant="body2">{token.balance.amount}</Typography>
|
|
56
|
+
<Typography variant="caption">
|
|
57
|
+
{`${token.balance.usdValue}$`}
|
|
58
|
+
</Typography>
|
|
59
|
+
</TokenAmountContainer>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
>
|
|
63
|
+
<TokenNameContainer>
|
|
64
|
+
<Typography variant="body1">{token.symbol}</Typography>
|
|
65
|
+
<Typography variant="body2">{token.name}</Typography>
|
|
66
|
+
</TokenNameContainer>
|
|
67
|
+
</Button>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import React, { forwardRef, useEffect, useState } from 'react';
|
|
2
2
|
import { CommonProps } from 'react-window';
|
|
3
|
-
import { styled } from '../../theme';
|
|
4
3
|
import { Token } from 'rango-sdk';
|
|
5
|
-
import { Button } from '../Button/Button';
|
|
6
|
-
import { Typography } from '../Typography';
|
|
7
4
|
import { VirtualizedList } from '../VirtualizedList/VirtualizedList';
|
|
8
|
-
import {
|
|
9
|
-
import { containsText } from '../../helper';
|
|
5
|
+
import { TokenItem } from './TokenItem';
|
|
10
6
|
|
|
11
7
|
export interface TokenWithAmount extends Token {
|
|
12
8
|
balance?: {
|
|
@@ -25,40 +21,6 @@ export interface PropTypes {
|
|
|
25
21
|
selectedList?: TokenWithAmount[] | 'all';
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
const TokenImage = styled('img', {
|
|
29
|
-
width: '$32',
|
|
30
|
-
maxHeight: '$32',
|
|
31
|
-
marginRight: '$16',
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const TokenNameContainer = styled('div', {
|
|
35
|
-
display: 'flex',
|
|
36
|
-
flexDirection: 'column',
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const TokenAmountContainer = styled('div', {
|
|
40
|
-
display: 'flex',
|
|
41
|
-
flexDirection: 'column',
|
|
42
|
-
alignItems: 'flex-end',
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const filterTokens = (
|
|
46
|
-
list: Token[],
|
|
47
|
-
searchedText: string,
|
|
48
|
-
outputCount?: number
|
|
49
|
-
) => {
|
|
50
|
-
if (searchedText)
|
|
51
|
-
return list
|
|
52
|
-
.filter(
|
|
53
|
-
(token) =>
|
|
54
|
-
containsText(token.symbol, searchedText) ||
|
|
55
|
-
containsText(token.address || '', searchedText) ||
|
|
56
|
-
containsText(token.name || '', searchedText)
|
|
57
|
-
)
|
|
58
|
-
.slice(0, outputCount);
|
|
59
|
-
else return list.slice(0, outputCount);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
24
|
export function TokenList(props: PropTypes) {
|
|
63
25
|
const { list, searchedText, onChange, multiSelect, selectedList } = props;
|
|
64
26
|
|
|
@@ -69,7 +31,7 @@ export function TokenList(props: PropTypes) {
|
|
|
69
31
|
onChange(token);
|
|
70
32
|
};
|
|
71
33
|
|
|
72
|
-
const
|
|
34
|
+
const isSelected = (token: Token) => {
|
|
73
35
|
if (multiSelect && selectedList) {
|
|
74
36
|
return (
|
|
75
37
|
selectedList === 'all' ||
|
|
@@ -83,79 +45,20 @@ export function TokenList(props: PropTypes) {
|
|
|
83
45
|
);
|
|
84
46
|
};
|
|
85
47
|
|
|
86
|
-
const Token = ({
|
|
87
|
-
filteredTokens,
|
|
88
|
-
index,
|
|
89
|
-
style,
|
|
90
|
-
}: {
|
|
91
|
-
filteredTokens: TokenWithAmount[];
|
|
92
|
-
index: number;
|
|
93
|
-
style: CSSProperties | undefined;
|
|
94
|
-
}) => {
|
|
95
|
-
const currentToken = filteredTokens[index];
|
|
96
|
-
return (
|
|
97
|
-
<div
|
|
98
|
-
style={{
|
|
99
|
-
display: 'flex',
|
|
100
|
-
alignItems: 'center',
|
|
101
|
-
width: '100%',
|
|
102
|
-
...style,
|
|
103
|
-
height: '48px',
|
|
104
|
-
top: `${parseFloat(style?.top as string) + 0}px`,
|
|
105
|
-
}}
|
|
106
|
-
>
|
|
107
|
-
<Button
|
|
108
|
-
variant="outlined"
|
|
109
|
-
size="large"
|
|
110
|
-
align="start"
|
|
111
|
-
onClick={changeSelected.bind(null, currentToken)}
|
|
112
|
-
type={isSelect(currentToken) ? 'primary' : undefined}
|
|
113
|
-
prefix={<TokenImage src={currentToken.image} />}
|
|
114
|
-
suffix={
|
|
115
|
-
currentToken.balance?.amount && (
|
|
116
|
-
<TokenAmountContainer>
|
|
117
|
-
<Typography variant="body2">
|
|
118
|
-
{currentToken.balance.amount}
|
|
119
|
-
</Typography>
|
|
120
|
-
<Typography variant="caption">
|
|
121
|
-
{`${currentToken.balance.usdValue}$`}
|
|
122
|
-
</Typography>
|
|
123
|
-
</TokenAmountContainer>
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
>
|
|
127
|
-
<TokenNameContainer>
|
|
128
|
-
<Typography variant="body1">{currentToken.symbol}</Typography>
|
|
129
|
-
<Typography variant="body2">{currentToken.name}</Typography>
|
|
130
|
-
</TokenNameContainer>
|
|
131
|
-
</Button>
|
|
132
|
-
</div>
|
|
133
|
-
);
|
|
134
|
-
};
|
|
135
|
-
|
|
136
48
|
const [hasNextPage, setHasNextPage] = useState<boolean>(true);
|
|
137
|
-
const [
|
|
138
|
-
const [filteredTokens, setFilteredTokens] = useState<TokenWithAmount[]>(list);
|
|
49
|
+
const [tokens, setTokens] = useState<TokenWithAmount[]>(list);
|
|
139
50
|
|
|
140
51
|
const loadNextPage = () => {
|
|
141
|
-
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
setIsNextPageLoading(false);
|
|
144
|
-
setFilteredTokens(
|
|
145
|
-
filterTokens(list, searchedText, filteredTokens.length + PAGE_SIZE)
|
|
146
|
-
);
|
|
147
|
-
}, 0);
|
|
52
|
+
setTokens(list.slice(0, tokens.length + PAGE_SIZE));
|
|
148
53
|
};
|
|
149
54
|
|
|
150
55
|
useEffect(() => {
|
|
151
|
-
|
|
56
|
+
setTokens(list.slice(0, PAGE_SIZE));
|
|
152
57
|
}, [searchedText]);
|
|
153
58
|
|
|
154
59
|
useEffect(() => {
|
|
155
|
-
setHasNextPage(
|
|
156
|
-
|
|
157
|
-
);
|
|
158
|
-
}, [filteredTokens.length]);
|
|
60
|
+
setHasNextPage(list.length > tokens.length);
|
|
61
|
+
}, [tokens.length]);
|
|
159
62
|
|
|
160
63
|
const innerElementType: React.FC<CommonProps> = forwardRef(
|
|
161
64
|
({ style, ...rest }, ref) => {
|
|
@@ -165,7 +68,6 @@ export function TokenList(props: PropTypes) {
|
|
|
165
68
|
ref={ref as any}
|
|
166
69
|
style={{
|
|
167
70
|
...style,
|
|
168
|
-
// eslint-disable-next-line react/prop-types
|
|
169
71
|
height: `${parseFloat(style?.height as string) + 8 * 2}px`,
|
|
170
72
|
}}
|
|
171
73
|
{...rest}
|
|
@@ -178,11 +80,15 @@ export function TokenList(props: PropTypes) {
|
|
|
178
80
|
<div style={{ height: '450px' }}>
|
|
179
81
|
<VirtualizedList
|
|
180
82
|
Item={({ index, style }) => (
|
|
181
|
-
<
|
|
83
|
+
<TokenItem
|
|
84
|
+
token={tokens[index]}
|
|
85
|
+
style={style}
|
|
86
|
+
onClick={changeSelected}
|
|
87
|
+
selected={isSelected(tokens[index])}
|
|
88
|
+
/>
|
|
182
89
|
)}
|
|
183
90
|
hasNextPage={hasNextPage}
|
|
184
|
-
|
|
185
|
-
itemCount={filteredTokens.length}
|
|
91
|
+
itemCount={tokens.length}
|
|
186
92
|
loadNextPage={loadNextPage}
|
|
187
93
|
innerElementType={innerElementType}
|
|
188
94
|
size={56}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { containsText } from '../../helper';
|
|
2
3
|
import { SecondaryPage } from '../SecondaryPage/SecondaryPage';
|
|
3
4
|
import { TokenList } from '../TokenList';
|
|
4
5
|
import { TokenWithAmount } from '../TokenList/TokenList';
|
|
@@ -14,6 +15,14 @@ export interface PropTypes {
|
|
|
14
15
|
selectedList?: TokenWithAmount[] | 'all';
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
const filterTokens = (list: TokenWithAmount[], searchedFor: string) =>
|
|
19
|
+
list.filter(
|
|
20
|
+
(token) =>
|
|
21
|
+
containsText(token.symbol, searchedFor) ||
|
|
22
|
+
containsText(token.address || '', searchedFor) ||
|
|
23
|
+
containsText(token.name || '', searchedFor)
|
|
24
|
+
);
|
|
25
|
+
|
|
17
26
|
export function TokenSelector(props: PropTypes) {
|
|
18
27
|
const {
|
|
19
28
|
list,
|
|
@@ -37,7 +46,7 @@ export function TokenSelector(props: PropTypes) {
|
|
|
37
46
|
{(searchedFor) => (
|
|
38
47
|
<TokenList
|
|
39
48
|
searchedText={searchedFor}
|
|
40
|
-
list={list}
|
|
49
|
+
list={filterTokens(list, searchedFor)}
|
|
41
50
|
selected={selected}
|
|
42
51
|
selectedList={selectedList}
|
|
43
52
|
multiSelect={multiSelect}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { PropsWithChildren
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
2
|
import { ReactElementType, VariableSizeList as List } from 'react-window';
|
|
3
3
|
import InfiniteLoader from 'react-window-infinite-loader';
|
|
4
4
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
|
@@ -15,8 +15,6 @@ export type VirtualizedListItem = ({
|
|
|
15
15
|
type PropTypes = {
|
|
16
16
|
itemCount: number;
|
|
17
17
|
hasNextPage: boolean;
|
|
18
|
-
isNextPageLoading: boolean;
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
18
|
loadNextPage: () => void;
|
|
21
19
|
Item: VirtualizedListItem;
|
|
22
20
|
innerElementType: ReactElementType | undefined;
|
|
@@ -24,39 +22,25 @@ type PropTypes = {
|
|
|
24
22
|
};
|
|
25
23
|
|
|
26
24
|
export function VirtualizedList(props: PropsWithChildren<PropTypes>) {
|
|
27
|
-
const {
|
|
28
|
-
|
|
29
|
-
hasNextPage,
|
|
30
|
-
isNextPageLoading,
|
|
31
|
-
loadNextPage,
|
|
32
|
-
Item,
|
|
33
|
-
innerElementType,
|
|
34
|
-
size,
|
|
35
|
-
} = props;
|
|
36
|
-
const listRef = useRef<any>(null);
|
|
25
|
+
const { itemCount, hasNextPage, loadNextPage, Item, innerElementType, size } =
|
|
26
|
+
props;
|
|
37
27
|
|
|
38
28
|
const isItemLoaded = (index: number) => !hasNextPage || index < itemCount;
|
|
39
29
|
|
|
40
30
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
threshold={1}
|
|
52
|
-
>
|
|
53
|
-
{({ onItemsRendered }) => {
|
|
54
|
-
return (
|
|
55
|
-
<AutoSizer>
|
|
56
|
-
{({ width, height }) => (
|
|
31
|
+
<AutoSizer>
|
|
32
|
+
{({ width, height }) => (
|
|
33
|
+
<InfiniteLoader
|
|
34
|
+
isItemLoaded={isItemLoaded}
|
|
35
|
+
itemCount={hasNextPage ? itemCount + 1 : itemCount}
|
|
36
|
+
loadMoreItems={loadNextPage}
|
|
37
|
+
threshold={1}
|
|
38
|
+
>
|
|
39
|
+
{({ onItemsRendered, ref }) => {
|
|
40
|
+
return (
|
|
57
41
|
<List
|
|
58
42
|
innerElementType={innerElementType}
|
|
59
|
-
ref={
|
|
43
|
+
ref={ref}
|
|
60
44
|
itemSize={() => size}
|
|
61
45
|
itemCount={itemCount}
|
|
62
46
|
height={height}
|
|
@@ -69,10 +53,10 @@ export function VirtualizedList(props: PropsWithChildren<PropTypes>) {
|
|
|
69
53
|
) : null
|
|
70
54
|
}
|
|
71
55
|
</List>
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
</
|
|
56
|
+
);
|
|
57
|
+
}}
|
|
58
|
+
</InfiniteLoader>
|
|
59
|
+
)}
|
|
60
|
+
</AutoSizer>
|
|
77
61
|
);
|
|
78
62
|
}
|