Skip to content

Commit ad76bb6

Browse files
authored
refactor: message & notification (#5113)
* refactor: notification * refactor: message * refactor: notification * test: update message & notification test
1 parent 8a3724f commit ad76bb6

31 files changed

+938
-574
lines changed

components/components.ts

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export { default as Modal } from './modal';
114114
export type { StatisticProps } from './statistic';
115115
export { default as Statistic, StatisticCountdown } from './statistic';
116116

117+
export type { NotificationPlacement } from './notification';
117118
export { default as notification } from './notification';
118119

119120
export type { PageHeaderProps } from './page-header';

components/config-provider/index.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import type { TransformCellTextProps } from '../table/interface';
99
import LocaleReceiver from '../locale-provider/LocaleReceiver';
1010
import type { RequiredMark } from '../form/Form';
1111
import type { MaybeRef } from '../_util/type';
12+
import message from '../message';
13+
import notification from '../notification';
1214

1315
export type SizeType = 'small' | 'middle' | 'large' | undefined;
1416

@@ -248,6 +250,17 @@ const ConfigProvider = defineComponent({
248250
);
249251
};
250252

253+
watchEffect(() => {
254+
if (props.direction) {
255+
message.config({
256+
rtl: props.direction === 'rtl',
257+
});
258+
notification.config({
259+
rtl: props.direction === 'rtl',
260+
});
261+
}
262+
});
263+
251264
return () => (
252265
<LocaleReceiver children={(_, __, legacyLocale) => renderProvider(legacyLocale as Locale)} />
253266
);

components/message/__tests__/__snapshots__/demo.test.js.snap

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`renders ./components/message/demo/custom-style.vue correctly 1`] = `
4+
<button class="ant-btn" type="button">
5+
<!----><span>Customized style</span>
6+
</button>
7+
`;
8+
39
exports[`renders ./components/message/demo/duration.vue correctly 1`] = `
410
<button class="ant-btn" type="button">
511
<!----><span>Customized display duration</span>
@@ -36,6 +42,11 @@ exports[`renders ./components/message/demo/thenable.vue correctly 1`] = `
3642

3743
exports[`renders ./components/message/demo/update.vue correctly 1`] = `
3844
<button class="ant-btn ant-btn-primary" type="button">
39-
<!----><span>Open the message box</span>
45+
<!----><span>Open the message box (update by key)</span>
46+
</button>
47+
<br>
48+
<br>
49+
<button class="ant-btn ant-btn-primary" type="button">
50+
<!----><span>Open the message box (update by reactive)</span>
4051
</button>
4152
`;
+43-53
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
import { asyncExpect } from '../../../tests/utils';
2-
import message from '..';
2+
import message, { getInstance } from '..';
33
import SmileOutlined from '@ant-design/icons-vue/SmileOutlined';
44

55
describe('message', () => {
66
beforeEach(() => {
7+
jest.useFakeTimers();
78
document.body.outerHTML = '';
89
});
910

1011
afterEach(() => {
1112
message.destroy();
1213
});
1314

15+
afterEach(() => {
16+
message.destroy();
17+
jest.useRealTimers();
18+
});
19+
1420
it('should be able to config top', async () => {
1521
message.config({
1622
top: '100px',
@@ -41,53 +47,42 @@ describe('message', () => {
4147
message.info('test');
4248
}
4349
message.info('last');
44-
await asyncExpect(() => {
45-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(5);
46-
expect(document.querySelectorAll('.ant-message-notice')[4].textContent).toBe('last');
47-
}, 0);
50+
await Promise.resolve();
51+
jest.runAllTimers();
52+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(5);
53+
expect(document.querySelectorAll('.ant-message-notice')[4].textContent).toBe('last');
4854
});
4955

5056
it('should be able to hide manually', async () => {
5157
const hide1 = message.info('whatever', 0);
5258
const hide2 = message.info('whatever', 0);
53-
await asyncExpect(() => {
54-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
55-
hide1();
56-
}, 0);
57-
await asyncExpect(() => {
58-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(1);
59-
hide2();
60-
}, 0);
61-
await asyncExpect(() => {
62-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
63-
}, 0);
59+
await Promise.resolve();
60+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
61+
hide1();
62+
jest.runAllTimers();
63+
expect(getInstance().component.value.notices).toHaveLength(1);
64+
hide2();
65+
jest.runAllTimers();
66+
expect(getInstance().component.value.notices).toHaveLength(0);
6467
});
6568

6669
it('should be able to destroy globally', async () => {
67-
await asyncExpect(() => {
68-
message.info('whatever', 0);
69-
});
70-
await asyncExpect(() => {
71-
message.info('whatever', 0);
72-
});
73-
await asyncExpect(() => {
74-
expect(document.querySelectorAll('.ant-message').length).toBe(1);
75-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
76-
});
77-
await asyncExpect(() => {
78-
message.destroy();
79-
});
80-
await asyncExpect(() => {
81-
expect(document.querySelectorAll('.ant-message').length).toBe(0);
82-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
83-
});
70+
message.info('whatever', 0);
71+
message.info('whatever', 0);
72+
await Promise.resolve();
73+
expect(document.querySelectorAll('.ant-message').length).toBe(1);
74+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
75+
message.destroy();
76+
expect(document.querySelectorAll('.ant-message').length).toBe(0);
77+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
8478
});
8579

8680
it('should not need to use duration argument when using the onClose arguments', () => {
8781
message.info('whatever', () => {});
8882
});
8983

9084
it('should have the default duration when using the onClose arguments', done => {
85+
jest.useRealTimers();
9186
const defaultDuration = 3;
9287
const now = Date.now();
9388
message.info('whatever', () => {
@@ -99,6 +94,7 @@ describe('message', () => {
9994
});
10095

10196
it('should be called like promise', done => {
97+
jest.useRealTimers();
10298
const defaultDuration = 3;
10399
const now = Date.now();
104100
message.info('whatever').then(() => {
@@ -112,38 +108,32 @@ describe('message', () => {
112108
// https:// github.com/ant-design/ant-design/issues/8201
113109
it('should hide message correctly', async () => {
114110
let hide = message.loading('Action in progress..', 0);
115-
await asyncExpect(() => {
116-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(1);
117-
hide();
118-
}, 0);
119-
await asyncExpect(() => {
120-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
121-
}, 0);
111+
await Promise.resolve();
112+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(1);
113+
hide();
114+
await Promise.resolve();
115+
jest.runAllTimers();
116+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
122117
});
123118
it('should allow custom icon', async () => {
124119
message.open({ content: 'Message', icon: <SmileOutlined /> });
125-
await asyncExpect(() => {
126-
expect(document.querySelectorAll('.anticon-smile').length).toBe(1);
127-
}, 0);
120+
await Promise.resolve();
121+
expect(document.querySelectorAll('.anticon-smile').length).toBe(1);
128122
});
129123

130124
it('should have no icon', async () => {
131125
message.open({ content: 'Message' });
132-
await asyncExpect(() => {
133-
expect(document.querySelectorAll('.ant-message-notice .anticon').length).toBe(0);
134-
}, 0);
126+
await Promise.resolve();
127+
expect(document.querySelectorAll('.ant-message-notice .anticon').length).toBe(0);
135128
});
136129
// https://github.com/ant-design/ant-design/issues/8201
137130
it('should destroy messages correctly', async () => {
138131
message.loading('Action in progress1..', 0);
139132
message.loading('Action in progress2..', 0);
140133
setTimeout(() => message.destroy(), 1000);
141-
142-
await asyncExpect(() => {
143-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
144-
}, 0);
145-
await asyncExpect(() => {
146-
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
147-
}, 1500);
134+
await Promise.resolve();
135+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(2);
136+
jest.runAllTimers();
137+
expect(document.querySelectorAll('.ant-message-notice').length).toBe(0);
148138
});
149139
});
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<docs>
2+
---
3+
order: 6
4+
title:
5+
zh-CN: 自定义样式
6+
en-US: Customized style
7+
---
8+
9+
## zh-CN
10+
11+
使用 `style` 和 `class` 来定义样式。
12+
13+
## en-US
14+
15+
The `style` and `class` are available to customize Message.
16+
17+
</docs>
18+
19+
<template>
20+
<a-button @click="success">Customized style</a-button>
21+
</template>
22+
<script lang="ts">
23+
import { message } from 'ant-design-vue';
24+
import { defineComponent } from 'vue';
25+
export default defineComponent({
26+
setup() {
27+
const success = () => {
28+
message.success({
29+
content: () => 'This is a prompt message with custom className and style',
30+
class: 'custom-class',
31+
style: {
32+
marginTop: '20vh',
33+
},
34+
});
35+
};
36+
return {
37+
success,
38+
};
39+
},
40+
});
41+
</script>
42+
<style>
43+
.custom-class {
44+
color: red;
45+
}
46+
</style>

components/message/demo/index.vue

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<loading />
77
<thenable />
88
<update />
9+
<customStyleVue />
910
</demo-sort>
1011
</template>
1112
<script lang="ts">
@@ -15,6 +16,7 @@ import Duration from './duration.vue';
1516
import Loading from './loading.vue';
1617
import Thenable from './thenable.vue';
1718
import Update from './update.vue';
19+
import customStyleVue from './custom-style.vue';
1820
import CN from '../index.zh-CN.md';
1921
import US from '../index.en-US.md';
2022
import { defineComponent } from 'vue';
@@ -28,6 +30,7 @@ export default defineComponent({
2830
Loading,
2931
Thenable,
3032
Update,
33+
customStyleVue,
3134
},
3235
setup() {
3336
return {};

components/message/demo/update.vue

+18-4
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,25 @@ title:
88

99
## zh-CN
1010

11-
可以通过唯一的 `key` 来更新内容。
11+
可以通过唯一的 `key` 来更新内容、或者响应式数据
1212

1313
## en-US
1414

15-
Update message content with unique `key`.
15+
Update message content with unique `key`,or use reactive data.
1616

1717
</docs>
1818

1919
<template>
20-
<a-button type="primary" @click="openMessage">Open the message box</a-button>
20+
<a-button type="primary" @click="openMessage">Open the message box (update by key)</a-button>
21+
<br />
22+
<br />
23+
<a-button type="primary" @click="openMessage2">
24+
Open the message box (update by reactive)
25+
</a-button>
2126
</template>
2227
<script lang="ts">
2328
import { message } from 'ant-design-vue';
24-
import { defineComponent } from 'vue';
29+
import { defineComponent, ref } from 'vue';
2530
const key = 'updatable';
2631
export default defineComponent({
2732
setup() {
@@ -31,8 +36,17 @@ export default defineComponent({
3136
message.success({ content: 'Loaded!', key, duration: 2 });
3237
}, 1000);
3338
};
39+
const content = ref('Loading...');
40+
const openMessage2 = () => {
41+
// content must use function
42+
message.loading({ content: () => content.value });
43+
setTimeout(() => {
44+
content.value = 'Loaded!';
45+
}, 1000);
46+
};
3447
return {
3548
openMessage,
49+
openMessage2,
3650
};
3751
},
3852
});

components/message/index.en-US.md

+17-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ This components provides some static methods, with usage and arguments as follow
2525

2626
| Argument | Description | Type | Default |
2727
| --- | --- | --- | --- |
28-
| content | content of the message | string\| VNode | - |
28+
| content | content of the message | string\| VNode \| () => VNode | - |
2929
| duration | time(seconds) before auto-dismiss, don't dismiss if set to 0 | number | 1.5 |
3030
| onClose | Specify a function that will be called when the message is closed | Function | - |
3131

@@ -48,11 +48,15 @@ The properties of config are as follows:
4848

4949
| Property | Description | Type | Default | Version |
5050
| --- | --- | --- | --- | --- |
51-
| content | content of the message | string\| VNode | - | |
51+
| class | Customized CSS class | string | - |
52+
| content | content of the message | string\| VNode \| () => VNode | - | |
5253
| duration | time(seconds) before auto-dismiss, don't dismiss if set to 0 | number | 3 | |
5354
| onClose | Specify a function that will be called when the message is closed | function | - | |
54-
| icon | Customized Icon | VNode | - | |
55+
| icon | Customized Icon | VNode \| ()=> VNode | - | |
5556
| key | The unique identifier of the Message | string\|number | - | |
57+
| style | Customized inline style | CSSProperties | - | |
58+
| onClick | Specify a function that will be called when the message is clicked | function | - | |
59+
| onClose | Specify a function that will be called when the message is closed | function | - | |
5660

5761
### Global static methods
5862

@@ -68,12 +72,16 @@ message.config({
6872
top: '100px',
6973
duration: 2,
7074
maxCount: 3,
75+
rtl: true,
76+
prefixCls: 'my-message',
7177
});
7278
```
7379

74-
| Argument | Description | Type | Default |
75-
| --- | --- | --- | --- |
76-
| duration | time before auto-dismiss, in seconds | number | 1.5 |
77-
| getContainer | Return the mount node for Message | () => HTMLElement | () => document.body |
78-
| maxCount | max message show, drop oldest if exceed limit | number | - |
79-
| top | distance from top | string | `24px` |
80+
| Argument | Description | Type | Default | Version |
81+
| --- | --- | --- | --- | --- |
82+
| duration | time before auto-dismiss, in seconds | number | 1.5 | |
83+
| getContainer | Return the mount node for Message | () => HTMLElement | () => document.body | |
84+
| maxCount | max message show, drop oldest if exceed limit | number | - | |
85+
| prefixCls | The prefix className of message node | string | `ant-message` | 3.0 |
86+
| rtl | Whether to enable RTL mode | boolean | false | 3.0 |
87+
| top | distance from top | string | `8px` |

0 commit comments

Comments
 (0)