diff --git a/components/components.ts b/components/components.ts index 73b8623053..45a9c4ab72 100644 --- a/components/components.ts +++ b/components/components.ts @@ -114,6 +114,7 @@ export { default as Modal } from './modal'; export type { StatisticProps } from './statistic'; export { default as Statistic, StatisticCountdown } from './statistic'; +export type { NotificationPlacement } from './notification'; export { default as notification } from './notification'; export type { PageHeaderProps } from './page-header'; diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx index 07ba5f5c4d..6dd282e64c 100644 --- a/components/config-provider/index.tsx +++ b/components/config-provider/index.tsx @@ -9,6 +9,8 @@ import type { TransformCellTextProps } from '../table/interface'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; import type { RequiredMark } from '../form/Form'; import type { MaybeRef } from '../_util/type'; +import message from '../message'; +import notification from '../notification'; export type SizeType = 'small' | 'middle' | 'large' | undefined; @@ -248,6 +250,17 @@ const ConfigProvider = defineComponent({ ); }; + watchEffect(() => { + if (props.direction) { + message.config({ + rtl: props.direction === 'rtl', + }); + notification.config({ + rtl: props.direction === 'rtl', + }); + } + }); + return () => ( renderProvider(legacyLocale as Locale)} /> ); diff --git a/components/message/__tests__/__snapshots__/demo.test.js.snap b/components/message/__tests__/__snapshots__/demo.test.js.snap index 45e34c08df..218b35d0c4 100644 --- a/components/message/__tests__/__snapshots__/demo.test.js.snap +++ b/components/message/__tests__/__snapshots__/demo.test.js.snap @@ -1,5 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`renders ./components/message/demo/custom-style.vue correctly 1`] = ` + +`; + exports[`renders ./components/message/demo/duration.vue correctly 1`] = ` +
+
+ `; diff --git a/components/message/__tests__/index.test.js b/components/message/__tests__/index.test.js index 33e727348c..99e8c3a48d 100644 --- a/components/message/__tests__/index.test.js +++ b/components/message/__tests__/index.test.js @@ -1,9 +1,10 @@ import { asyncExpect } from '../../../tests/utils'; -import message from '..'; +import message, { getInstance } from '..'; import SmileOutlined from '@ant-design/icons-vue/SmileOutlined'; describe('message', () => { beforeEach(() => { + jest.useFakeTimers(); document.body.outerHTML = ''; }); @@ -11,6 +12,11 @@ describe('message', () => { message.destroy(); }); + afterEach(() => { + message.destroy(); + jest.useRealTimers(); + }); + it('should be able to config top', async () => { message.config({ top: '100px', @@ -41,46 +47,34 @@ describe('message', () => { message.info('test'); } message.info('last'); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(5); - expect(document.querySelectorAll('.ant-message-notice')[4].textContent).toBe('last'); - }, 0); + await Promise.resolve(); + jest.runAllTimers(); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(5); + expect(document.querySelectorAll('.ant-message-notice')[4].textContent).toBe('last'); }); it('should be able to hide manually', async () => { const hide1 = message.info('whatever', 0); const hide2 = message.info('whatever', 0); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(2); - hide1(); - }, 0); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(1); - hide2(); - }, 0); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(0); - }, 0); + await Promise.resolve(); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(2); + hide1(); + jest.runAllTimers(); + expect(getInstance().component.value.notices).toHaveLength(1); + hide2(); + jest.runAllTimers(); + expect(getInstance().component.value.notices).toHaveLength(0); }); it('should be able to destroy globally', async () => { - await asyncExpect(() => { - message.info('whatever', 0); - }); - await asyncExpect(() => { - message.info('whatever', 0); - }); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message').length).toBe(1); - expect(document.querySelectorAll('.ant-message-notice').length).toBe(2); - }); - await asyncExpect(() => { - message.destroy(); - }); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message').length).toBe(0); - expect(document.querySelectorAll('.ant-message-notice').length).toBe(0); - }); + message.info('whatever', 0); + message.info('whatever', 0); + await Promise.resolve(); + expect(document.querySelectorAll('.ant-message').length).toBe(1); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(2); + message.destroy(); + expect(document.querySelectorAll('.ant-message').length).toBe(0); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(0); }); it('should not need to use duration argument when using the onClose arguments', () => { @@ -88,6 +82,7 @@ describe('message', () => { }); it('should have the default duration when using the onClose arguments', done => { + jest.useRealTimers(); const defaultDuration = 3; const now = Date.now(); message.info('whatever', () => { @@ -99,6 +94,7 @@ describe('message', () => { }); it('should be called like promise', done => { + jest.useRealTimers(); const defaultDuration = 3; const now = Date.now(); message.info('whatever').then(() => { @@ -112,38 +108,32 @@ describe('message', () => { // https:// github.com/ant-design/ant-design/issues/8201 it('should hide message correctly', async () => { let hide = message.loading('Action in progress..', 0); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(1); - hide(); - }, 0); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(0); - }, 0); + await Promise.resolve(); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(1); + hide(); + await Promise.resolve(); + jest.runAllTimers(); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(0); }); it('should allow custom icon', async () => { message.open({ content: 'Message', icon: }); - await asyncExpect(() => { - expect(document.querySelectorAll('.anticon-smile').length).toBe(1); - }, 0); + await Promise.resolve(); + expect(document.querySelectorAll('.anticon-smile').length).toBe(1); }); it('should have no icon', async () => { message.open({ content: 'Message' }); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice .anticon').length).toBe(0); - }, 0); + await Promise.resolve(); + expect(document.querySelectorAll('.ant-message-notice .anticon').length).toBe(0); }); // https://github.com/ant-design/ant-design/issues/8201 it('should destroy messages correctly', async () => { message.loading('Action in progress1..', 0); message.loading('Action in progress2..', 0); setTimeout(() => message.destroy(), 1000); - - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(2); - }, 0); - await asyncExpect(() => { - expect(document.querySelectorAll('.ant-message-notice').length).toBe(0); - }, 1500); + await Promise.resolve(); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(2); + jest.runAllTimers(); + expect(document.querySelectorAll('.ant-message-notice').length).toBe(0); }); }); diff --git a/components/message/demo/custom-style.vue b/components/message/demo/custom-style.vue new file mode 100644 index 0000000000..3c70c80d34 --- /dev/null +++ b/components/message/demo/custom-style.vue @@ -0,0 +1,46 @@ + +--- +order: 6 +title: + zh-CN: 自定义样式 + en-US: Customized style +--- + +## zh-CN + +使用 `style` 和 `class` 来定义样式。 + +## en-US + +The `style` and `class` are available to customize Message. + + + + + + diff --git a/components/message/demo/index.vue b/components/message/demo/index.vue index 8cc38ab40d..6ad3af47cf 100644 --- a/components/message/demo/index.vue +++ b/components/message/demo/index.vue @@ -6,6 +6,7 @@ + + diff --git a/components/notification/demo/placement.vue b/components/notification/demo/placement.vue index 6a6bbfc541..4e400515ef 100644 --- a/components/notification/demo/placement.vue +++ b/components/notification/demo/placement.vue @@ -46,6 +46,7 @@ import { } from '@ant-design/icons-vue'; import { notification } from 'ant-design-vue'; import { defineComponent } from 'vue'; +import type { NotificationPlacement } from 'ant-design-vue'; export default defineComponent({ components: { RadiusUpleftOutlined, @@ -54,7 +55,7 @@ export default defineComponent({ RadiusBottomrightOutlined, }, setup() { - const openNotification = (placement: string) => { + const openNotification = (placement: NotificationPlacement) => { notification.open({ message: `Notification ${placement}`, description: diff --git a/components/notification/demo/update.vue b/components/notification/demo/update.vue index 69d5c215bb..6b0dd9938f 100644 --- a/components/notification/demo/update.vue +++ b/components/notification/demo/update.vue @@ -1,27 +1,34 @@ --- -order: 7 -title: - zh-CN: 更新消息内容 +order: 7 +title: + zh-CN: 更新消息内容 en-US: Update Message Content --- ## zh-CN -可以通过唯一的 key 来更新内容。 +可以通过唯一的 key 来更新内容, 或者通过响应式数据更新。 ## en-US -Update content with unique key. +Update content with unique key, or use reactive data.