UNPKG

reanimated-masonry-list

Version:

Reanimated2 Masonry List for Pinterest like UI implemented just like the [FlatList].

68 lines (67 loc) 3.88 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import React, { memo, useState } from 'react'; import { RefreshControl, View } from 'react-native'; import Animated from 'react-native-reanimated'; const isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }, onEndReachedThreshold) => { const paddingToBottom = contentSize.height * onEndReachedThreshold; return (Math.ceil(layoutMeasurement.height + contentOffset.y) >= contentSize.height - paddingToBottom); }; function MasonryList(props) { const [isRefreshing, setIsRefreshing] = useState(false); const { refreshing, data, innerRef, ListHeaderComponent, ListEmptyComponent, ListFooterComponent, ListHeaderComponentStyle, containerStyle, contentContainerStyle, renderItem, onEndReachedThreshold, onEndReached, onRefresh, loading, LoadingView, numColumns = 2, horizontal, onScroll, removeClippedSubviews = false, keyExtractor, keyboardShouldPersistTaps = 'handled', refreshControl = true, refreshControlProps, } = props; const { style } = props, propsWithoutStyle = __rest(props, ["style"]); return (<Animated.ScrollView {...propsWithoutStyle} ref={innerRef} keyboardShouldPersistTaps={keyboardShouldPersistTaps} style={[{ flex: 1, alignSelf: 'stretch' }, containerStyle]} contentContainerStyle={contentContainerStyle} removeClippedSubviews={removeClippedSubviews} refreshControl={refreshControl ? (<RefreshControl refreshing={!!(refreshing || isRefreshing)} onRefresh={() => { setIsRefreshing(true); onRefresh === null || onRefresh === void 0 ? void 0 : onRefresh(); setIsRefreshing(false); }} {...refreshControlProps}/>) : null} scrollEventThrottle={16} onScroll={(e) => { const nativeEvent = e.nativeEvent; if (isCloseToBottom(nativeEvent, onEndReachedThreshold || 0.1)) { onEndReached === null || onEndReached === void 0 ? void 0 : onEndReached(); } onScroll === null || onScroll === void 0 ? void 0 : onScroll(e); }}> <> <View style={ListHeaderComponentStyle}>{ListHeaderComponent}</View> {data.length === 0 && ListEmptyComponent ? (React.isValidElement(ListEmptyComponent) ? (ListEmptyComponent) : (<ListEmptyComponent />)) : (<View style={[ { flex: 1, flexDirection: horizontal ? 'column' : 'row', }, style, ]}> {Array.from(Array(numColumns), (_, num) => { return (<View key={`masonry-column-${num}`} style={{ flex: 1 / numColumns, flexDirection: horizontal ? 'row' : 'column', }}> {data .map((el, i) => { if (i % numColumns === num) { return (<View key={(keyExtractor === null || keyExtractor === void 0 ? void 0 : keyExtractor(el, i)) || `masonry-row-${num}-${i}`}> {renderItem({ item: el, i })} </View>); } return null; }) .filter((e) => !!e)} </View>); })} </View>)} {loading && LoadingView} {ListFooterComponent} </> </Animated.ScrollView>); } export default memo(MasonryList);