feat(components): [el-message] config-provider message max attr (#5063)

* feat(components): [el-message] config-provider message max attr

* chore: update test

* feat: update test and message-method

* chore: format config-provider.md

* test: add multiple config-provider

* test: config-provider nesting
This commit is contained in:
btea 2022-01-08 06:03:13 -06:00 committed by GitHub
parent 53fe828273
commit 70fa3e7f26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 149 additions and 10 deletions

View File

@ -25,14 +25,23 @@ config-provider/button
:::
## message configurations
:::demo
config-provider/message
:::
## Config Provider Attributes
| Attribute | Description | Type | Accepted Values | Default |
| --------- | --------------------------------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------- | ----------------------- |
| locale | Locale Object | Object\<Language\> | [languages](https://github.com/element-plus/element-plus/tree/dev/packages/locale/lang) | English |
| size | global component size | string | large / default /small | default |
| zIndex | global Initial zIndex | number | - | - |
| button | button related configuration, [see the following table](#button-attributes) | ButtonGlobalConfig | - | see the following table |
| Attribute | Description | Type | Accepted Values | Default |
| --------- | ----------------------------------------------------------------------------- | ------------------- | --------------------------------------------------------------------------------------- | ----------------------- |
| locale | Locale Object | Object\<Language\> | [languages](https://github.com/element-plus/element-plus/tree/dev/packages/locale/lang) | English |
| size | global component size | string | large / default /small | default |
| zIndex | global Initial zIndex | number | - | - |
| button | button related configuration, [see the following table](#button-attributes) | ButtonGlobalConfig | - | see the following table |
| message | message related configuration, [see the following table](#message-attributes) | MessageGlobalConfig | - | see the following table |
## Button Attributes
@ -40,6 +49,12 @@ config-provider/button
| --------------- | ----------------------------------------------------------- | ------- | --------------- | ------- |
| autoInsertSpace | automatically insert a space between two chinese characters | boolean | - | false |
## Message Attributes
| Attribute | Description | Type | Accepted Values | Default |
| --------- | --------------------------------------------------------------------- | ------ | --------------- | ------- |
| max | the maximum number of messages that can be displayed at the same time | number | - | - |
## ConfigProvider Slots
| Name | Description |

View File

@ -0,0 +1,18 @@
<template>
<div>
<el-config-provider :message="config">
<el-button @click="open">open</el-button>
</el-config-provider>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
const config = reactive({
max: 3,
})
const open = () => {
ElMessage('this is a message.')
}
</script>

View File

@ -18,6 +18,6 @@ module.exports = {
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
// u can change this option to a more specific folder for test single component or util when dev
// for example, ['<rootDir>/packages/input']
// for example, ['<rootDir>/packages/components/input']
roots: ['<rootDir>'],
}

View File

@ -3,7 +3,8 @@ import { mount } from '@vue/test-utils'
import { useLocale } from '@element-plus/hooks'
import Chinese from '@element-plus/locale/lang/zh-cn'
import English from '@element-plus/locale/lang/en'
import { ElButton } from '@element-plus/components'
import { ElButton, ElMessage } from '@element-plus/components'
import { sleep } from '@element-plus/test-utils'
import ConfigProvider from '../src/config-provider'
import type { Language } from '@element-plus/locale'
@ -120,4 +121,87 @@ describe('config-provider', () => {
).toBeFalsy()
})
})
describe('message-config', () => {
it('limit the number of messages displayed at the same time', async () => {
const wrapper = mount({
components: {
[ConfigProvider.name]: ConfigProvider,
ElButton,
},
setup() {
const config = reactive({
max: 3,
})
const open = () => {
ElMessage('this is a message.')
}
return {
config,
open,
}
},
template: `
<el-config-provider :message="config">
<el-button @click="open">open</el-button>
</el-config-provider>
`,
})
await nextTick()
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
await nextTick()
expect(document.querySelectorAll('.el-message').length).toBe(3)
wrapper.vm.config.max = 10
await nextTick()
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
await nextTick()
expect(document.querySelectorAll('.el-message').length).toBe(7)
})
it('multiple config-provider config override', async () => {
const wrapper = mount({
components: {
[ConfigProvider.name]: ConfigProvider,
ElButton,
},
setup() {
const config = reactive({
max: 3,
})
const overrideConfig = reactive({
max: 1,
})
const open = () => {
ElMessage('this is a message.')
}
return {
config,
overrideConfig,
open,
}
},
template: `
<el-config-provider :message="config">
<el-config-provider :message="overrideConfig">
<el-button @click="open">open</el-button>
</el-config-provider>
</el-config-provider>
`,
})
ElMessage.closeAll()
await sleep(40)
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
wrapper.find('.el-button').trigger('click')
await nextTick()
expect(document.querySelectorAll('.el-message').length).toBe(1)
})
})
})

View File

@ -1,8 +1,11 @@
import { defineComponent, renderSlot } from 'vue'
import { defineComponent, renderSlot, watch } from 'vue'
import { buildProps, definePropType } from '@element-plus/utils/props'
import { provideGlobalConfig } from '@element-plus/hooks'
import type { Language } from '@element-plus/locale'
import type { ButtonConfigContext } from '@element-plus/components/button'
import type { MessageConfigContext } from '@element-plus/components/message'
export const messageConfig: MessageConfigContext = {}
export const configProviderProps = buildProps({
locale: {
@ -18,6 +21,10 @@ export const configProviderProps = buildProps({
type: definePropType<ButtonConfigContext>(Object),
},
message: {
type: definePropType<MessageConfigContext>(Object),
},
zIndex: {
type: Number,
},
@ -28,6 +35,13 @@ export default defineComponent({
props: configProviderProps,
setup(props, { slots }) {
watch(
() => props.message,
(val) => {
Object.assign(messageConfig, val ?? {})
},
{ immediate: true, deep: true }
)
const config = provideGlobalConfig(props)
return () => renderSlot(slots, 'default', { config: config?.value })
},

View File

@ -1,8 +1,9 @@
import { createVNode, render } from 'vue'
import { isClient } from '@vueuse/core'
import { isVNode } from '@element-plus/utils/util'
import { isVNode, isNumber } from '@element-plus/utils/util'
import { PopupManager } from '@element-plus/utils/popup-manager'
import { debugWarn } from '@element-plus/utils/error'
import { messageConfig } from '@element-plus/components/config-provider/src/config-provider'
import MessageConstructor from './message.vue'
import { messageTypes } from './message'
@ -16,6 +17,9 @@ let seed = 1
const message: MessageFn & Partial<Message> = function (options = {}) {
if (!isClient) return { close: () => undefined }
if (isNumber(messageConfig.max) && instances.length >= messageConfig.max) {
return { close: () => undefined }
}
if (
!isVNode(options) &&

View File

@ -4,6 +4,10 @@ import type { VNode, ExtractPropTypes, Component } from 'vue'
export const messageTypes = ['success', 'info', 'warning', 'error'] as const
export interface MessageConfigContext {
max?: number
}
export const messageProps = buildProps({
customClass: {
type: String,