react-native-gallery-preview
Version:
<div> <img align="right" height="720" src="example.gif"> </div>
149 lines (148 loc) • 5.49 kB
JavaScript
"use strict";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Dimensions, I18nManager, StyleSheet, useWindowDimensions, View } from "react-native";
import Animated, { runOnJS, useAnimatedReaction, useAnimatedStyle, useSharedValue, withDelay, withTiming } from "react-native-reanimated";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { SPRING_CONFIG, MAX_SCALE } from "../../constants";
import { DefaultHeader } from "../DefaultHeader/DefaultHeader";
import { GalleryStatusBar } from "../GalleryStatusBar/GalleryStatusBar";
import { ModalContainer } from "../ModalContainer/ModalContainer";
import { GalleryChildrenItem } from "./GalleryChildrenItem";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
export const GalleryPreviewForChildren = ({
isVisible,
onRequestClose,
initialIndex = 0,
gap = 24,
simultaneousRenderedImages = 6,
OverlayComponent = DefaultHeader,
springConfig = SPRING_CONFIG,
maxScale = MAX_SCALE,
doubleTabEnabled = true,
pinchEnabled = true,
swipeToCloseEnabled = true,
backgroundColor = "#000",
headerTextColor = "#fff",
children
}) => {
const rtl = I18nManager.isRTL;
const dimensions = useWindowDimensions();
const [index, setIndex] = useState(initialIndex);
const [isFocused, setIsFocused] = useState(true);
const translateX = useSharedValue(initialIndex * -(dimensions.width + gap) * (rtl ? -1 : 1));
const opacity = useSharedValue(1);
const currentIndex = useSharedValue(initialIndex);
useAnimatedReaction(() => currentIndex.value, newIndex => {
runOnJS(setIndex)(newIndex);
}, [currentIndex]);
const wrapperAnimatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value
}), [isFocused]);
const containerAnimatedStyle = useAnimatedStyle(() => ({
transform: [{
translateX: translateX.value
}]
}));
const listOfChildren = useMemo(() => {
return children ? React.Children.toArray(children) : [];
}, [children]);
const isChildrenVisible = useCallback(imageIndex => {
const halfVisible = Math.floor(simultaneousRenderedImages / 2);
const start = Math.max(0, index - halfVisible);
const end = Math.min(listOfChildren.length - 1, start + simultaneousRenderedImages - 1);
return imageIndex >= start && imageIndex <= end;
}, [listOfChildren.length, index, simultaneousRenderedImages]);
const getImagePositionX = useCallback(i => {
return i * -(Dimensions.get("window").width + gap) * (rtl ? -1 : 1);
}, [gap, rtl]);
useEffect(() => {
if (isVisible) {
opacity.value = 1;
currentIndex.value = initialIndex;
translateX.value = getImagePositionX(initialIndex);
setIsFocused(true);
}
}, [currentIndex, getImagePositionX, initialIndex, isVisible, opacity, translateX]);
useEffect(() => {
const subscription = Dimensions.addEventListener("change", ({
window
}) => {
const {
width
} = window;
translateX.value = withDelay(0, withTiming(currentIndex.value * -(width + gap) * (rtl ? -1 : 1)));
});
return () => {
subscription.remove();
};
}, [currentIndex.value, gap, rtl, translateX]);
return /*#__PURE__*/_jsxs(ModalContainer, {
isVisible: isVisible,
onRequestClose: onRequestClose,
children: [/*#__PURE__*/_jsx(GalleryStatusBar, {
isFocused: isFocused,
backgroundColor: backgroundColor
}), /*#__PURE__*/_jsxs(Animated.View, {
style: [wrapperAnimatedStyle, styles.wrapper, {
backgroundColor
}],
children: [/*#__PURE__*/_jsx(GestureHandlerRootView, {
style: styles.gestureContainer,
children: /*#__PURE__*/_jsx(Animated.View, {
style: [containerAnimatedStyle, styles.container, {
columnGap: gap
}],
children: listOfChildren.map((child, i) => {
const visible = isChildrenVisible(i);
return /*#__PURE__*/_jsx(View, {
style: {
...dimensions
},
children: visible && /*#__PURE__*/_jsx(GalleryChildrenItem, {
index: i,
currentIndex: currentIndex,
isFirst: i === 0,
isLast: i === listOfChildren.length - 1,
rootTranslateX: translateX,
opacity: opacity,
width: dimensions.width,
height: dimensions.height,
dataLength: listOfChildren.length,
gap: gap,
onClose: onRequestClose,
isFocused: isFocused,
setIsFocused: setIsFocused,
springConfig: springConfig,
maxScale: maxScale,
swipeToCloseEnabled: swipeToCloseEnabled,
pinchEnabled: pinchEnabled,
doubleTabEnabled: doubleTabEnabled,
rtl: rtl,
children: child
})
}, i);
})
})
}), /*#__PURE__*/_jsx(OverlayComponent, {
isFocused: isFocused,
imagesLength: listOfChildren.length,
currentImageIndex: index,
onClose: onRequestClose,
containerBackgroundColor: backgroundColor,
textColor: headerTextColor
})]
})]
});
};
const styles = StyleSheet.create({
wrapper: {
flex: 1
},
gestureContainer: {
flex: 1
},
container: {
flexDirection: "row"
}
});
//# sourceMappingURL=GalleryPreviewForChildren.js.map