Skip to content

Commit

Permalink
Trigger onClose when Dialog backdrop is clicked (#4613)
Browse files Browse the repository at this point in the history
* Trigger onClose when Dialog backdrop is clicked

* Update docs with new backdrop gesture

* refactor: re-use escape gesture for backdrop click

* chore: update changeset

* docs: update jsdoc for handler

* chore: run format

* test: update test to call for escape instead of backdrop

---------

Co-authored-by: Dusty Greif <dustin.greif@gmail.com>
Co-authored-by: Josh Black <joshblack@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 11, 2024
1 parent f252337 commit eb2ab13
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-jokes-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

`Dialog` and `ConfirmationDialog` can now be closed by clicking on the backdrop surrounding the dialog. This will cause `onClose` to be called with the `escape` gesture.
19 changes: 17 additions & 2 deletions packages/react/src/Dialog/Dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,22 @@ describe('Dialog', () => {

await user.click(getByLabelText('Close'))

expect(onClose).toHaveBeenCalled()
expect(onClose).toHaveBeenCalledWith('close-button')
expect(onClose).toHaveBeenCalledTimes(1) // Ensure it's not called with a backdrop gesture as well
})

it('calls `onClose` when clicking the backdrop', async () => {
const user = userEvent.setup()
const onClose = jest.fn()
const {getByRole} = render(<Dialog onClose={onClose}>Pay attention to me</Dialog>)

expect(onClose).not.toHaveBeenCalled()

const dialog = getByRole('dialog')
const backdrop = dialog.parentElement!
await user.click(backdrop)

expect(onClose).toHaveBeenCalledWith('escape')
})

it('calls `onClose` when keying "Escape"', async () => {
Expand All @@ -80,7 +95,7 @@ describe('Dialog', () => {

await user.keyboard('{Escape}')

expect(onClose).toHaveBeenCalled()
expect(onClose).toHaveBeenCalledWith('escape')
})

it('changes the <body> style for `overflow` if it is not set to "hidden"', () => {
Expand Down
16 changes: 12 additions & 4 deletions packages/react/src/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useRef, useState} from 'react'
import React, {useCallback, useEffect, useRef, useState, type SyntheticEvent} from 'react'
import styled from 'styled-components'
import type {ButtonProps} from '../Button'
import {Button} from '../Button'
Expand Down Expand Up @@ -98,9 +98,9 @@ export interface DialogProps extends SxProp {

/**
* This method is invoked when a gesture to close the dialog is used (either
* an Escape key press or clicking the "X" in the top-right corner). The
* an Escape key press, clicking the backdrop, or clicking the "X" in the top-right corner). The
* gesture argument indicates the gesture that was used to close the dialog
* (either 'close-button' or 'escape').
* ('close-button' or 'escape').
*/
onClose: (gesture: 'close-button' | 'escape') => void

Expand Down Expand Up @@ -414,6 +414,14 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP
}
}
const defaultedProps = {...props, title, subtitle, role, dialogLabelId, dialogDescriptionId}
const onBackdropClick = useCallback(
(e: SyntheticEvent) => {
if (e.target === e.currentTarget) {
onClose('escape')
}
},
[onClose],
)

const dialogRef = useRef<HTMLDivElement>(null)
useRefObjectAsForwardedRef(forwardedRef, dialogRef)
Expand Down Expand Up @@ -465,7 +473,7 @@ const _Dialog = React.forwardRef<HTMLDivElement, React.PropsWithChildren<DialogP
return (
<>
<Portal>
<Backdrop ref={backdropRef} {...positionDataAttributes}>
<Backdrop ref={backdropRef} {...positionDataAttributes} onClick={onBackdropClick}>
<StyledDialog
width={width}
height={height}
Expand Down

0 comments on commit eb2ab13

Please sign in to comment.