Skip to content

Commit

Permalink
fix: Portal event bubble (#204)
Browse files Browse the repository at this point in the history
* fix: Portal event popup

* test: Add test case
  • Loading branch information
zombieJ committed Oct 11, 2020
1 parent 4cc8bc0 commit 8feb251
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 2 deletions.
8 changes: 7 additions & 1 deletion examples/ant-design.tsx
@@ -1,6 +1,8 @@
/* eslint no-console:0 */
import '../assets/index.less';
import * as React from 'react';
import Select from 'rc-select';
import 'rc-select/assets/index.less';
import Dialog from '../src/DialogWrap';

const clearPath =
Expand Down Expand Up @@ -133,7 +135,11 @@ const MyControl = () => {
<button type="button" onClick={toggleCloseIcon}>
use custom icon, is using icon: {(useIcon && 'true') || 'false'}.
</button>
<div style={{ height: 200 }} />
<div style={{ height: 200 }}>
<Select dropdownStyle={{ zIndex: 9999999 }}>
<Select.Option value="light">Light</Select.Option>
</Select>
</div>
</Dialog>
);

Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -69,6 +69,7 @@
"np": "^6.4.0",
"prettier": "^2.1.1",
"rc-drawer": "4.1.0",
"rc-select": "^11.4.1",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-draggable": "^4.4.3",
Expand Down
3 changes: 3 additions & 0 deletions src/Dialog/Content.tsx
Expand Up @@ -11,6 +11,7 @@ export interface ContentProps extends IDialogChildProps {
motionName: string;
ariaId: string;
onVisibleChanged: (visible: boolean) => void;
onClick: React.MouseEventHandler;
}

export interface ContentRef {
Expand Down Expand Up @@ -41,6 +42,7 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
ariaId,
onClose,
onVisibleChanged,
onClick,
mousePosition,
} = props;

Expand Down Expand Up @@ -142,6 +144,7 @@ const Content = React.forwardRef<ContentRef, ContentProps>((props, ref) => {
ref={motionRef}
style={{ ...motionStyle, ...style, ...contentStyle }}
className={classNames(prefixCls, className, motionClassName)}
onClick={onClick}
>
<div tabIndex={0} ref={sentinelStartRef} style={sentinelStyle} aria-hidden="true" />
{modalRender ? modalRender(content) : content}
Expand Down
21 changes: 20 additions & 1 deletion src/Dialog/index.tsx
Expand Up @@ -88,12 +88,29 @@ export default function Dialog(props: IDialogChildProps) {
onClose?.(e);
}

// >>> Content
const contentClickRef = useRef(false);
const contentTimeoutRef = useRef<number>();

// We need record content click incase content popup out of dialog
const onContentClick: React.MouseEventHandler = () => {
clearTimeout(contentTimeoutRef.current);
contentClickRef.current = true;

contentTimeoutRef.current = setTimeout(() => {
contentClickRef.current = false;
});
};

// >>> Wrapper
// Close only when element not on dialog
let onWrapperClick: (e: React.SyntheticEvent) => void = null;
if (maskClosable) {
onWrapperClick = (e) => {
if (!contains(contentRef.current.getDOM(), e.target as HTMLElement)) {
if (
!contentClickRef.current &&
!contains(contentRef.current.getDOM(), e.target as HTMLElement)
) {
onInternalClose(e);
}
};
Expand Down Expand Up @@ -126,6 +143,7 @@ export default function Dialog(props: IDialogChildProps) {
useEffect(
() => () => {
switchScrollingEffect();
clearTimeout(contentTimeoutRef.current);
},
[],
);
Expand Down Expand Up @@ -156,6 +174,7 @@ export default function Dialog(props: IDialogChildProps) {
>
<Content
{...props}
onClick={onContentClick}
ref={contentRef}
closable={closable}
ariaId={ariaIdRef.current}
Expand Down
39 changes: 39 additions & 0 deletions tests/portal.spec.tsx
@@ -0,0 +1,39 @@
/* eslint-disable react/no-render-return-value, max-classes-per-file, func-names, no-console */
import React from 'react';
import Select from 'rc-select';
import { act } from 'react-dom/test-utils';
import { mount } from 'enzyme';
import Dialog from '../src';

/**
* Since overflow scroll test need a clear env which may affect by other test.
* Use a clean env instead.
*/
describe('Dialog.Portal', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.useRealTimers();
});

it('event should bubble', () => {
const onClose = jest.fn();

const wrapper = mount(
<Dialog onClose={onClose} visible>
<Select virtual={false} open>
<Select.Option value="bamboo">Bamboo</Select.Option>
</Select>
</Dialog>,
);

act(() => {
jest.runAllTimers();
});

wrapper.find('.rc-select-item-option-content').simulate('click');
expect(onClose).not.toHaveBeenCalled();
});
});

1 comment on commit 8feb251

@vercel
Copy link

@vercel vercel bot commented on 8feb251 Oct 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.