react-zoom-pan-pinch
react-zoom-pan-pinch copied to clipboard
[help] How to prevent click event propagation when clicking on an image inside TransformComponent?
Hi, thank you for maintaining this amazing library!
I'm using react-zoom-pan-pinch in my Next.js project, and I encountered an issue with event propagation.
I want to close the modal when the user clicks outside the image area.
I'm trying it out with alerts first.
I think I only need to prevent the event from propagating when the user clicks on the image, but it's not working.
If I comment out the TransformWrapper and TransformComponent, it works as intended.
How can I achieve this while still using the TransformWrapper and TransformComponent?
import type { Dispatch, FC, SetStateAction } from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
TransformWrapper,
TransformComponent,
useControls,
} from "react-zoom-pan-pinch";
import { DialogClose } from "@radix-ui/react-dialog";
import { Minus, Plus, SearchX, X } from "lucide-react";
import { cn } from "@/lib/utils";
type Props = {
open: boolean;
onOpenChange: Dispatch<SetStateAction<boolean>>;
};
const PreviewModal: FC<Props> = ({ open, onOpenChange }) => {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent
className="h-screen min-w-full flex items-center justify-center p-0 border-none bg-transparent"
onClick={() => alert("clicked")}
>
<div className="w-full h-full relative">
<DialogHeader className="absolute top-0 left-0 bg-black w-full z-10 opacity-50 h-14 text-white flex">
<div className="flex items-center justify-between px-4 my-auto">
<div>
<DialogTitle>title</DialogTitle>
<DialogDescription>description</DialogDescription>
</div>
<DialogClose className="rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogClose>
</div>
</DialogHeader>
<TransformWrapper minScale={0.5}>
<MyControl className="absolute bottom-4 left-1/2 transform -translate-x-1/2 z-10" />
<TransformComponent
contentStyle={{
width: "100%",
height: "100%",
}}
wrapperStyle={{
width: "100%",
height: "100%",
}}
>
<div className="w-[calc(100%-24rem)] h-[calc(100%-12rem)] mx-auto my-auto flex bg-red-400">
<img
src="https://placehold.jp/300x200.png"
alt="Preview"
className="max-w-full max-h-full object-contain mx-auto"
onClick={(e) => e.stopPropagation()}
/>
</div>
</TransformComponent>
</TransformWrapper>
</div>
</DialogContent>
</Dialog>
);
};
export default PreviewModal;
type MyControlProps = {
className?: string;
};
const MyControl: FC<MyControlProps> = ({ className }) => {
const { zoomIn, zoomOut, resetTransform } = useControls();
return (
<div
className={cn(
"inline-flex items-center gap-4 rounded-full bg-black/40 p-1 shadow-md",
className
)}
>
<button
type="button"
onClick={() => zoomOut()}
className="rounded-full p-2 text-white"
>
<Minus />
</button>
<button
type="button"
onClick={() => resetTransform()}
className="rounded-full p-2 text-white"
>
<SearchX />
</button>
<button
type="button"
onClick={() => zoomIn()}
className="rounded-full p-2 text-white"
>
<Plus />
</button>
</div>
);
};
If there is any information you are missing, please don't hesitate to let me know. I will provide it immediately.