react-native-gallery-preview
Version:
<div> <img align="right" height="720" src="example.gif"> </div>
315 lines (308 loc) • 15 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GestureItemComponent = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
var _reactNativeGestureHandler = require("react-native-gesture-handler");
var _constants = require("../../constants");
var _clamp = require("../../utils/clamp");
var _useVector = require("../../utils/useVector");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
// import { DebugView } from "./DebugView/DebugView";
const GestureItemComponent = exports.GestureItemComponent = /*#__PURE__*/(0, _react.memo)(({
children,
index,
currentIndex,
isFirst,
isLast,
rootTranslateX,
opacity,
dataLength,
width,
height,
gap,
onClose,
setIsFocused,
isFocused,
maxScale,
springConfig,
doubleTabEnabled,
swipeToCloseEnabled,
pinchEnabled,
rtl,
contentCenterX,
contentCenterY,
contentContainerSize
}) => {
const initRootTranslateX = (0, _reactNativeReanimated.useSharedValue)(0);
const offset = (0, _useVector.useVector)(0, 0);
const translation = (0, _useVector.useVector)(0, 0);
const savedTranslation = (0, _useVector.useVector)(0, 0);
const initialFocal = (0, _useVector.useVector)(0, 0);
const scale = (0, _reactNativeReanimated.useSharedValue)(1);
const savedScale = (0, _reactNativeReanimated.useSharedValue)(1);
const isPanningOut = (0, _reactNativeReanimated.useSharedValue)(false);
const shouldClose = (0, _reactNativeReanimated.useSharedValue)(false);
const animationContentContainerStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
return {
transform: [{
translateX: offset.x.value + translation.x.value
}, {
translateY: offset.y.value + translation.y.value
}, {
scale: scale.value
}]
};
});
const onStartInteraction = withUnFocus => {
"worklet";
offset.x.value = offset.x.value + translation.x.value;
offset.y.value = offset.y.value + translation.y.value;
translation.x.value = 0;
translation.y.value = 0;
if (withUnFocus) {
(0, _reactNativeReanimated.runOnJS)(setIsFocused)(false);
}
};
const getImagePositionX = (0, _react.useCallback)(i => {
"worklet";
if (rtl) {
return [(width + gap) * i, width * (i + 1)];
}
return [-(width + gap) * i, -width * (i + 1)];
}, [gap, width, rtl]);
const getScaledEdgesX = scaleValue => {
"worklet";
const _scale = scaleValue !== undefined ? scaleValue : scale.value;
const scaledWith = _scale * contentContainerSize.width;
const xPoint = Math.abs((scaledWith - width) / 2);
return [-xPoint, xPoint];
};
const getScaledEdgesY = scaleValue => {
"worklet";
const _scale = scaleValue !== undefined ? scaleValue : scale.value;
const scaledHeight = _scale * contentContainerSize.height;
const yPoint = Math.abs((scaledHeight - height) / 2);
return [-yPoint, yPoint];
};
const reset = () => {
"worklet";
translation.x.value = scale.value > 1 ? (0, _reactNativeReanimated.withTiming)(0, {
duration: _constants.DURATION
}) : (0, _reactNativeReanimated.withSpring)(0, springConfig);
translation.y.value = scale.value > 1 ? (0, _reactNativeReanimated.withTiming)(0, {
duration: _constants.DURATION
}) : (0, _reactNativeReanimated.withSpring)(0, springConfig);
offset.x.value = scale.value > 1 ? (0, _reactNativeReanimated.withTiming)(0, {
duration: _constants.DURATION
}) : (0, _reactNativeReanimated.withSpring)(0, springConfig);
offset.y.value = scale.value > 1 ? (0, _reactNativeReanimated.withTiming)(0, {
duration: _constants.DURATION
}) : (0, _reactNativeReanimated.withSpring)(0, springConfig);
opacity.value = (0, _reactNativeReanimated.withTiming)(1, {
duration: _constants.DURATION
});
scale.value = (0, _reactNativeReanimated.withTiming)(1, {
duration: _constants.DURATION
});
rootTranslateX.value = (0, _reactNativeReanimated.withSpring)(getImagePositionX(index)[0], springConfig);
};
const pinchGesture = _reactNativeGestureHandler.Gesture.Pinch().enabled(pinchEnabled).onStart(event => {
onStartInteraction(true);
initialFocal.x.value = event.focalX - (width / 2 + offset.x.value);
initialFocal.y.value = event.focalY - (height / 2 + offset.y.value);
savedScale.value = scale.value;
}).onUpdate(event => {
if (event.numberOfPointers !== 2) return;
const deltaX = event.focalX - (width / 2 + offset.x.value);
const deltaY = event.focalY - (height / 2 + offset.y.value);
translation.x.value = deltaX + -1 * scale.value / savedScale.value * initialFocal.x.value;
translation.y.value = deltaY + -1 * scale.value / savedScale.value * initialFocal.y.value;
scale.value = (0, _clamp.withRubberClamp)(savedScale.value * event.scale, 0.45, maxScale, _constants.MIN_SCALE, maxScale);
}).onEnd(() => {
if (scale.value <= 1) {
reset();
} else {
if (scale.value > maxScale) {
const diffX = -1 * maxScale / savedScale.value * initialFocal.x.value - -1 * scale.value / savedScale.value * initialFocal.x.value;
const diffY = -1 * maxScale / savedScale.value * initialFocal.y.value - -1 * scale.value / savedScale.value * initialFocal.y.value;
translation.x.value = (0, _reactNativeReanimated.withTiming)(translation.x.value + diffX, {
duration: _constants.DURATION
});
translation.y.value = (0, _reactNativeReanimated.withTiming)(translation.y.value + diffY, {
duration: _constants.DURATION
});
scale.value = (0, _reactNativeReanimated.withTiming)(maxScale, {
duration: _constants.DURATION
});
} else {
const edgesX = getScaledEdgesX();
const edgesY = getScaledEdgesY();
if (offset.x.value + translation.x.value > edgesX[1]) {
translation.x.value = (0, _reactNativeReanimated.withSpring)(edgesX[1] - offset.x.value, springConfig);
} else if (offset.x.value + translation.x.value < edgesX[0]) {
translation.x.value = (0, _reactNativeReanimated.withSpring)(edgesX[0] - offset.x.value, springConfig);
}
const currHeight = contentContainerSize.height * scale.value;
if (currHeight > height) {
if (offset.y.value + translation.y.value > edgesY[1]) {
translation.y.value = (0, _reactNativeReanimated.withSpring)(edgesY[1] - offset.y.value, springConfig);
} else if (offset.y.value + translation.y.value < edgesY[0]) {
translation.y.value = (0, _reactNativeReanimated.withSpring)(edgesY[0] - offset.y.value, springConfig);
}
} else {
translation.y.value = (0, _reactNativeReanimated.withSpring)(0, springConfig);
offset.y.value = (0, _reactNativeReanimated.withSpring)(0, springConfig);
}
}
}
});
const panGesture = _reactNativeGestureHandler.Gesture.Pan().minDistance(10).maxPointers(1).onStart(event => {
onStartInteraction();
if (scale.value === 1 && event.velocityY > event.velocityX) {
rootTranslateX.value = getImagePositionX(currentIndex.value)[0];
}
initRootTranslateX.value = rootTranslateX.value;
savedTranslation.x.value = translation.x.value;
savedTranslation.y.value = translation.y.value;
isPanningOut.value = false;
shouldClose.value = false;
}).onUpdate(event => {
const {
translationX,
translationY,
velocityY,
velocityX
} = event;
const edgesX = getScaledEdgesX();
const edgesY = getScaledEdgesY();
isPanningOut.value = !isPanningOut.value ? swipeToCloseEnabled && scale.value === 1 && getImagePositionX(index)[0] === rootTranslateX.value && (velocityY > 0 && velocityY > Math.abs(velocityX) || translationY > Math.abs(translationX)) : isPanningOut.value;
if (scale.value === 1 && !isPanningOut.value) {
if (rtl) {
rootTranslateX.value = (0, _clamp.withRubberClamp)(initRootTranslateX.value + translationX, {
dir0: isLast ? 0.55 : 1.15,
dir1: isFirst ? 0.55 : 1.15
}, width, 0, getImagePositionX(dataLength - 1)[0]);
} else {
rootTranslateX.value = (0, _clamp.withRubberClamp)(initRootTranslateX.value + translationX, {
dir0: isFirst ? 0.55 : 1.15,
dir1: isLast ? 0.55 : 1.15
}, width, getImagePositionX(dataLength - 1)[0], 0);
}
return;
} else {
translation.x.value = (0, _clamp.withRubberClamp)(savedTranslation.x.value + translationX, 0.55, contentContainerSize.width * scale.value, edgesX[0], edgesX[1]);
}
if (isPanningOut.value) {
if (translation.y.value === 0 && Math.abs(velocityY) > Math.abs(velocityX) && velocityY > height) {
shouldClose.value = true;
(0, _reactNativeReanimated.runOnJS)(onClose)();
return;
}
translation.y.value = (0, _clamp.withRubberClamp)(savedTranslation.y.value + translationY, {
dir0: 1,
dir1: 0.55
}, contentContainerSize.height * scale.value, 0, edgesY[1]);
opacity.value = (0, _reactNativeReanimated.interpolate)(translation.y.value, [0, height / 2], [1, 0]);
scale.value = (0, _reactNativeReanimated.interpolate)(translation.y.value, [0, height / 2], [1, 0.66]);
shouldClose.value = velocityY >= 0 && translation.y.value + velocityY * 0.3 > contentContainerSize.height / 10;
} else {
translation.y.value = (0, _clamp.withRubberClamp)(savedTranslation.y.value + translationY, 0.55, contentContainerSize.height * scale.value, edgesY[0], edgesY[1]);
}
}).onEnd(event => {
if (shouldClose.value) {
(0, _reactNativeReanimated.runOnJS)(onClose)();
return;
} else if (isPanningOut.value) {
reset();
return;
}
const currentImagePositionX = getImagePositionX(index);
const {
velocityX,
translationX
} = event;
const edgesX = getScaledEdgesX();
const edgesY = getScaledEdgesY();
if (scale.value === 1) {
const needToTransX = Math.abs(getImagePositionX(1)[0] / 2);
if (rtl && (isFirst && translationX < 0 || isLast && translationX > 0) || !rtl && (isFirst && translationX > 0 || isLast && translationX < 0)) {
rootTranslateX.value = (0, _reactNativeReanimated.withSpring)(currentImagePositionX[0], springConfig);
} else if (Math.abs(velocityX) >= needToTransX || Math.abs(translationX) >= needToTransX) {
const newIndex = rtl ? !isFirst && velocityX <= 0 && translationX < 0 ? index - 1 : !isLast && velocityX >= 0 && translationX > 0 ? index + 1 : index : !isFirst && velocityX >= 0 && translationX > 0 ? index - 1 : !isLast && velocityX <= 0 && translationX < 0 ? index + 1 : index;
const newPosition = getImagePositionX(newIndex);
rootTranslateX.value = (0, _reactNativeReanimated.withSpring)(newPosition[0], springConfig);
currentIndex.value = newIndex;
} else {
rootTranslateX.value = (0, _reactNativeReanimated.withSpring)(currentImagePositionX[0], springConfig);
}
} else {
if (translation.x.value + offset.x.value > edgesX[1] || translation.x.value + offset.x.value < edgesX[0]) {
translation.x.value = (0, _reactNativeReanimated.withSpring)((0, _reactNativeReanimated.clamp)(translation.x.value, edgesX[0] - offset.x.value, edgesX[1] - offset.x.value), springConfig);
}
if (translation.y.value + offset.y.value > edgesY[1] || translation.y.value + offset.y.value < edgesY[0]) {
translation.y.value = (0, _reactNativeReanimated.withSpring)((0, _reactNativeReanimated.clamp)(translation.y.value, edgesY[0] - offset.y.value, edgesY[1] - offset.y.value), springConfig);
}
}
});
const doubleTap = _reactNativeGestureHandler.Gesture.Tap().enabled(doubleTabEnabled).numberOfTaps(2).onStart(() => {
onStartInteraction(true);
}).onEnd(event => {
if (event.numberOfPointers !== 1) {
return;
}
if (scale.value > 1) {
reset();
} else {
const zoomScale = height > width ? Math.min(contentContainerSize.width > contentContainerSize.height ? height / contentContainerSize.height * 1.1 : 2.5, maxScale) : Math.min(contentContainerSize.height > contentContainerSize.width ? width / contentContainerSize.width * 1.1 : 2.5, maxScale);
const edgesX = getScaledEdgesX(zoomScale);
const edgesY = getScaledEdgesY(zoomScale);
translation.x.value = (0, _reactNativeReanimated.withTiming)((0, _reactNativeReanimated.clamp)((contentCenterX - event.x) * (zoomScale - 1), edgesX[0], edgesX[1]), {
duration: _constants.DURATION
});
translation.y.value = (0, _reactNativeReanimated.withTiming)((0, _reactNativeReanimated.clamp)((contentCenterY - event.y) * (zoomScale - 1), edgesY[0], edgesY[1]), {
duration: _constants.DURATION
});
scale.value = (0, _reactNativeReanimated.withTiming)(zoomScale, {
duration: _constants.DURATION
});
savedScale.value = zoomScale;
}
});
const tap = _reactNativeGestureHandler.Gesture.Tap().numberOfTaps(1).requireExternalGestureToFail(doubleTap).onEnd(() => {
(0, _reactNativeReanimated.runOnJS)(setIsFocused)(!isFocused);
});
const gestures = _reactNativeGestureHandler.Gesture.Exclusive(_reactNativeGestureHandler.Gesture.Race(panGesture, pinchGesture), tap);
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.wrapper,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
gesture: gestures,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.container,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
style: animationContentContainerStyle,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
gesture: doubleTap,
children: children
})
})
})
})
});
});
const styles = _reactNative.StyleSheet.create({
wrapper: {
flex: 1
},
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
overflow: "hidden"
}
});
//# sourceMappingURL=GestureItemComponent.js.map