diff --git a/README.md b/README.md
index 43984c6..69d446b 100644
--- a/README.md
+++ b/README.md
@@ -136,6 +136,12 @@ props details:
false |
show with progress bar for auto-closing notification |
+
+ | pauseOnHover |
+ boolean |
+ true |
+ keep the timer running or not on hover |
+
| style |
Object |
diff --git a/docs/examples/showProgress.tsx b/docs/examples/showProgress.tsx
index 50e80eb..4d0ebbc 100644
--- a/docs/examples/showProgress.tsx
+++ b/docs/examples/showProgress.tsx
@@ -18,6 +18,16 @@ export default () => {
>
Show With Progress
+
{contextHolder}
>
);
diff --git a/src/Notice.tsx b/src/Notice.tsx
index 69bb940..38a9b9c 100644
--- a/src/Notice.tsx
+++ b/src/Notice.tsx
@@ -22,6 +22,7 @@ const Notify = React.forwardRef {
- clearTimeout(timeout);
+ if (pauseOnHover) {
+ clearTimeout(timeout);
+ }
setSpentTime(Date.now() - start);
};
}
@@ -71,7 +74,7 @@ const Notify = React.forwardRef {
- if (!mergedHovering && mergedShowProgress) {
+ if (!mergedHovering && mergedShowProgress && (pauseOnHover || spentTime === 0)) {
const start = performance.now();
let animationFrame: number;
@@ -90,11 +93,13 @@ const Notify = React.forwardRef {
- cancelAnimationFrame(animationFrame);
+ if (pauseOnHover) {
+ cancelAnimationFrame(animationFrame);
+ }
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [duration, mergedHovering, mergedShowProgress, times]);
+ }, [duration, spentTime, mergedHovering, mergedShowProgress, times]);
// ======================== Closable ========================
const closableObj = React.useMemo(() => {
diff --git a/src/hooks/useNotification.tsx b/src/hooks/useNotification.tsx
index 31f5d81..783b72b 100644
--- a/src/hooks/useNotification.tsx
+++ b/src/hooks/useNotification.tsx
@@ -18,6 +18,7 @@ export interface NotificationConfig {
maxCount?: number;
duration?: number;
showProgress?: boolean;
+ pauseOnHover?: boolean;
/** @private. Config for notification holder style. Safe to remove if refactor */
className?: (placement: Placement) => string;
/** @private. Config for notification holder style. Safe to remove if refactor */
diff --git a/src/interface.ts b/src/interface.ts
index b5d48f1..52ccbe0 100644
--- a/src/interface.ts
+++ b/src/interface.ts
@@ -8,6 +8,7 @@ export interface NoticeConfig {
content?: React.ReactNode;
duration?: number | null;
showProgress?: boolean;
+ pauseOnHover?: boolean;
closeIcon?: React.ReactNode;
closable?: boolean | ({ closeIcon?: React.ReactNode } & React.AriaAttributes);
className?: string;
diff --git a/tests/index.test.tsx b/tests/index.test.tsx
index 5dbbeb5..4217e31 100644
--- a/tests/index.test.tsx
+++ b/tests/index.test.tsx
@@ -309,6 +309,74 @@ describe('Notification.Basic', () => {
expect(document.querySelector('.test')).toBeFalsy();
});
+ describe('pauseOnHover is false', () => {
+ it('does not freeze when pauseOnHover is false', () => {
+ const { instance } = renderDemo();
+
+ act(() => {
+ instance.open({
+ content: (
+
+ not freeze
+
+ ),
+ duration: 0.3,
+ pauseOnHover: false,
+ });
+ });
+
+ expect(document.querySelectorAll('.not-freeze')).toHaveLength(1);
+
+ // Mouse in should remove
+ fireEvent.mouseEnter(document.querySelector('.rc-notification-notice'));
+ act(() => {
+ vi.runAllTimers();
+ });
+ expect(document.querySelectorAll('.not-freeze')).toHaveLength(0);
+ });
+
+ it('continue timing after hover', () => {
+ const { instance } = renderDemo({
+ duration: 1,
+ pauseOnHover: false,
+ });
+
+ act(() => {
+ instance.open({
+ content: 1
,
+ });
+ });
+
+ expect(document.querySelector('.test')).toBeTruthy();
+
+ // Wait for 500ms
+ act(() => {
+ vi.advanceTimersByTime(500);
+ });
+ expect(document.querySelector('.test')).toBeTruthy();
+
+ // Mouse in should not remove
+ fireEvent.mouseEnter(document.querySelector('.rc-notification-notice'));
+ act(() => {
+ vi.advanceTimersByTime(200);
+ });
+ expect(document.querySelector('.test')).toBeTruthy();
+
+ // Mouse out should not remove until 500ms later
+ fireEvent.mouseLeave(document.querySelector('.rc-notification-notice'));
+ act(() => {
+ vi.advanceTimersByTime(200);
+ });
+ expect(document.querySelector('.test')).toBeTruthy();
+
+ //
+ act(() => {
+ vi.advanceTimersByTime(100);
+ });
+ expect(document.querySelector('.test')).toBeFalsy();
+ });
+ });
+
describe('maxCount', () => {
it('remove work when maxCount set', () => {
const { instance } = renderDemo({