vuetify
Version:
Vue Material Component Framework
253 lines (225 loc) • 5.88 kB
text/typescript
// Styles
import './VAlert.sass'
// Extensions
import VSheet from '../VSheet'
// Components
import VBtn from '../VBtn'
import VIcon from '../VIcon'
// Mixins
import Toggleable from '../../mixins/toggleable'
import Themeable from '../../mixins/themeable'
import Transitionable from '../../mixins/transitionable'
// Utilities
import mixins from '../../util/mixins'
import { breaking } from '../../util/console'
// Types
import { VNodeData } from 'vue'
import { VNode } from 'vue/types'
/* @vue/component */
export default mixins(
VSheet,
Toggleable,
Transitionable
).extend({
name: 'v-alert',
props: {
border: {
type: String,
validator (val: string) {
return [
'top',
'right',
'bottom',
'left',
].includes(val)
},
},
closeLabel: {
type: String,
default: '$vuetify.close',
},
coloredBorder: Boolean,
dense: Boolean,
dismissible: Boolean,
closeIcon: {
type: String,
default: '$cancel',
},
icon: {
default: '',
type: [Boolean, String],
validator (val: boolean | string) {
return typeof val === 'string' || val === false
},
},
outlined: Boolean,
prominent: Boolean,
text: Boolean,
type: {
type: String,
validator (val: string) {
return [
'info',
'error',
'success',
'warning',
].includes(val)
},
},
value: {
type: Boolean,
default: true,
},
},
computed: {
__cachedBorder (): VNode | null {
if (!this.border) return null
let data: VNodeData = {
staticClass: 'v-alert__border',
class: {
[`v-alert__border--${this.border}`]: true,
},
}
if (this.coloredBorder) {
data = this.setBackgroundColor(this.computedColor, data)
data.class['v-alert__border--has-color'] = true
}
return this.$createElement('div', data)
},
__cachedDismissible (): VNode | null {
if (!this.dismissible) return null
const color = this.iconColor
return this.$createElement(VBtn, {
staticClass: 'v-alert__dismissible',
props: {
color,
icon: true,
small: true,
},
attrs: {
'aria-label': this.$vuetify.lang.t(this.closeLabel),
},
on: {
click: () => (this.isActive = false),
},
}, [
this.$createElement(VIcon, {
props: { color },
}, this.closeIcon),
])
},
__cachedIcon (): VNode | null {
if (!this.computedIcon) return null
return this.$createElement(VIcon, {
staticClass: 'v-alert__icon',
props: { color: this.iconColor },
}, this.computedIcon)
},
classes (): object {
const classes: Record<string, boolean> = {
...VSheet.options.computed.classes.call(this),
'v-alert--border': Boolean(this.border),
'v-alert--dense': this.dense,
'v-alert--outlined': this.outlined,
'v-alert--prominent': this.prominent,
'v-alert--text': this.text,
}
if (this.border) {
classes[`v-alert--border-${this.border}`] = true
}
return classes
},
computedColor (): string {
return this.color || this.type
},
computedIcon (): string | boolean {
if (this.icon === false) return false
if (typeof this.icon === 'string' && this.icon) return this.icon
if (!['error', 'info', 'success', 'warning'].includes(this.type)) return false
return `$${this.type}`
},
hasColoredIcon (): boolean {
return (
this.hasText ||
(Boolean(this.border) && this.coloredBorder)
)
},
hasText (): boolean {
return this.text || this.outlined
},
iconColor (): string | undefined {
return this.hasColoredIcon ? this.computedColor : undefined
},
isDark (): boolean {
if (
this.type &&
!this.coloredBorder &&
!this.outlined
) return true
return Themeable.options.computed.isDark.call(this)
},
},
created () {
/* istanbul ignore next */
if (this.$attrs.hasOwnProperty('outline')) {
breaking('outline', 'outlined', this)
}
},
methods: {
genWrapper (): VNode {
const children = [
this.$slots.prepend || this.__cachedIcon,
this.genContent(),
this.__cachedBorder,
this.$slots.append,
this.$scopedSlots.close
? this.$scopedSlots.close({ toggle: this.toggle })
: this.__cachedDismissible,
]
const data: VNodeData = {
staticClass: 'v-alert__wrapper',
}
return this.$createElement('div', data, children)
},
genContent (): VNode {
return this.$createElement('div', {
staticClass: 'v-alert__content',
}, this.$slots.default)
},
genAlert (): VNode {
let data: VNodeData = {
staticClass: 'v-alert',
attrs: {
role: 'alert',
},
on: this.listeners$,
class: this.classes,
style: this.styles,
directives: [{
name: 'show',
value: this.isActive,
}],
}
if (!this.coloredBorder) {
const setColor = this.hasText ? this.setTextColor : this.setBackgroundColor
data = setColor(this.computedColor, data)
}
return this.$createElement('div', data, [this.genWrapper()])
},
/** @public */
toggle () {
this.isActive = !this.isActive
},
},
render (h): VNode {
const render = this.genAlert()
if (!this.transition) return render
return h('transition', {
props: {
name: this.transition,
origin: this.origin,
mode: this.mode,
},
}, [render])
},
})