UNPKG

vuetify

Version:

Vue Material Component Framework

188 lines (161 loc) 4.39 kB
// Styles import './VListItem.sass' // Mixins import Colorable from '../../mixins/colorable' import Routable from '../../mixins/routable' import { factory as GroupableFactory } from '../../mixins/groupable' import Themeable from '../../mixins/themeable' import { factory as ToggleableFactory } from '../../mixins/toggleable' // Directives import Ripple from '../../directives/ripple' // Utilities import { keyCodes } from './../../util/helpers' import { ExtractVue } from './../../util/mixins' import { removed } from '../../util/console' // Types import mixins from '../../util/mixins' import { VNode } from 'vue' import { PropType, PropValidator } from 'vue/types/options' const baseMixins = mixins( Colorable, Routable, Themeable, GroupableFactory('listItemGroup'), ToggleableFactory('inputValue') ) interface options extends ExtractVue<typeof baseMixins> { $el: HTMLElement isInGroup: boolean isInList: boolean isInMenu: boolean isInNav: boolean } /* @vue/component */ export default baseMixins.extend<options>().extend({ name: 'v-list-item', directives: { Ripple, }, inject: { isInGroup: { default: false, }, isInList: { default: false, }, isInMenu: { default: false, }, isInNav: { default: false, }, }, inheritAttrs: false, props: { activeClass: { type: String, default (): string | undefined { if (!this.listItemGroup) return '' return this.listItemGroup.activeClass }, } as any as PropValidator<string>, dense: Boolean, inactive: Boolean, link: Boolean, selectable: { type: Boolean, }, tag: { type: String, default: 'div', }, threeLine: Boolean, twoLine: Boolean, value: null as any as PropType<any>, }, data: () => ({ proxyClass: 'v-list-item--active', }), computed: { classes (): object { return { 'v-list-item': true, ...Routable.options.computed.classes.call(this), 'v-list-item--dense': this.dense, 'v-list-item--disabled': this.disabled, 'v-list-item--link': this.isClickable && !this.inactive, 'v-list-item--selectable': this.selectable, 'v-list-item--three-line': this.threeLine, 'v-list-item--two-line': this.twoLine, ...this.themeClasses, } }, isClickable (): boolean { return Boolean( Routable.options.computed.isClickable.call(this) || this.listItemGroup ) }, }, created () { /* istanbul ignore next */ if (this.$attrs.hasOwnProperty('avatar')) { removed('avatar', this) } }, methods: { click (e: MouseEvent | KeyboardEvent) { if (e.detail) this.$el.blur() this.$emit('click', e) this.to || this.toggle() }, genAttrs () { const attrs: Record<string, any> = { 'aria-disabled': this.disabled ? true : undefined, tabindex: this.isClickable && !this.disabled ? 0 : -1, ...this.$attrs, } if (this.$attrs.hasOwnProperty('role')) { // do nothing, role already provided } else if (this.isInNav) { // do nothing, role is inherit } else if (this.isInGroup) { attrs.role = 'listitem' attrs['aria-selected'] = String(this.isActive) } else if (this.isInMenu) { attrs.role = this.isClickable ? 'menuitem' : undefined attrs.id = attrs.id || `list-item-${this._uid}` } else if (this.isInList) { attrs.role = 'listitem' } return attrs }, }, render (h): VNode { let { tag, data } = this.generateRouteLink() data.attrs = { ...data.attrs, ...this.genAttrs(), } data[this.to ? 'nativeOn' : 'on'] = { ...data[this.to ? 'nativeOn' : 'on'], keydown: (e: KeyboardEvent) => { /* istanbul ignore else */ if (e.keyCode === keyCodes.enter) this.click(e) this.$emit('keydown', e) }, } if (this.inactive) tag = 'div' if (this.inactive && this.to) { data.on = data.nativeOn delete data.nativeOn } const children = this.$scopedSlots.default ? this.$scopedSlots.default({ active: this.isActive, toggle: this.toggle, }) : this.$slots.default return h(tag, this.setTextColor(this.color, data), children) }, })