@@ -342,87 +342,101 @@ function MediaEditorModalContent( {
342342 } ;
343343
344344 return (
345- < >
346- < Modal
347- className = "media-editor-modal"
348- title = { __ ( 'Edit media' ) }
349- size = "fill"
350- isDismissible = { false }
351- shouldCloseOnEsc = { ! hasChanges }
352- shouldCloseOnClickOutside = { ! hasChanges }
353- onRequestClose = { handleRequestClose }
354- headerActions = {
355- < HeaderActions
356- isSaving = { isSaving }
357- hasMedia = { ! ! media }
358- hasChanges = { hasChanges }
359- onCancel = { handleRequestClose }
360- onSave = { handleSave }
361- />
345+ < Modal
346+ className = "media-editor-modal"
347+ title = { __ ( 'Edit media' ) }
348+ size = "fill"
349+ isDismissible = { false }
350+ shouldCloseOnClickOutside = { ! hasChanges }
351+ onKeyDown = { ( event ) => {
352+ // When there are pending changes, intercept ESC and
353+ // open the confirm dialog ourselves. `preventDefault`
354+ // short-circuits Modal's own ESC-to-close handler on
355+ // the overlay so the modal doesn't animate out before
356+ // the dialog appears.
357+ if (
358+ hasChanges &&
359+ ( event . code === 'Escape' || event . key === 'Escape' )
360+ ) {
361+ event . preventDefault ( ) ;
362+ setIsDiscardDialogOpen ( true ) ;
362363 }
364+ } }
365+ onRequestClose = { handleRequestClose }
366+ headerActions = {
367+ < HeaderActions
368+ isSaving = { isSaving }
369+ hasMedia = { ! ! media }
370+ hasChanges = { hasChanges }
371+ onCancel = { handleRequestClose }
372+ onSave = { handleSave }
373+ />
374+ }
375+ >
376+ < MediaEditorProvider
377+ value = { media ?? undefined }
378+ onChange = { handleChange }
379+ settings = { { fields } }
363380 >
364- < MediaEditorProvider
365- value = { media ?? undefined }
366- onChange = { handleChange }
367- settings = { { fields } }
368- >
369- { ! media ? (
370- < Spinner />
371- ) : (
372- < >
373- < Tabs >
374- < MediaEditorModalSidebar tabs = { tabs } />
375- </ Tabs >
376- < InterfaceSkeleton
377- className = "media-editor-modal__skeleton"
378- content = {
379- < div className = "media-editor-modal__canvas" >
380- { isImage ? (
381- < MediaEditorCanvas
382- aspectRatio = { resolveAspectRatio (
383- aspectRatioValue ,
384- imageAspectRatio
385- ) }
386- freeformCrop = { freeformCrop }
387- />
388- ) : (
389- < MediaPreview />
390- ) }
391- </ div >
392- }
393- footer = {
394- isImage ? (
395- < MediaEditorToolbar
396- onReset = { ( ) => {
397- setAspectRatioValue ( '0' ) ;
398- setFreeformCrop ( true ) ;
399- } }
381+ { ! media ? (
382+ < Spinner />
383+ ) : (
384+ < >
385+ < Tabs >
386+ < MediaEditorModalSidebar tabs = { tabs } />
387+ </ Tabs >
388+ < InterfaceSkeleton
389+ className = "media-editor-modal__skeleton"
390+ content = {
391+ < div className = "media-editor-modal__canvas" >
392+ { isImage ? (
393+ < MediaEditorCanvas
394+ aspectRatio = { resolveAspectRatio (
395+ aspectRatioValue ,
396+ imageAspectRatio
397+ ) }
398+ freeformCrop = { freeformCrop }
400399 />
401- ) : undefined
402- }
403- sidebar = {
404- < ComplementaryArea . Slot scope = "media-editor" />
405- }
406- />
407- </ >
408- ) }
409- </ MediaEditorProvider >
410- </ Modal >
411- < ConfirmDialog
412- isOpen = { isDiscardDialogOpen }
413- confirmButtonText = { __ ( 'Discard' ) }
414- cancelButtonText = { __ ( 'Keep editing' ) }
415- onCancel = { ( ) => setIsDiscardDialogOpen ( false ) }
416- onConfirm = { ( ) => {
417- setIsDiscardDialogOpen ( false ) ;
418- discardAndClose ( ) ;
419- } }
420- >
421- { __ (
422- 'Are you sure you want to discard your unsaved changes?'
400+ ) : (
401+ < MediaPreview />
402+ ) }
403+ </ div >
404+ }
405+ footer = {
406+ isImage ? (
407+ < MediaEditorToolbar
408+ onReset = { ( ) => {
409+ setAspectRatioValue ( '0' ) ;
410+ setFreeformCrop ( true ) ;
411+ } }
412+ />
413+ ) : undefined
414+ }
415+ sidebar = {
416+ < ComplementaryArea . Slot scope = "media-editor" />
417+ }
418+ />
419+ </ >
423420 ) }
424- </ ConfirmDialog >
425- </ >
421+ { /* Rendered inside the parent Modal so it's tracked as
422+ a nested dismisser. As a top-level sibling it would,
423+ on mount, request the parent Modal close. */ }
424+ < ConfirmDialog
425+ isOpen = { isDiscardDialogOpen }
426+ confirmButtonText = { __ ( 'Discard' ) }
427+ cancelButtonText = { __ ( 'Keep editing' ) }
428+ onCancel = { ( ) => setIsDiscardDialogOpen ( false ) }
429+ onConfirm = { ( ) => {
430+ setIsDiscardDialogOpen ( false ) ;
431+ discardAndClose ( ) ;
432+ } }
433+ >
434+ { __ (
435+ 'Are you sure you want to discard your unsaved changes?'
436+ ) }
437+ </ ConfirmDialog >
438+ </ MediaEditorProvider >
439+ </ Modal >
426440 ) ;
427441}
428442
0 commit comments