diff --git a/src/Dialog/index.tsx b/src/Dialog/index.tsx index 5e509097..d714eaeb 100644 --- a/src/Dialog/index.tsx +++ b/src/Dialog/index.tsx @@ -110,37 +110,27 @@ const Dialog: React.FC = (props) => { } // >>> Content - const contentClickRef = useRef(false); - const contentTimeoutRef = useRef>(null); - - // We need record content click in case content popup out of dialog - const onContentMouseDown: React.MouseEventHandler = () => { - clearTimeout(contentTimeoutRef.current); - contentClickRef.current = true; - }; - - const onContentMouseUp: React.MouseEventHandler = () => { - contentTimeoutRef.current = setTimeout(() => { - contentClickRef.current = false; - }); - }; + const mouseDownOnMaskRef = useRef(false); // >>> Wrapper // Close only when element not on dialog let onWrapperClick: (e: React.SyntheticEvent) => void = null; if (maskClosable) { onWrapperClick = (e) => { - if (contentClickRef.current) { - contentClickRef.current = false; - } else if (wrapperRef.current === e.target) { + if (wrapperRef.current === e.target && mouseDownOnMaskRef.current) { onInternalClose(e); } }; } + function onWrapperMouseDown(e: React.MouseEvent) { + mouseDownOnMaskRef.current = e.target === wrapperRef.current; + } + // ========================= Effect ========================= useEffect(() => { if (visible) { + mouseDownOnMaskRef.current = false; setAnimatedVisible(true); saveLastOutSideActiveElementRef(); @@ -158,14 +148,6 @@ const Dialog: React.FC = (props) => { } }, [visible]); - // Remove direct should also check the scroll bar update - useEffect( - () => () => { - clearTimeout(contentTimeoutRef.current); - }, - [], - ); - const mergedStyle: React.CSSProperties = { zIndex, ...wrapStyle, @@ -192,14 +174,13 @@ const Dialog: React.FC = (props) => { className={clsx(`${prefixCls}-wrap`, wrapClassName, modalClassNames?.wrapper)} ref={wrapperRef} onClick={onWrapperClick} + onMouseDown={onWrapperMouseDown} style={mergedStyle} {...wrapProps} > { const { rerender } = render(); // Mask close - fireEvent.click(document.querySelector('.rc-dialog-wrap')); + const mask = document.querySelector('.rc-dialog-wrap'); + fireEvent.mouseDown(mask); + fireEvent.mouseUp(mask); + fireEvent.click(mask); jest.runAllTimers(); expect(onClose).toHaveBeenCalled(); onClose.mockReset(); @@ -185,6 +188,30 @@ describe('dialog', () => { expect(onClose).not.toHaveBeenCalled(); }); + it('should not close when dragging from content to mask', () => { + const onClose = jest.fn(); + const { getByText } = render( + + Content + + ); + + jest.runAllTimers(); + + const content = getByText('Content'); + const mask = document.querySelector('.rc-dialog-wrap'); + if (!mask) throw new Error('Mask not found'); + + // Simulate mouse down on content + fireEvent.mouseDown(content); + // Simulate mouse up on mask + fireEvent.mouseUp(mask); + // Simulate click on mask (since click follows mouseup) + fireEvent.click(mask); + + expect(onClose).not.toHaveBeenCalled(); + }); + it('renderToBody', () => { const container = document.createElement('div'); document.body.appendChild(container);