|
1 |
| -import 'react-virtualized/styles.css'; |
2 | 1 | import * as React from '@theia/core/shared/react';
|
3 |
| -import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer'; |
4 |
| -import { |
5 |
| - CellMeasurer, |
6 |
| - CellMeasurerCache, |
7 |
| -} from 'react-virtualized/dist/commonjs/CellMeasurer'; |
8 |
| -import type { |
9 |
| - ListRowProps, |
10 |
| - ListRowRenderer, |
11 |
| -} from 'react-virtualized/dist/commonjs/List'; |
12 |
| -import List from 'react-virtualized/dist/commonjs/List'; |
| 2 | +import { Virtuoso } from '@theia/core/shared/react-virtuoso'; |
13 | 3 | import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
14 | 4 | import { Installable } from '../../../common/protocol/installable';
|
15 | 5 | import { ComponentListItem } from './component-list-item';
|
16 | 6 | import { ListItemRenderer } from './list-item-renderer';
|
17 | 7 |
|
18 |
| -function sameAs<T>( |
19 |
| - left: T[], |
20 |
| - right: T[], |
21 |
| - ...compareProps: (keyof T)[] |
22 |
| -): boolean { |
23 |
| - if (left === right) { |
24 |
| - return true; |
25 |
| - } |
26 |
| - const leftLength = left.length; |
27 |
| - if (leftLength !== right.length) { |
28 |
| - return false; |
29 |
| - } |
30 |
| - for (let i = 0; i < leftLength; i++) { |
31 |
| - for (const prop of compareProps) { |
32 |
| - const leftValue = left[i][prop]; |
33 |
| - const rightValue = right[i][prop]; |
34 |
| - if (leftValue !== rightValue) { |
35 |
| - return false; |
36 |
| - } |
37 |
| - } |
38 |
| - } |
39 |
| - return true; |
40 |
| -} |
41 |
| - |
42 | 8 | export class ComponentList<T extends ArduinoComponent> extends React.Component<
|
43 | 9 | ComponentList.Props<T>
|
44 | 10 | > {
|
45 |
| - private readonly cache: CellMeasurerCache; |
46 |
| - private resizeAllFlag: boolean; |
47 |
| - private list: List | undefined; |
48 |
| - private mostRecentWidth: number | undefined; |
49 |
| - |
50 |
| - constructor(props: ComponentList.Props<T>) { |
51 |
| - super(props); |
52 |
| - this.cache = new CellMeasurerCache({ |
53 |
| - defaultHeight: 140, |
54 |
| - fixedWidth: true, |
55 |
| - }); |
56 |
| - } |
57 |
| - |
58 | 11 | override render(): React.ReactNode {
|
59 | 12 | return (
|
60 |
| - <AutoSizer> |
61 |
| - {({ width, height }) => { |
62 |
| - if (this.mostRecentWidth && this.mostRecentWidth !== width) { |
63 |
| - this.resizeAllFlag = true; |
64 |
| - setTimeout(() => this.clearAll(), 0); |
65 |
| - } |
66 |
| - this.mostRecentWidth = width; |
67 |
| - return ( |
68 |
| - <List |
69 |
| - className={'items-container'} |
70 |
| - rowRenderer={this.createItem} |
71 |
| - height={height} |
72 |
| - width={width} |
73 |
| - rowCount={this.props.items.length} |
74 |
| - rowHeight={this.cache.rowHeight} |
75 |
| - deferredMeasurementCache={this.cache} |
76 |
| - ref={this.setListRef} |
77 |
| - estimatedRowSize={140} |
78 |
| - // If default value, then `react-virtualized` will optimize and list item will not receive a `:hover` event. |
79 |
| - // Hence, install and version `<select>` won't be visible even if the mouse cursor is over the `<div>`. |
80 |
| - // See https://github.com/bvaughn/react-virtualized/blob/005be24a608add0344284053dae7633be86053b2/source/Grid/Grid.js#L38-L42 |
81 |
| - scrollingResetTimeInterval={0} |
82 |
| - /> |
83 |
| - ); |
84 |
| - }} |
85 |
| - </AutoSizer> |
86 |
| - ); |
87 |
| - } |
88 |
| - |
89 |
| - override componentDidUpdate(prevProps: ComponentList.Props<T>): void { |
90 |
| - if ( |
91 |
| - this.resizeAllFlag || |
92 |
| - !sameAs(this.props.items, prevProps.items, 'name', 'installedVersion') |
93 |
| - ) { |
94 |
| - this.clearAll(true); |
95 |
| - } |
96 |
| - } |
97 |
| - |
98 |
| - private readonly setListRef = (ref: List | null): void => { |
99 |
| - this.list = ref || undefined; |
100 |
| - }; |
101 |
| - |
102 |
| - private clearAll(scrollToTop = false): void { |
103 |
| - this.resizeAllFlag = false; |
104 |
| - this.cache.clearAll(); |
105 |
| - if (this.list) { |
106 |
| - this.list.recomputeRowHeights(); |
107 |
| - if (scrollToTop) { |
108 |
| - this.list.scrollToPosition(0); |
109 |
| - } |
110 |
| - } |
111 |
| - } |
112 |
| - |
113 |
| - private readonly createItem: ListRowRenderer = ({ |
114 |
| - index, |
115 |
| - parent, |
116 |
| - key, |
117 |
| - style, |
118 |
| - }: ListRowProps): React.ReactNode => { |
119 |
| - const item = this.props.items[index]; |
120 |
| - return ( |
121 |
| - <CellMeasurer |
122 |
| - cache={this.cache} |
123 |
| - columnIndex={0} |
124 |
| - key={key} |
125 |
| - rowIndex={index} |
126 |
| - parent={parent} |
127 |
| - > |
128 |
| - {({ registerChild }) => ( |
129 |
| - // eslint-disable-next-line @typescript-eslint/ban-ts-comment |
130 |
| - // @ts-ignore |
131 |
| - <div ref={registerChild} style={style}> |
132 |
| - <ComponentListItem<T> |
133 |
| - key={this.props.itemLabel(item)} |
134 |
| - item={item} |
135 |
| - itemRenderer={this.props.itemRenderer} |
136 |
| - install={this.props.install} |
137 |
| - uninstall={this.props.uninstall} |
138 |
| - /> |
139 |
| - </div> |
| 13 | + <Virtuoso |
| 14 | + data={this.props.items} |
| 15 | + itemContent={(_: number, item: T) => ( |
| 16 | + <ComponentListItem<T> |
| 17 | + key={this.props.itemLabel(item)} |
| 18 | + item={item} |
| 19 | + itemRenderer={this.props.itemRenderer} |
| 20 | + install={this.props.install} |
| 21 | + uninstall={this.props.uninstall} |
| 22 | + /> |
140 | 23 | )}
|
141 |
| - </CellMeasurer> |
| 24 | + /> |
142 | 25 | );
|
143 |
| - }; |
| 26 | + } |
144 | 27 | }
|
145 |
| - |
146 | 28 | export namespace ComponentList {
|
147 | 29 | export interface Props<T extends ArduinoComponent> {
|
148 | 30 | readonly items: T[];
|
|
0 commit comments