mirror of
https://github.com/element-plus/element-plus.git
synced 2024-12-27 03:01:14 +08:00
fix(message-box): fix incompatible migration (#1671)
* fix(message-box): fix incompatible migration * docs(message-box): add docs of buttonSize
This commit is contained in:
parent
99451a1ef6
commit
25868c2446
@ -2,7 +2,7 @@
|
||||
<transition name="fade-in-linear" @after-leave="$emit('vanish')">
|
||||
<el-overlay
|
||||
v-show="visible"
|
||||
:z-index="state.zIndex"
|
||||
:z-index="zIndex"
|
||||
:overlay-class="['is-message-box', modalClass]"
|
||||
:mask="modal"
|
||||
@click.self="handleWrapperClick"
|
||||
@ -60,46 +60,46 @@
|
||||
<div v-show="showInput" class="el-message-box__input">
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
v-model="state.inputValue"
|
||||
v-model="inputValue"
|
||||
:type="inputType"
|
||||
:placeholder="inputPlaceholder"
|
||||
:class="{ invalid: state.validateError }"
|
||||
:class="{ invalid: validateError }"
|
||||
@keydown.prevent.enter="handleInputEnter"
|
||||
/>
|
||||
<div
|
||||
class="el-message-box__errormsg"
|
||||
:style="{
|
||||
visibility: !!state.editorErrorMessage ? 'visible' : 'hidden',
|
||||
visibility: !!editorErrorMessage ? 'visible' : 'hidden',
|
||||
}"
|
||||
>
|
||||
{{ state.editorErrorMessage }}
|
||||
{{ editorErrorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-message-box__btns">
|
||||
<el-button
|
||||
v-if="showCancelButton"
|
||||
:loading="state.cancelButtonLoading"
|
||||
:loading="cancelButtonLoading"
|
||||
:class="[cancelButtonClass]"
|
||||
:round="roundButton"
|
||||
size="small"
|
||||
:size="buttonSize || 'small'"
|
||||
@click="handleAction('cancel')"
|
||||
@keydown.enter="handleAction('cancel')"
|
||||
>
|
||||
{{ state.cancelButtonText || t('el.messagebox.cancel') }}
|
||||
{{ cancelButtonText || t('el.messagebox.cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-show="showConfirmButton"
|
||||
ref="confirmRef"
|
||||
:loading="state.confirmButtonLoading"
|
||||
:loading="confirmButtonLoading"
|
||||
:class="[confirmButtonClasses]"
|
||||
:round="roundButton"
|
||||
:disabled="state.confirmButtonDisabled"
|
||||
size="small"
|
||||
:disabled="confirmButtonDisabled"
|
||||
:size="buttonSize || 'small'"
|
||||
@click="handleAction('confirm')"
|
||||
@keydown.enter="handleAction('confirm')"
|
||||
>
|
||||
{{ state.confirmButtonText || t('el.messagebox.confirm') }}
|
||||
{{ confirmButtonText || t('el.messagebox.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@ -116,7 +116,8 @@ import {
|
||||
watch,
|
||||
reactive,
|
||||
ref,
|
||||
isVNode,
|
||||
toRefs,
|
||||
PropType,
|
||||
} from 'vue'
|
||||
import ElButton from '@element-plus/button'
|
||||
import ElInput from '@element-plus/input'
|
||||
@ -126,11 +127,11 @@ import { useModal, useLockScreen, useRestoreActive, usePreventGlobal } from '@el
|
||||
import { TrapFocus } from '@element-plus/directives'
|
||||
import PopupManager from '@element-plus/utils/popup-manager'
|
||||
import { on, off } from '@element-plus/utils/dom'
|
||||
import { isString } from '@element-plus/utils/util'
|
||||
import { EVENT_CODE } from '@element-plus/utils/aria'
|
||||
import { isValidComponentSize } from '@element-plus/utils/validators'
|
||||
|
||||
import type { ComponentPublicInstance, PropType, VNode } from 'vue'
|
||||
import type { Action, MessageBoxState } from './message-box.type'
|
||||
import type { ComponentPublicInstance } from 'vue'
|
||||
import type { Action, MessageBoxState, MessageBoxType } from './message-box.type'
|
||||
|
||||
const TypeMap: Indexable<string> = {
|
||||
success: 'success',
|
||||
@ -141,25 +142,32 @@ const TypeMap: Indexable<string> = {
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElMessageBox',
|
||||
directives: {
|
||||
TrapFocus,
|
||||
},
|
||||
components: {
|
||||
ElButton,
|
||||
ElInput,
|
||||
ElOverlay,
|
||||
},
|
||||
directives: {
|
||||
TrapFocus,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
beforeClose: {
|
||||
type: Function as PropType<(action: Action, state: MessageBoxState, doClose: () => void) => any>,
|
||||
default: undefined,
|
||||
buttonSize: {
|
||||
type: String as PropType<ComponentSize>,
|
||||
validator: isValidComponentSize,
|
||||
},
|
||||
callback: Function,
|
||||
cancelButtonText: {
|
||||
type: String,
|
||||
modal: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
lockScroll: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
cancelButtonClass: String,
|
||||
center: Boolean,
|
||||
closeOnClickModal: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
@ -172,85 +180,54 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
confirmButtonText: {
|
||||
type: String,
|
||||
center: Boolean,
|
||||
roundButton: {
|
||||
default: false,
|
||||
type: Boolean,
|
||||
},
|
||||
confirmButtonClass: String,
|
||||
container: {
|
||||
type: String, // default append to body
|
||||
default: 'body',
|
||||
},
|
||||
customClass: String,
|
||||
dangerouslyUseHTMLString: Boolean,
|
||||
distinguishCancelAndClose: Boolean,
|
||||
iconClass: String,
|
||||
inputPattern: {
|
||||
type: Object as PropType<RegExp>,
|
||||
default: () => undefined,
|
||||
validator: (val: unknown) => (val instanceof RegExp || val === 'undefined'),
|
||||
boxType: {
|
||||
type: String as PropType<MessageBoxType>,
|
||||
default: '',
|
||||
},
|
||||
inputPlaceholder: {
|
||||
type: String,
|
||||
},
|
||||
inputType: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
inputValue: {
|
||||
type: String,
|
||||
},
|
||||
inputValidator: {
|
||||
type: Function as PropType<(...args: any[]) => boolean | string>,
|
||||
default: null,
|
||||
},
|
||||
inputErrorMessage: String,
|
||||
lockScroll: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
message: {
|
||||
type: [String, Object] as PropType<string | VNode>,
|
||||
validator: (val: unknown) => {
|
||||
return isString(val) || isVNode(val)
|
||||
},
|
||||
},
|
||||
modalFade: { // implement this feature
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
modalClass: String,
|
||||
modal: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
roundButton: Boolean,
|
||||
showCancelButton: Boolean,
|
||||
showConfirmButton: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
type: String,
|
||||
title: String,
|
||||
showInput: Boolean,
|
||||
zIndex: Number,
|
||||
},
|
||||
emits: ['vanish', 'action'],
|
||||
setup(props, { emit }) {
|
||||
// const popup = usePopup(props, doClose)
|
||||
const visible = ref(false)
|
||||
// s represents state
|
||||
const state = reactive({
|
||||
const state = reactive<MessageBoxState>({
|
||||
beforeClose: null,
|
||||
callback: null,
|
||||
cancelButtonText: '',
|
||||
cancelButtonClass: '',
|
||||
confirmButtonText: '',
|
||||
confirmButtonClass: '',
|
||||
customClass: '',
|
||||
dangerouslyUseHTMLString: false,
|
||||
distinguishCancelAndClose: false,
|
||||
iconClass: '',
|
||||
inputPattern: null,
|
||||
inputPlaceholder: '',
|
||||
inputType: 'text',
|
||||
inputValue: null,
|
||||
inputValidator: null,
|
||||
inputErrorMessage: '',
|
||||
message: null,
|
||||
modalFade: true,
|
||||
modalClass: '',
|
||||
showCancelButton: false,
|
||||
showConfirmButton: true,
|
||||
type: '',
|
||||
title: undefined,
|
||||
showInput: false,
|
||||
action: '' as Action,
|
||||
inputValue: props.inputValue,
|
||||
confirmButtonLoading: false,
|
||||
cancelButtonLoading: false,
|
||||
cancelButtonText: props.cancelButtonText,
|
||||
confirmButtonDisabled: false,
|
||||
confirmButtonText: props.confirmButtonText,
|
||||
editorErrorMessage: '',
|
||||
// refer to: https://github.com/ElemeFE/element/commit/2999279ae34ef10c373ca795c87b020ed6753eed
|
||||
// seemed ok for now without this state.
|
||||
@ -258,28 +235,28 @@ export default defineComponent({
|
||||
validateError: false,
|
||||
zIndex: PopupManager.nextZIndex(),
|
||||
})
|
||||
const icon = computed(() => props.iconClass || (props.type && TypeMap[props.type] ? `el-icon-${TypeMap[props.type]}` : ''))
|
||||
const hasMessage = computed(() => !!props.message)
|
||||
const icon = computed(() => state.iconClass || (state.type && TypeMap[state.type] ? `el-icon-${TypeMap[state.type]}` : ''))
|
||||
const hasMessage = computed(() => !!state.message)
|
||||
const inputRef = ref<ComponentPublicInstance>(null)
|
||||
const confirmRef = ref<ComponentPublicInstance>(null)
|
||||
|
||||
const confirmButtonClasses = computed(() => `el-button--primary ${props.confirmButtonClass}`)
|
||||
const confirmButtonClasses = computed(() => `el-button--primary ${state.confirmButtonClass}`)
|
||||
|
||||
watch(() => state.inputValue, async val => {
|
||||
await nextTick()
|
||||
if (props.type === 'prompt' && val !== null) {
|
||||
if (props.boxType === 'prompt' && val !== null) {
|
||||
validate()
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => visible.value, val => {
|
||||
if (val) {
|
||||
if (props.type === 'alert' || props.type === 'confirm') {
|
||||
if (props.boxType === 'alert' || props.boxType === 'confirm') {
|
||||
nextTick().then(() => { confirmRef.value?.$el?.focus?.() })
|
||||
}
|
||||
state.zIndex = PopupManager.nextZIndex()
|
||||
}
|
||||
if (props.type !== 'prompt') return
|
||||
if (props.boxType !== 'prompt') return
|
||||
if (val) {
|
||||
nextTick().then(() => {
|
||||
if (inputRef.value && inputRef.value.$el) {
|
||||
@ -315,43 +292,43 @@ export default defineComponent({
|
||||
|
||||
const handleWrapperClick = () => {
|
||||
if (props.closeOnClickModal) {
|
||||
handleAction(props.distinguishCancelAndClose ? 'close' : 'cancel')
|
||||
handleAction(state.distinguishCancelAndClose ? 'close' : 'cancel')
|
||||
}
|
||||
}
|
||||
|
||||
const handleInputEnter = () => {
|
||||
if (props.inputType !== 'textarea') {
|
||||
if (state.inputType !== 'textarea') {
|
||||
return handleAction('confirm')
|
||||
}
|
||||
}
|
||||
|
||||
const handleAction = (action: Action) => {
|
||||
if (props.type === 'prompt' && action === 'confirm' && !validate()) {
|
||||
if (props.boxType === 'prompt' && action === 'confirm' && !validate()) {
|
||||
return
|
||||
}
|
||||
|
||||
state.action = action
|
||||
|
||||
if (props.beforeClose) {
|
||||
props.beforeClose?.(action, state, doClose)
|
||||
if (state.beforeClose) {
|
||||
state.beforeClose?.(action, state, doClose)
|
||||
} else {
|
||||
doClose()
|
||||
}
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
if (props.type === 'prompt') {
|
||||
const inputPattern = props.inputPattern
|
||||
if (props.boxType === 'prompt') {
|
||||
const inputPattern = state.inputPattern
|
||||
if (inputPattern && !inputPattern.test(state.inputValue || '')) {
|
||||
state.editorErrorMessage = props.inputErrorMessage || t('el.messagebox.error')
|
||||
state.editorErrorMessage = state.inputErrorMessage || t('el.messagebox.error')
|
||||
state.validateError = true
|
||||
return false
|
||||
}
|
||||
const inputValidator = props.inputValidator
|
||||
const inputValidator = state.inputValidator
|
||||
if (typeof inputValidator === 'function') {
|
||||
const validateResult = inputValidator(state.inputValue)
|
||||
if (validateResult === false) {
|
||||
state.editorErrorMessage = props.inputErrorMessage || t('el.messagebox.error')
|
||||
state.editorErrorMessage = state.inputErrorMessage || t('el.messagebox.error')
|
||||
state.validateError = true
|
||||
return false
|
||||
}
|
||||
@ -399,7 +376,7 @@ export default defineComponent({
|
||||
useRestoreActive(visible)
|
||||
|
||||
return {
|
||||
state,
|
||||
...toRefs(state),
|
||||
visible,
|
||||
hasMessage,
|
||||
icon,
|
||||
|
@ -1,7 +1,8 @@
|
||||
import type { VNode } from 'vue'
|
||||
|
||||
export type Action = 'confirm' | 'close' | 'cancel'
|
||||
export type MessageType = 'success' | 'warning' | 'info' | 'error'
|
||||
export type MessageType = '' | 'success' | 'warning' | 'info' | 'error'
|
||||
export type MessageBoxType = '' | 'prompt' | 'alert' | 'confirm'
|
||||
export type MessageBoxData = MessageBoxInputData & Action
|
||||
export interface MessageBoxInputData {
|
||||
value: string
|
||||
@ -12,28 +13,13 @@ export interface MessageBoxInputValidator {
|
||||
(value: string): boolean | string
|
||||
}
|
||||
|
||||
export interface MessageBoxState {
|
||||
action: Action
|
||||
cancelButtonLoading: boolean
|
||||
cancelButtonText: string
|
||||
confirmButtonLoading: boolean
|
||||
confirmButtonDisabled: boolean
|
||||
confirmButtonText: string
|
||||
editorErrorMessage: string
|
||||
// isOnComposition: boolean temporary commented
|
||||
inputValue: string
|
||||
validateError: boolean
|
||||
zIndex: number
|
||||
}
|
||||
|
||||
export declare class ElMessageBoxComponent {
|
||||
export declare interface MessageBoxState {
|
||||
title: string
|
||||
message: string
|
||||
type: MessageType
|
||||
iconClass: string
|
||||
customClass: string
|
||||
showInput: boolean
|
||||
showClose: boolean
|
||||
inputValue: string
|
||||
inputPlaceholder: string
|
||||
inputType: string
|
||||
@ -53,7 +39,16 @@ export declare class ElMessageBoxComponent {
|
||||
cancelButtonClass: string
|
||||
editorErrorMessage: string
|
||||
|
||||
close(): any
|
||||
beforeClose: null | ((action: Action, instance: MessageBoxState, done: () => void) => void)
|
||||
callback: null | Callback
|
||||
distinguishCancelAndClose: boolean
|
||||
modalFade: boolean
|
||||
modalClass: string
|
||||
// refer to: https://github.com/ElemeFE/element/commit/2999279ae34ef10c373ca795c87b020ed6753eed
|
||||
// seemed ok for now without this state.
|
||||
// isOnComposition: false, // temporary remove
|
||||
validateError: boolean
|
||||
zIndex: number
|
||||
}
|
||||
|
||||
export type Callback =
|
||||
@ -66,7 +61,7 @@ export interface ElMessageBoxOptions {
|
||||
/** Callback before MessageBox closes, and it will prevent MessageBox from closing */
|
||||
beforeClose?: (
|
||||
action: Action,
|
||||
instance: ElMessageBoxComponent,
|
||||
instance: MessageBoxState,
|
||||
done: () => void,
|
||||
) => void
|
||||
|
||||
@ -100,6 +95,9 @@ export interface ElMessageBoxOptions {
|
||||
/** Message type, used for icon display */
|
||||
type?: MessageType
|
||||
|
||||
/** Message box type */
|
||||
boxType?: MessageBoxType
|
||||
|
||||
/** Custom icon's class */
|
||||
iconClass?: string
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { h, render } from 'vue'
|
||||
import { h, watch, render } from 'vue'
|
||||
import MessageBoxConstructor from './index.vue'
|
||||
import isServer from '@element-plus/utils/isServer'
|
||||
import { isVNode, isString } from '@element-plus/utils/util'
|
||||
@ -55,7 +55,7 @@ const showMessage = (options: any) => {
|
||||
const currentMsg = messageInstance.get(vm)
|
||||
let resolve: Action | { value: string; action: Action; }
|
||||
if (options.showInput) {
|
||||
resolve = { value: vm.state.inputValue, action }
|
||||
resolve = { value: vm.inputValue, action }
|
||||
} else {
|
||||
resolve = action
|
||||
}
|
||||
@ -81,14 +81,26 @@ const showMessage = (options: any) => {
|
||||
// get component instance like v2.
|
||||
const vm = instance.proxy as ComponentPublicInstance<{
|
||||
visible: boolean
|
||||
state: MessageBoxState
|
||||
doClose: () => void
|
||||
}>
|
||||
} & MessageBoxState>
|
||||
|
||||
if (isVNode(options.message)) {
|
||||
// Override slots since message is vnode type.
|
||||
instance.slots.default = () => [options.message]
|
||||
for (const prop in options) {
|
||||
if (options.hasOwnProperty(prop) && !vm.$props.hasOwnProperty(prop)) {
|
||||
vm[prop] = options[prop]
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => vm.message, (newVal, oldVal) => {
|
||||
if (isVNode(newVal)) {
|
||||
// Override slots since message is vnode type.
|
||||
instance.slots.default = () => [newVal]
|
||||
} else if(isVNode(oldVal) && !isVNode(newVal)){
|
||||
delete instance.slots.default
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
// change visibility after everything is settled
|
||||
vm.visible = true
|
||||
return vm
|
||||
@ -137,11 +149,14 @@ MessageBox.alert = (
|
||||
{
|
||||
title: title,
|
||||
message: message,
|
||||
type: 'alert',
|
||||
type: '',
|
||||
closeOnPressEscape: false,
|
||||
closeOnClickModal: false,
|
||||
},
|
||||
options,
|
||||
{
|
||||
boxType: 'alert',
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -162,10 +177,13 @@ MessageBox.confirm = (
|
||||
{
|
||||
title: title,
|
||||
message: message,
|
||||
type: 'confirm',
|
||||
type: '',
|
||||
showCancelButton: true,
|
||||
},
|
||||
options,
|
||||
{
|
||||
boxType: 'confirm',
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -188,9 +206,12 @@ MessageBox.prompt = (
|
||||
message: message,
|
||||
showCancelButton: true,
|
||||
showInput: true,
|
||||
type: 'prompt',
|
||||
type: '',
|
||||
},
|
||||
options,
|
||||
{
|
||||
boxType: 'prompt',
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -327,3 +327,4 @@ The corresponding methods are: `ElMessageBox`, `ElMessageBox.alert`, `ElMessageB
|
||||
| inputErrorMessage | error message when validation fails | string | — | Illegal input |
|
||||
| center | whether to align the content in center | boolean | — | false |
|
||||
| roundButton | whether to use round button | boolean | — | false |
|
||||
| buttonSize | custom size of confirm and cancel buttons | string | mini / small / medium / large | small |
|
||||
|
@ -330,3 +330,4 @@ Los métodos correspondientes: `ElMessageBox`, `ElMessageBox.alert`, `ElMessageB
|
||||
| inputErrorMessage | mensaje de error cuando la validación falla | string | — | Illegal input |
|
||||
| center | utilizado para alinear el contenido al centro | boolean | — | false |
|
||||
| roundButton | utilizado para redondear el botón | boolean | — | false |
|
||||
| buttonSize | custom size of confirm and cancel buttons | string | mini / small / medium / large | small |
|
||||
|
@ -329,3 +329,4 @@ Les méthodes correspondantes sont: `ElMessageBox`, `ElMessageBox.alert`, `ElMes
|
||||
| inputErrorMessage | Message d'erreur lorsque la validation échoue. | string | — | Illegal input |
|
||||
| center | Si le contenu doit être centré. | boolean | — | false |
|
||||
| roundButton | Si le bouton doit être rond. | boolean | — | false |
|
||||
| buttonSize | custom size of confirm and cancel buttons | string | mini / small / medium / large | small |
|
||||
|
@ -326,3 +326,4 @@ import { ElMessageBox } from 'element-plus';
|
||||
| inputErrorMessage | バリデーション失敗時のエラーメッセージ | string | — | Illegal input |
|
||||
| center | コンテンツを中央に配置するかどうか | boolean | — | false |
|
||||
| roundButton | 丸いボタンを使うかどうか | boolean | — | false |
|
||||
| buttonSize | custom size of confirm and cancel buttons | string | mini / small / medium / large | small |
|
||||
|
@ -325,3 +325,4 @@ import { ElMessageBox } from 'element-plus';
|
||||
| inputErrorMessage | 校验未通过时的提示文本 | string | — | 输入的数据不合法! |
|
||||
| center | 是否居中布局 | boolean | — | false |
|
||||
| roundButton | 是否使用圆角按钮 | boolean | — | false |
|
||||
| buttonSize | 自定义确认按钮及取消按钮的大小 | string | mini / small / medium / large | small |
|
||||
|
Loading…
Reference in New Issue
Block a user