Skip to content

Commit

Permalink
fix: zoom inside dialog that has 'click outside' handler
Browse files Browse the repository at this point in the history
  • Loading branch information
rpearce committed Nov 12, 2024
1 parent e97307e commit c550ba7
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 17 deletions.
15 changes: 14 additions & 1 deletion source/Controlled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro

render() {
const {
handleBtnUnzoomClick,
handleDialogCancel,
handleDialogClick,
handleUnzoom,
Expand Down Expand Up @@ -257,7 +258,7 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro
const modalBtnUnzoom = <button
aria-label={a11yNameButtonUnzoom}
data-rmiz-btn-unzoom=""
onClick={handleUnzoom}
onClick={handleBtnUnzoomClick}
type="button"
>
<IconUnzoom />
Expand Down Expand Up @@ -531,6 +532,17 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro

// ===========================================================================

/**
* Capture click event when clicking unzoom button
*/
handleBtnUnzoomClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
e.stopPropagation()
this.handleUnzoom()
}

// ===========================================================================

/**
* Prevent the browser from removing the dialog on Escape
*/
Expand All @@ -545,6 +557,7 @@ class ControlledBase extends React.Component<ControlledPropsWithDefaults, Contro
*/
handleDialogClick = (e: React.MouseEvent<HTMLDialogElement>) => {
if (e.target === this.refModalContent.current || e.target === this.refModalImg.current) {
e.stopPropagation()
this.handleUnzoom()
}
}
Expand Down
85 changes: 69 additions & 16 deletions stories/Img.stories.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -44,7 +44,7 @@ function shuffle<T extends unknown[]>(xs: T): T {

// =============================================================================

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

// =============================================================================

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

// =============================================================================

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

// =============================================================================

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

// =============================================================================

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

// =============================================================================

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

// =============================================================================

export const CustomModalStyles = (props) => {
export const CustomModalStyles = (props: typeof Zoom) => {
return (
<main aria-label="Story">
<h1>Custom Modal Styles</h1>
Expand Down Expand Up @@ -242,7 +242,60 @@ export const CustomModalStyles = (props) => {

// =============================================================================

export const ModalFigureCaption = (props) => (
export const ZoomImageFromInsideDialog = (props: typeof Zoom) => {
const refBtn = React.useRef<HTMLButtonElement>(null)
const refModal = React.useRef<HTMLDialogElement>(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 (
<main aria-label="Story">
<h1>Zoom Image From Inside Dialog</h1>
<div className="mw-600">
<button onClick={handleBtnClick} ref={refBtn} type="button">
Open Modal
</button>
<dialog aria-modal="true" ref={refModal}>
<form method="dialog">
<button type="submit">Close</button>
</form>
<h1>Zooming should work!</h1>
<div>
<Zoom {...props}>
<img
alt={imgGlenorchyLagoon.alt}
src={imgGlenorchyLagoon.src}
width="400"
/>
</Zoom>
</div>
</dialog>
</div>
</main>
)
}
// =============================================================================

export const ModalFigureCaption = (props: typeof Zoom) => (
<main aria-label="Story">
<h1>Modal With Figure And Caption</h1>
<p>
Expand Down Expand Up @@ -369,7 +422,7 @@ const DelayedImg = (props: DelayedImgProps) => {
)
}

export const DelayedImageRender = (props) => {
export const DelayedImageRender = (props: typeof Zoom) => {
const { timer } = useTimer(5000)

return (
Expand Down Expand Up @@ -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'

Expand Down Expand Up @@ -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')

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

// =============================================================================

export const InlineImage = (props) => (
export const InlineImage = (props: typeof Zoom) => (
<main aria-label="Story">
<h1>Inline Image</h1>
<p className="inline">
Expand All @@ -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(() => {
Expand Down Expand Up @@ -533,7 +586,7 @@ export const CycleImages = (props) => {

// =============================================================================

export const SwipeToUnzoomDisabled = (props) => (
export const SwipeToUnzoomDisabled = (props: typeof Zoom) => (
<main aria-label="Story">
<h1>Swipe to Unzoom Disabled</h1>
<p>
Expand All @@ -555,7 +608,7 @@ export const SwipeToUnzoomDisabled = (props) => (
</main>
)

export const SwipeToUnzoomThreshold = (props) => (
export const SwipeToUnzoomThreshold = (props: typeof Zoom) => (
<main aria-label="Story">
<h1>Swipe to Unzoom Threshold</h1>
<p>
Expand Down

0 comments on commit c550ba7

Please sign in to comment.