Skip to content

Commit

Permalink
Merge pull request #594 from nia3y/feature/fix-popup
Browse files Browse the repository at this point in the history
fix(popup):  嵌套浮层内触发 mouseDown、click 时不应该关闭上一级的浮层
  • Loading branch information
honkinglin authored Apr 14, 2022
2 parents 2dddf32 + f40c1f8 commit c475255
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 5 deletions.
57 changes: 57 additions & 0 deletions src/popup/__tests__/popup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,63 @@ describe('Popup 组件测试', () => {
expect(popupContainer).toHaveStyle(testStyle);
});

test('测试浮层嵌套', async () => {
const wrappedTriggerElement = '嵌套触发元素';
const wrappedPopupTestId = 'wrapped-popup-test-id';
const wrappedPopupText = '嵌套弹出层内容';
const { getByText, queryByTestId } = render(
<Popup
placement="top"
trigger="click"
destroyOnClose
content={
<Popup
placement="top"
trigger="click"
destroyOnClose
content={<div data-testid={wrappedPopupTestId}>{wrappedPopupText}</div>}
>
<div data-testid={popupTestId}>{wrappedTriggerElement}</div>
</Popup>
}
>
{triggerElement}
</Popup>,
);

// 初始时,所有浮层都不存在
const popupElement1 = await waitFor(() => queryByTestId(popupTestId));
const wrappedPopupElement1 = await waitFor(() => queryByTestId(wrappedPopupTestId));
expect(popupElement1).toBeNull();
expect(wrappedPopupElement1).toBeNull();

// 触发浮层和嵌套浮层
act(() => {
fireEvent.click(getByText(triggerElement));
jest.runAllTimers();
fireEvent.click(getByText(wrappedTriggerElement));
jest.runAllTimers();
});

// 所有浮层都展示出来
const popupElement2 = await waitFor(() => queryByTestId(popupTestId));
const wrappedPopupElement2 = await waitFor(() => queryByTestId(wrappedPopupTestId));
expect(popupElement2).not.toBeNull();
expect(wrappedPopupElement2).not.toBeNull();

// 嵌套元素的浮层触发 mouseDown,不应该关闭任何浮层
act(() => {
fireEvent.mouseDown(queryByTestId(wrappedPopupTestId));
jest.runAllTimers();
});

// 所有浮层都展示出来
const popupElement3 = await waitFor(() => queryByTestId(popupTestId));
const wrappedPopupElement3 = await waitFor(() => queryByTestId(wrappedPopupTestId));
expect(popupElement3).not.toBeNull();
expect(wrappedPopupElement3).not.toBeNull();
});

test('异常情况:浮层隐藏时点击其他地方,浮层不可以展示出来', async () => {
const testClassName = 'test-class-name';
render(
Expand Down
21 changes: 16 additions & 5 deletions src/popup/hooks/useTriggerProps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTMLAttributes, MutableRefObject } from 'react';
import React, { HTMLAttributes, MutableRefObject, useRef } from 'react';
import useClickOutside from '../../_util/useClickOutside';
import { TdPopupProps, PopupVisibleChangeContext, PopupTriggerEvent } from '../type';
import { ChangeHandler } from '../../_util/useDefault';
Expand All @@ -15,18 +15,19 @@ export default function useTriggerProps(
visible: boolean,
setVisible: ChangeHandler<boolean, [PopupVisibleChangeContext]>,
disabled = false,
originTrigger: JSX.Element,
originTrigger: React.ReactElement<HTMLAttributes<HTMLElement>>,
): [TriggerProps, PopupProps] {
const triggerProps: TriggerProps = {};
const popupProps: PopupProps = {};

const hasPopupMouseDown = useRef(false);
const mouseDownTimer = useRef<number>();
const toggle: HandleTrigger = (e, trigger) => setVisible(!visible, { e, trigger });
const show: HandleTrigger = (e, trigger) => setVisible(true, { e, trigger });
const hide: HandleTrigger = (e, trigger) => setVisible(false, { e, trigger });

// click outside 用于处理点击其他地方隐藏
useClickOutside([ref, triggerNode], (e: any) => {
if (visible && (triggers.includes('click') || triggers.includes('context-menu'))) {
if (visible && (triggers.includes('click') || triggers.includes('context-menu')) && !hasPopupMouseDown.current) {
hide(e, 'trigger-element-blur');
}
});
Expand All @@ -35,7 +36,8 @@ export default function useTriggerProps(

// eslint-disable-next-line no-restricted-syntax
for (const trigger of triggers) {
const { onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, onContextMenu, onKeyDown } = originTrigger.props;
const { onClick, onMouseEnter, onMouseLeave, onMouseDown, onFocus, onBlur, onContextMenu, onKeyDown } =
originTrigger.props;
// 点击触发
if (trigger === 'click') {
triggerProps.onClick = (e) => {
Expand Down Expand Up @@ -81,6 +83,15 @@ export default function useTriggerProps(
};
}

popupProps.onMouseDown = (e) => {
clearTimeout(mouseDownTimer.current);
hasPopupMouseDown.current = true;
mouseDownTimer.current = window.setTimeout(() => {
hasPopupMouseDown.current = false;
});
onMouseDown?.(e);
};

triggerProps.onKeyDown = (e) => {
if (e.key === ESC_KEY) hide(e, 'keydown-esc');
onKeyDown && onKeyDown(e);
Expand Down

0 comments on commit c475255

Please sign in to comment.