diff --git a/dev/Dev.vue b/dev/Dev.vue
index ab8e964..b6f4164 100644
--- a/dev/Dev.vue
+++ b/dev/Dev.vue
@@ -1,21 +1,72 @@
-
+
+
+
+
+
+
+ {{ option.label }}
+
+
+
+
+
+
+
+
+
+
{{ group }}
+
+
+ {{ option.label }}
+
+
+
+
+
+
diff --git a/src/components/DropdownMenu.vue b/src/components/DropdownMenu.vue
index c6ec331..c2dd662 100644
--- a/src/components/DropdownMenu.vue
+++ b/src/components/DropdownMenu.vue
@@ -1,15 +1,34 @@
- (VueSelectInjectionKey)
@mouseup="context.onMouseUp"
>
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/DropdownMenuItem.vue b/src/components/DropdownMenuItem.vue
new file mode 100644
index 0000000..2d1f7d9
--- /dev/null
+++ b/src/components/DropdownMenuItem.vue
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
diff --git a/src/components/Select.vue b/src/components/Select.vue
index ae5267a..3cdf167 100644
--- a/src/components/Select.vue
+++ b/src/components/Select.vue
@@ -82,36 +82,30 @@
-
-
-
-
- {{ getOptionLabel(option) }}
+
+
+
+
+
+
+ {{ getOptionLabel(option) }}
+
+
+
+
+ Sorry, no matching options.
+
+
-
-
-
- Sorry, no matching options.
-
-
-
-
+
+
+
@@ -123,19 +117,14 @@ import ajax from '@/mixins/ajax.js'
import childComponents from '@/components/childComponents.js'
import sortAndStringify from '@/utility/sortAndStringify.js'
import uniqueId from '@/utility/uniqueId.js'
-import { computed, ComputedRef, defineComponent } from 'vue'
+import { computed, defineComponent } from 'vue'
import { VueSelectInjectionKey } from '@/symbols.js'
import DropdownMenu from '@/components/DropdownMenu.vue'
-
-export interface VueSelectContext {
- uid: ComputedRef
- dropdownOpen: ComputedRef
- onMousedown: (e: MouseEvent) => void
- onMouseup: (e: MouseEvent) => void
-}
+import type { VueSelectContext, VueSelectOption } from '@/types'
+import DropdownMenuItem from '@/components/DropdownMenuItem.vue'
export default defineComponent({
- components: { DropdownMenu, ...childComponents },
+ components: { DropdownMenuItem, DropdownMenu, ...childComponents },
mixins: [pointerScroll, typeAheadPointer, ajax],
@@ -309,7 +298,7 @@ export default defineComponent({
*/
reduce: {
type: Function,
- default: (option) => option,
+ default: (option: VueSelectOption) => option,
},
/**
@@ -318,12 +307,10 @@ export default defineComponent({
*
* @type {Function}
* @since 3.3.0
- * @param {Object|String} option
- * @return {Boolean}
*/
selectable: {
type: Function,
- default: (option) => true,
+ default: (option: VueSelectOption): boolean => true,
},
/**
@@ -341,7 +328,7 @@ export default defineComponent({
*/
getOptionLabel: {
type: Function,
- default(option) {
+ default(option: VueSelectOption) {
if (typeof option === 'object') {
if (!option.hasOwnProperty(this.label)) {
return console.warn(
@@ -374,7 +361,7 @@ export default defineComponent({
*/
getOptionKey: {
type: Function,
- default(option) {
+ default(option: VueSelectOption): unknown {
if (typeof option !== 'object') {
return option
}
@@ -659,7 +646,7 @@ export default defineComponent({
*/
dropdownShouldOpen: {
type: Function,
- default({ noDrop, open, mutableLoading }) {
+ default({ noDrop, open, mutableLoading }): boolean {
return noDrop ? false : open && !mutableLoading
},
},
@@ -676,12 +663,28 @@ export default defineComponent({
provide() {
return {
- [VueSelectInjectionKey]: computed(() => {
+ [VueSelectInjectionKey]: computed(() => {
return {
uid: this.uid,
+ getOptionKey: this.getOptionKey,
+ isOptionDeselectable: this.isOptionDeselectable,
+ isOptionSelected: this.isOptionSelected,
+ typeAheadPointer: this.typeAheadPointer,
+ setTypeAheadPointer: this.setTypeAheadPointer,
dropdownOpen: this.dropdownOpen,
onMousedown: this.onMousedown,
onMouseup: this.onMouseUp,
+ selectable: this.selectable,
+ select: this.select,
+ setDropdownMenuEl: (ref: HTMLElement) => {
+ this.dropdownMenuEl = ref
+ },
+ registerSelectableEl: (ref: HTMLElement) => {
+ this.selectableEls.push(ref)
+ },
+ unRegisterSelectableEl: (ref: HTMLElement) => {
+ this.selectableEls = this.selectableEls.filter((el) => el !== ref)
+ },
}
}),
}
@@ -696,6 +699,17 @@ export default defineComponent({
// eslint-disable-next-line vue/no-reserved-keys
_value: [], // Internal value managed by Vue Select if no `value` prop is passed
deselectButtons: [],
+ dropdownMenuEl: null,
+ selectableEls: [],
+ } as {
+ search: string
+ open: boolean
+ isComposing: boolean
+ pushedTags: VueSelectOption[]
+ _value: any[]
+ deselectButtons: any[]
+ dropdownMenuEl: HTMLElement | null
+ selectableEls: HTMLElement[]
}
},
@@ -862,7 +876,7 @@ export default defineComponent({
* dropdown menu.
* @return {Boolean} True if open
*/
- dropdownOpen() {
+ dropdownOpen(): boolean {
return this.dropdownShouldOpen(this)
},
@@ -1131,7 +1145,7 @@ export default defineComponent({
* @param {Object|String} option
* @return {Boolean} True when selected | False otherwise
*/
- isOptionSelected(option) {
+ isOptionSelected(option: VueSelectOption): boolean {
return this.selectedValue.some((value) =>
this.optionComparator(value, option)
)
@@ -1140,7 +1154,7 @@ export default defineComponent({
/**
* Can the current option be removed via the dropdown?
*/
- isOptionDeselectable(option) {
+ isOptionDeselectable(option: VueSelectOption) {
return this.isOptionSelected(option) && this.deselectFromDropdown
},
diff --git a/src/mixins/pointerScroll.js b/src/mixins/pointerScroll.js
index c60619a..aa9019a 100644
--- a/src/mixins/pointerScroll.js
+++ b/src/mixins/pointerScroll.js
@@ -20,6 +20,10 @@ export default {
},
methods: {
+ setTypeAheadPointer(index) {
+ this.typeAheadPointer = index
+ },
+
/**
* Adjust the scroll position of the dropdown list
* if the current pointer is outside of the
@@ -28,16 +32,16 @@ export default {
*/
maybeAdjustScroll() {
const optionEl =
- this.$refs.dropdownMenu?.children[this.typeAheadPointer] || false
+ this.dropdownMenuEl?.children[this.typeAheadPointer] || false
if (optionEl) {
const bounds = this.getDropdownViewport()
const { top, bottom, height } = optionEl.getBoundingClientRect()
if (top < bounds.top) {
- return (this.$refs.dropdownMenu.scrollTop = optionEl.offsetTop)
+ return (this.dropdownMenuEl.scrollTop = optionEl.offsetTop)
} else if (bottom > bounds.bottom) {
- return (this.$refs.dropdownMenu.scrollTop =
+ return (this.dropdownMenuEl.scrollTop =
optionEl.offsetTop - (bounds.height - height))
}
}
@@ -48,8 +52,8 @@ export default {
* @returns {{top: (string|*|number), bottom: *}}
*/
getDropdownViewport() {
- return this.$refs.dropdownMenu
- ? this.$refs.dropdownMenu.getBoundingClientRect()
+ return this.dropdownMenuEl
+ ? this.dropdownMenuEl.getBoundingClientRect()
: {
height: 0,
top: 0,
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..03bcda5
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,20 @@
+import type { ComputedRef } from 'vue'
+
+export interface VueSelectContext {
+ uid: string | number | undefined
+ dropdownOpen: boolean
+ typeAheadPointer: number
+ setTypeAheadPointer: (index: number) => void
+ isOptionDeselectable: (option: VueSelectOption) => boolean
+ isOptionSelected: (option: VueSelectOption) => boolean
+ onMousedown: (e: MouseEvent) => void
+ onMouseup: (e: MouseEvent) => void
+ select: (option: VueSelectOption) => void
+ setDropdownMenuEl: (el: HTMLElement | null) => void
+ registerSelectableEl: (el: HTMLElement | null) => void
+ unRegisterSelectableEl: (el: HTMLElement | null) => void
+}
+
+export type InjectedVueSelectContext = ComputedRef
+
+export type VueSelectOption = unknown
diff --git a/src/utility/uniqueId.js b/src/utility/uniqueId.ts
similarity index 83%
rename from src/utility/uniqueId.js
rename to src/utility/uniqueId.ts
index 53de592..83f9f45 100644
--- a/src/utility/uniqueId.js
+++ b/src/utility/uniqueId.ts
@@ -5,7 +5,7 @@ let idCount = 0
* Thanks lodash!
* @return {number}
*/
-function uniqueId() {
+function uniqueId(): number {
return ++idCount
}