diff --git a/packages/main/src/components/MessageBox/MessageBox.cy.tsx b/packages/main/src/components/MessageBox/MessageBox.cy.tsx index 3a6be954846..f49ec9343e2 100644 --- a/packages/main/src/components/MessageBox/MessageBox.cy.tsx +++ b/packages/main/src/components/MessageBox/MessageBox.cy.tsx @@ -1,4 +1,5 @@ import addIcon from '@ui5/webcomponents-icons/dist/add.js'; +import { useState } from 'react'; import { Button, Icon, MessageBoxAction, MessageBoxType } from '../..'; import { MessageBox } from './index.js'; @@ -29,6 +30,54 @@ describe('MessageBox', () => { }); }); + it('close event', () => { + const callback = cy.spy().as('close'); + function TestComp() { + const [open, setOpen] = useState(false); + const [type, setType] = useState(''); + return ( + <> + + { + callback(e); + setType(e.type); + setOpen(false); + }} + > + My Message Box Content + + {type} + + ); + } + + cy.mount(); + + cy.findByText('Open').click(); + cy.findByText('OK').click(); + cy.get('@close').should('have.been.calledOnce'); + cy.wrap(callback).should( + 'have.been.calledWith', + Cypress.sinon.match({ + type: 'click' + }) + ); + cy.findByTestId('eventType').should('have.text', 'click'); + + cy.findByText('Open').click(); + cy.realPress('Escape'); + cy.get('@close').should('have.been.calledTwice'); + cy.findByTestId('eventType').should('have.text', 'before-close'); + }); + it('Custom Button', () => { const click = cy.spy().as('onButtonClick'); const close = cy.spy().as('onMessageBoxClose'); diff --git a/packages/main/src/components/MessageBox/index.tsx b/packages/main/src/components/MessageBox/index.tsx index 0b336daded0..e58a67c1cee 100644 --- a/packages/main/src/components/MessageBox/index.tsx +++ b/packages/main/src/components/MessageBox/index.tsx @@ -27,8 +27,8 @@ import { WARNING, YES } from '../../i18n/i18n-defaults.js'; -import { stopPropagation } from '../../internal/stopPropagation.js'; -import type { ButtonPropTypes, DialogDomRef, DialogPropTypes } from '../../webComponents/index.js'; +import type { Ui5CustomEvent } from '../../types/index.js'; +import type { ButtonDomRef, ButtonPropTypes, DialogDomRef, DialogPropTypes } from '../../webComponents/index.js'; import { Button, Dialog, Icon, Title } from '../../webComponents/index.js'; import { Text } from '../Text/index.js'; import { classNames, styleData } from './MessageBox.module.css.js'; @@ -90,9 +90,17 @@ export interface MessageBoxPropTypes */ initialFocus?: MessageBoxActionType; /** - * Callback to be executed when the `MessageBox` is closed (either by pressing on one of the `actions` or by pressing the `ESC` key). `event.detail.action` contains the pressed action button. + * Callback to be executed when the `MessageBox` is closed (either by pressing on one of the `actions` or by pressing the `ESC` key). + * `event.detail.action` contains the pressed action button. + * + * __Note:__ The target of the event differs according to how the user closed the dialog. */ - onClose?: (event: CustomEvent<{ action: MessageBoxActionType }>) => void; + onClose?: ( + //todo adjust this once enrichEventWithDetails forwards the native `detail` + event: + | Ui5CustomEvent + | (MouseEvent & ButtonDomRef & { detail: { action: MessageBoxActionType } }) + ) => void; } const getIcon = (icon, type, classes) => { @@ -188,9 +196,18 @@ const MessageBox = forwardRef((props, ref) => } }; - const handleOnClose = (e) => { - const { action } = e.target.dataset; - stopPropagation(e); + const handleDialogClose: DialogPropTypes['onBeforeClose'] = (e) => { + if (typeof props.onBeforeClose === 'function') { + props.onBeforeClose(e); + } + if (e.detail.escPressed) { + // @ts-expect-error: todo check type + onClose(enrichEventWithDetails(e, { action: undefined })); + } + }; + + const handleOnClose: ButtonPropTypes['onClick'] = (e) => { + const { action } = e.currentTarget.dataset; onClose(enrichEventWithDetails(e, { action })); }; @@ -206,7 +223,7 @@ const MessageBox = forwardRef((props, ref) => }; // @ts-expect-error: footer, headerText and onClose are already omitted via prop types - const { footer: _0, headerText: _1, onClose: _2, ...restWithoutOmitted } = rest; + const { footer: _0, headerText: _1, onClose: _2, onBeforeClose: _3, ...restWithoutOmitted } = rest; const iconToRender = getIcon(icon, type, classNames); const needsCustomHeader = !props.header && !!iconToRender; @@ -216,7 +233,7 @@ const MessageBox = forwardRef((props, ref) => open={open} ref={ref} className={clsx(classNames.messageBox, className)} - onClose={open ? handleOnClose : stopPropagation} + onBeforeClose={handleDialogClose} accessibleNameRef={needsCustomHeader ? `${messageBoxId}-title ${messageBoxId}-text` : undefined} accessibleRole={PopupAccessibleRole.AlertDialog} {...restWithoutOmitted}