Skip to content

Commit c1289b3

Browse files
zombieJclaude
andcommitted
feat: add custom progress component support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e013739 commit c1289b3

File tree

7 files changed

+73
-7
lines changed

7 files changed

+73
-7
lines changed

src/Notification.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { clsx } from 'clsx';
33
import useNoticeTimer from './hooks/useNoticeTimer';
44
import { useEvent } from '@rc-component/util';
55
import useClosable, { type ClosableType } from './hooks/useClosable';
6+
import DefaultProgress from './Progress';
7+
import type { NotificationProgressProps } from './Progress';
68

79
export interface NotificationClassNames {
810
wrapper?: string;
@@ -22,13 +24,18 @@ export interface NotificationStyles {
2224
progress?: React.CSSProperties;
2325
}
2426

27+
export interface ComponentsType {
28+
progress?: React.ComponentType<NotificationProgressProps>;
29+
}
30+
2531
export interface NotificationProps {
2632
// Style
2733
prefixCls: string;
2834
className?: string;
2935
style?: React.CSSProperties;
3036
classNames?: NotificationClassNames;
3137
styles?: NotificationStyles;
38+
components?: ComponentsType;
3239

3340
// UI
3441
title?: React.ReactNode;
@@ -65,6 +72,7 @@ const Notification = React.forwardRef<HTMLDivElement, NotificationProps>((props,
6572
style,
6673
classNames,
6774
styles,
75+
components,
6876

6977
// UI
7078
title,
@@ -104,6 +112,7 @@ const Notification = React.forwardRef<HTMLDivElement, NotificationProps>((props,
104112
const [onResume, onPause] = useNoticeTimer(duration, onInternalClose, setPercent, !!showProgress);
105113

106114
const validPercent = 100 - Math.min(Math.max(percent * 100, 0), 100);
115+
const Progress = components?.progress || DefaultProgress;
107116

108117
React.useEffect(() => {
109118
if (!pauseOnHover) {
@@ -230,17 +239,18 @@ const Notification = React.forwardRef<HTMLDivElement, NotificationProps>((props,
230239
{actions && <div className="actions">{actions}</div>}
231240

232241
{showProgress && typeof duration === 'number' && duration > 0 && (
233-
<progress
242+
<Progress
234243
className={clsx(`${noticePrefixCls}-progress`, classNames?.progress)}
235-
max="100"
236-
value={validPercent}
244+
percent={validPercent}
237245
style={styles?.progress}
238246
/>
239247
)}
240248
</div>
241249
);
242250
});
243251

244-
Notification.displayName = 'Notification';
252+
if (process.env.NODE_ENV !== 'production') {
253+
Notification.displayName = 'Notification';
254+
}
245255

246256
export default Notification;

src/NotificationList.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as React from 'react';
55
import type { StackConfig } from './interface';
66
import { NotificationContext } from './legacy/NotificationProvider';
77
import Notification, {
8+
type ComponentsType,
89
type NotificationClassNames,
910
type NotificationProps,
1011
type NotificationStyles,
@@ -29,6 +30,7 @@ export interface NotificationListProps {
2930
pauseOnHover?: boolean;
3031
classNames?: NotificationClassNames;
3132
styles?: NotificationStyles;
33+
components?: ComponentsType;
3234
stack?: boolean | StackConfig;
3335
motion?: CSSMotionProps | ((placement: Placement) => CSSMotionProps);
3436
className?: string;
@@ -52,6 +54,7 @@ const NotificationList: React.FC<NotificationListProps> = (props) => {
5254
pauseOnHover,
5355
classNames,
5456
styles,
57+
components,
5558
stack: stackConfig,
5659
motion,
5760
placement,
@@ -218,6 +221,10 @@ const NotificationList: React.FC<NotificationListProps> = (props) => {
218221
...config.styles?.progress,
219222
},
220223
}}
224+
components={{
225+
...components,
226+
...config.components,
227+
}}
221228
hovering={stackEnabled && listHovering}
222229
pauseOnHover={config.pauseOnHover ?? pauseOnHover}
223230
onClose={() => {

src/Notifications.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import NotificationList, {
99
type Placement,
1010
type StackConfig,
1111
} from './NotificationList';
12+
import type { ComponentsType } from './Notification';
1213

1314
export interface NotificationsProps {
1415
// Style
1516
prefixCls?: string;
1617
classNames?: NotificationClassNames;
1718
styles?: NotificationStyles;
19+
components?: ComponentsType;
1820
className?: (placement: Placement) => string;
1921
style?: (placement: Placement) => React.CSSProperties;
2022

@@ -54,6 +56,7 @@ const Notifications = React.forwardRef<NotificationsRef, NotificationsProps>((pr
5456
pauseOnHover,
5557
classNames,
5658
styles,
59+
components,
5760
className,
5861
style,
5962
onAllRemoved,
@@ -159,6 +162,7 @@ const Notifications = React.forwardRef<NotificationsRef, NotificationsProps>((pr
159162
pauseOnHover={pauseOnHover}
160163
classNames={classNames}
161164
styles={styles}
165+
components={components}
162166
className={className?.(placement)}
163167
style={style?.(placement)}
164168
motion={motion}

src/Progress.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as React from 'react';
2+
3+
export interface NotificationProgressProps {
4+
className?: string;
5+
style?: React.CSSProperties;
6+
percent: number;
7+
}
8+
9+
const Progress: React.FC<NotificationProgressProps> = ({ className, style, percent }) => (
10+
<progress className={className} max="100" value={percent} style={style} />
11+
);
12+
13+
export default Progress;

src/hooks/useNotification.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export default function useNotification(
8484
pauseOnHover,
8585
classNames,
8686
styles,
87+
components,
8788
maxCount,
8889
className,
8990
style,
@@ -113,6 +114,7 @@ export default function useNotification(
113114
pauseOnHover={pauseOnHover}
114115
classNames={classNames}
115116
styles={styles}
117+
components={components}
116118
className={className}
117119
style={style}
118120
onAllRemoved={onAllRemoved}

src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import useNotification from './hooks/useNotification';
22
import Notice from './legacy/Notice';
33
import type { NotificationAPI, NotificationConfig } from './hooks/useNotification';
44
import NotificationProvider from './legacy/NotificationProvider';
5+
import Progress from './Progress';
6+
import type { ComponentsType } from './Notification';
7+
import type { NotificationProgressProps } from './Progress';
58

6-
export { useNotification, Notice, NotificationProvider };
7-
export type { NotificationAPI, NotificationConfig };
9+
export { useNotification, Notice, NotificationProvider, Progress };
10+
export type { NotificationAPI, NotificationConfig, ComponentsType, NotificationProgressProps };

tests/index.test.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { fireEvent, render } from '@testing-library/react';
22
import React from 'react';
33
import { act } from 'react-dom/test-utils';
4-
import type { NotificationAPI, NotificationConfig } from '../src';
4+
import type { NotificationAPI, NotificationConfig, NotificationProgressProps } from '../src';
55
import { useNotification } from '../src';
66

77
require('../assets/index.less');
@@ -966,6 +966,33 @@ describe('Notification.Basic', () => {
966966

967967
expect(document.querySelector('.rc-notification-notice-progress')).toBeFalsy();
968968
});
969+
970+
it('supports custom progress component', () => {
971+
const CustomProgress: React.FC<NotificationProgressProps> = ({ className, percent }) => (
972+
<div className={className} data-testid="custom-progress">
973+
{percent}
974+
</div>
975+
);
976+
977+
const { instance } = renderDemo({
978+
duration: 1,
979+
components: {
980+
progress: CustomProgress,
981+
},
982+
});
983+
984+
act(() => {
985+
instance.open({
986+
description: <p className="test">1</p>,
987+
showProgress: true,
988+
});
989+
});
990+
991+
expect(document.querySelector('progress')).toBeFalsy();
992+
expect(document.querySelector('.rc-notification-notice-progress')?.textContent).toEqual(
993+
'100',
994+
);
995+
});
969996
});
970997

971998
describe('Modifying properties through useState can take effect', () => {

0 commit comments

Comments
 (0)