Skip to content

Commit b9a9947

Browse files
author
Rajat Sancheti
committed
Adds types in index.tsx
1 parent 5e1d3bd commit b9a9947

File tree

2 files changed

+84
-71
lines changed

2 files changed

+84
-71
lines changed

src/index.tsx

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
import React, { Component, ReactNode, CSSProperties } from "react";
2-
import PropTypes from "prop-types";
32
import throttle from "./utils/throttle";
43
import { ThresholdUnits, parseThreshold } from "./utils/threshold";
4+
55
type Fn = () => any;
66
interface Props {
77
next: Fn;
8-
hasMore: ReactNode;
8+
hasMore: boolean;
99
children: ReactNode;
1010
loader: ReactNode;
1111
scrollThreshold: number | string;
1212
endMessage: ReactNode;
1313
style: CSSProperties;
1414
height: number;
1515
scrollableTarget: ReactNode;
16-
hasChildren: ReactNode;
17-
pullDownToRefresh: ReactNode;
16+
hasChildren: boolean;
17+
pullDownToRefresh: boolean;
1818
pullDownToRefreshContent: ReactNode;
1919
releaseToRefreshContent: ReactNode;
2020
pullDownToRefreshThreshold: number;
2121
refreshFunction: Fn;
22-
onScroll: Fn;
22+
onScroll: (e: MouseEvent) => any;
2323
dataLength: number;
24+
initialScrollY: number;
25+
key: string;
26+
className: string;
2427
}
2528

2629
interface State {
@@ -29,7 +32,6 @@ interface State {
2932
}
3033

3134
export default class InfiniteScroll extends Component<Props, State> {
32-
private throttledOnScrollListener: () => void;
3335
constructor(props: Props) {
3436
super(props);
3537

@@ -48,32 +50,43 @@ export default class InfiniteScroll extends Component<Props, State> {
4850
this.getScrollableTarget = this.getScrollableTarget.bind(this);
4951
}
5052

53+
private throttledOnScrollListener: () => void;
54+
private _scrollableNode: HTMLElement | undefined | null;
55+
private el: HTMLElement | undefined | Window & typeof globalThis;
56+
private _infScroll: HTMLDivElement | undefined;
5157
private lastScrollTop = 0;
5258
private actionTriggered = false;
59+
private _pullDown: HTMLDivElement | undefined;
5360

5461
// variables to keep track of pull down behaviour
55-
private startY = 0;
56-
private currentY = 0;
57-
private dragging = false;
62+
private startY: number = 0;
63+
private currentY: number = 0;
64+
private dragging: boolean = false;
5865

5966
// will be populated in componentDidMount
6067
// based on the height of the pull down element
61-
private maxPullDownDistance = 0;
68+
private maxPullDownDistance: number = 0;
69+
6270
componentDidMount() {
6371
this._scrollableNode = this.getScrollableTarget();
6472
this.el = this.props.height
6573
? this._infScroll
6674
: this._scrollableNode || window;
67-
this.el.addEventListener("scroll", this.throttledOnScrollListener);
75+
76+
if (this.el) {
77+
this.el.addEventListener("scroll", this.throttledOnScrollListener);
78+
}
6879

6980
if (
7081
typeof this.props.initialScrollY === "number" &&
82+
this.el &&
83+
this.el instanceof HTMLElement &&
7184
this.el.scrollHeight > this.props.initialScrollY
7285
) {
7386
this.el.scrollTo(0, this.props.initialScrollY);
7487
}
7588

76-
if (this.props.pullDownToRefresh) {
89+
if (this.props.pullDownToRefresh && this.el) {
7790
this.el.addEventListener("touchstart", this.onStart);
7891
this.el.addEventListener("touchmove", this.onMove);
7992
this.el.addEventListener("touchend", this.onEnd);
@@ -83,7 +96,12 @@ export default class InfiniteScroll extends Component<Props, State> {
8396
this.el.addEventListener("mouseup", this.onEnd);
8497

8598
// get BCR of pullDown element to position it above
86-
this.maxPullDownDistance = this._pullDown.firstChild.getBoundingClientRect().height;
99+
this.maxPullDownDistance =
100+
(this._pullDown &&
101+
this._pullDown.firstChild &&
102+
(this._pullDown.firstChild as HTMLDivElement).getBoundingClientRect()
103+
.height) ||
104+
0;
87105
this.forceUpdate();
88106

89107
if (typeof this.props.refreshFunction !== "function") {
@@ -97,20 +115,22 @@ export default class InfiniteScroll extends Component<Props, State> {
97115
}
98116

99117
componentWillUnmount() {
100-
this.el.removeEventListener("scroll", this.throttledOnScrollListener);
118+
if (this.el) {
119+
this.el.removeEventListener("scroll", this.throttledOnScrollListener);
101120

102-
if (this.props.pullDownToRefresh) {
103-
this.el.removeEventListener("touchstart", this.onStart);
104-
this.el.removeEventListener("touchmove", this.onMove);
105-
this.el.removeEventListener("touchend", this.onEnd);
121+
if (this.props.pullDownToRefresh) {
122+
this.el.removeEventListener("touchstart", this.onStart);
123+
this.el.removeEventListener("touchmove", this.onMove);
124+
this.el.removeEventListener("touchend", this.onEnd);
106125

107-
this.el.removeEventListener("mousedown", this.onStart);
108-
this.el.removeEventListener("mousemove", this.onMove);
109-
this.el.removeEventListener("mouseup", this.onEnd);
126+
this.el.removeEventListener("mousedown", this.onStart);
127+
this.el.removeEventListener("mousemove", this.onMove);
128+
this.el.removeEventListener("mouseup", this.onEnd);
129+
}
110130
}
111131
}
112132

113-
componentWillReceiveProps(props) {
133+
componentWillReceiveProps(props: Props) {
114134
// do nothing when dataLength and key are unchanged
115135
if (
116136
this.props.key === props.key &&
@@ -141,20 +161,32 @@ export default class InfiniteScroll extends Component<Props, State> {
141161
return null;
142162
}
143163

144-
onStart(evt) {
164+
onStart: EventListener = (evt: Event) => {
145165
if (this.lastScrollTop) return;
146166

147167
this.dragging = true;
148-
this.startY = evt.pageY || evt.touches[0].pageY;
168+
169+
if (evt instanceof MouseEvent) {
170+
this.startY = evt.pageY;
171+
} else if (evt instanceof TouchEvent) {
172+
this.startY = evt.touches[0].pageY;
173+
}
149174
this.currentY = this.startY;
150175

151-
this._infScroll.style.willChange = "transform";
152-
this._infScroll.style.transition = `transform 0.2s cubic-bezier(0,0,0.31,1)`;
153-
}
176+
if (this._infScroll) {
177+
this._infScroll.style.willChange = "transform";
178+
this._infScroll.style.transition = `transform 0.2s cubic-bezier(0,0,0.31,1)`;
179+
}
180+
};
154181

155-
onMove(evt) {
182+
onMove: EventListener = (evt: Event) => {
156183
if (!this.dragging) return;
157-
this.currentY = evt.pageY || evt.touches[0].pageY;
184+
185+
if (evt instanceof MouseEvent) {
186+
this.currentY = evt.pageY;
187+
} else if (evt instanceof TouchEvent) {
188+
this.currentY = evt.touches[0].pageY;
189+
}
158190

159191
// user is scrolling down to up
160192
if (this.currentY < this.startY) return;
@@ -168,12 +200,14 @@ export default class InfiniteScroll extends Component<Props, State> {
168200
// so you can drag upto 1.5 times of the maxPullDownDistance
169201
if (this.currentY - this.startY > this.maxPullDownDistance * 1.5) return;
170202

171-
this._infScroll.style.overflow = "visible";
172-
this._infScroll.style.transform = `translate3d(0px, ${this.currentY -
173-
this.startY}px, 0px)`;
174-
}
203+
if (this._infScroll) {
204+
this._infScroll.style.overflow = "visible";
205+
this._infScroll.style.transform = `translate3d(0px, ${this.currentY -
206+
this.startY}px, 0px)`;
207+
}
208+
};
175209

176-
onEnd(evt) {
210+
onEnd: EventListener = evt => {
177211
this.startY = 0;
178212
this.currentY = 0;
179213

@@ -191,9 +225,12 @@ export default class InfiniteScroll extends Component<Props, State> {
191225
this._infScroll.style.willChange = "none";
192226
}
193227
});
194-
}
228+
};
195229

196-
isElementAtBottom(target, scrollThreshold = 0.8) {
230+
isElementAtBottom(
231+
target: HTMLElement,
232+
scrollThreshold: string | number = 0.8
233+
) {
197234
const clientHeight =
198235
target === document.body || target === document.documentElement
199236
? window.screen.availHeight
@@ -213,7 +250,7 @@ export default class InfiniteScroll extends Component<Props, State> {
213250
);
214251
}
215252

216-
onScrollListener(event) {
253+
onScrollListener(event: MouseEvent) {
217254
if (typeof this.props.onScroll === "function") {
218255
// Execute this callback in next tick so that it does not affect the
219256
// functionality of the library.
@@ -222,7 +259,7 @@ export default class InfiniteScroll extends Component<Props, State> {
222259

223260
let target =
224261
this.props.height || this._scrollableNode
225-
? event.target
262+
? (event.target as HTMLElement)
226263
: document.documentElement.scrollTop
227264
? document.documentElement
228265
: document.body;
@@ -249,10 +286,14 @@ export default class InfiniteScroll extends Component<Props, State> {
249286
overflow: "auto",
250287
WebkitOverflowScrolling: "touch",
251288
...this.props.style
252-
};
289+
} as CSSProperties;
253290
const hasChildren =
254291
this.props.hasChildren ||
255-
!!(this.props.children && this.props.children.length);
292+
!!(
293+
this.props.children &&
294+
this.props.children instanceof Array &&
295+
this.props.children.length
296+
);
256297

257298
// because heighted infiniteScroll visualy breaks
258299
// on drag down as overflow becomes visible
@@ -264,13 +305,13 @@ export default class InfiniteScroll extends Component<Props, State> {
264305
<div style={outerDivStyle}>
265306
<div
266307
className={`infinite-scroll-component ${this.props.className || ""}`}
267-
ref={infScroll => (this._infScroll = infScroll)}
308+
ref={(infScroll: HTMLDivElement) => (this._infScroll = infScroll)}
268309
style={style}
269310
>
270311
{this.props.pullDownToRefresh && (
271312
<div
272313
style={{ position: "relative" }}
273-
ref={pullDown => (this._pullDown = pullDown)}
314+
ref={(pullDown: HTMLDivElement) => (this._pullDown = pullDown)}
274315
>
275316
<div
276317
style={{
@@ -298,31 +339,3 @@ export default class InfiniteScroll extends Component<Props, State> {
298339
);
299340
}
300341
}
301-
302-
InfiniteScroll.defaultProps = {
303-
pullDownToRefreshContent: <h3>Pull down to refresh</h3>,
304-
releaseToRefreshContent: <h3>Release to refresh</h3>,
305-
pullDownToRefreshThreshold: 100,
306-
disableBrowserPullToRefresh: true
307-
};
308-
309-
InfiniteScroll.propTypes = {
310-
next: PropTypes.func,
311-
hasMore: PropTypes.bool,
312-
children: PropTypes.node,
313-
loader: PropTypes.node.isRequired,
314-
scrollThreshold: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
315-
endMessage: PropTypes.node,
316-
style: PropTypes.object,
317-
height: PropTypes.number,
318-
scrollableTarget: PropTypes.node,
319-
hasChildren: PropTypes.bool,
320-
pullDownToRefresh: PropTypes.bool,
321-
pullDownToRefreshContent: PropTypes.node,
322-
releaseToRefreshContent: PropTypes.node,
323-
pullDownToRefreshThreshold: PropTypes.number,
324-
refreshFunction: PropTypes.func,
325-
onScroll: PropTypes.func,
326-
dataLength: PropTypes.number.isRequired,
327-
key: PropTypes.string
328-
};

src/utils/throttle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// https://remysharp.com/2010/07/21/throttling-function-calls
2-
export default function throttle(fn, threshhold, scope) {
2+
export default function throttle(fn, threshhold, scope = {}) {
33
threshhold || (threshhold = 250);
44
var last,
55
deferTimer;

0 commit comments

Comments
 (0)