@@ -10,6 +10,7 @@ import { GlobalEvents, GLOBAL_EVENTS, Slow } from '../util';
10
10
11
11
export interface ScrollAreaProps extends StyleProps , ThemeProps {
12
12
children : React . ReactNode ;
13
+ autoscroll ?: boolean ;
13
14
}
14
15
15
16
export namespace Action {
@@ -110,14 +111,17 @@ class ScrollArea extends React.PureComponent<Props, State> {
110
111
switch ( element ) {
111
112
case this . outerRef_ : {
112
113
if ( Vector2 . eq ( this . state . outerSize , size ) ) break ;
114
+
115
+ this . updateTopOnResize ( this . state . innerSize , size ) ;
113
116
this . setState ( {
114
117
outerSize : size
115
118
} ) ;
116
119
break ;
117
120
}
118
121
case this . innerRef_ : {
119
122
if ( Vector2 . eq ( this . state . innerSize , size ) ) break ;
120
-
123
+
124
+ this . updateTopOnResize ( size , this . state . outerSize ) ;
121
125
this . setState ( {
122
126
innerSize : size
123
127
} ) ;
@@ -126,6 +130,22 @@ class ScrollArea extends React.PureComponent<Props, State> {
126
130
}
127
131
} ;
128
132
133
+ private updateTopOnResize = ( newInnerSize : Vector2 , newOuterSize : Vector2 ) => {
134
+ const { action } = this . state ;
135
+
136
+ // Reset top to the bottom if...
137
+ // a) autoscroll is enabled and currently at the bottom, or
138
+ // b) top is no longer within the new scroll range
139
+ if ( ( this . props . autoscroll && action . type === Action . Type . None && action . top >= this . maxTop ) || Action . top ( action ) > newInnerSize . y - newOuterSize . y ) {
140
+ this . setState ( {
141
+ action : {
142
+ ...action ,
143
+ top : Math . max ( newInnerSize . y - newOuterSize . y , 0 ) ,
144
+ }
145
+ } ) ;
146
+ }
147
+ } ;
148
+
129
149
componentWillUnmount ( ) {
130
150
this . listener_ . disconnect ( ) ;
131
151
}
@@ -170,10 +190,11 @@ class ScrollArea extends React.PureComponent<Props, State> {
170
190
const current = Vector2 . fromClient ( event ) ;
171
191
172
192
let top = 0 ;
173
- if ( innerSize . y > outerSize . y ) {
193
+ const maxTop = this . maxTop ;
194
+ if ( maxTop > 0 ) {
174
195
const diff = Vector2 . subtract ( action . startOffset , current ) ;
175
196
const topDiff = diff . y * ( outerSize . y > 0 ? ( innerSize . y / outerSize . y ) : 1 ) ;
176
- top = clamp ( 0 , action . startTop - topDiff , innerSize . y - outerSize . y ) ;
197
+ top = clamp ( 0 , action . startTop - topDiff , maxTop ) ;
177
198
}
178
199
179
200
this . setState ( {
@@ -202,10 +223,11 @@ class ScrollArea extends React.PureComponent<Props, State> {
202
223
203
224
private onWheel_ = ( event : React . WheelEvent < HTMLDivElement > ) => {
204
225
const { state } = this ;
205
- const { outerSize , innerSize , action } = state ;
226
+ const { action } = state ;
206
227
if ( action . type !== Action . Type . None ) return ;
207
228
208
- const top = innerSize . y > outerSize . y ? clamp ( 0 , action . top + event . deltaY , innerSize . y - outerSize . y ) : 0 ;
229
+ const maxTop = this . maxTop ;
230
+ const top = clamp ( 0 , action . top + event . deltaY , maxTop ) ;
209
231
210
232
this . setState ( {
211
233
action : {
@@ -240,6 +262,10 @@ class ScrollArea extends React.PureComponent<Props, State> {
240
262
return ( innerSize . y > 0 ? outerSize . y / innerSize . y : 1 ) * outerSize . y ;
241
263
}
242
264
265
+ private get maxTop ( ) {
266
+ return Math . max ( this . state . innerSize . y - this . state . outerSize . y , 0 ) ;
267
+ }
268
+
243
269
private slow_ = new Slow ( ) ;
244
270
245
271
render ( ) {
@@ -287,4 +313,4 @@ class ScrollArea extends React.PureComponent<Props, State> {
287
313
}
288
314
}
289
315
290
- export default ScrollArea ;
316
+ export default ScrollArea ;
0 commit comments