Skip to content

Commit d8958f8

Browse files
authored
Merge pull request #763 from rpearce/fix/zoom-inside-dialog-with-click-outside
fix: zoom inside dialog that has 'click outside' handler
2 parents 521abc0 + b647071 commit d8958f8

File tree

3 files changed

+87
-16
lines changed

3 files changed

+87
-16
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-medium-image-zoom": patch
3+
---
4+
5+
fixes zooming inside a dialog with click outside behavior

source/Controlled.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro
142142

143143
render() {
144144
const {
145+
handleBtnUnzoomClick,
145146
handleDialogCancel,
146147
handleDialogClick,
147148
handleUnzoom,
@@ -257,7 +258,7 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro
257258
const modalBtnUnzoom = <button
258259
aria-label={a11yNameButtonUnzoom}
259260
data-rmiz-btn-unzoom=""
260-
onClick={handleUnzoom}
261+
onClick={handleBtnUnzoomClick}
261262
type="button"
262263
>
263264
<IconUnzoom />
@@ -531,6 +532,17 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro
531532

532533
// ===========================================================================
533534

535+
/**
536+
* Capture click event when clicking unzoom button
537+
*/
538+
handleBtnUnzoomClick = (e: React.MouseEvent<HTMLButtonElement>) => {
539+
e.preventDefault()
540+
e.stopPropagation()
541+
this.handleUnzoom()
542+
}
543+
544+
// ===========================================================================
545+
534546
/**
535547
* Prevent the browser from removing the dialog on Escape
536548
*/
@@ -545,6 +557,7 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro
545557
*/
546558
handleDialogClick = (e: React.MouseEvent<HTMLDialogElement>) => {
547559
if (e.target === this.refModalContent.current || e.target === this.refModalImg.current) {
560+
e.stopPropagation()
548561
this.handleUnzoom()
549562
}
550563
}

stories/Img.stories.tsx

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function shuffle<T extends unknown[]>(xs: T): T {
4444

4545
// =============================================================================
4646

47-
export const Regular = (props) => {
47+
export const Regular = (props: typeof Zoom) => {
4848
return (
4949
<main aria-label="Story">
5050
<h1>Zooming a regular image</h1>
@@ -65,7 +65,7 @@ export const Regular = (props) => {
6565

6666
// =============================================================================
6767

68-
export const ZoomMargin = (props) => (
68+
export const ZoomMargin = (props: typeof Zoom) => (
6969
<main aria-label="Story">
7070
<h1>Setting a zoomMargin of 45(px)</h1>
7171
<div className="mw-600">
@@ -87,7 +87,7 @@ export const ZoomMargin = (props) => (
8787

8888
// =============================================================================
8989

90-
export const SmallPortrait = (props) => (
90+
export const SmallPortrait = (props: typeof Zoom) => (
9191
<main aria-label="Story">
9292
<h1>A portrait image with a small width specified</h1>
9393
<div className="mw-600">
@@ -107,7 +107,7 @@ export const SmallPortrait = (props) => (
107107

108108
// =============================================================================
109109

110-
export const SVGSource = (props) => (
110+
export const SVGSource = (props: typeof Zoom) => (
111111
<main aria-label="Story">
112112
<h1>An image with an SVG src</h1>
113113
<div className="mw-600">
@@ -144,7 +144,7 @@ export const DataSVGSource = () => (
144144

145145
// =============================================================================
146146

147-
export const ProvideZoomImg = (props) => (
147+
export const ProvideZoomImg = (props: typeof Zoom) => (
148148
<main aria-label="Story">
149149
<h1>
150150
An image with a larger <code>zoomImg</code>
@@ -170,7 +170,7 @@ export const ProvideZoomImg = (props) => (
170170

171171
// =============================================================================
172172

173-
export const SmallSrcSize = (props) => (
173+
export const SmallSrcSize = (props: typeof Zoom) => (
174174
<main aria-label="Story">
175175
<h1>An image with a small size</h1>
176176
<div className="mw-600">
@@ -187,7 +187,7 @@ export const SmallSrcSize = (props) => (
187187

188188
// =============================================================================
189189

190-
export const CustomModalStyles = (props) => {
190+
export const CustomModalStyles = (props: typeof Zoom) => {
191191
return (
192192
<main aria-label="Story">
193193
<h1>Custom Modal Styles</h1>
@@ -242,7 +242,60 @@ export const CustomModalStyles = (props) => {
242242

243243
// =============================================================================
244244

245-
export const ModalFigureCaption = (props) => (
245+
export const ZoomImageFromInsideDialog = (props: typeof Zoom) => {
246+
const refBtn = React.useRef<HTMLButtonElement>(null)
247+
const refModal = React.useRef<HTMLDialogElement>(null)
248+
249+
const handleBtnClick = React.useCallback(() => {
250+
refModal.current?.showModal()
251+
}, [])
252+
253+
React.useEffect(() => {
254+
const handleDocumentClick = (e: MouseEvent) => {
255+
if (
256+
!refBtn.current?.contains(e.target as Element) &&
257+
!refModal.current?.contains(e.target as Element)
258+
) {
259+
refModal.current?.close()
260+
}
261+
}
262+
263+
document.addEventListener('click', handleDocumentClick)
264+
265+
return () => {
266+
document.removeEventListener('click', handleDocumentClick)
267+
}
268+
}, [])
269+
270+
return (
271+
<main aria-label="Story">
272+
<h1>Zoom Image From Inside Dialog</h1>
273+
<div className="mw-600">
274+
<button onClick={handleBtnClick} ref={refBtn} type="button">
275+
Open Modal
276+
</button>
277+
<dialog aria-modal="true" ref={refModal}>
278+
<form method="dialog">
279+
<button type="submit">Close</button>
280+
</form>
281+
<h1>Zooming should work!</h1>
282+
<div>
283+
<Zoom {...props}>
284+
<img
285+
alt={imgGlenorchyLagoon.alt}
286+
src={imgGlenorchyLagoon.src}
287+
width="400"
288+
/>
289+
</Zoom>
290+
</div>
291+
</dialog>
292+
</div>
293+
</main>
294+
)
295+
}
296+
// =============================================================================
297+
298+
export const ModalFigureCaption = (props: typeof Zoom) => (
246299
<main aria-label="Story">
247300
<h1>Modal With Figure And Caption</h1>
248301
<p>
@@ -369,7 +422,7 @@ const DelayedImg = (props: DelayedImgProps) => {
369422
)
370423
}
371424

372-
export const DelayedImageRender = (props) => {
425+
export const DelayedImageRender = (props: typeof Zoom) => {
373426
const { timer } = useTimer(5000)
374427

375428
return (
@@ -400,7 +453,7 @@ export const DelayedImageRender = (props) => {
400453

401454
// =============================================================================
402455

403-
export const DelayedDisplayNone = (props) => {
456+
export const DelayedDisplayNone = (props: typeof Zoom) => {
404457
const { timer } = useTimer(5000)
405458
const classImg = timer === 0 ? undefined : 'display-none'
406459

@@ -434,7 +487,7 @@ export const DelayedDisplayNone = (props) => {
434487

435488
// =============================================================================
436489

437-
export const CustomButtonIcons = (props) => {
490+
export const CustomButtonIcons = (props: typeof Zoom) => {
438491
React.useEffect(() => {
439492
document.body.classList.add('change-icons')
440493

@@ -464,7 +517,7 @@ export const CustomButtonIcons = (props) => {
464517

465518
// =============================================================================
466519

467-
export const InlineImage = (props) => (
520+
export const InlineImage = (props: typeof Zoom) => (
468521
<main aria-label="Story">
469522
<h1>Inline Image</h1>
470523
<p className="inline">
@@ -484,7 +537,7 @@ export const InlineImage = (props) => (
484537

485538
// =============================================================================
486539

487-
export const CycleImages = (props) => {
540+
export const CycleImages = (props: typeof Zoom) => {
488541
const [img, setImg] = React.useState(imgThatWanakaTree)
489542

490543
React.useEffect(() => {
@@ -533,7 +586,7 @@ export const CycleImages = (props) => {
533586

534587
// =============================================================================
535588

536-
export const SwipeToUnzoomDisabled = (props) => (
589+
export const SwipeToUnzoomDisabled = (props: typeof Zoom) => (
537590
<main aria-label="Story">
538591
<h1>Swipe to Unzoom Disabled</h1>
539592
<p>
@@ -555,7 +608,7 @@ export const SwipeToUnzoomDisabled = (props) => (
555608
</main>
556609
)
557610

558-
export const SwipeToUnzoomThreshold = (props) => (
611+
export const SwipeToUnzoomThreshold = (props: typeof Zoom) => (
559612
<main aria-label="Story">
560613
<h1>Swipe to Unzoom Threshold</h1>
561614
<p>

0 commit comments

Comments
 (0)