diff --git a/packages/fluentui/CHANGELOG.md b/packages/fluentui/CHANGELOG.md index 36faefd1d1525..b69fec65b93b4 100644 --- a/packages/fluentui/CHANGELOG.md +++ b/packages/fluentui/CHANGELOG.md @@ -30,6 +30,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - fix `Tooltip` constrast style for pointing and subtle=false @yuanboxue-amber ([#22696](https://github.com/microsoft/fluentui/pull/22696)) - Vertical menu background color should not change on focus in dark theme @yuanboxue-amber ([#22707](https://github.com/microsoft/fluentui/pull/22707)) - Align `default` scheme colors between v0 and v9 @jurokapsiar ([#22699](https://github.com/microsoft/fluentui/pull/22699)) +- Fix `Dialog` to keep it open when press click on content and release outside @yuanboxue-amber ([#22849](https://github.com/microsoft/fluentui/pull/22849)) - Align Avatar `font-weight` between v0 and v9 @annabratseiko ([#22822](https://github.com/microsoft/fluentui/pull/22822)) - Fix `Pill` to be selectable by keyboard @chpalac ([#22839](https://github.com/microsoft/fluentui/pull/22839)) diff --git a/packages/fluentui/e2e/tests/dialog-example.tsx b/packages/fluentui/e2e/tests/dialog-example.tsx new file mode 100644 index 0000000000000..9780b7f8a0d53 --- /dev/null +++ b/packages/fluentui/e2e/tests/dialog-example.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { Button, Dialog } from '@fluentui/react-northstar'; + +export const selectors = { + trigger: 'trigger', + cancelButton: 'cancelButton', +}; + +const DialogBlockBodyScrollExample = () => ( + } + /> +); + +export default DialogBlockBodyScrollExample; diff --git a/packages/fluentui/e2e/tests/dialog.spec.ts b/packages/fluentui/e2e/tests/dialog.spec.ts new file mode 100644 index 0000000000000..1b301af7b2f9c --- /dev/null +++ b/packages/fluentui/e2e/tests/dialog.spec.ts @@ -0,0 +1,50 @@ +import { selectors } from './dialog-example'; + +describe('Dialog', () => { + const trigger = `#${selectors.trigger}`; + const cancelButton = `#${selectors.cancelButton}`; + + beforeEach(() => { + cy.gotoTestCase(__filename, trigger); + cy.get('body').click('bottomRight'); + }); + + it('should open on click trigger', () => { + cy.clickOn(trigger); + cy.visible(cancelButton); + }); + + it('should close on click cancel button', () => { + cy.clickOn(trigger); + cy.visible(cancelButton); + + cy.clickOn(cancelButton); + cy.notExist(cancelButton); + }); + + it('should close on click overlay', () => { + cy.clickOn(trigger); + cy.visible(cancelButton); + + cy.get('.ui-dialog__overlay').click('topLeft'); + cy.notExist(cancelButton); + }); + + it('should keep open when mouse down on button, and drag mouse outside of Dialog', () => { + cy.clickOn(trigger); + cy.visible(cancelButton); + + // press click within Dialog content, drag mouse outside of Dialog content + cy.get(cancelButton).trigger('mousedown', { eventConstructor: 'MouseEvent', button: 0 }).trigger('mousemove', { + eventConstructor: 'MouseEvent', + clientX: 1, + clientY: 1, + pageX: 1, + pageY: 1, + screenX: 1, + screenY: 1, + }); // move mouse to top-left corner + cy.get('.ui-dialog__overlay').click('topLeft'); + cy.visible(cancelButton); + }); +}); diff --git a/packages/fluentui/react-northstar/src/components/Dialog/Dialog.tsx b/packages/fluentui/react-northstar/src/components/Dialog/Dialog.tsx index 806ff2f355010..e7dbdf5706a7d 100644 --- a/packages/fluentui/react-northstar/src/components/Dialog/Dialog.tsx +++ b/packages/fluentui/react-northstar/src/components/Dialog/Dialog.tsx @@ -258,10 +258,24 @@ export const Dialog = (React.forwardRef((props, ref }, }); + // when press left click on Dialog content and hold, and mouse up on Dialog overlay, Dialog should keep open + const isMouseDownInsideContent = React.useRef(false); + const registerMouseDownOnDialogContent = (e: React.MouseEvent) => { + if (e.button === 0) { + isMouseDownInsideContent.current = true; + } + if (unhandledProps.onMouseDown) { + _.invoke(unhandledProps, 'onMouseDown', e); + } + }; + const handleOverlayClick = (e: MouseEvent) => { // Dialog has different conditions to close than Popup, so we don't need to iterate across all // refs - const isInsideContentClick = doesNodeContainClick(contentRef.current, e, context.target); + const isInsideContentClick = + isMouseDownInsideContent.current || doesNodeContainClick(contentRef.current, e, context.target); + isMouseDownInsideContent.current = false; + const isInsideOverlayClick = doesNodeContainClick(overlayRef.current, e, context.target); const shouldClose = !isInsideContentClick && isInsideOverlayClick; @@ -318,6 +332,7 @@ export const Dialog = (React.forwardRef((props, ref className: classes.root, ref, ...unhandledProps, + onMouseDown: registerMouseDownOnDialogContent, })} > {Header.create(header, {