Commit 06a74f9ed76645f476b4818aaaad136798a76012
1 parent
f7f65c84
Allow select to navigate AutoComplete custom children
Showing
1 changed file
with
42 additions
and
9 deletions
Show diff stats
src/components/select/select.vue
... | ... | @@ -92,6 +92,20 @@ |
92 | 92 | } |
93 | 93 | }; |
94 | 94 | |
95 | + const findOptionsInVNode = (node) => { | |
96 | + const opts = node.componentOptions; | |
97 | + if (opts && opts.tag === 'Option') return [node]; | |
98 | + if (!node.children) return []; | |
99 | + const options = node.children.reduce( | |
100 | + (arr, el) => [...arr, ...findOptionsInVNode(el)], [] | |
101 | + ).filter(Boolean); | |
102 | + return options.length > 0 ? options : []; | |
103 | + }; | |
104 | + | |
105 | + const extractOptions = (options) => options.reduce((options, slotEntry) => { | |
106 | + return options.concat(findOptionsInVNode(slotEntry)); | |
107 | + }, []); | |
108 | + | |
95 | 109 | export default { |
96 | 110 | name: 'iSelect', |
97 | 111 | mixins: [ Emitter, Locale ], |
... | ... | @@ -275,16 +289,39 @@ |
275 | 289 | }, |
276 | 290 | selectOptions() { |
277 | 291 | const selectOptions = []; |
292 | + const slotOptions = (this.slotOptions || []); | |
278 | 293 | let optionCounter = -1; |
279 | 294 | const currentIndex = this.focusIndex; |
280 | 295 | const selectedValues = this.values.map(({value}) => value); |
281 | - if (this.autoComplete) return this.slotOptions; | |
296 | + if (this.autoComplete) { | |
297 | + const copyChildren = (node, fn) => { | |
298 | + return { | |
299 | + ...node, | |
300 | + children: (node.children || []).map(fn).map(child => copyChildren(child, fn)) | |
301 | + }; | |
302 | + }; | |
303 | + const autoCompleteOptions = extractOptions(slotOptions); | |
304 | + const selectedSlotOption = autoCompleteOptions[currentIndex]; | |
305 | + | |
306 | + return slotOptions.map(node => copyChildren(node, (child) => { | |
307 | + if (child !== selectedSlotOption) return child; | |
308 | + return { | |
309 | + ...child, | |
310 | + componentOptions: { | |
311 | + ...child.componentOptions, | |
312 | + propsData: { | |
313 | + ...child.componentOptions.propsData, | |
314 | + isFocused: true, | |
315 | + } | |
316 | + } | |
317 | + }; | |
318 | + })); | |
319 | + } | |
282 | 320 | |
283 | - for (let option of (this.slotOptions || [])) { | |
321 | + for (let option of slotOptions) { | |
284 | 322 | |
285 | 323 | const cOptions = option.componentOptions; |
286 | 324 | if (!cOptions) continue; |
287 | - | |
288 | 325 | if (cOptions.tag.match(optionGroupRegexp)){ |
289 | 326 | let children = cOptions.children; |
290 | 327 | |
... | ... | @@ -315,11 +352,7 @@ |
315 | 352 | return selectOptions; |
316 | 353 | }, |
317 | 354 | flatOptions(){ |
318 | - return this.selectOptions.reduce((options, option) => { | |
319 | - const isOptionGroup = option.componentOptions.tag.match(optionGroupRegexp); | |
320 | - if (isOptionGroup) return options.concat(option.componentOptions.children || []); | |
321 | - else return options.concat(option); | |
322 | - }, []); | |
355 | + return extractOptions(this.selectOptions); | |
323 | 356 | }, |
324 | 357 | selectTabindex(){ |
325 | 358 | return this.disabled || this.filterable ? -1 : 0; |
... | ... | @@ -595,7 +628,7 @@ |
595 | 628 | } |
596 | 629 | }, |
597 | 630 | focusIndex(index){ |
598 | - if (index < 0) return; | |
631 | + if (index < 0 || this.autoComplete) return; | |
599 | 632 | // update scroll |
600 | 633 | const optionValue = this.flatOptions[index].componentOptions.propsData.value; |
601 | 634 | const optionInstance = findChild(this, ({$options}) => { | ... | ... |