mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-01 03:29:39 +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>
|
||||
`;
|
||||
|
||||
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"
|
||||
|
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.
|
||||
|
||||
## 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 |
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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 |
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user