1
// Components
2 1
import VSimpleCheckbox from '../VCheckbox/VSimpleCheckbox'
3 1
import VDivider from '../VDivider'
4 1
import VSubheader from '../VSubheader'
5 1
import {
6
  VList,
7
  VListItem,
8
  VListItemAction,
9
  VListItemContent,
10
  VListItemTitle,
11
} from '../VList'
12

13
// Directives
14 1
import ripple from '../../directives/ripple'
15

16
// Mixins
17 1
import Colorable from '../../mixins/colorable'
18 1
import Themeable from '../../mixins/themeable'
19

20
// Helpers
21 1
import {
22
  escapeHTML,
23
  getPropertyFromItem,
24
} from '../../util/helpers'
25

26
// Types
27 1
import mixins from '../../util/mixins'
28
import { VNode, PropType, VNodeChildren } from 'vue'
29
import { PropValidator } from 'vue/types/options'
30
import { SelectItemKey } from 'vuetify/types'
31

32
type ListTile = { item: any, disabled?: null | boolean, value?: boolean, index: number };
33

34
/* @vue/component */
35 1
export default mixins(Colorable, Themeable).extend({
36
  name: 'v-select-list',
37

38
  // https://github.com/vuejs/vue/issues/6872
39
  directives: {
40
    ripple,
41
  },
42

43
  props: {
44
    action: Boolean,
45
    dense: Boolean,
46
    hideSelected: Boolean,
47
    items: {
48
      type: Array,
49 1
      default: () => [],
50
    } as PropValidator<any[]>,
51
    itemDisabled: {
52
      type: [String, Array, Function] as PropType<SelectItemKey>,
53
      default: 'disabled',
54
    },
55
    itemText: {
56
      type: [String, Array, Function] as PropType<SelectItemKey>,
57
      default: 'text',
58
    },
59
    itemValue: {
60
      type: [String, Array, Function] as PropType<SelectItemKey>,
61
      default: 'value',
62
    },
63
    noDataText: String,
64
    noFilter: Boolean,
65
    searchInput: null as unknown as PropType<any>,
66
    selectedItems: {
67
      type: Array,
68 1
      default: () => [],
69
    } as PropValidator<any[]>,
70
  },
71

72
  computed: {
73 1
    parsedItems (): any[] {
74 1
      return this.selectedItems.map(item => this.getValue(item))
75
    },
76 1
    tileActiveClass (): string {
77 1
      return Object.keys(this.setTextColor(this.color).class || {}).join(' ')
78
    },
79 1
    staticNoDataTile (): VNode {
80 1
      const tile = {
81
        attrs: {
82
          role: undefined,
83
        },
84
        on: {
85 0
          mousedown: (e: Event) => e.preventDefault(), // Prevent onBlur from being called
86
        },
87
      }
88

89 1
      return this.$createElement(VListItem, tile, [
90
        this.genTileContent(this.noDataText),
91
      ])
92
    },
93
  },
94

95
  methods: {
96 1
    genAction (item: object, inputValue: any): VNode {
97 1
      return this.$createElement(VListItemAction, [
98
        this.$createElement(VSimpleCheckbox, {
99
          props: {
100
            color: this.color,
101
            value: inputValue,
102
          },
103
          on: {
104 1
            input: () => this.$emit('select', item),
105
          },
106
        }),
107
      ])
108
    },
109 1
    genDivider (props: { [key: string]: any }) {
110 1
      return this.$createElement(VDivider, { props })
111
    },
112 1
    genFilteredText (text: string) {
113 1
      text = text || ''
114

115 1
      if (!this.searchInput || this.noFilter) return escapeHTML(text)
116

117 1
      const { start, middle, end } = this.getMaskedCharacters(text)
118

119 1
      return `${escapeHTML(start)}${this.genHighlight(middle)}${escapeHTML(end)}`
120
    },
121 1
    genHeader (props: { [key: string]: any }): VNode {
122 1
      return this.$createElement(VSubheader, { props }, props.header)
123
    },
124 1
    genHighlight (text: string): string {
125 1
      return `<span class="v-list-item__mask">${escapeHTML(text)}</span>`
126
    },
127 1
    getMaskedCharacters (text: string): {
128
      start: string
129
      middle: string
130
      end: string
131
    } {
132 1
      const searchInput = (this.searchInput || '').toString().toLocaleLowerCase()
133 1
      const index = text.toLocaleLowerCase().indexOf(searchInput)
134

135 1
      if (index < 0) return { start: '', middle: text, end: '' }
136

137 1
      const start = text.slice(0, index)
138 1
      const middle = text.slice(index, index + searchInput.length)
139 1
      const end = text.slice(index + searchInput.length)
140 1
      return { start, middle, end }
141
    },
142 1
    genTile ({
143 1
      item,
144 1
      index,
145 1
      disabled = null,
146 1
      value = false,
147 1
    }: ListTile): VNode | VNode[] | undefined {
148 1
      if (!value) value = this.hasItem(item)
149

150 1
      if (item === Object(item)) {
151 1
        disabled = disabled !== null
152 1
          ? disabled
153 1
          : this.getDisabled(item)
154
      }
155

156 1
      const tile = {
157
        attrs: {
158
          // Default behavior in list does not
159
          // contain aria-selected by default
160
          'aria-selected': String(value),
161
          id: `list-item-${this._uid}-${index}`,
162
          role: 'option',
163
        },
164
        on: {
165 0
          mousedown: (e: Event) => {
166
            // Prevent onBlur from being called
167 0
            e.preventDefault()
168
          },
169 1
          click: () => disabled || this.$emit('select', item),
170
        },
171
        props: {
172
          activeClass: this.tileActiveClass,
173
          disabled,
174
          ripple: true,
175
          inputValue: value,
176
        },
177
      }
178

179 1
      if (!this.$scopedSlots.item) {
180 1
        return this.$createElement(VListItem, tile, [
181 1
          this.action && !this.hideSelected && this.items.length > 0
182 1
            ? this.genAction(item, value)
183 1
            : null,
184
          this.genTileContent(item, index),
185
        ])
186
      }
187

188 0
      const parent = this
189 0
      const scopedSlot = this.$scopedSlots.item({
190
        parent,
191
        item,
192
        attrs: {
193
          ...tile.attrs,
194
          ...tile.props,
195
        },
196
        on: tile.on,
197
      })
198

199 0
      return this.needsTile(scopedSlot)
200 1
        ? this.$createElement(VListItem, tile, scopedSlot)
201 0
        : scopedSlot
202
    },
203 1
    genTileContent (item: any, index = 0): VNode {
204 1
      const innerHTML = this.genFilteredText(this.getText(item))
205

206 1
      return this.$createElement(VListItemContent,
207
        [this.$createElement(VListItemTitle, {
208
          domProps: { innerHTML },
209
        })]
210
      )
211
    },
212 1
    hasItem (item: object) {
213 1
      return this.parsedItems.indexOf(this.getValue(item)) > -1
214
    },
215 0
    needsTile (slot: VNode[] | undefined) {
216 1
      return slot!.length !== 1 ||
217 0
        slot![0].componentOptions == null ||
218 0
        slot![0].componentOptions.Ctor.options.name !== 'v-list-item'
219
    },
220 1
    getDisabled (item: object) {
221 1
      return Boolean(getPropertyFromItem(item, this.itemDisabled, false))
222
    },
223 1
    getText (item: object) {
224 1
      return String(getPropertyFromItem(item, this.itemText, item))
225
    },
226 1
    getValue (item: object) {
227 1
      return getPropertyFromItem(item, this.itemValue, this.getText(item))
228
    },
229
  },
230

231 1
  render (): VNode {
232 1
    const children: VNodeChildren = []
233 1
    const itemsLength = this.items.length
234 1
    for (let index = 0; index < itemsLength; index++) {
235 1
      const item = this.items[index]
236

237 1
      if (this.hideSelected &&
238 1
        this.hasItem(item)
239 1
      ) continue
240

241 1
      if (item == null) children.push(this.genTile({ item, index }))
242 1
      else if (item.header) children.push(this.genHeader(item))
243 1
      else if (item.divider) children.push(this.genDivider(item))
244 1
      else children.push(this.genTile({ item, index }))
245
    }
246

247 1
    children.length || children.push(this.$slots['no-data'] || this.staticNoDataTile)
248

249 1
    this.$slots['prepend-item'] && children.unshift(this.$slots['prepend-item'])
250

251 1
    this.$slots['append-item'] && children.push(this.$slots['append-item'])
252

253 1
    return this.$createElement(VList, {
254
      staticClass: 'v-select-list',
255
      class: this.themeClasses,
256
      attrs: {
257
        role: 'listbox',
258
        tabindex: -1,
259
      },
260
      props: { dense: this.dense },
261
    }, children)
262
  },
263
})

Read our documentation on viewing source code .

Loading