diff --git a/.changeset/popular-jokes-kiss.md b/.changeset/popular-jokes-kiss.md new file mode 100644 index 00000000000..5ceab42ea24 --- /dev/null +++ b/.changeset/popular-jokes-kiss.md @@ -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. diff --git a/packages/react/src/Dialog/Dialog.test.tsx b/packages/react/src/Dialog/Dialog.test.tsx index 8dcfbe31160..f1d33d57d49 100644 --- a/packages/react/src/Dialog/Dialog.test.tsx +++ b/packages/react/src/Dialog/Dialog.test.tsx @@ -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(Pay attention to me) + + 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 () => { @@ -80,7 +95,7 @@ describe('Dialog', () => { await user.keyboard('{Escape}') - expect(onClose).toHaveBeenCalled() + expect(onClose).toHaveBeenCalledWith('escape') }) it('changes the style for `overflow` if it is not set to "hidden"', () => { diff --git a/packages/react/src/Dialog/Dialog.tsx b/packages/react/src/Dialog/Dialog.tsx index 81692f9ae45..40026326b58 100644 --- a/packages/react/src/Dialog/Dialog.tsx +++ b/packages/react/src/Dialog/Dialog.tsx @@ -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' @@ -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 @@ -414,6 +414,14 @@ const _Dialog = React.forwardRef { + if (e.target === e.currentTarget) { + onClose('escape') + } + }, + [onClose], + ) const dialogRef = useRef(null) useRefObjectAsForwardedRef(forwardedRef, dialogRef) @@ -465,7 +473,7 @@ const _Dialog = React.forwardRef - +