Skip to content

Commit 62a5947

Browse files
authored
fix: should collapse when close (#314)
* fix: should collapse when close * chore: update * test: add test case * chore: add comment
1 parent 8eca7f0 commit 62a5947

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

src/NoticeList.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { CSSProperties, FC } from 'react';
2-
import React, { useContext, useRef, useState } from 'react';
2+
import React, { useContext, useEffect, useRef, useState } from 'react';
33
import clsx from 'classnames';
44
import type { CSSMotionProps } from 'rc-motion';
55
import { CSSMotionList } from 'rc-motion';
@@ -47,7 +47,7 @@ const NoticeList: FC<NoticeListProps> = (props) => {
4747

4848
const dictRef = useRef<Record<React.Key, HTMLDivElement>>({});
4949
const [latestNotice, setLatestNotice] = useState<HTMLDivElement>(null);
50-
const [hoverCount, setHoverCount] = useState(0);
50+
const [hoverKeys, setHoverKeys] = useState<React.Key[]>([]);
5151

5252
const keys = configList.map((config) => ({
5353
config,
@@ -56,10 +56,19 @@ const NoticeList: FC<NoticeListProps> = (props) => {
5656

5757
const [stack, { offset, threshold, gap }] = useStack(stackConfig);
5858

59-
const expanded = stack && (hoverCount > 0 || keys.length <= threshold);
59+
const expanded = stack && (hoverKeys.length > 0 || keys.length <= threshold);
6060

6161
const placementMotion = typeof motion === 'function' ? motion(placement) : motion;
6262

63+
// Clean hover key
64+
useEffect(() => {
65+
if (hoverKeys.length > 1) {
66+
setHoverKeys((prev) =>
67+
prev.filter((key) => keys.some(({ key: dataKey }) => key === dataKey)),
68+
);
69+
}
70+
}, [hoverKeys, keys]);
71+
6372
return (
6473
<CSSMotionList
6574
key={placement}
@@ -127,8 +136,10 @@ const NoticeList: FC<NoticeListProps> = (props) => {
127136
...stackStyle,
128137
...configStyle,
129138
}}
130-
onMouseEnter={() => setHoverCount((c) => c + 1)}
131-
onMouseLeave={() => setHoverCount((c) => c - 1)}
139+
onMouseEnter={() =>
140+
setHoverKeys((prev) => (prev.includes(key) ? prev : [...prev, key]))
141+
}
142+
onMouseLeave={() => setHoverKeys((prev) => prev.filter((k) => k !== key))}
132143
>
133144
<Notice
134145
{...config}
@@ -145,7 +156,7 @@ const NoticeList: FC<NoticeListProps> = (props) => {
145156
key={key}
146157
eventKey={key}
147158
onNoticeClose={onNoticeClose}
148-
hovering={hoverCount > 0}
159+
hovering={hoverKeys.length > 0}
149160
/>
150161
</div>
151162
);

tests/stack.test.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,47 @@ describe('stack', () => {
4343
fireEvent.mouseEnter(document.querySelector('.rc-notification-notice'));
4444
expect(document.querySelector('.rc-notification-stack-expanded')).toBeTruthy();
4545
});
46+
47+
it('should collapse when amount is less than threshold', () => {
48+
const Demo = () => {
49+
const [api, holder] = useNotification({
50+
stack: { threshold: 3 },
51+
});
52+
return (
53+
<>
54+
<button
55+
type="button"
56+
onClick={() => {
57+
api.open({
58+
content: <div className="context-content">Test</div>,
59+
duration: null,
60+
closable: true,
61+
});
62+
}}
63+
/>
64+
{holder}
65+
</>
66+
);
67+
};
68+
69+
const { container } = render(<Demo />);
70+
for (let i = 0; i < 5; i++) {
71+
fireEvent.click(container.querySelector('button'));
72+
}
73+
expect(document.querySelectorAll('.rc-notification-notice')).toHaveLength(5);
74+
expect(document.querySelector('.rc-notification-stack')).toBeTruthy();
75+
expect(document.querySelector('.rc-notification-stack-expanded')).toBeFalsy();
76+
77+
fireEvent.mouseEnter(document.querySelector('.rc-notification-notice'));
78+
expect(document.querySelector('.rc-notification-stack-expanded')).toBeTruthy();
79+
80+
fireEvent.click(document.querySelector('.rc-notification-notice-close'));
81+
expect(document.querySelectorAll('.rc-notification-notice')).toHaveLength(4);
82+
expect(document.querySelector('.rc-notification-stack-expanded')).toBeTruthy();
83+
84+
// mouseleave will not triggerred if notice is closed
85+
fireEvent.mouseEnter(document.querySelector('.rc-notification-notice-wrapper'));
86+
fireEvent.mouseLeave(document.querySelector('.rc-notification-notice-wrapper'));
87+
expect(document.querySelector('.rc-notification-stack-expanded')).toBeFalsy();
88+
});
4689
});

0 commit comments

Comments
 (0)