UNPKG

react-native-reanimated-viewer

Version:

A high performance image viewer in react-native used by react-native-reanimated

753 lines (751 loc) 29 kB
var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; // src/components/ImageViewer.tsx import React, { forwardRef, useRef, useState, useImperativeHandle, useCallback, useMemo } from "react"; import { StyleSheet, Modal, ActivityIndicator, Dimensions, Image, View } from "react-native"; import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withTiming, withDecay, useWorkletCallback, runOnUI, cancelAnimation, useAnimatedReaction } from "react-native-reanimated"; import { GestureDetector, Gesture, GestureHandlerRootView } from "react-native-gesture-handler"; import { useStateRef } from "react-hooks-extension"; var GestureEnum = /* @__PURE__ */ ((GestureEnum2) => { GestureEnum2["TAP"] = "TAP"; GestureEnum2["MODAL"] = "MODAL"; return GestureEnum2; })(GestureEnum || {}); var IMAGE_SPACE = 20; var styles = StyleSheet.create({ full: { flex: 1 }, absolute: { position: "absolute" }, animatedContainer: { backgroundColor: "#000000", width: "100%", height: "100%" }, loading: { alignItems: "center", justifyContent: "center" } }); var ImageViewer = forwardRef((props, ref) => { const screenDimensions = Dimensions.get("screen"); const { data, renderCustomComponent, onLongPress, imageResizeMode = "contain", onChange, dragUpToCloseEnabled, maxScale = 3, doubleTapScale = 2, shouldCloseViewer, originalLayoutOffset } = props; const imageItemRef = useRef([]); const imageMemoSizeRef = useRef({}); const initIndexRef = useRef(0); const [activeSource, setSourceData] = useState(); const activeLayout = useSharedValue(void 0); const [animatedOver, setAnimatedOver] = useState(false); const [loading, setLoading] = useState(false); const loadedIndexListRef = useRef([]); const [finishInit, setFinishInit] = useState(false); const [isScale, setIsScale] = useState(false); const originalImageSize = useSharedValue({}); const imageSize = useSharedValue({}); const activeIndex = useSharedValue(0); const [activeIndexState, setActiveIndexState, activeIndexStateRef] = useStateRef(0); const animatedRate = useSharedValue(0); const imageX = useSharedValue(0); const imageY = useSharedValue(0); const closeRate = useSharedValue(0); const imageScale = useSharedValue(1); const savedImageScale = useSharedValue(1); const savedImageX = useSharedValue(0); const savedImageY = useSharedValue(0); useAnimatedReaction( () => savedImageScale.value !== 1, (value) => runOnJS(setIsScale)(value) ); const formatImageStyle = useWorkletCallback( (imagePosition, imageSizeValue, currentOriginalImageSize, closeRateValue, imageXValue, imageYValue, activeLayoutValue, activeIndexValue, imageScaleValue) => { var _a, _b, _c; const relativeActiveIndex = (activeIndexValue % 3 + 3) % 3; const currentIndex = Math.floor(activeIndexValue / 3) * 3 + (relativeActiveIndex > imagePosition && activeIndexValue > 0 ? 3 : 0) + imagePosition - 1; if (!((_a = data[currentIndex]) == null ? void 0 : _a.key)) { return {}; } const currentImageSize = imageSizeValue[data[currentIndex].key]; const imageWHRate = ((_b = currentImageSize == null ? void 0 : currentImageSize.width) != null ? _b : 1) / ((_c = currentImageSize == null ? void 0 : currentImageSize.height) != null ? _c : 1); const screenWHRate = screenDimensions.width / screenDimensions.height; const currentHeight = imageWHRate > screenWHRate ? screenDimensions.width / imageWHRate : screenDimensions.height; const currentWidth = imageWHRate > screenWHRate ? screenDimensions.width : screenDimensions.height * imageWHRate; const changeHeight = dragUpToCloseEnabled || imageYValue > 0 ? (((currentOriginalImageSize == null ? void 0 : currentOriginalImageSize.height) || 0) - screenDimensions.height) * (imageScaleValue === 1 ? -Math.abs(imageYValue) : 1) / screenDimensions.height / 3 : 0; const manualWidth = Math.min(currentWidth, currentWidth + changeHeight * imageWHRate); const manualHeight = Math.min(currentHeight, currentHeight + changeHeight); const manualTop = (screenDimensions.height - manualHeight) / 2 + imageYValue; const manualLeft = imageXValue; const resultWidth = manualWidth + (((activeLayoutValue == null ? void 0 : activeLayoutValue.width) || 0) - manualWidth) * closeRateValue; const resultHeight = manualHeight + (((activeLayoutValue == null ? void 0 : activeLayoutValue.height) || 0) - manualHeight) * closeRateValue; return { width: resultWidth * imageScaleValue, height: resultHeight * imageScaleValue, transform: [ { translateX: manualLeft - (screenDimensions.width + IMAGE_SPACE) * activeIndexValue + resultWidth * (1 - imageScaleValue) / 2 + (screenDimensions.width - manualWidth) * (1 - closeRateValue) / 2 + (((activeLayoutValue == null ? void 0 : activeLayoutValue.pageX) || 0) - manualLeft) * closeRateValue / imageScaleValue + (imagePosition - 1 + Math.floor(activeIndexValue / 3) * 3 + (relativeActiveIndex > imagePosition && activeIndexValue > 0 ? 3 : 0)) * (screenDimensions.width + IMAGE_SPACE) }, { translateY: manualTop + resultHeight * (1 - imageScaleValue) / 2 + (((activeLayoutValue == null ? void 0 : activeLayoutValue.pageY) || 0) - manualTop) * closeRateValue / imageScaleValue } ], display: (relativeActiveIndex + 1) % 3 !== imagePosition && (imageYValue || imageScaleValue < 1) ? "none" : "flex" }; }, [screenDimensions.width, data, dragUpToCloseEnabled] ); const imageStyle_0 = useAnimatedStyle( () => formatImageStyle( 0, imageSize.value, originalImageSize.value, closeRate.value, imageX.value, imageY.value, activeLayout.value, activeIndex.value, imageScale.value ), [formatImageStyle] ); const imageStyle_1 = useAnimatedStyle( () => formatImageStyle( 1, imageSize.value, originalImageSize.value, closeRate.value, imageX.value, imageY.value, activeLayout.value, activeIndex.value, imageScale.value ), [formatImageStyle] ); const imageStyle_2 = useAnimatedStyle( () => formatImageStyle( 2, imageSize.value, originalImageSize.value, closeRate.value, imageX.value, imageY.value, activeLayout.value, activeIndex.value, imageScale.value ), [formatImageStyle] ); const imageStyleList = [imageStyle_0, imageStyle_1, imageStyle_2]; const originalImageStyle = useAnimatedStyle(() => { var _a, _b; const currentLayout = activeLayout.value; if (!currentLayout) { return {}; } const imageWHRate = ((_a = originalImageSize.value.width) != null ? _a : 1) / ((_b = originalImageSize.value.height) != null ? _b : 1); const screenWHRate = screenDimensions.width / screenDimensions.height; const currentHeight = currentLayout.height + ((imageWHRate > screenWHRate ? screenDimensions.width / imageWHRate : screenDimensions.height) - currentLayout.height) * animatedRate.value; const currentWidth = currentLayout.width + ((imageWHRate > screenWHRate ? screenDimensions.width : screenDimensions.height * imageWHRate) - currentLayout.width) * animatedRate.value; return { width: currentWidth, height: currentHeight, transform: [ { translateX: currentLayout.pageX + (Math.max(0, (screenDimensions.width - currentWidth) / 2) - currentLayout.pageX) * animatedRate.value }, { translateY: currentLayout.pageY + (Math.max(0, (screenDimensions.height - currentHeight) / 2) - currentLayout.pageY) * animatedRate.value } ] }; }, [screenDimensions.width]); const imageContainerStyle = useAnimatedStyle(() => { let opacity = imageScale.value === 1 && (dragUpToCloseEnabled || imageY.value > 0) || closeRate.value > 0 ? Math.round( 255 * (1 - Math.abs(imageY.value) / screenDimensions.height) * (1 - closeRate.value) ).toString(16) : "ff"; opacity.length === 1 && (opacity = `0${opacity}`); return { backgroundColor: `#000000${opacity}` }; }, [screenDimensions.height, dragUpToCloseEnabled]); const hideOriginalImage = useCallback(() => { var _a, _b; (_b = (_a = imageItemRef.current[activeIndexStateRef.current || 0]) == null ? void 0 : _a.current) == null ? void 0 : _b.setNativeProps({ style: { opacity: 0 } }); }, [activeIndexStateRef]); const showOriginalImage = useCallback(() => { var _a, _b; (_b = (_a = imageItemRef.current[activeIndexStateRef.current || 0]) == null ? void 0 : _a.current) == null ? void 0 : _b.setNativeProps({ style: { alignSelf: "flex-start", opacity: 1 } }); }, [activeIndexStateRef]); const onCloseFinish = useCallback( (shouldCloseGesture) => { if (shouldCloseGesture && shouldCloseViewer && activeIndexStateRef.current !== void 0 && !shouldCloseViewer({ gesture: shouldCloseGesture, index: activeIndexStateRef.current, imageData: data[activeIndexStateRef.current], loaded: false })) return; setSourceData(void 0); setLoading(false); setFinishInit(false); setAnimatedOver(false); setTimeout(() => { animatedRate.value = 0; imageY.value = 0; imageX.value = 0; closeRate.value = 0; showOriginalImage(); }, 0); }, [ shouldCloseViewer, activeIndexStateRef, data, animatedRate, imageY, imageX, closeRate, showOriginalImage ] ); const onCloseMeasure = useCallback( (_imageSize, shouldCloseGesture) => { var _a, _b, _c, _d, _e; if (shouldCloseGesture && shouldCloseViewer && activeIndexStateRef.current !== void 0 && !shouldCloseViewer({ gesture: shouldCloseGesture, index: activeIndexStateRef.current, imageData: data[activeIndexStateRef.current], loaded: true })) return; const imageWHRate = ((_a = _imageSize == null ? void 0 : _imageSize.width) != null ? _a : 1) / ((_b = _imageSize == null ? void 0 : _imageSize.height) != null ? _b : 1); const screenWHRate = screenDimensions.width / screenDimensions.height; const currentWidth = imageWHRate > screenWHRate ? screenDimensions.width : screenDimensions.height * imageWHRate; const currentHeight = imageWHRate > screenWHRate ? screenDimensions.width / imageWHRate : screenDimensions.height; const layoutFinish = (width = currentWidth / 3, height = currentHeight / 3, pageX = (screenDimensions.width - currentWidth / 2) / 2, pageY = (initIndexRef.current > (activeIndexStateRef.current || 0) ? -1 : 1) * screenDimensions.height) => { activeLayout.value = { width, height, pageX, pageY }; setTimeout(() => { animatedRate.value = withTiming(1, void 0, (finished) => { finished && runOnJS(setAnimatedOver)(true); }); closeRate.value = withTiming(1, void 0, (finished) => { if (finished) { runOnJS(onCloseFinish)(); } }); }, 0); }; if ((_d = imageItemRef.current[(_c = activeIndexStateRef.current) != null ? _c : -1]) == null ? void 0 : _d.current) { (_e = imageItemRef.current[activeIndexStateRef.current].current) == null ? void 0 : _e.measure( (_x, _y, width, height, pageX, pageY) => { layoutFinish( width, height, pageX + ((originalLayoutOffset == null ? void 0 : originalLayoutOffset.pageX) || 0), pageY + ((originalLayoutOffset == null ? void 0 : originalLayoutOffset.pageY) || 0) ); } ); } else { layoutFinish(); } }, [ shouldCloseViewer, activeIndexStateRef, data, screenDimensions.width, screenDimensions.height, activeLayout, animatedRate, closeRate, onCloseFinish, originalLayoutOffset == null ? void 0 : originalLayoutOffset.pageX, originalLayoutOffset == null ? void 0 : originalLayoutOffset.pageY ] ); const onClose = useWorkletCallback( (shouldCloseGesture) => { imageScale.value = withTiming(1); runOnJS(onCloseMeasure)(imageSize.value[data[activeIndex.value].key], shouldCloseGesture); savedImageScale.value = 1; savedImageX.value = 0; savedImageY.value = 0; }, [data, onCloseMeasure] ); const onRequestClose = useWorkletCallback(() => { onClose("MODAL" /* MODAL */); }, [onClose]); const setImageSize = useWorkletCallback((key, _source) => { imageSize.value = Object.assign({}, imageSize.value, { [key]: _source }); }, []); const dragLastTime = useSharedValue(0); const imageDragGestureY = useMemo( () => Gesture.Pan().activeOffsetY(dragUpToCloseEnabled ? [-20, 20] : 20).onStart(() => { runOnJS(hideOriginalImage)(); dragLastTime.value = Date.now().valueOf(); }).onUpdate((event) => { imageX.value = event.translationX; imageY.value = event.translationY; }).onEnd((event) => { const translationY = dragUpToCloseEnabled ? Math.abs(event.translationY) : event.translationY; if (translationY < 100 && (Date.now().valueOf() - dragLastTime.value > 500 || event.translationY <= 0 && !dragUpToCloseEnabled)) { imageX.value = withTiming(0); imageY.value = withTiming(0); runOnJS(showOriginalImage)(); } else { onClose(); } }), [ dragUpToCloseEnabled, hideOriginalImage, dragLastTime, imageX, imageY, showOriginalImage, onClose ] ); const _onChange = useCallback( (currentIndex) => { setActiveIndexState(currentIndex); onChange == null ? void 0 : onChange(currentIndex); }, [onChange, setActiveIndexState] ); const imageDragGestureX = useMemo( () => Gesture.Pan().activeOffsetX([-20, 20]).onStart(() => { dragLastTime.value = Date.now().valueOf(); }).onUpdate((event) => { imageX.value = event.translationX * ((event.translationX < 0 ? activeIndex.value < data.length - 1 : activeIndex.value > 0) ? 1 : 0.4); }).onEnd((event) => { if ((event.translationX < 0 ? activeIndex.value < data.length - 1 : activeIndex.value > 0) && (Date.now().valueOf() - dragLastTime.value < 500 || Math.abs(event.translationX) > screenDimensions.width / 2)) { imageX.value = withTiming( (screenDimensions.width + IMAGE_SPACE) * (event.translationX < 0 ? -1 : 1), { duration: 200 }, () => { activeIndex.value += event.translationX < 0 ? 1 : -1; imageX.value = 0; runOnJS(_onChange)(activeIndex.value); } ); } else { imageX.value = withTiming(0); } savedImageX.value = 0; }), [dragLastTime, imageX, activeIndex, savedImageX, screenDimensions.width, data, _onChange] ); const imageDragGestureMove = useMemo( () => Gesture.Pan().minDistance(5).onStart(() => { cancelAnimation(imageX); cancelAnimation(imageY); }).onUpdate((event) => { imageX.value = savedImageX.value + event.translationX; imageY.value = savedImageY.value + event.translationY; }).onEnd((event) => { var _a, _b; savedImageX.value = imageX.value; savedImageY.value = imageY.value; const currentImageSize = imageSize.value[data[activeIndex.value].key]; const imageWHRate = ((_a = currentImageSize.width) != null ? _a : 1) / ((_b = currentImageSize.height) != null ? _b : 1); const screenWHRate = screenDimensions.width / screenDimensions.height; const currentImageHeight = imageWHRate > screenWHRate ? screenDimensions.width / imageWHRate : screenDimensions.height; const currentImageWidth = imageWHRate > screenWHRate ? screenDimensions.width : screenDimensions.height * imageWHRate; const currentWidthRange = currentImageWidth * (savedImageScale.value - 1) / 2; const currentImageX = Math.min( currentWidthRange, Math.max(-currentWidthRange, savedImageX.value) ); if (currentImageX !== savedImageX.value) { imageX.value = withTiming(currentImageX); savedImageX.value = currentImageX; } else if (event == null ? void 0 : event.velocityX) { const targetImageX = Math.min( currentWidthRange, Math.max( -currentWidthRange, savedImageX.value + (event.velocityX > 0 ? 100 : -100) * savedImageScale.value ) ); imageX.value = withDecay( { velocity: event.velocityX, clamp: event.velocityX > 0 ? [savedImageX.value, targetImageX] : [targetImageX, savedImageX.value] }, () => { savedImageX.value = imageX.value; } ); } const currentHeightRange = Math.abs( (currentImageHeight * savedImageScale.value - screenDimensions.height) / 2 ); const currentImageY = Math.min( currentHeightRange, Math.max(-currentHeightRange, savedImageY.value) ); if (currentImageY !== savedImageY.value) { imageY.value = withTiming(currentImageY); savedImageY.value = currentImageY; } else if (event == null ? void 0 : event.velocityY) { const targetImageY = Math.min( currentHeightRange, Math.max( -currentHeightRange, savedImageY.value + (event.velocityY > 0 ? 100 : -100) * savedImageScale.value ) ); imageY.value = withDecay( { velocity: event.velocityY, clamp: event.velocityY > 0 ? [savedImageY.value, targetImageY] : [targetImageY, savedImageY.value] }, () => { savedImageY.value = imageY.value; } ); } }), [ activeIndex, data, imageSize, imageX, imageY, savedImageScale, savedImageX, savedImageY, screenDimensions.height, screenDimensions.width ] ); const resetScale = useWorkletCallback(() => { imageScale.value = withTiming(1); imageX.value = withTiming(0); imageY.value = withTiming(0); savedImageScale.value = 1; savedImageX.value = 0; savedImageY.value = 0; }, []); const imageOriginalTapGesture = useMemo( () => Gesture.Tap().onEnd(() => { runOnJS(onCloseFinish)("TAP" /* TAP */); }), [onCloseFinish] ); const imageSingleTapGesture = useMemo( () => Gesture.Tap().onStart(() => { if (imageScale.value === 1) { runOnJS(hideOriginalImage)(); } onClose("TAP" /* TAP */); }), [onClose, hideOriginalImage, imageScale] ); const imageDoubleTapGesture = useMemo( () => Gesture.Tap().numberOfTaps(2).onStart((event) => { if (imageScale.value !== 1) { resetScale(); } else { imageScale.value = withTiming(doubleTapScale); savedImageScale.value = doubleTapScale; const currentX = (screenDimensions.width / 2 - event.x) * doubleTapScale; imageX.value = withTiming(currentX); savedImageX.value = currentX; const currentY = (screenDimensions.height / 2 - event.y) * doubleTapScale; imageY.value = withTiming(currentY); savedImageY.value = currentY; } }), [ imageScale, resetScale, doubleTapScale, savedImageScale, screenDimensions.width, screenDimensions.height, imageX, savedImageX, imageY, savedImageY ] ); const imageTapGesture = useMemo( () => Gesture.Exclusive(imageDoubleTapGesture, imageSingleTapGesture), [imageDoubleTapGesture, imageSingleTapGesture] ); const imagePinchGesture = useMemo( () => Gesture.Pinch().onUpdate((event) => { imageScale.value = savedImageScale.value * event.scale; imageX.value = savedImageX.value * event.scale; imageY.value = savedImageY.value * event.scale; }).onEnd(() => { const currentScale = Math.min(Math.max(1, imageScale.value), maxScale); if (currentScale === 1) { resetScale(); } else { imageScale.value = withTiming(currentScale); const changedScale = currentScale / savedImageScale.value; savedImageScale.value = currentScale; const currentImageX = savedImageX.value * changedScale; const currentImageY = savedImageY.value * changedScale; imageX.value = withTiming(currentImageX); imageY.value = withTiming(currentImageY); savedImageX.value = currentImageX; savedImageY.value = currentImageY; } }), [imageScale, savedImageScale, imageX, imageY, savedImageX, savedImageY, maxScale, resetScale] ); const imageLongPressGesture = useMemo( () => Gesture.LongPress().onStart(() => { if (onLongPress) { runOnJS(onLongPress)({ index: activeIndex.value, item: data[activeIndex.value] }); } }), [onLongPress, activeIndex, data] ); const imageGesture = useMemo( () => Gesture.Race( imageDragGestureY, imageDragGestureX, imageTapGesture, imagePinchGesture, imageLongPressGesture ), [ imageDragGestureY, imageDragGestureX, imageTapGesture, imagePinchGesture, imageLongPressGesture ] ); const imageGestureWithScale = useMemo( () => Gesture.Race(imageDragGestureMove, imageTapGesture, imagePinchGesture, imageLongPressGesture), [imageDragGestureMove, imageTapGesture, imagePinchGesture, imageLongPressGesture] ); useImperativeHandle(ref, () => ({ init: ({ itemRef, index }) => { imageItemRef.current[index] = itemRef; }, show: ({ index, source = data[index].source }) => { var _a, _b; const _screenDimensions = Dimensions.get("screen"); initIndexRef.current = index; activeIndex.value = index; setActiveIndexState(index); setSourceData(source); const startShow = () => { var _a2; if ((_a2 = imageItemRef.current[index]) == null ? void 0 : _a2.current) { imageItemRef.current[index].current.measure((_x, _y, width, height, pageX, pageY) => { activeLayout.value = { width, height, pageX: pageX + ((originalLayoutOffset == null ? void 0 : originalLayoutOffset.pageX) || 0), pageY: pageY + ((originalLayoutOffset == null ? void 0 : originalLayoutOffset.pageY) || 0) }; setTimeout(() => { animatedRate.value = withTiming(1, void 0, (finished) => { finished && runOnJS(setAnimatedOver)(true); }); }, 0); }); } else { setTimeout(() => { animatedRate.value = withTiming(1, void 0, (finished) => { finished && runOnJS(setAnimatedOver)(true); }); }, 0); } }; if (source.width && source.height) { originalImageSize.value = { width: source.width, height: source.height }; startShow(); } else if (imageMemoSizeRef.current[source.uri || ""]) { originalImageSize.value = imageMemoSizeRef.current[source.uri || ""]; startShow(); } else { (_b = (_a = Image.getSize( source.uri || "", // 0.77.0 开始支持 后续可以移除 (width, height) => { imageMemoSizeRef.current[source.uri || ""] = originalImageSize.value = { width, height }; startShow(); }, () => { originalImageSize.value = _screenDimensions; startShow(); } )) == null ? void 0 : _a.then) == null ? void 0 : _b.call(_a, ({ width, height }) => { imageMemoSizeRef.current[source.uri || ""] = originalImageSize.value = { width, height }; startShow(); }).catch(() => { originalImageSize.value = _screenDimensions; startShow(); }); } } })); return <Modal visible={!!activeSource} animationType="fade" transparent onRequestClose={onRequestClose} statusBarTranslucent ><GestureHandlerRootView style={styles.full}> {activeSource ? <GestureDetector gesture={!animatedOver || !finishInit ? imageOriginalTapGesture : isScale ? imageGestureWithScale : imageGesture} ><View> <Animated.View style={[styles.animatedContainer, imageContainerStyle]}> {Array.from(new Array(3)).map((_, index) => { const relativeActiveIndex = (activeIndexState % 3 + 3) % 3; const currentIndex = Math.floor(activeIndexState / 3) * 3 + (relativeActiveIndex > index && activeIndexState > 0 ? 3 : 0) + index - 1; if (currentIndex < 0 || currentIndex >= data.length) { return null; } const currentData = data[currentIndex]; return <Animated.Image key={`image-viewer-${currentIndex}`} resizeMode={imageResizeMode} source={typeof currentData.source === "object" ? __spreadValues({}, currentData.source) : currentData.source} onLoadStart={() => { if (relativeActiveIndex === index - 1 && !loadedIndexListRef.current.includes(activeIndexState)) { setLoading(true); } }} onLoad={({ nativeEvent: { source } }) => { runOnUI(setImageSize)(currentData.key, source || currentData.source); if (relativeActiveIndex === index - 1) { setLoading(false); setFinishInit(true); if (!loadedIndexListRef.current.includes(activeIndexState)) { loadedIndexListRef.current.push(activeIndexState); } } }} style={[styles.absolute, imageStyleList[index]]} />; })} {loading && animatedOver ? <ActivityIndicator style={[StyleSheet.absoluteFill, styles.loading]} color="#fff" /> : null} </Animated.View> {!animatedOver || !finishInit ? <View style={[StyleSheet.absoluteFill, styles.animatedContainer]}> <Animated.Image source={typeof activeSource === "object" ? __spreadValues({}, activeSource) : activeSource} resizeMode={imageResizeMode} style={[styles.absolute, originalImageStyle]} /> {!finishInit && animatedOver ? <ActivityIndicator style={[StyleSheet.absoluteFill, styles.loading]} color="#fff" /> : null} </View> : null} </View></GestureDetector> : null} {renderCustomComponent == null ? void 0 : renderCustomComponent({ item: data[activeIndexState], index: activeIndexState })} </GestureHandlerRootView></Modal>; }); var ImageViewer_default = React.memo(ImageViewer); // src/components/ImageWrapper.tsx import React2, { useCallback as useCallback2, useEffect, useRef as useRef2 } from "react"; import { TouchableOpacity } from "react-native"; var ImageWrapper = (props) => { const { viewerRef, index, children, source, style, onPress, wrapperProps } = props; const containerRef = useRef2(null); const _onPress = useCallback2(() => { var _a; if ((onPress == null ? void 0 : onPress()) === false) { return; } (_a = viewerRef.current) == null ? void 0 : _a.show({ index, source }); }, [index, source, viewerRef, onPress]); useEffect(() => { var _a; (_a = viewerRef.current) == null ? void 0 : _a.init({ itemRef: containerRef, index }); }, [index, viewerRef]); return <TouchableOpacity activeOpacity={1} onPress={_onPress} {...wrapperProps} ref={containerRef} style={[{ alignSelf: "flex-start" }, style]} >{children}</TouchableOpacity>; }; var ImageWrapper_default = React2.memo(ImageWrapper); export { GestureEnum, ImageViewer_default as ImageViewer, ImageWrapper_default as ImageWrapper }; //# sourceMappingURL=index.js.map