@jgjergj/vuetify-toolkit
Version:
Vuetify.js Additional components set
243 lines (237 loc) • 8.27 kB
text/typescript
import { VNode } from 'vue'
import { consoleError } from '../../vuetify-import'
import { VAutocompleteA, VSelectA, VChipA } from '../../shims-vuetify'
import DefaultMenuProps from '../../utils/MenuProps'
import CommandToolbar from './commandToolbar'
import InternalMenu from '../mixin/internalMenu'
import { mergeProps } from '../../utils/mergeProps'
export default VAutocompleteA.extend({
props: {
...(VSelectA as any).options.props,
...(VAutocompleteA as any).options.props,
autocomplete: {
type: Boolean,
default: false
},
highlightClass: String,
menuProps: {
type: [String, Array, Object],
default: () => DefaultMenuProps
},
...(CommandToolbar as any).options.props
},
data: () => ({
selectedItems: [] as any[],
currentItem: null as any
}),
computed: {
classes (): Object {
if (this.$props.autocomplete) {
return Object.assign({}, (VSelectA as any).options.computed.classes.call(this), {
'v-autocomplete': true,
'v-autocomplete--is-selecting-index': this.$data.selectedIndex > -1
})
} else {
return Object.assign({}, (VSelectA as any).options.computed.classes.call(this), {})
}
},
internalSearch: {
get (): string {
const result = this.$props.autocomplete ? (VAutocompleteA as any).options.computed.internalSearch.get.call(this)
: ''
return result
},
set (val: string) {
if (this.$props.autocomplete) {
(VAutocompleteA as any).options.computed.internalSearch.set.call(this, val)
}
}
},
listData (): Object {
const data = (VSelectA as any).options.computed.listData.call(this)
mergeProps(data.props, this.$props, (CommandToolbar as any).options.props)
data.props.highlightClass = this.$props.highlightClass
data.props.multiple = this.$props.multiple
Object.assign(data.on, {
'close-menu': () => { this.$data.isMenuActive = false },
'select-ok': (items: any[]) => {
this.selectItems(items)
this.$data.isMenuActive = false
},
'update-dimensions': () => ((this as any).$refs.menu as any).updateDimensions()
})
return data
},
staticList (): VNode {
if (this.$slots['no-data'] || this.$slots['prepend-item'] || this.$slots['append-item'] ||
this.$slots['search-item'] || this.$slots['search-overflow']) {
consoleError('assert: staticList should not be called if slots are used')
}
return this.$createElement('div', this.listData)
},
hasChips (): boolean {
return this.$props.chips || this.$props.smallChips || this.$props.deletableChips
}
},
watch: {
value: {
immediate: true,
handler (val) {
if (val) {
if (Array.isArray(val)) {
this.selectedItems = val.flat()
} else {
this.selectedItems = []
this.currentItem = null
}
}
}
},
currentItem: {
immediate: true,
handler (val) {
if (this.$refs.menu) {
(this.$refs.menu as any).updateDimensions()
}
}
}
},
methods: {
register () {},
genInput (): VNode {
return this.$props.autocomplete ? (VAutocompleteA as any).options.methods.genInput.call(this)
: (VSelectA as any).options.methods.genInput.call(this)
},
genMenu (): VNode {
const props = (this as any).$_menuProps as any
props.activator = this.$refs['input-slot']
// Attach to root el so that
// menu covers prepend/append icons
if (
// TODO: make this a computed property or helper or something
(this as any).attach === '' || // If used as a boolean prop (<v-menu attach>)
(this as any).attach === true || // If bound to a boolean (<v-menu :attach="true">)
(this as any).attach === 'attach' // If bound as boolean prop in pug (v-menu(attach))
) {
props.attach = this.$el
} else {
props.attach = (this as any).attach
}
mergeProps(props, this.$props, (CommandToolbar as any).options.props)
props.filteredItems = (this as any).filteredItems
props.itemText = this.$props.itemText
props.autocomplete = this.$props.autocomplete
props.dense = this.$props.dense
return this.$createElement(InternalMenu, {
attrs: { role: undefined },
props,
on: {
input: (val: boolean) => {
(this as any).isMenuActive = val;
(this as any).isFocused = val
},
scroll: (this as any).onScroll
},
ref: 'menu'
}, [(this as any).genList()])
},
genSlots (): VNode[] {
return ['prepend-item', 'no-data', 'append-item']
.filter(slotName => this.$slots[slotName])
.map(slotName => this.$createElement('template', {
slot: slotName
}, this.$slots[slotName]))
},
genChipSelection (item: object, index: number) {
const isDisabled = false // (
// !(this as any).isInteractive ||
// (this as any).getDisabled(item)
// )
return this.$createElement(VChipA, {
staticClass: 'v-chip--select',
attrs: { tabindex: -1 },
props: {
close: this.$props.deletableChips && !isDisabled,
disabled: isDisabled,
inputValue: item, // index === (this as any).selectedIndex,
small: this.$props.smallChips,
value: item
},
on: {
click: (e: MouseEvent) => {
if (isDisabled) return
this.currentItem = item as any
(this as any).selectedIndex = index
},
'click:close': () => {
this.selectedItems = this.selectedItems.filter(v => v !== item)
}
},
key: JSON.stringify((this as any).getValue(item))
}, (this as any).getText(item))
},
genCommaSelection (item: object, index: number, last: boolean) {
const color = index === (this as any).selectedIndex && (this as any).computedColor
const isDisabled = false // (
// !(this as any).isInteractive ||
// (this as any).getDisabled(item)
// )
return this.$createElement('div', (this as any).setTextColor(color, {
staticClass: 'v-select__selection v-select__selection--comma',
class: {
'v-select__selection--disabled': isDisabled
},
on: {
click: (e: MouseEvent) => {
if (isDisabled) return
this.currentItem = item as any
(this as any).selectedIndex = index
}
},
key: JSON.stringify((this as any).getValue(item))
}), `${(this as any).getText(item)}${last ? '' : ', '}`)
},
genSelections (): VNode {
let length = this.selectedItems.length
const children = new Array(length)
let genSelection
if (this.$scopedSlots.selection) {
genSelection = (this as any).genSlotSelection
} else if ((this as any).hasChips) {
genSelection = (this as any).genChipSelection
} else {
genSelection = (this as any).genCommaSelection
}
while (length--) {
children[length] = genSelection(
this.selectedItems[length],
length,
length === children.length - 1
)
}
return this.$createElement('div', {
staticClass: 'v-select__selections'
}, children)
},
selectItems (items: any[]) {
this.selectedItems = items
if (!this.$props.multiple) {
this.$data.isMenuActive = false
}
this.$data.internalSearch = ''
this.$emit('input', items)
},
clearableCallback () {
this.currentItem = null
this.selectedItems = []
this.$emit('change', [])
this.$emit('input', [])
},
OK () {
this.$data.isMenuActive = false
},
closeMenu () {
this.$data.isMenuActive = false
}
}
})