Merge pull request #16123 from Nouzbe/feature

feat: Make notification functions accept top, bottom and getContainer as arguments
This commit is contained in:
偏右 2019-04-23 19:41:04 +08:00 committed by GitHub
commit 7409150ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 187 additions and 123 deletions

View File

@ -28,126 +28,157 @@ describe('Notification.placement', () => {
open();
}
it('change notification placement by `open` method', () => {
const defaultTop = '24px';
const defaultBottom = '24px';
let style;
describe('placement', () => {
it('can be configured per notification using the `open` method', () => {
const defaultTop = '24px';
const defaultBottom = '24px';
let style;
// topLeft
open({
placement: 'topLeft',
});
style = getStyle($$('.ant-notification-topLeft')[0]);
expect(style.top).toBe(defaultTop);
expect(style.left).toBe('0px');
expect(style.bottom).toBe('');
// topLeft
open({
placement: 'topLeft',
top: 50,
});
style = getStyle($$('.ant-notification-topLeft')[0]);
expect(style.top).toBe('50px');
expect(style.left).toBe('0px');
expect(style.bottom).toBe('');
open({
placement: 'topLeft',
});
expect($$('.ant-notification-topLeft').length).toBe(1);
open({
placement: 'topLeft',
});
expect($$('.ant-notification-topLeft').length).toBe(1);
// topRight
open({
placement: 'topRight',
});
style = getStyle($$('.ant-notification-topRight')[0]);
expect(style.top).toBe(defaultTop);
expect(style.right).toBe('0px');
expect(style.bottom).toBe('');
// topRight
open({
placement: 'topRight',
});
style = getStyle($$('.ant-notification-topRight')[0]);
expect(style.top).toBe(defaultTop);
expect(style.right).toBe('0px');
expect(style.bottom).toBe('');
open({
placement: 'topRight',
});
expect($$('.ant-notification-topRight').length).toBe(1);
open({
placement: 'topRight',
});
expect($$('.ant-notification-topRight').length).toBe(1);
// bottomRight
open({
placement: 'bottomRight',
});
style = getStyle($$('.ant-notification-bottomRight')[0]);
expect(style.top).toBe('');
expect(style.right).toBe('0px');
expect(style.bottom).toBe(defaultBottom);
// bottomRight
open({
placement: 'bottomRight',
bottom: 100,
});
style = getStyle($$('.ant-notification-bottomRight')[0]);
expect(style.top).toBe('');
expect(style.right).toBe('0px');
expect(style.bottom).toBe('100px');
open({
placement: 'bottomRight',
});
expect($$('.ant-notification-bottomRight').length).toBe(1);
open({
placement: 'bottomRight',
});
expect($$('.ant-notification-bottomRight').length).toBe(1);
// bottomLeft
open({
placement: 'bottomLeft',
});
style = getStyle($$('.ant-notification-bottomLeft')[0]);
expect(style.top).toBe('');
expect(style.left).toBe('0px');
expect(style.bottom).toBe(defaultBottom);
// bottomLeft
open({
placement: 'bottomLeft',
});
style = getStyle($$('.ant-notification-bottomLeft')[0]);
expect(style.top).toBe('');
expect(style.left).toBe('0px');
expect(style.bottom).toBe(defaultBottom);
open({
placement: 'bottomLeft',
open({
placement: 'bottomLeft',
});
expect($$('.ant-notification-bottomLeft').length).toBe(1);
});
it('can be configured globally using the `config` method', () => {
let style;
// topLeft
config({
placement: 'topLeft',
top: 50,
bottom: 50,
});
style = getStyle($$('.ant-notification-topLeft')[0]);
expect(style.top).toBe('50px');
expect(style.left).toBe('0px');
expect(style.bottom).toBe('');
// topRight
config({
placement: 'topRight',
top: 100,
bottom: 50,
});
style = getStyle($$('.ant-notification-topRight')[0]);
expect(style.top).toBe('100px');
expect(style.right).toBe('0px');
expect(style.bottom).toBe('');
// bottomRight
config({
placement: 'bottomRight',
top: 50,
bottom: 100,
});
style = getStyle($$('.ant-notification-bottomRight')[0]);
expect(style.top).toBe('');
expect(style.right).toBe('0px');
expect(style.bottom).toBe('100px');
// bottomLeft
config({
placement: 'bottomLeft',
top: 100,
bottom: 50,
});
style = getStyle($$('.ant-notification-bottomLeft')[0]);
expect(style.top).toBe('');
expect(style.left).toBe('0px');
expect(style.bottom).toBe('50px');
});
expect($$('.ant-notification-bottomLeft').length).toBe(1);
});
it('change notification placement by `config` method', () => {
let style;
// topLeft
config({
placement: 'topLeft',
top: 50,
bottom: 50,
});
style = getStyle($$('.ant-notification-topLeft')[0]);
expect(style.top).toBe('50px');
expect(style.left).toBe('0px');
expect(style.bottom).toBe('');
// topRight
config({
placement: 'topRight',
top: 100,
bottom: 50,
});
style = getStyle($$('.ant-notification-topRight')[0]);
expect(style.top).toBe('100px');
expect(style.right).toBe('0px');
expect(style.bottom).toBe('');
// bottomRight
config({
placement: 'bottomRight',
top: 50,
bottom: 100,
});
style = getStyle($$('.ant-notification-bottomRight')[0]);
expect(style.top).toBe('');
expect(style.right).toBe('0px');
expect(style.bottom).toBe('100px');
// bottomLeft
config({
placement: 'bottomLeft',
top: 100,
bottom: 50,
});
style = getStyle($$('.ant-notification-bottomLeft')[0]);
expect(style.top).toBe('');
expect(style.left).toBe('0px');
expect(style.bottom).toBe('50px');
});
it('change notification mountNode by `config` method', () => {
describe('mountNode', () => {
const $container = document.createElement('div');
document.body.appendChild($container);
config({
top: 50,
bottom: 100,
getContainer() {
return $container;
},
beforeEach(() => {
document.body.appendChild($container);
});
afterEach(() => {
$container.remove();
});
it('can be configured per notification using the `open` method', () => {
open({
getContainer: () => $container,
});
expect($container.querySelector('.ant-notification')).not.toBe(null);
notification.destroy();
setTimeout(() => {
// Upcoming notifications still use their default mountNode and not $container
open();
expect($container.querySelector('.ant-notification')).toBe(null);
});
});
it('can be configured globally using the `config` method', () => {
config({
getContainer: () => $container,
});
expect($container.querySelector('.ant-notification')).not.toBe(null);
notification.destroy();
setTimeout(() => {
// Upcoming notifications are mounted in $container
open();
expect($container.querySelector('.ant-notification')).not.toBe(null);
});
});
expect($container.querySelector('.ant-notification')).not.toBe(null);
$container.remove();
});
});

View File

@ -32,17 +32,20 @@ The properties of config are as follows:
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| bottom | Distance from the bottom of the viewport, when `placement` is `bottomRight` or `bottomLeft` (unit: pixels). | number | 24 |
| btn | Customized close button | ReactNode | - |
| className | Customized CSS class | string | - |
| description | The content of notification box (required) | string\|ReactNode | - |
| duration | Time in seconds before Notification is closed. When set to 0 or null, it will never be closed automatically | number | 4.5 |
| getContainer | Return the mount node for Notification | () => HTMLNode | () => document.body |
| icon | Customized icon | ReactNode | - |
| key | The unique identifier of the Notification | string | - |
| message | The title of notification box (required) | string\|ReactNode | - |
| placement | Position of Notification, can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | `topRight` |
| style | Customized inline style | [React.CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - |
| onClose | Specify a function that will be called when the close button is clicked | Function | - |
| onClick | Specify a function that will be called when the notification is clicked | Function | - |
| placement | Position of Notification, can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | `topRight` |
| style | Customized inline style | [React.CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - |
| top | Distance from the top of the viewport, when `placement` is `topRight` or `topLeft` (unit: pixels). | number | 24 |
`notification` also provides a global `config()` method that can be used for specifying the default options. Once this method is used, all the notification boxes will take into account these globally defined options when displaying.

View File

@ -40,20 +40,24 @@ function setNotificationConfig(options: ConfigProps) {
}
}
function getPlacementStyle(placement: NotificationPlacement) {
function getPlacementStyle(
placement: NotificationPlacement,
top: number = defaultTop,
bottom: number = defaultBottom,
) {
let style;
switch (placement) {
case 'topLeft':
style = {
left: 0,
top: defaultTop,
top,
bottom: 'auto',
};
break;
case 'topRight':
style = {
right: 0,
top: defaultTop,
top,
bottom: 'auto',
};
break;
@ -61,23 +65,36 @@ function getPlacementStyle(placement: NotificationPlacement) {
style = {
left: 0,
top: 'auto',
bottom: defaultBottom,
bottom,
};
break;
default:
style = {
right: 0,
top: 'auto',
bottom: defaultBottom,
bottom,
};
break;
}
return style;
}
type NotificationInstanceProps = {
prefixCls: string;
placement?: NotificationPlacement;
getContainer?: () => HTMLElement;
top?: number;
bottom?: number;
};
function getNotificationInstance(
prefixCls: string,
placement: NotificationPlacement,
{
prefixCls,
placement = defaultPlacement,
getContainer = defaultGetContainer,
top,
bottom,
}: NotificationInstanceProps,
callback: (n: any) => void,
) {
const cacheKey = `${prefixCls}-${placement}`;
@ -89,8 +106,8 @@ function getNotificationInstance(
{
prefixCls,
className: `${prefixCls}-${placement}`,
style: getPlacementStyle(placement),
getContainer: defaultGetContainer,
style: getPlacementStyle(placement, top, bottom),
getContainer,
closeIcon: <Icon className={`${prefixCls}-close-icon`} type={'close'} />,
},
(notification: any) => {
@ -121,6 +138,9 @@ export interface ArgsProps {
className?: string;
readonly type?: IconType;
onClick?: () => void;
top?: number;
bottom?: number;
getContainer?: () => HTMLElement;
}
function notice(args: ArgsProps) {
@ -143,9 +163,16 @@ function notice(args: ArgsProps) {
<span className={`${prefixCls}-message-single-line-auto-margin`} />
) : null;
const { placement, top, bottom, getContainer } = args;
getNotificationInstance(
outerPrefixCls,
args.placement || defaultPlacement,
{
prefixCls: outerPrefixCls,
placement,
top,
bottom,
getContainer,
},
(notification: any) => {
notification.notice({
content: (

View File

@ -32,16 +32,19 @@ config 参数如下:
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| btn | 自定义关闭按钮 | ReactNode | - |
| bottom | 消息从底部弹出时,距离底部的位置,单位像素。 | number | 24 |
| className | 自定义 CSS class | string | - |
| description | 通知提醒内容,必选 | string\|ReactNode | - |
| duration | 默认 4.5 秒后自动关闭,配置为 null 则不自动关闭 | number | 4.5 |
| getContainer | 配置渲染节点的输出位置 | () => HTMLNode | () => document.body |
| icon | 自定义图标 | ReactNode | - |
| key | 当前通知唯一标志 | string | - |
| message | 通知提醒标题,必选 | string\|ReactNode | - |
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
| style | 自定义内联样式 | [React.CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - |
| onClose | 点击默认关闭按钮时触发的回调函数 | Function | - |
| onClick | 点击通知时触发的回调函数 | Function | - |
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
| style | 自定义内联样式 | [React.CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - |
| top | 消息从顶部弹出时,距离顶部的位置,单位像素。 | number | 24 |
还提供了一个全局配置方法,在调用前提前配置,全局一次生效。