Skip to content

Commit 63c7359

Browse files
author
Rayan Arnaout
committed
Added animation to scrollToItem, changed grid call to match list call parameters
1 parent 9d097fb commit 63c7359

File tree

3 files changed

+80
-34
lines changed

3 files changed

+80
-34
lines changed

src/createGridComponent.js

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { cancelTimeout, requestTimeout } from './timer';
66
import { getScrollbarSize, getRTLOffsetType } from './domHelpers';
77

88
import type { TimeoutID } from './timer';
9+
import { animatedScrollTo } from './scrollTo';
910

1011
type Direction = 'ltr' | 'rtl';
1112
export type ScrollToAlign = 'auto' | 'smart' | 'center' | 'start' | 'end';
@@ -215,6 +216,7 @@ export default function createGridComponent({
215216
? this.props.initialScrollTop
216217
: 0,
217218
scrollUpdateWasRequested: false,
219+
scrollAnimated: false,
218220
verticalScrollDirection: 'forward',
219221
};
220222

@@ -237,6 +239,7 @@ export default function createGridComponent({
237239
scrollTo({
238240
scrollLeft,
239241
scrollTop,
242+
animated
240243
}: {
241244
scrollLeft: number,
242245
scrollTop: number,
@@ -268,33 +271,21 @@ export default function createGridComponent({
268271
prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
269272
scrollLeft: scrollLeft,
270273
scrollTop: scrollTop,
274+
scrollAnimated: animated,
271275
scrollUpdateWasRequested: true,
272276
verticalScrollDirection:
273277
prevState.scrollTop < scrollTop ? 'forward' : 'backward',
274278
};
275279
}, this._resetIsScrollingDebounced);
276280
}
277281

278-
scrollToItem({
279-
align = 'auto',
280-
columnIndex,
281-
rowIndex,
282-
}: {
283-
align: ScrollToAlign,
284-
columnIndex?: number,
285-
rowIndex?: number,
286-
}): void {
282+
scrollToItem(index: number, align: ScrollToAlign = 'auto', animated: boolean = false): void {
287283
const { columnCount, height, rowCount, width } = this.props;
288284
const { scrollLeft, scrollTop } = this.state;
289285
const scrollbarSize = getScrollbarSize();
290286

291-
if (columnIndex !== undefined) {
292-
columnIndex = Math.max(0, Math.min(columnIndex, columnCount - 1));
293-
}
294-
if (rowIndex !== undefined) {
295-
rowIndex = Math.max(0, Math.min(rowIndex, rowCount - 1));
296-
}
297-
287+
const rowIndex = parseInt(index / columnCount);
288+
298289
const estimatedTotalHeight = getEstimatedTotalHeight(
299290
this.props,
300291
this._instanceProps
@@ -313,17 +304,6 @@ export default function createGridComponent({
313304
estimatedTotalHeight > height ? scrollbarSize : 0;
314305

315306
this.scrollTo({
316-
scrollLeft:
317-
columnIndex !== undefined
318-
? getOffsetForColumnAndAlignment(
319-
this.props,
320-
columnIndex,
321-
align,
322-
scrollLeft,
323-
this._instanceProps,
324-
verticalScrollbarSize
325-
)
326-
: scrollLeft,
327307
scrollTop:
328308
rowIndex !== undefined
329309
? getOffsetForRowAndAlignment(
@@ -335,6 +315,7 @@ export default function createGridComponent({
335315
horizontalScrollbarSize
336316
)
337317
: scrollTop,
318+
animated: animated,
338319
});
339320
}
340321

@@ -356,7 +337,7 @@ export default function createGridComponent({
356337

357338
componentDidUpdate() {
358339
const { direction } = this.props;
359-
const { scrollLeft, scrollTop, scrollUpdateWasRequested } = this.state;
340+
const { scrollLeft, scrollTop, scrollUpdateWasRequested, scrollAnimated } = this.state;
360341

361342
if (scrollUpdateWasRequested && this._outerRef != null) {
362343
// TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
@@ -380,7 +361,8 @@ export default function createGridComponent({
380361
outerRef.scrollLeft = Math.max(0, scrollLeft);
381362
}
382363

383-
outerRef.scrollTop = Math.max(0, scrollTop);
364+
if (scrollAnimated) animatedScrollTo(outerRef, scrollTop, undefined, 200)
365+
else outerRef.scrollTop = Math.max(0, scrollTop);
384366
}
385367

386368
this._callPropsCallbacks();

src/createListComponent.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { cancelTimeout, requestTimeout } from './timer';
66
import { getScrollbarSize, getRTLOffsetType } from './domHelpers';
77

88
import type { TimeoutID } from './timer';
9+
import { animatedScrollTo } from './scrollTo';
910

1011
export type ScrollToAlign = 'auto' | 'smart' | 'center' | 'start' | 'end';
1112

@@ -177,6 +178,7 @@ export default function createListComponent({
177178
typeof this.props.initialScrollOffset === 'number'
178179
? this.props.initialScrollOffset
179180
: 0,
181+
scrollAnimated: false,
180182
scrollUpdateWasRequested: false,
181183
};
182184

@@ -196,7 +198,7 @@ export default function createListComponent({
196198
return null;
197199
}
198200

199-
scrollTo(scrollOffset: number): void {
201+
scrollTo(scrollOffset: number, animated: boolean = false): void {
200202
scrollOffset = Math.max(0, scrollOffset);
201203

202204
this.setState(prevState => {
@@ -208,11 +210,12 @@ export default function createListComponent({
208210
prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
209211
scrollOffset: scrollOffset,
210212
scrollUpdateWasRequested: true,
213+
scrollAnimated: animated,
211214
};
212215
}, this._resetIsScrollingDebounced);
213216
}
214217

215-
scrollToItem(index: number, align: ScrollToAlign = 'auto'): void {
218+
scrollToItem(index: number, align: ScrollToAlign = 'auto', animated: boolean = false): void {
216219
const { itemCount, layout } = this.props;
217220
const { scrollOffset } = this.state;
218221

@@ -245,7 +248,8 @@ export default function createListComponent({
245248
scrollOffset,
246249
this._instanceProps,
247250
scrollbarSize
248-
)
251+
),
252+
animated
249253
);
250254
}
251255

@@ -267,7 +271,7 @@ export default function createListComponent({
267271

268272
componentDidUpdate() {
269273
const { direction, layout } = this.props;
270-
const { scrollOffset, scrollUpdateWasRequested } = this.state;
274+
const { scrollOffset, scrollUpdateWasRequested, scrollAnimated } = this.state;
271275

272276
if (scrollUpdateWasRequested && this._outerRef != null) {
273277
const outerRef = ((this._outerRef: any): HTMLElement);
@@ -294,9 +298,11 @@ export default function createListComponent({
294298
outerRef.scrollLeft = scrollOffset;
295299
}
296300
} else {
297-
outerRef.scrollTop = scrollOffset;
301+
if (scrollAnimated) animatedScrollTo(outerRef, scrollOffset, undefined, 200)
302+
else outerRef.scrollTop = scrollOffset;
298303
}
299304
}
305+
300306

301307
this._callPropsCallbacks();
302308
}

src/scrollTo.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// easing functions http://goo.gl/5HLl8
2+
Math.easeInOutQuad = function (t, b, c, d) {
3+
t /= d/2;
4+
if (t < 1) {
5+
return c/2*t*t + b
6+
}
7+
t--;
8+
return -c/2 * (t*(t-2) - 1) + b;
9+
};
10+
11+
Math.easeInCubic = function(t, b, c, d) {
12+
var tc = (t/=d)*t*t;
13+
return b+c*(tc);
14+
};
15+
16+
Math.inOutQuintic = function(t, b, c, d) {
17+
var ts = (t/=d)*t,
18+
tc = ts*t;
19+
return b+c*(6*tc*ts + -15*ts*ts + 10*tc);
20+
};
21+
22+
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
23+
var requestAnimFrame = (function(){
24+
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); };
25+
})();
26+
27+
export function animatedScrollTo(element, to, callback, duration) {
28+
// because it's so fucking difficult to detect the scrolling element, just move them all
29+
function move(amount) {
30+
element.scrollTop = amount;
31+
}
32+
function position() {
33+
return element.scrollTop;
34+
}
35+
var start = position(),
36+
change = to - start,
37+
currentTime = 0,
38+
increment = 20;
39+
duration = (typeof(duration) === 'undefined') ? 500 : duration;
40+
var animateScroll = function() {
41+
// increment the time
42+
currentTime += increment;
43+
// find the value with the quadratic in-out easing function
44+
var val = Math.easeInOutQuad(currentTime, start, change, duration);
45+
// move the document.body
46+
move(val);
47+
// do the animation unless its over
48+
if (currentTime < duration) {
49+
requestAnimFrame(animateScroll);
50+
} else {
51+
if (callback && typeof(callback) === 'function') {
52+
// the animation is done so lets callback
53+
callback();
54+
}
55+
}
56+
};
57+
animateScroll();
58+
}

0 commit comments

Comments
 (0)