@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
import { useRef } from 'react' ;
3
3
import classNames from 'classnames' ;
4
4
import Filler from './Filler' ;
5
+ import ScrollBar from './ScrollBar' ;
5
6
import { RenderFunc , SharedConfig , GetKey } from './interface' ;
6
7
import useChildren from './hooks/useChildren' ;
7
8
import useHeights from './hooks/useHeights' ;
@@ -12,7 +13,7 @@ import useFrameWheel from './hooks/useFrameWheel';
12
13
13
14
const EMPTY_DATA = [ ] ;
14
15
15
- const ScrollStyle = {
16
+ const ScrollStyle : React . CSSProperties = {
16
17
overflowY : 'auto' ,
17
18
overflowAnchor : 'none' ,
18
19
} ;
@@ -50,7 +51,7 @@ export interface ListProps<T> extends React.HTMLAttributes<any> {
50
51
51
52
export function RawList < T > ( props : ListProps < T > , ref : React . Ref < ListRef > ) {
52
53
const {
53
- prefixCls,
54
+ prefixCls = 'rc-virtual-list' ,
54
55
className,
55
56
height,
56
57
itemHeight,
@@ -89,6 +90,21 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
89
90
getKey,
90
91
} ;
91
92
93
+ // ================================ Scroll ================================
94
+ function syncScrollTop ( newTop : number | ( ( prev : number ) => number ) ) {
95
+ setScrollTop ( origin => {
96
+ let value : number ;
97
+ if ( typeof newTop === 'function' ) {
98
+ value = newTop ( origin ) ;
99
+ } else {
100
+ value = newTop ;
101
+ }
102
+
103
+ componentRef . current . scrollTop = value ;
104
+ return value ;
105
+ } ) ;
106
+ }
107
+
92
108
// ================================ Legacy ================================
93
109
// Put ref here since the range is generate by follow
94
110
const rangeRef = useRef ( { start : 0 , end : mergedData . length } ) ;
@@ -142,7 +158,8 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
142
158
itemTop = currentItemBottom ;
143
159
}
144
160
145
- // Fallback to normal if not match
161
+ // Fallback to normal if not match. This code should never reach
162
+ /* istanbul ignore next */
146
163
if ( startIndex === undefined ) {
147
164
startIndex = 0 ;
148
165
startOffset = 0 ;
@@ -171,20 +188,25 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
171
188
// ================================ Scroll ================================
172
189
// Since this added in global,should use ref to keep update
173
190
const onRawWheel = useFrameWheel ( inVirtual , offsetY => {
174
- setScrollTop ( top => {
191
+ syncScrollTop ( top => {
175
192
const newTop = keepInRange ( top + offsetY ) ;
176
-
177
- componentRef . current . scrollTop = newTop ;
178
193
return newTop ;
179
194
} ) ;
180
195
} ) ;
181
196
182
- // Additional handle the scroll which not trigger by wheel
183
- function onRawScroll ( event : React . UIEvent ) {
184
- const newScrollTop = ( event . target as HTMLDivElement ) . scrollTop ;
197
+ function onScrollBar ( newScrollTop : number ) {
185
198
const newTop = keepInRange ( newScrollTop ) ;
186
199
if ( newTop !== scrollTop ) {
187
- setScrollTop ( newTop ) ;
200
+ syncScrollTop ( newTop ) ;
201
+ }
202
+ }
203
+
204
+ // This code may only trigger in test case.
205
+ // But we still need a sync if some special escape
206
+ function onFallbackScroll ( e : React . UIEvent ) {
207
+ const { scrollTop : newScrollTop } = e . currentTarget ;
208
+ if ( newScrollTop !== scrollTop ) {
209
+ syncScrollTop ( newScrollTop ) ;
188
210
}
189
211
}
190
212
@@ -203,6 +225,7 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
203
225
itemHeight ,
204
226
getKey ,
205
227
collectHeight ,
228
+ syncScrollTop ,
206
229
) ;
207
230
208
231
React . useImperativeHandle ( ref , ( ) => ( {
@@ -212,25 +235,46 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
212
235
// ================================ Render ================================
213
236
const listChildren = useChildren ( mergedData , start , end , setInstanceRef , children , sharedConfig ) ;
214
237
238
+ let componentStyle : React . CSSProperties = null ;
239
+ if ( height ) {
240
+ componentStyle = { [ fullHeight ? 'height' : 'maxHeight' ] : height , ...ScrollStyle } ;
241
+ componentStyle . overflowY = 'hidden' ;
242
+ }
243
+
215
244
return (
216
- < Component
217
- style = {
218
- height ? { ...style , [ fullHeight ? 'height' : 'maxHeight' ] : height , ...ScrollStyle } : style
219
- }
245
+ < div
246
+ style = { {
247
+ ...style ,
248
+ position : 'relative' ,
249
+ } }
220
250
className = { mergedClassName }
221
251
{ ...restProps }
222
- ref = { componentRef }
223
- onScroll = { onRawScroll }
224
252
>
225
- < Filler
226
- prefixCls = { prefixCls }
227
- height = { scrollHeight }
228
- offset = { offset }
229
- onInnerResize = { collectHeight }
253
+ < Component
254
+ className = { ` ${ prefixCls } -holder` }
255
+ style = { componentStyle }
256
+ ref = { componentRef }
257
+ onScroll = { onFallbackScroll }
230
258
>
231
- { listChildren }
232
- </ Filler >
233
- </ Component >
259
+ < Filler
260
+ prefixCls = { prefixCls }
261
+ height = { scrollHeight }
262
+ offset = { offset }
263
+ onInnerResize = { collectHeight }
264
+ >
265
+ { listChildren }
266
+ </ Filler >
267
+ </ Component >
268
+
269
+ < ScrollBar
270
+ prefixCls = { prefixCls }
271
+ scrollTop = { scrollTop }
272
+ height = { height }
273
+ scrollHeight = { scrollHeight }
274
+ count = { mergedData . length }
275
+ onScroll = { onScrollBar }
276
+ />
277
+ </ div >
234
278
) ;
235
279
}
236
280
0 commit comments