react-native-gesture-image-viewer
Version:
🖼️ React Native Image Viewer - Reanimated-powered image gestures with full control
186 lines (185 loc) • 5.69 kB
JavaScript
"use strict";
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { Platform, StyleSheet, useWindowDimensions, View } from 'react-native';
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
import { registry } from "./GestureViewerRegistry.js";
import { useGestureViewer } from "./useGestureViewer.js";
import { createLoopData, isFlashListLike, isFlatListLike, isScrollViewLike } from "./utils.js";
import WebPagingFixStyle from "./WebPagingFixStyle.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
export function GestureViewer({
id = 'default',
data,
renderItem: renderItemProp,
renderContainer,
ListComponent,
width: customWidth,
height: customHeight,
listProps,
backdropStyle: backdropStyleProps,
containerStyle,
initialIndex = 0,
itemSpacing = 0,
useSnap = false,
enableLoop = false,
...props
}) {
const Component = ListComponent;
const dataRef = useRef(data);
const {
width: screenWidth,
height: screenHeight
} = useWindowDimensions();
const width = customWidth || screenWidth;
const height = customHeight || screenHeight;
const loopData = useMemo(() => createLoopData(dataRef, enableLoop), [enableLoop]);
const isScrollView = isScrollViewLike(Component);
const {
listRef,
isZoomed,
isRotated,
dismissGesture,
zoomGesture,
onMomentumScrollEnd,
onScrollBeginDrag,
handleDismiss,
animatedStyle,
backdropStyle
} = useGestureViewer({
id,
data,
width,
height,
initialIndex,
itemSpacing,
enableLoop,
...props
});
const keyExtractor = useCallback((item, index) => {
if (enableLoop) {
return typeof item === 'string' ? `${item}-${index}` : `item-${index}`;
}
return typeof item === 'string' ? item : `image-${index}`;
}, [enableLoop]);
const renderItem = useCallback(({
item,
index
}) => {
return /*#__PURE__*/_jsx(View, {
style: [{
width,
height,
marginHorizontal: itemSpacing / 2
}, styles.item],
children: renderItemProp(item, index)
}, isScrollView ? keyExtractor(item, index) : undefined);
}, [width, itemSpacing, renderItemProp, keyExtractor, isScrollView, height]);
const getItemLayout = useCallback((_, index) => ({
length: width + itemSpacing,
offset: (width + itemSpacing) * index,
index
}), [width, itemSpacing]);
const gesture = useMemo(() => {
return Gesture.Race(dismissGesture, zoomGesture);
}, [zoomGesture, dismissGesture]);
useEffect(() => {
dataRef.current = data;
}, [data]);
useEffect(() => {
registry.createManager(id);
return () => registry.deleteManager(id);
}, [id]);
const commonProps = useMemo(() => ({
horizontal: true,
scrollEnabled: !isZoomed && !isRotated,
showsHorizontalScrollIndicator: false,
onMomentumScrollEnd: onMomentumScrollEnd,
onScrollBeginDrag,
...(useSnap ? {
snapToInterval: width + itemSpacing,
snapToAlignment: 'center',
decelerationRate: 'fast'
} : {
pagingEnabled: true
}),
scrollEventThrottle: 16,
removeClippedSubviews: true
}), [width, itemSpacing, isZoomed, isRotated, onMomentumScrollEnd, onScrollBeginDrag, useSnap]);
const control = useMemo(() => ({
dismiss: handleDismiss
}), [handleDismiss]);
const listComponent = /*#__PURE__*/_jsx(GestureHandlerRootView, {
children: /*#__PURE__*/_jsx(GestureDetector, {
gesture: gesture,
children: /*#__PURE__*/_jsxs(View, {
style: [{
height,
width
}, containerStyle],
children: [/*#__PURE__*/_jsx(Animated.View, {
style: [styles.background, backdropStyleProps, backdropStyle]
}), /*#__PURE__*/_jsx(Animated.View, {
style: [styles.content, animatedStyle],
...(Platform.OS === 'web' && isFlashListLike(Component) && {
dataSet: {
'flash-list-paging-enabled-fix': true
}
}),
children: isScrollView ? /*#__PURE__*/_jsx(Component, {
ref: listRef,
...commonProps,
...listProps,
children: loopData.map((item, index) => renderItem({
item,
index
}))
}) : isFlatListLike(Component) && /*#__PURE__*/_jsx(Component, {
ref: listRef,
...commonProps,
data: loopData,
renderItem: renderItem,
initialScrollIndex: enableLoop && data.length > 1 ? initialIndex + 1 : initialIndex,
keyExtractor: keyExtractor,
getItemLayout: getItemLayout,
...(isFlashListLike(Component) ? {
estimatedItemSize: width + itemSpacing
} : {
windowSize: 3,
maxToRenderPerBatch: 3
}),
...(Platform.OS === 'web' && isFlatListLike(Component) && {
dataSet: {
'flat-list-paging-enabled-fix': true
}
}),
...listProps
})
}), /*#__PURE__*/_jsx(WebPagingFixStyle, {
Component: Component
})]
})
})
});
return renderContainer ? renderContainer(listComponent, control) : listComponent;
}
const styles = StyleSheet.create({
item: {
justifyContent: 'center',
alignItems: 'center'
},
content: {
flex: 1,
width: '100%',
height: '100%'
},
background: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'black'
}
});
//# sourceMappingURL=GestureViewer.js.map