support notification pop up from topLeft or bottomRight or bottomLeft (#4700)

* update snapshots

* update snapshots

* support notification pop up from topLeft or bottomRight or bottomLeft

* update snapshots

* 1. add test
2. update doc
3. support `placement` arguments in `open` method

* update doc

* update doc.
This commit is contained in:
Rex 2017-01-27 17:12:25 +08:00 committed by 偏右
parent fd233cf430
commit aadf623dc6
7 changed files with 315 additions and 21 deletions

View File

@ -0,0 +1,121 @@
import notification from '..';
describe('Notification.placement', () => {
function $$(className) {
return document.body.querySelectorAll(className);
}
function getStyle(el, prop, getComputedStyle, style) {
getComputedStyle = window.getComputedStyle;
style = getComputedStyle ? getComputedStyle(el) : el.currentStyle;
// If a css property's value is `auto`, it will return an empty string.
return prop ? style[prop] : style;
}
function open(args) {
notification.open({
message: 'Notification Title',
description: 'This is the content of the notification.',
...args,
});
}
function config(args) {
notification.config({
...args,
});
open();
}
it('change notification placement by `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('');
// topRight
open({
placement: 'topRight',
});
style = getStyle($$('.ant-notification-topRight')[0]);
expect(style.top).toBe(defaultTop);
expect(style.right).toBe('0px');
expect(style.bottom).toBe('');
// bottomRight
open({
placement: 'bottomRight',
});
style = getStyle($$('.ant-notification-bottomRight')[0]);
expect(style.top).toBe('');
expect(style.right).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);
});
it('change notification placement by `config` method', () => {
let style;
// topLeft
config({
placement: 'topLeft',
top: 50,
bottom: 50,
});
style = getStyle($$('.ant-notification-topLeft')[1]);
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')[1]);
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')[1]);
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')[1]);
expect(style.top).toBe('');
expect(style.left).toBe('0px');
expect(style.bottom).toBe('50px');
});
});

View File

@ -28,6 +28,46 @@ exports[`test renders ./components/notification/demo/duration.md correctly 1`] =
</button>
`;
exports[`test renders ./components/notification/demo/placement.md correctly 1`] = `
<div>
<div
class="ant-select ant-select-enabled"
style="width:120px;margin-right:10px;">
<div
aria-autocomplete="list"
aria-expanded="false"
aria-haspopup="true"
class="ant-select-selection
ant-select-selection--single"
role="combobox"
tabindex="0">
<div
class="ant-select-selection__rendered">
<div
class="ant-select-selection-selected-value"
style="display:block;opacity:1;"
title="topRight">
topRight
</div>
</div>
<span
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none;"
unselectable="unselectable">
<b />
</span>
</div>
</div>
<button
class="ant-btn ant-btn-primary"
type="button">
<span>
Open the notification box
</span>
</button>
</div>
`;
exports[`test renders ./components/notification/demo/with-btn.md correctly 1`] = `
<button
class="ant-btn ant-btn-primary"

View File

@ -0,0 +1,49 @@
---
order: 5
title:
zh-CN: 位置
en-US: Placement
---
## zh-CN
可以设置通知从右上角、右下角、左下角、左上角弹出。
## en-US
A notification box can pop up from `topRight` or `bottomRight` or `bottomLeft` or `topLeft`.
````__react
import { Button, Select, notification } from 'antd';
const { Option } = Select;
const options = ['topLeft', 'topRight','bottomLeft', 'bottomRight'];
const openNotification = () => {
notification.open({
message: 'Notification Title',
description: 'This is the content of the notification. This is the content of the notification. This is the content of the notification.',
});
};
ReactDOM.render(
<div>
<Select
defaultValue="topRight"
style={{ width: 120, marginRight: 10 }}
onChange={val => {
notification.config({
placement: val,
});
}}
>
{options.map(val => <Option key={val} value={val}>{val}</Option>)}
</Select>
<Button
type="primary"
onClick={openNotification}
>
Open the notification box
</Button>
</div>
, mountNode);
````

View File

@ -8,7 +8,7 @@ title: Notification
To display a notification message globally.
## When To Use
To display a notification message at the top right of the view port. Typically it can be
To display a notification message at the four corner of the view port. Typically it can be
used in the following cases:
- A notification with complex content.
@ -36,22 +36,26 @@ The properties of config are as follows:
| icon | Customized icon | React.Node | _ |
| key | The unique identifier of current notification | String | - |
| onClose | Specify a function that will be called after clicking the default close button | Function | - |
| duration | A notification box is closed after 4.5s by default. When specifying `duration` to null or 0, it will never be closed automatically | Number | 4.5 |
| duration | A notification box is closed after 4.5s by default. When specifying `duration` to null or 0, it will never be closed automatically | number | 4.5 |
| placement | To set the position, which can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
`notification` also provide 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 before displaying.
- `notification.config(options)`
```js
notification.config({
top: 100,
placement: 'bottomRight',
bottom: 50,
duration: 3,
});
```
| Property | Description | Type | Default |
|------------|--------------------|----------------------------|--------------|
| top | Offset to top of message | Number | 24px |
| duration | A duration to close notification automatically by default (unit: second) | Number | 4.5 |
| placement | To set the position, which can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
| top | Offset to top, when message pop up from `topRight` or `topLeft` (unit: pixels). | number | 24 |
| bottom | Offset to bottom, when message pop up from `bottomRight` or `bottomLeft` (unit: pixels). | number | 24 |
| duration | A duration to close notification automatically by default (unit: second) | number | 4.5 |

View File

@ -2,9 +2,47 @@ import React from 'react';
import Notification from 'rc-notification';
import Icon from '../icon';
import assign from 'object-assign';
let defaultTop = 24;
let notificationInstance;
let defaultDuration = 4.5;
let defaultTop = 24;
let defaultBottom = 24;
let defaultPlacement = 'topRight';
export type notificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
function getPlacementStyle(placement) {
let style;
switch (placement) {
case 'topLeft':
style = {
left: 0,
top: defaultTop,
bottom: 'auto',
};
break;
case 'bottomLeft':
style = {
left: 0,
top: 'auto',
bottom: defaultBottom,
};
break;
case 'bottomRight':
style = {
right: 0,
top: 'auto',
bottom: defaultBottom,
};
break;
default:
style = {
right: 0,
top: defaultTop,
bottom: 'auto',
};
}
return style;
}
export interface ArgsProps {
message: React.ReactNode | string;
@ -14,11 +52,14 @@ export interface ArgsProps {
onClose?: () => void;
duration?: number;
icon?: React.ReactNode;
placement?: notificationPlacement;
}
export interface ConfigProps {
top?: number;
bottom?: number;
duration?: number;
placement?: notificationPlacement;
}
function getNotificationInstance(prefixCls) {
@ -27,10 +68,8 @@ function getNotificationInstance(prefixCls) {
}
notificationInstance = (Notification as any).newInstance({
prefixCls: prefixCls,
style: {
top: defaultTop,
right: 0,
},
className: `${prefixCls}-${defaultPlacement}`,
style: getPlacementStyle(defaultPlacement),
});
return notificationInstance;
}
@ -39,6 +78,11 @@ function notice(args) {
const outerPrefixCls = args.prefixCls || 'ant-notification';
const prefixCls = `${outerPrefixCls}-notice`;
if (args.placement !== undefined) {
defaultPlacement = args.placement;
notificationInstance = null; // delete notificationInstance for new defaultPlacement
}
let duration;
if (args.duration === undefined) {
duration = defaultDuration;
@ -113,12 +157,22 @@ const api: {
}
},
config(options: ConfigProps) {
if (options.top !== undefined) {
defaultTop = options.top;
notificationInstance = null; // delete notificationInstance for new defaultTop
const { duration, placement, bottom, top } = options;
if (placement !== undefined) {
defaultPlacement = placement;
}
if (options.duration !== undefined) {
defaultDuration = options.duration;
if (bottom !== undefined) {
defaultBottom = bottom;
}
if (top !== undefined) {
defaultTop = top;
}
// delete notificationInstance
if (placement !== undefined || bottom !== undefined || top !== undefined) {
notificationInstance = null;
}
if (duration !== undefined) {
defaultDuration = duration;
}
},
destroy() {

View File

@ -10,7 +10,7 @@ subtitle: 通知提醒框
## 何时使用
在系统右上角显示通知提醒信息。经常用于以下情况:
在系统四个角显示通知提醒信息。经常用于以下情况:
- 较为复杂的通知内容。
- 带有交互的通知,给出用户下一步的行动点。
@ -36,7 +36,8 @@ config 参数如下:
| icon | 自定义图标 | React.Node | - |
| key | 当前通知唯一标志 | String | - |
| onClose | 点击默认关闭按钮时触发的回调函数 | Function | - |
| duration | 默认 4.5 秒后自动关闭,配置为 null 则不自动关闭 | Number | 4.5 |
| duration | 默认 4.5 秒后自动关闭,配置为 null 则不自动关闭 | number | 4.5 |
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
还提供了一个全局配置方法,在调用前提前配置,全局一次生效。
@ -44,12 +45,15 @@ config 参数如下:
```js
notification.config({
top: 100,
placement: 'bottomRight',
bottom: 50,
duration: 3,
});
```
| 参数 | 说明 | 类型 | 默认值 |
|------------|--------------------|----------------------------|--------------|
| top | 消息距离顶部的位置 | Number | 24px |
| duration | 默认自动关闭延时,单位秒 | Number | 4.5 |
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
| top | 消息从顶部弹出时,距离顶部的位置,单位像素。 | number | 24 |
| bottom | 消息从底部弹出时,距离底部的位置,单位像素。 | number | 24 |
| duration | 默认自动关闭延时,单位秒 | number | 4.5 |

View File

@ -12,6 +12,17 @@
width: @notification-width;
margin-right: 24px;
&-topLeft,
&-bottomLeft {
margin-left: 24px;
margin-right: 0;
.@{notification-prefix-cls}-fade-enter.@{notification-prefix-cls}-fade-enter-active,
.@{notification-prefix-cls}-fade-appear.@{notification-prefix-cls}-fade-appear-active {
animation-name: NotificationLeftFadeIn;
}
}
&-notice {
padding: @notification-padding;
border-radius: @border-radius-base;
@ -133,6 +144,17 @@
}
}
@keyframes NotificationLeftFadeIn {
0% {
opacity: 0;
right: @notification-width;
}
100% {
right: 0;
opacity: 1;
}
}
@keyframes NotificationFadeOut {
0% {
opacity: 1;