From c550ba7c720409b6e4d496cf247492c16f8b2dd7 Mon Sep 17 00:00:00 2001 From: "Robert W. Pearce" Date: Mon, 11 Nov 2024 21:29:21 -0500 Subject: [PATCH] fix: zoom inside dialog that has 'click outside' handler --- source/Controlled.tsx | 15 +++++++- stories/Img.stories.tsx | 85 +++++++++++++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/source/Controlled.tsx b/source/Controlled.tsx index b4b4ab81..108524e6 100644 --- a/source/Controlled.tsx +++ b/source/Controlled.tsx @@ -142,6 +142,7 @@ class ControlledBase extends React.Component @@ -531,6 +532,17 @@ class ControlledBase extends React.Component) => { + e.preventDefault() + e.stopPropagation() + this.handleUnzoom() + } + + // =========================================================================== + /** * Prevent the browser from removing the dialog on Escape */ @@ -545,6 +557,7 @@ class ControlledBase extends React.Component) => { if (e.target === this.refModalContent.current || e.target === this.refModalImg.current) { + e.stopPropagation() this.handleUnzoom() } } diff --git a/stories/Img.stories.tsx b/stories/Img.stories.tsx index 07fa2a18..bce269cd 100644 --- a/stories/Img.stories.tsx +++ b/stories/Img.stories.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { MouseEventHandler } from 'react' import type { Meta } from '@storybook/react' import { waitFor, within, userEvent, expect } from '@storybook/test' @@ -44,7 +44,7 @@ function shuffle(xs: T): T { // ============================================================================= -export const Regular = (props) => { +export const Regular = (props: typeof Zoom) => { return (

Zooming a regular image

@@ -65,7 +65,7 @@ export const Regular = (props) => { // ============================================================================= -export const ZoomMargin = (props) => ( +export const ZoomMargin = (props: typeof Zoom) => (

Setting a zoomMargin of 45(px)

@@ -87,7 +87,7 @@ export const ZoomMargin = (props) => ( // ============================================================================= -export const SmallPortrait = (props) => ( +export const SmallPortrait = (props: typeof Zoom) => (

A portrait image with a small width specified

@@ -107,7 +107,7 @@ export const SmallPortrait = (props) => ( // ============================================================================= -export const SVGSource = (props) => ( +export const SVGSource = (props: typeof Zoom) => (

An image with an SVG src

@@ -144,7 +144,7 @@ export const DataSVGSource = () => ( // ============================================================================= -export const ProvideZoomImg = (props) => ( +export const ProvideZoomImg = (props: typeof Zoom) => (

An image with a larger zoomImg @@ -170,7 +170,7 @@ export const ProvideZoomImg = (props) => ( // ============================================================================= -export const SmallSrcSize = (props) => ( +export const SmallSrcSize = (props: typeof Zoom) => (

An image with a small size

@@ -187,7 +187,7 @@ export const SmallSrcSize = (props) => ( // ============================================================================= -export const CustomModalStyles = (props) => { +export const CustomModalStyles = (props: typeof Zoom) => { return (

Custom Modal Styles

@@ -242,7 +242,60 @@ export const CustomModalStyles = (props) => { // ============================================================================= -export const ModalFigureCaption = (props) => ( +export const ZoomImageFromInsideDialog = (props: typeof Zoom) => { + const refBtn = React.useRef(null) + const refModal = React.useRef(null) + + const handleBtnClick = React.useCallback(() => { + refModal.current?.showModal() + }, []) + + React.useEffect(() => { + const handleDocumentClick = (e: MouseEvent) => { + if ( + !refBtn.current?.contains(e.target as Element) && + !refModal.current?.contains(e.target as Element) + ) { + refModal.current?.close() + } + } + + document.addEventListener('click', handleDocumentClick) + + return () => { + document.removeEventListener('click', handleDocumentClick) + } + }, []) + + return ( +
+

Zoom Image From Inside Dialog

+
+ + +
+ +
+

Zooming should work!

+
+ + {imgGlenorchyLagoon.alt} + +
+
+
+
+ ) +} +// ============================================================================= + +export const ModalFigureCaption = (props: typeof Zoom) => (

Modal With Figure And Caption

@@ -369,7 +422,7 @@ const DelayedImg = (props: DelayedImgProps) => { ) } -export const DelayedImageRender = (props) => { +export const DelayedImageRender = (props: typeof Zoom) => { const { timer } = useTimer(5000) return ( @@ -400,7 +453,7 @@ export const DelayedImageRender = (props) => { // ============================================================================= -export const DelayedDisplayNone = (props) => { +export const DelayedDisplayNone = (props: typeof Zoom) => { const { timer } = useTimer(5000) const classImg = timer === 0 ? undefined : 'display-none' @@ -434,7 +487,7 @@ export const DelayedDisplayNone = (props) => { // ============================================================================= -export const CustomButtonIcons = (props) => { +export const CustomButtonIcons = (props: typeof Zoom) => { React.useEffect(() => { document.body.classList.add('change-icons') @@ -464,7 +517,7 @@ export const CustomButtonIcons = (props) => { // ============================================================================= -export const InlineImage = (props) => ( +export const InlineImage = (props: typeof Zoom) => (

Inline Image

@@ -484,7 +537,7 @@ export const InlineImage = (props) => ( // ============================================================================= -export const CycleImages = (props) => { +export const CycleImages = (props: typeof Zoom) => { const [img, setImg] = React.useState(imgThatWanakaTree) React.useEffect(() => { @@ -533,7 +586,7 @@ export const CycleImages = (props) => { // ============================================================================= -export const SwipeToUnzoomDisabled = (props) => ( +export const SwipeToUnzoomDisabled = (props: typeof Zoom) => (

Swipe to Unzoom Disabled

@@ -555,7 +608,7 @@ export const SwipeToUnzoomDisabled = (props) => (

) -export const SwipeToUnzoomThreshold = (props) => ( +export const SwipeToUnzoomThreshold = (props: typeof Zoom) => (

Swipe to Unzoom Threshold