import * as React from "react";
import {
Dimensions,
EmitterSubscription,
LayoutChangeEvent,
NativeScrollEvent,
NativeSyntheticEvent,
ScrollView,
View,
} from "react-native";
import BaseScrollComponent, { ScrollComponentProps } from "../../../core/scrollcomponent/BaseScrollComponent";
import TSCast from "../../../utils/TSCast";
import debounce = require("lodash.debounce");
/***
* The responsibility of a scroll component is to report its size, scroll events and provide a way to scroll to a given offset.
* RecyclerListView works on top of this interface and doesn't care about the implementation. To support web we only had to provide
* another component written on top of web elements
*/
export default class ScrollComponent extends BaseScrollComponent {
public static defaultProps = {
contentHeight: 0,
contentWidth: 0,
externalScrollView: TSCast.cast(ScrollView), //TSI
isHorizontal: false,
scrollThrottle: 16,
};
private static _defaultContainer(props: object, children: React.ReactNode): React.ReactNode | null {
return (
{children}
);
}
private _height: number;
private _width: number;
private _offset: number;
private _isSizeChangedCalledOnce: boolean;
private _scrollViewRef: ScrollView | null = null;
private _dimensionsChangeSubscription: EmitterSubscription | null = null;
constructor(args: ScrollComponentProps) {
super(args);
this._height = 0;
this._width = 0;
this._offset = 0;
this._isSizeChangedCalledOnce = false;
}
public componentDidMount(): void {
this._dimensionsChangeSubscription = Dimensions.addEventListener("change", debounce(({window}) => {
this.props.onWindowResize({
width: window.width,
height: window.height,
});
}, 100));
}
public componentWillUnmount(): void {
if (this._dimensionsChangeSubscription) {
this._dimensionsChangeSubscription.remove();
}
}
public scrollTo(x: number, y: number, isAnimated: boolean): void {
if (this._scrollViewRef) {
this._scrollViewRef.scrollTo({ x, y, animated: isAnimated });
}
}
public render(): JSX.Element {
const Scroller = TSCast.cast(this.props.externalScrollView); //TSI
const renderContentContainer = this.props.renderContentContainer ? this.props.renderContentContainer : ScrollComponent._defaultContainer;
const contentContainerProps = {
style: {
height: this.props.contentHeight,
width: this.props.contentWidth,
},
horizontal : this.props.isHorizontal,
scrollOffset : this._offset,
windowSize: (this.props.isHorizontal ? this._width : this._height) + this.props.renderAheadOffset,
};
//TODO:Talha
// const {
// useWindowScroll,
// contentHeight,
// contentWidth,
// externalScrollView,
// canChangeSize,
// renderHeader,
// renderFooter,
// isHorizontal,
// scrollThrottle,
// ...props,
// } = this.props;
return (
// @ts-ignore
{this.props.renderHeader && this.props.renderHeader()}
{renderContentContainer(contentContainerProps, this.props.children)}
{this.props.renderFooter && this.props.renderFooter()}
);
}
private _getScrollViewRef = (scrollView: any) => { this._scrollViewRef = scrollView as (ScrollView | null); };
private _onScroll = (event?: NativeSyntheticEvent): void => {
if (event) {
const contentOffset = event.nativeEvent.contentOffset;
this._offset = this.props.isHorizontal ? contentOffset.x : contentOffset.y;
this.props.onScroll(contentOffset.x, contentOffset.y, event);
}
}
private _onLayout = (event: LayoutChangeEvent): void => {
if (this._height !== event.nativeEvent.layout.height || this._width !== event.nativeEvent.layout.width) {
this._height = event.nativeEvent.layout.height;
this._width = event.nativeEvent.layout.width;
if (this.props.onSizeChanged) {
this._isSizeChangedCalledOnce = true;
this.props.onSizeChanged(event.nativeEvent.layout);
}
}
if (this.props.onLayout) {
this.props.onLayout(event);
}
}
}