mirror of
https://github.com/ant-design/ant-design.git
synced 2025-08-06 16:06:28 +08:00
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:
parent
fd233cf430
commit
aadf623dc6
121
components/notification/__tests__/Notification.placement.test.js
Normal file
121
components/notification/__tests__/Notification.placement.test.js
Normal 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');
|
||||||
|
});
|
||||||
|
});
|
@ -28,6 +28,46 @@ exports[`test renders ./components/notification/demo/duration.md correctly 1`] =
|
|||||||
</button>
|
</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`] = `
|
exports[`test renders ./components/notification/demo/with-btn.md correctly 1`] = `
|
||||||
<button
|
<button
|
||||||
class="ant-btn ant-btn-primary"
|
class="ant-btn ant-btn-primary"
|
||||||
|
49
components/notification/demo/placement.md
Executable file
49
components/notification/demo/placement.md
Executable 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);
|
||||||
|
````
|
@ -8,7 +8,7 @@ title: Notification
|
|||||||
To display a notification message globally.
|
To display a notification message globally.
|
||||||
|
|
||||||
## When To Use
|
## 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:
|
used in the following cases:
|
||||||
|
|
||||||
- A notification with complex content.
|
- A notification with complex content.
|
||||||
@ -36,22 +36,26 @@ The properties of config are as follows:
|
|||||||
| icon | Customized icon | React.Node | _ |
|
| icon | Customized icon | React.Node | _ |
|
||||||
| key | The unique identifier of current notification | String | - |
|
| key | The unique identifier of current notification | String | - |
|
||||||
| onClose | Specify a function that will be called after clicking the default close button | Function | - |
|
| 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
|
`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.
|
will take into account these globally defined options before displaying.
|
||||||
|
|
||||||
- `notification.config(options)`
|
- `notification.config(options)`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
notification.config({
|
notification.config({
|
||||||
top: 100,
|
placement: 'bottomRight',
|
||||||
|
bottom: 50,
|
||||||
duration: 3,
|
duration: 3,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
| Property | Description | Type | Default |
|
| Property | Description | Type | Default |
|
||||||
|------------|--------------------|----------------------------|--------------|
|
|------------|--------------------|----------------------------|--------------|
|
||||||
| top | Offset to top of message | Number | 24px |
|
| placement | To set the position, which can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
|
||||||
| duration | A duration to close notification automatically by default (unit: second) | Number | 4.5 |
|
| 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 |
|
||||||
|
|
||||||
|
@ -2,9 +2,47 @@ import React from 'react';
|
|||||||
import Notification from 'rc-notification';
|
import Notification from 'rc-notification';
|
||||||
import Icon from '../icon';
|
import Icon from '../icon';
|
||||||
import assign from 'object-assign';
|
import assign from 'object-assign';
|
||||||
let defaultTop = 24;
|
|
||||||
let notificationInstance;
|
let notificationInstance;
|
||||||
let defaultDuration = 4.5;
|
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 {
|
export interface ArgsProps {
|
||||||
message: React.ReactNode | string;
|
message: React.ReactNode | string;
|
||||||
@ -14,11 +52,14 @@ export interface ArgsProps {
|
|||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
placement?: notificationPlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigProps {
|
export interface ConfigProps {
|
||||||
top?: number;
|
top?: number;
|
||||||
|
bottom?: number;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
|
placement?: notificationPlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNotificationInstance(prefixCls) {
|
function getNotificationInstance(prefixCls) {
|
||||||
@ -27,10 +68,8 @@ function getNotificationInstance(prefixCls) {
|
|||||||
}
|
}
|
||||||
notificationInstance = (Notification as any).newInstance({
|
notificationInstance = (Notification as any).newInstance({
|
||||||
prefixCls: prefixCls,
|
prefixCls: prefixCls,
|
||||||
style: {
|
className: `${prefixCls}-${defaultPlacement}`,
|
||||||
top: defaultTop,
|
style: getPlacementStyle(defaultPlacement),
|
||||||
right: 0,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
return notificationInstance;
|
return notificationInstance;
|
||||||
}
|
}
|
||||||
@ -39,6 +78,11 @@ function notice(args) {
|
|||||||
const outerPrefixCls = args.prefixCls || 'ant-notification';
|
const outerPrefixCls = args.prefixCls || 'ant-notification';
|
||||||
const prefixCls = `${outerPrefixCls}-notice`;
|
const prefixCls = `${outerPrefixCls}-notice`;
|
||||||
|
|
||||||
|
if (args.placement !== undefined) {
|
||||||
|
defaultPlacement = args.placement;
|
||||||
|
notificationInstance = null; // delete notificationInstance for new defaultPlacement
|
||||||
|
}
|
||||||
|
|
||||||
let duration;
|
let duration;
|
||||||
if (args.duration === undefined) {
|
if (args.duration === undefined) {
|
||||||
duration = defaultDuration;
|
duration = defaultDuration;
|
||||||
@ -113,12 +157,22 @@ const api: {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
config(options: ConfigProps) {
|
config(options: ConfigProps) {
|
||||||
if (options.top !== undefined) {
|
const { duration, placement, bottom, top } = options;
|
||||||
defaultTop = options.top;
|
if (placement !== undefined) {
|
||||||
notificationInstance = null; // delete notificationInstance for new defaultTop
|
defaultPlacement = placement;
|
||||||
}
|
}
|
||||||
if (options.duration !== undefined) {
|
if (bottom !== undefined) {
|
||||||
defaultDuration = options.duration;
|
defaultBottom = bottom;
|
||||||
|
}
|
||||||
|
if (top !== undefined) {
|
||||||
|
defaultTop = top;
|
||||||
|
}
|
||||||
|
// delete notificationInstance
|
||||||
|
if (placement !== undefined || bottom !== undefined || top !== undefined) {
|
||||||
|
notificationInstance = null;
|
||||||
|
}
|
||||||
|
if (duration !== undefined) {
|
||||||
|
defaultDuration = duration;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroy() {
|
destroy() {
|
||||||
|
@ -10,7 +10,7 @@ subtitle: 通知提醒框
|
|||||||
|
|
||||||
## 何时使用
|
## 何时使用
|
||||||
|
|
||||||
在系统右上角显示通知提醒信息。经常用于以下情况:
|
在系统四个角显示通知提醒信息。经常用于以下情况:
|
||||||
|
|
||||||
- 较为复杂的通知内容。
|
- 较为复杂的通知内容。
|
||||||
- 带有交互的通知,给出用户下一步的行动点。
|
- 带有交互的通知,给出用户下一步的行动点。
|
||||||
@ -36,7 +36,8 @@ config 参数如下:
|
|||||||
| icon | 自定义图标 | React.Node | - |
|
| icon | 自定义图标 | React.Node | - |
|
||||||
| key | 当前通知唯一标志 | String | - |
|
| key | 当前通知唯一标志 | String | - |
|
||||||
| onClose | 点击默认关闭按钮时触发的回调函数 | Function | - |
|
| 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
|
```js
|
||||||
notification.config({
|
notification.config({
|
||||||
top: 100,
|
placement: 'bottomRight',
|
||||||
|
bottom: 50,
|
||||||
duration: 3,
|
duration: 3,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|------------|--------------------|----------------------------|--------------|
|
|------------|--------------------|----------------------------|--------------|
|
||||||
| top | 消息距离顶部的位置 | Number | 24px |
|
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
|
||||||
| duration | 默认自动关闭延时,单位秒 | Number | 4.5 |
|
| top | 消息从顶部弹出时,距离顶部的位置,单位像素。 | number | 24 |
|
||||||
|
| bottom | 消息从底部弹出时,距离底部的位置,单位像素。 | number | 24 |
|
||||||
|
| duration | 默认自动关闭延时,单位秒 | number | 4.5 |
|
||||||
|
@ -12,6 +12,17 @@
|
|||||||
width: @notification-width;
|
width: @notification-width;
|
||||||
margin-right: 24px;
|
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 {
|
&-notice {
|
||||||
padding: @notification-padding;
|
padding: @notification-padding;
|
||||||
border-radius: @border-radius-base;
|
border-radius: @border-radius-base;
|
||||||
@ -133,6 +144,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes NotificationLeftFadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
right: @notification-width;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
right: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes NotificationFadeOut {
|
@keyframes NotificationFadeOut {
|
||||||
0% {
|
0% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user