Skip to content

Commit f411b69

Browse files
authored
feat: support renderNotifications (#310)
* feat: support renderNotifications * chore: code clean * feat: add key info
1 parent 861f24e commit f411b69

File tree

6 files changed

+61
-25
lines changed

6 files changed

+61
-25
lines changed

src/NoticeList.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import type { CSSProperties, FC } from 'react';
2-
import React from 'react';
3-
import classNames from 'classnames';
2+
import React, { useContext } from 'react';
3+
import clsx from 'classnames';
44
import type { CSSMotionProps } from 'rc-motion';
55
import { CSSMotionList } from 'rc-motion';
66
import type { InnerOpenConfig, NoticeConfig, OpenConfig, Placement } from './interface';
77
import Notice from './Notice';
8+
import { NotificationContext } from './NotificationProvider';
89

910
export interface NoticeListProps {
1011
configList?: OpenConfig[];
@@ -16,9 +17,6 @@ export interface NoticeListProps {
1617
onAllNoticeRemoved?: (placement: Placement) => void;
1718
onNoticeClose?: (key: React.Key) => void;
1819

19-
// Hook Slots
20-
useStyle?: (prefixCls: string) => { notice?: string; list?: string };
21-
2220
// Common
2321
className?: string;
2422
style?: CSSProperties;
@@ -31,13 +29,12 @@ const NoticeList: FC<NoticeListProps> = (props) => {
3129
prefixCls,
3230
className,
3331
style,
34-
useStyle,
3532
motion,
3633
onAllNoticeRemoved,
3734
onNoticeClose,
3835
} = props;
3936

40-
const styles = useStyle?.(prefixCls);
37+
const { classNames: ctxCls } = useContext(NotificationContext);
4138

4239
const keys = configList.map((config) => ({
4340
config,
@@ -49,7 +46,7 @@ const NoticeList: FC<NoticeListProps> = (props) => {
4946
return (
5047
<CSSMotionList
5148
key={placement}
52-
className={classNames(prefixCls, `${prefixCls}-${placement}`, styles?.list, className)}
49+
className={clsx(prefixCls, `${prefixCls}-${placement}`, ctxCls?.list, className)}
5350
style={style}
5451
keys={keys}
5552
motionAppear
@@ -67,7 +64,7 @@ const NoticeList: FC<NoticeListProps> = (props) => {
6764
{...config}
6865
ref={nodeRef}
6966
prefixCls={prefixCls}
70-
className={classNames(motionClassName, configClassName, styles?.notice)}
67+
className={clsx(motionClassName, configClassName, ctxCls?.notice)}
7168
style={{
7269
...motionStyle,
7370
...configStyle,

src/NotificationProvider.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { FC } from 'react';
2+
import React from 'react';
3+
4+
export interface NotificationContextProps {
5+
classNames?: {
6+
notice?: string;
7+
list?: string;
8+
};
9+
}
10+
11+
export const NotificationContext = React.createContext<NotificationContextProps>({});
12+
13+
export interface NotificationProviderProps extends NotificationContextProps {
14+
children: React.ReactNode;
15+
}
16+
17+
const NotificationProvider: FC<NotificationProviderProps> = ({ children, classNames }) => {
18+
return (
19+
<NotificationContext.Provider value={{ classNames }}>{children}</NotificationContext.Provider>
20+
);
21+
};
22+
23+
export default NotificationProvider;

src/Notifications.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import * as React from 'react';
2+
import { ReactElement } from 'react';
23
import { createPortal } from 'react-dom';
34
import type { CSSMotionProps } from 'rc-motion';
45
import type { InnerOpenConfig, OpenConfig, Placement, Placements } from './interface';
5-
import NoticeList, { NoticeListProps } from './NoticeList';
6+
import NoticeList from './NoticeList';
67

78
export interface NotificationsProps {
89
prefixCls?: string;
@@ -12,7 +13,10 @@ export interface NotificationsProps {
1213
className?: (placement: Placement) => string;
1314
style?: (placement: Placement) => React.CSSProperties;
1415
onAllRemoved?: VoidFunction;
15-
useStyle?: NoticeListProps['useStyle'];
16+
renderNotifications?: (
17+
node: ReactElement,
18+
info: { prefixCls: string; key: React.Key },
19+
) => ReactElement;
1620
}
1721

1822
export interface NotificationsRef {
@@ -31,7 +35,7 @@ const Notifications = React.forwardRef<NotificationsRef, NotificationsProps>((pr
3135
className,
3236
style,
3337
onAllRemoved,
34-
useStyle,
38+
renderNotifications,
3539
} = props;
3640
const [configList, setConfigList] = React.useState<OpenConfig[]>([]);
3741

@@ -139,7 +143,7 @@ const Notifications = React.forwardRef<NotificationsRef, NotificationsProps>((pr
139143
{placementList.map((placement) => {
140144
const placementConfigList = placements[placement];
141145

142-
return (
146+
const list = (
143147
<NoticeList
144148
key={placement}
145149
configList={placementConfigList}
@@ -150,9 +154,12 @@ const Notifications = React.forwardRef<NotificationsRef, NotificationsProps>((pr
150154
motion={motion}
151155
onNoticeClose={onNoticeClose}
152156
onAllNoticeRemoved={onAllNoticeRemoved}
153-
useStyle={useStyle}
154157
/>
155158
);
159+
160+
return renderNotifications
161+
? renderNotifications(list, { prefixCls, key: placement })
162+
: list;
156163
})}
157164
</>,
158165
container,

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import useNotification from './useNotification';
22
import Notice from './Notice';
33
import type { NotificationAPI, NotificationConfig } from './useNotification';
4+
import NotificationProvider from './NotificationProvider';
45

5-
export { useNotification, Notice };
6+
export { useNotification, Notice, NotificationProvider };
67
export type { NotificationAPI, NotificationConfig };

src/useNotification.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type { CSSMotionProps } from 'rc-motion';
22
import * as React from 'react';
3-
import type { NotificationsRef } from './Notifications';
3+
import type { NotificationsProps, NotificationsRef } from './Notifications';
44
import Notifications from './Notifications';
55
import type { OpenConfig, Placement } from './interface';
6-
import type { NoticeListProps } from './NoticeList';
76

87
const defaultGetContainer = () => document.body;
98

@@ -25,7 +24,7 @@ export interface NotificationConfig {
2524
/** @private Trigger when all the notification closed. */
2625
onAllRemoved?: VoidFunction;
2726
/** @private Slot for style in Notifications */
28-
useStyle?: NoticeListProps['useStyle'];
27+
renderNotifications?: NotificationsProps['renderNotifications'];
2928
}
3029

3130
export interface NotificationAPI {
@@ -81,7 +80,7 @@ export default function useNotification(
8180
className,
8281
style,
8382
onAllRemoved,
84-
useStyle,
83+
renderNotifications,
8584
...shareConfig
8685
} = rootConfig;
8786

@@ -97,7 +96,7 @@ export default function useNotification(
9796
className={className}
9897
style={style}
9998
onAllRemoved={onAllRemoved}
100-
useStyle={useStyle}
99+
renderNotifications={renderNotifications}
101100
/>
102101
);
103102

tests/hooks.test.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React from 'react';
1+
import React, { ReactElement } from 'react';
22
import { render, fireEvent, act } from '@testing-library/react';
33
import { useNotification } from '../src';
44
import type { NotificationAPI, NotificationConfig } from '../src';
5+
import NotificationProvider from '../src/NotificationProvider';
56

67
require('../assets/index.less');
78

@@ -153,12 +154,20 @@ describe('Notification.Hooks', () => {
153154
expect(document.querySelector('.light')).toBeTruthy();
154155
});
155156

156-
it('support style slot', () => {
157-
const useStyle = () => {
158-
return { notice: 'apple', list: 'banana' };
157+
it('support renderNotifications', () => {
158+
const Wrapper = ({ children }) => {
159+
return (
160+
<NotificationProvider classNames={{ notice: 'apple', list: 'banana' }}>
161+
{children}
162+
</NotificationProvider>
163+
);
164+
};
165+
166+
const renderNotifications = (node: ReactElement) => {
167+
return <Wrapper>{node}</Wrapper>;
159168
};
160169
const { instance } = renderDemo({
161-
useStyle,
170+
renderNotifications,
162171
});
163172

164173
act(() => {

0 commit comments

Comments
 (0)