-
Notifications
You must be signed in to change notification settings - Fork 295
/
VirtualAddressesList.tsx
122 lines (112 loc) · 3.23 KB
/
VirtualAddressesList.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// @flow
import React, { Component } from 'react';
import { throttle } from 'lodash';
import { observer } from 'mobx-react';
import { AutoSizer, List } from 'react-virtualized';
import WalletAddress from '../../../domains/WalletAddress';
import styles from './VirtualAddressesList.scss';
type Props = {
rows: Array<WalletAddress>,
renderRow: Function,
};
/**
*
* The breakpoints define the number of lines
* based on the width of the following element:
*
* `.ReactVirtualized__Grid__innerScrollContainer`
*
*/
const BREAKPOINT_1_LINE = 1108;
const BREAKPOINT_2_LINES = 635;
const ADDRESS_LINE_HEIGHT = 22;
const ADDRESS_LINE_PADDING = 21;
const ADDRESS_SELECTOR = '.Address';
@observer
export class VirtualAddressesList extends Component<Props> {
list: List;
listWidth: number = 0;
addressHeight: number = 0;
/**
* Estimate the address height based on number of lines
*/
estimateAddressHeight = (lines: number): number =>
ADDRESS_LINE_HEIGHT * lines + ADDRESS_LINE_PADDING;
/**
* Gets the number of lines based on the container width
*/
getLinesFromWidth = (width: number): number => {
if (width >= BREAKPOINT_1_LINE) return 1;
if (width >= BREAKPOINT_2_LINES) return 2;
return 3;
};
/**
* Virtual row heights only once per tick (debounced)
*/
updateRowHeights = () => {
const { list, addressHeight } = this;
if (!list) return;
const firstAddress = document.querySelector(ADDRESS_SELECTOR);
if (firstAddress instanceof HTMLElement) {
this.addressHeight = firstAddress.offsetHeight;
} else {
this.addressHeight = this.estimateAddressHeight(
this.getLinesFromWidth(this.listWidth)
);
// Since we could only estimate the address heights, re-try
// the update and hope that DOM is rendered then (for exact measurements)
setTimeout(this.updateRowHeights, 100);
}
if (addressHeight !== this.addressHeight) {
list.recomputeRowHeights(0);
}
};
/**
* Update row height and recompute virtual rows.
*/
onResize = ({ width }: { width: number }): void => {
this.listWidth = width;
this.updateRowHeights();
};
rowRenderer = ({
index, // Index of row
key, // Unique key within array of rendered rows
style, // Style object to be applied to row (to position it);
}: {
index: number,
key: string,
style: string,
}) => {
const { rows, renderRow } = this.props;
const address = rows[index];
return (
<div key={key} style={style} className={styles.address}>
{renderRow(address, index)}
</div>
);
};
render() {
const { rows } = this.props;
if (!rows.length) return null;
return (
<div className={styles.component}>
<AutoSizer onResize={throttle(this.onResize, 100)}>
{({ width, height }) => (
<List
className={styles.list}
ref={(list) => {
this.list = list;
}}
width={width}
height={height}
rowCount={rows.length}
rowHeight={() => this.addressHeight}
rowRenderer={this.rowRenderer}
style={{ overflowY: 'scroll' }}
/>
)}
</AutoSizer>
</div>
);
}
}