mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-22 10:30:34 +03:00
create dropdown component, inject context
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import vAppendToBody from '@/directives/appendToBody.js'
|
||||
import { VueSelectInjectionKey } from '@/symbols'
|
||||
import type { VueSelectInjectedProps } from '@/components/Select.vue'
|
||||
|
||||
const context = inject<VueSelectInjectedProps>(VueSelectInjectionKey)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul
|
||||
v-if="context.dropdownOpen"
|
||||
:id="`vs${context.uid}__listbox`"
|
||||
ref="dropdownMenu"
|
||||
:key="`vs${context.uid}__listbox`"
|
||||
v-append-to-body
|
||||
class="vs__dropdown-menu"
|
||||
role="listbox"
|
||||
tabindex="-1"
|
||||
@mousedown.prevent="context.onMousedown"
|
||||
@mouseup="context.onMouseUp"
|
||||
>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
<ul
|
||||
v-else
|
||||
:id="`vs${context.uid}__listbox`"
|
||||
role="listbox"
|
||||
style="display: none; visibility: hidden"
|
||||
></ul>
|
||||
</template>
|
||||
+29
-29
@@ -83,18 +83,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<transition :name="transition">
|
||||
<ul
|
||||
v-if="dropdownOpen"
|
||||
:id="`vs${uid}__listbox`"
|
||||
ref="dropdownMenu"
|
||||
:key="`vs${uid}__listbox`"
|
||||
v-append-to-body
|
||||
class="vs__dropdown-menu"
|
||||
role="listbox"
|
||||
tabindex="-1"
|
||||
@mousedown.prevent="onMousedown"
|
||||
@mouseup="onMouseUp"
|
||||
>
|
||||
<DropdownMenu>
|
||||
<slot name="list-header" v-bind="scope.listHeader" />
|
||||
<li
|
||||
v-for="(option, index) in filteredOptions"
|
||||
@@ -123,37 +112,35 @@
|
||||
</slot>
|
||||
</li>
|
||||
<slot name="list-footer" v-bind="scope.listFooter" />
|
||||
</ul>
|
||||
<ul
|
||||
v-else
|
||||
:id="`vs${uid}__listbox`"
|
||||
role="listbox"
|
||||
style="display: none; visibility: hidden"
|
||||
></ul>
|
||||
</DropdownMenu>
|
||||
</transition>
|
||||
<slot name="footer" v-bind="scope.footer" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import pointerScroll from '@/mixins/pointerScroll.js'
|
||||
import typeAheadPointer from '@/mixins/typeAheadPointer.js'
|
||||
import ajax from '@/mixins/ajax.js'
|
||||
import childComponents from '@/components/childComponents.js'
|
||||
import appendToBody from '@/directives/appendToBody.js'
|
||||
import sortAndStringify from '@/utility/sortAndStringify.js'
|
||||
import uniqueId from '@/utility/uniqueId.js'
|
||||
import { computed, ComputedRef, defineComponent } from 'vue'
|
||||
import { VueSelectInjectionKey } from '@/symbols.js'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
|
||||
/**
|
||||
* @name VueSelect
|
||||
*/
|
||||
export default {
|
||||
components: { ...childComponents },
|
||||
export interface VueSelectContext {
|
||||
uid: ComputedRef<string>
|
||||
dropdownOpen: ComputedRef<boolean>
|
||||
onMousedown: (e: MouseEvent) => void
|
||||
onMouseup: (e: MouseEvent) => void
|
||||
}
|
||||
|
||||
directives: { appendToBody },
|
||||
export default defineComponent({
|
||||
components: { DropdownMenu, ...childComponents },
|
||||
|
||||
mixins: [pointerScroll, typeAheadPointer, ajax],
|
||||
|
||||
|
||||
compatConfig: {
|
||||
MODE: 3,
|
||||
},
|
||||
@@ -689,6 +676,19 @@ export default {
|
||||
},
|
||||
},
|
||||
|
||||
provide() {
|
||||
return {
|
||||
[VueSelectInjectionKey]: computed(() => {
|
||||
return {
|
||||
uid: this.uid,
|
||||
dropdownOpen: this.dropdownOpen,
|
||||
onMousedown: this.onMousedown,
|
||||
onMouseup: this.onMouseUp,
|
||||
}
|
||||
}),
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
@@ -1362,5 +1362,5 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { InjectionKey } from 'vue'
|
||||
|
||||
export const VueSelectInjectionKey = Symbol(
|
||||
'VueSelectInjectionKey'
|
||||
) as InjectionKey<string>
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import { mount, shallowMount } from '@vue/test-utils'
|
||||
import VueSelect from '@/components/Select.vue'
|
||||
|
||||
/**
|
||||
@@ -50,7 +50,7 @@ export const selectTag = async (Wrapper, searchText) => {
|
||||
* @returns {Wrapper<Vue>}
|
||||
*/
|
||||
export const selectWithProps = (props = {}) => {
|
||||
return shallowMount(VueSelect, { props })
|
||||
return mount(VueSelect, { props })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ export const selectWithProps = (props = {}) => {
|
||||
* @return {Wrapper<Vue>}
|
||||
*/
|
||||
export const mountDefault = (props = {}, options = {}) => {
|
||||
return shallowMount(VueSelect, {
|
||||
return mount(VueSelect, {
|
||||
props: {
|
||||
options: ['one', 'two', 'three'],
|
||||
...props,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { it, describe, expect, vi } from 'vitest'
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import VueSelect from '@/components/Select.vue'
|
||||
import { selectWithProps } from '@tests/helpers.js'
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('Labels', () => {
|
||||
})
|
||||
|
||||
it('should display a placeholder if the value is empty', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
options: ['one'],
|
||||
},
|
||||
@@ -66,7 +66,7 @@ describe('Labels', () => {
|
||||
*/
|
||||
// it('will not call getOptionLabel if both scoped option slots are used and a filter is provided', () => {
|
||||
// const spy = spyOn(VueSelect.props.getOptionLabel, 'default')
|
||||
// const Select = shallowMount(VueSelect, {
|
||||
// const Select = mount(VueSelect, {
|
||||
// props: {
|
||||
// options: [{ name: 'one' }],
|
||||
// filter: () => {},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { it, describe, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { mount, shallowMount } from '@vue/test-utils'
|
||||
import { mount, mount } from '@vue/test-utils'
|
||||
import VueSelect from '@/components/Select.vue'
|
||||
import typeAheadPointer from '@/mixins/typeAheadPointer.js'
|
||||
import { mountDefault } from '@tests/helpers.js'
|
||||
@@ -20,14 +20,14 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can accept an array with pre-selected values', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: defaultProps,
|
||||
})
|
||||
expect(Select.vm.selectedValue[0]).toEqual(Select.vm.modelValue)
|
||||
})
|
||||
|
||||
it('can accept an array of objects and pre-selected value (single)', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
modelValue: { label: 'This is Foo', value: 'foo' },
|
||||
options: [
|
||||
@@ -40,7 +40,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can accept an array of objects and pre-selected values (multiple)', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
modelValue: [
|
||||
{ label: 'This is Foo', value: 'foo' },
|
||||
@@ -59,7 +59,7 @@ describe('VS - Selecting Values', () => {
|
||||
|
||||
it('can select an option on tab', () => {
|
||||
spy = vi.spyOn(typeAheadPointer.methods, 'typeAheadSelect')
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
selectOnTab: true,
|
||||
},
|
||||
@@ -71,7 +71,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can deselect a pre-selected object', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
multiple: true,
|
||||
options: [
|
||||
@@ -93,7 +93,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can deselect a pre-selected string', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
multiple: true,
|
||||
options: ['foo', 'bar'],
|
||||
@@ -107,7 +107,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can deselect an option when multiple is false', () => {
|
||||
const Select = shallowMount(VueSelect)
|
||||
const Select = mount(VueSelect)
|
||||
|
||||
Select.vm.$data._value = 'foo'
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can determine if the value prop is empty', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
options: ['one', 'two', 'three'],
|
||||
},
|
||||
@@ -142,7 +142,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('should reset the selected values when the multiple property changes', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
multiple: true,
|
||||
options: ['one', 'two', 'three'],
|
||||
@@ -157,7 +157,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can retain values present in a new array of options', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
modelValue: ['one'],
|
||||
options: ['one', 'two', 'three'],
|
||||
@@ -169,7 +169,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can determine if an object is already selected', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
modelValue: [{ label: 'one' }],
|
||||
options: [{ label: 'one' }],
|
||||
@@ -195,7 +195,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('can check if a string value is selected when the value is an object and multiple is true', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: {
|
||||
multiple: true,
|
||||
modelValue: [{ label: 'foo', value: 'bar' }],
|
||||
@@ -238,13 +238,13 @@ describe('VS - Selecting Values', () => {
|
||||
|
||||
describe('input Event', () => {
|
||||
it('will trigger the input event when the selection changes', () => {
|
||||
const Select = shallowMount(VueSelect)
|
||||
const Select = mount(VueSelect)
|
||||
Select.vm.select('bar')
|
||||
expect(Select.emitted('update:modelValue')[0]).toEqual(['bar'])
|
||||
})
|
||||
|
||||
it('will trigger the input event when the selection changes and multiple is true', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
props: { multiple: true, modelValue: ['foo'], options: ['foo', 'bar'] },
|
||||
})
|
||||
Select.vm.select('bar')
|
||||
@@ -252,7 +252,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('will not trigger the input event when multiple is true and selection is repeated', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: {
|
||||
multiple: true,
|
||||
value: ['foo ', 'bar'],
|
||||
@@ -267,13 +267,13 @@ describe('VS - Selecting Values', () => {
|
||||
|
||||
describe('option:selecting Event', () => {
|
||||
it('will trigger the option:selecting event when an option is selected', () => {
|
||||
const Select = shallowMount(VueSelect)
|
||||
const Select = mount(VueSelect)
|
||||
Select.vm.select('bar')
|
||||
expect(Select.emitted('option:selecting')[0]).toEqual(['bar'])
|
||||
})
|
||||
|
||||
it('will trigger the option:selecting event regardless of current value', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: { value: ['foo'], options: ['foo', 'bar'] },
|
||||
})
|
||||
Select.vm.select('foo')
|
||||
@@ -282,7 +282,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('will trigger the option:selecting event with current selected item when multiple is true', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: { multiple: true, value: ['foo'], options: ['foo', 'bar'] },
|
||||
})
|
||||
Select.vm.select('bar')
|
||||
@@ -290,7 +290,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('will trigger the option:selecting event regardless of current value when multiple is true', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: {
|
||||
multiple: true,
|
||||
value: ['foo', 'bar'],
|
||||
@@ -305,7 +305,7 @@ describe('VS - Selecting Values', () => {
|
||||
|
||||
describe('option:deselected Event', () => {
|
||||
it('will trigger the option:deselected event when an option is deselected', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: { value: ['foo'], options: ['foo', 'bar'] },
|
||||
})
|
||||
Select.vm.deselect('foo')
|
||||
@@ -313,7 +313,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('will trigger the option:deselected event regardless of current value', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: { value: ['foo'], options: ['foo', 'bar'] },
|
||||
})
|
||||
Select.vm.deselect('foo')
|
||||
@@ -322,7 +322,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('will trigger the option:selected event with current selected item when multiple is true', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: { multiple: true, value: ['foo'], options: ['foo', 'bar'] },
|
||||
})
|
||||
Select.vm.deselect('bar')
|
||||
@@ -330,7 +330,7 @@ describe('VS - Selecting Values', () => {
|
||||
})
|
||||
|
||||
it('will trigger the option:selected event regardless of current value when multiple is true', () => {
|
||||
const Select = shallowMount(VueSelect, {
|
||||
const Select = mount(VueSelect, {
|
||||
propsData: {
|
||||
multiple: true,
|
||||
value: ['foo', 'bar'],
|
||||
|
||||
Reference in New Issue
Block a user