mirror of
https://github.com/tenrok/vue-select.git
synced 2026-05-17 02:29:37 +03:00
split up provided contexts
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { inject, onMounted, ref, watch } from 'vue'
|
||||
import vAppendToBody from '@/directives/appendToBody.js'
|
||||
import { VueSelectInjectionKey } from '@/symbols'
|
||||
import type { InjectedVueSelectContext } from '@/types'
|
||||
import { DropdownMenuKey } from '@/symbols'
|
||||
import type { InjectedDropdownMenuContext } from '@/types'
|
||||
|
||||
const context = inject<InjectedVueSelectContext>(VueSelectInjectionKey)
|
||||
const context = inject<InjectedDropdownMenuContext>(DropdownMenuKey)
|
||||
const dropdownMenu = ref<HTMLElement | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
@@ -28,7 +28,7 @@ withDefaults(defineProps<{ as?: string }>(), { as: 'ul' })
|
||||
<template>
|
||||
<Component
|
||||
:is="as"
|
||||
v-show="context.dropdownOpen"
|
||||
v-if="context.dropdownOpen"
|
||||
:id="`vs${context.uid}__listbox`"
|
||||
ref="dropdownMenu"
|
||||
:key="`vs${context.uid}__listbox`"
|
||||
@@ -40,28 +40,12 @@ withDefaults(defineProps<{ as?: string }>(), { as: 'ul' })
|
||||
@mouseup="context.onMouseUp"
|
||||
>
|
||||
<slot></slot>
|
||||
<!-- TODO: not sure why, but using the previous system of swapping the dropdown el at open causes performance to drop drastically with Vue dev tools open -->
|
||||
<!-- <Component-->
|
||||
<!-- :is="as"-->
|
||||
<!-- 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>-->
|
||||
<!-- </Component>-->
|
||||
<!-- <Component-->
|
||||
<!-- :is="as"-->
|
||||
<!-- v-else-->
|
||||
<!-- :id="`vs${context.uid}__listbox`"-->
|
||||
<!-- role="listbox"-->
|
||||
<!-- style="display: none; visibility: hidden"-->
|
||||
<!-- ></Component>-->
|
||||
</Component>
|
||||
<Component
|
||||
:is="as"
|
||||
v-else
|
||||
:id="`vs${context.uid}__listbox`"
|
||||
role="listbox"
|
||||
style="display: none; visibility: hidden"
|
||||
></Component>
|
||||
</template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { inject, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { VueSelectInjectionKey } from '@/symbols'
|
||||
import type { InjectedVueSelectContext, VueSelectOption } from '@/types'
|
||||
import { computed, inject, ref } from 'vue'
|
||||
import { DropdownMenuItemKey } from '@/symbols'
|
||||
import type { InjectedDropdownMenuItemContext, VueSelectOption } from '@/types'
|
||||
|
||||
const context = inject<InjectedVueSelectContext>(VueSelectInjectionKey)
|
||||
const context = inject<InjectedDropdownMenuItemContext>(DropdownMenuItemKey)
|
||||
|
||||
interface Props {
|
||||
as?: string
|
||||
@@ -12,26 +12,23 @@ interface Props {
|
||||
opinionated?: boolean
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), { as: 'li', opinionated: true })
|
||||
|
||||
const selectableOption = ref<HTMLElement | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (selectableOption.value) {
|
||||
context?.value.registerSelectableEl(selectableOption.value)
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
as: 'li',
|
||||
opinionated: true,
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (selectableOption.value) {
|
||||
context?.value.unRegisterSelectableEl(selectableOption.value)
|
||||
}
|
||||
const optionKey = computed(() => {
|
||||
return context?.value.getOptionKey(props.option)
|
||||
})
|
||||
|
||||
const shouldDisplay = computed(() => {
|
||||
return context?.value.filteredOptionKeys.includes(optionKey.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Component
|
||||
ref="selectableOption"
|
||||
v-if="shouldDisplay"
|
||||
:is="as"
|
||||
:id="`vs${context.uid}__option-${index}`"
|
||||
role="option"
|
||||
|
||||
+35
-29
@@ -117,10 +117,17 @@ 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, defineComponent } from 'vue'
|
||||
import { VueSelectInjectionKey } from '@/symbols.js'
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { DropdownMenuItemKey, DropdownMenuKey } from '@/symbols.js'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
import type { VueSelectContext, VueSelectOption } from '@/types'
|
||||
import type {
|
||||
DropdownMenuContext,
|
||||
DropdownMenuItemContext,
|
||||
RegisteredOption,
|
||||
SelectableElement,
|
||||
VueSelectOption,
|
||||
VueSelectOptionKey,
|
||||
} from '@/types'
|
||||
import DropdownMenuItem from '@/components/DropdownMenuItem.vue'
|
||||
|
||||
export default defineComponent({
|
||||
@@ -309,7 +316,7 @@ export default defineComponent({
|
||||
* @since 3.3.0
|
||||
*/
|
||||
selectable: {
|
||||
type: Function,
|
||||
type: Function as PropType<(option: VueSelectOption) => boolean>,
|
||||
default: (option: VueSelectOption): boolean => true,
|
||||
},
|
||||
|
||||
@@ -327,7 +334,7 @@ export default defineComponent({
|
||||
* @return {String}
|
||||
*/
|
||||
getOptionLabel: {
|
||||
type: Function,
|
||||
type: Function as PropType<(option: VueSelectOption) => string>,
|
||||
default(option: VueSelectOption) {
|
||||
if (typeof option === 'object') {
|
||||
if (!option.hasOwnProperty(this.label)) {
|
||||
@@ -354,13 +361,9 @@ export default defineComponent({
|
||||
* slow with lots of objects.
|
||||
*
|
||||
* The result of this function *must* be unique.
|
||||
*
|
||||
* @type {Function}
|
||||
* @param {Object || String} option
|
||||
* @return {String}
|
||||
*/
|
||||
getOptionKey: {
|
||||
type: Function,
|
||||
type: Function as PropType<(option: VueSelectOption) => unknown>,
|
||||
default(option: VueSelectOption): unknown {
|
||||
if (typeof option !== 'object') {
|
||||
return option
|
||||
@@ -587,7 +590,6 @@ export default defineComponent({
|
||||
* for the search input. Can be used to implement
|
||||
* custom behaviour for key presses.
|
||||
*/
|
||||
|
||||
mapKeydown: {
|
||||
type: Function,
|
||||
/**
|
||||
@@ -663,29 +665,31 @@ export default defineComponent({
|
||||
|
||||
provide() {
|
||||
return {
|
||||
[VueSelectInjectionKey]: computed<VueSelectContext>(() => {
|
||||
return {
|
||||
[DropdownMenuKey]: computed<DropdownMenuContext>(() => {
|
||||
const context: DropdownMenuContext = {
|
||||
uid: this.uid,
|
||||
dropdownOpen: this.dropdownOpen,
|
||||
onMousedown: this.onMousedown,
|
||||
onMouseup: this.onMouseUp,
|
||||
setDropdownMenuEl: (el: HTMLElement | null) => {
|
||||
this.dropdownMenuEl = el
|
||||
},
|
||||
}
|
||||
return context
|
||||
}),
|
||||
[DropdownMenuItemKey]: computed<DropdownMenuItemContext>(() => {
|
||||
const context: DropdownMenuItemContext = {
|
||||
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,
|
||||
filteredOptionKeys: this.filteredOptionKeys,
|
||||
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)
|
||||
},
|
||||
}
|
||||
return context
|
||||
}),
|
||||
}
|
||||
},
|
||||
@@ -700,7 +704,6 @@ export default defineComponent({
|
||||
_value: [], // Internal value managed by Vue Select if no `value` prop is passed
|
||||
deselectButtons: [],
|
||||
dropdownMenuEl: null,
|
||||
selectableEls: [],
|
||||
} as {
|
||||
search: string
|
||||
open: boolean
|
||||
@@ -709,7 +712,6 @@ export default defineComponent({
|
||||
_value: any[]
|
||||
deselectButtons: any[]
|
||||
dropdownMenuEl: HTMLElement | null
|
||||
selectableEls: HTMLElement[]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -752,7 +754,7 @@ export default defineComponent({
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
optionList() {
|
||||
optionList(): VueSelectOption[] {
|
||||
return this.options.concat(this.pushTags ? this.pushedTags : [])
|
||||
},
|
||||
|
||||
@@ -899,7 +901,7 @@ export default defineComponent({
|
||||
*
|
||||
* @return {array}
|
||||
*/
|
||||
filteredOptions() {
|
||||
filteredOptions(): VueSelectOption[] {
|
||||
const optionList = [].concat(this.optionList)
|
||||
|
||||
if (!this.filterable && !this.taggable) {
|
||||
@@ -918,6 +920,10 @@ export default defineComponent({
|
||||
return options
|
||||
},
|
||||
|
||||
filteredOptionKeys(): VueSelectOptionKey[] {
|
||||
return this.filteredOptions.map((option) => this.getOptionKey(option))
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if there aren't any options selected.
|
||||
* @return {Boolean}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
import type { InjectionKey } from 'vue'
|
||||
|
||||
export const VueSelectInjectionKey = Symbol(
|
||||
'VueSelectInjectionKey'
|
||||
) as InjectionKey<string>
|
||||
export const DropdownMenuKey = Symbol('DropdownMenuKey')
|
||||
|
||||
export const DropdownMenuItemKey = Symbol('DropdownMenuItemKey')
|
||||
|
||||
+15
-8
@@ -1,20 +1,27 @@
|
||||
import type { ComputedRef } from 'vue'
|
||||
|
||||
export interface VueSelectContext {
|
||||
export interface DropdownMenuContext {
|
||||
uid: string | number | undefined
|
||||
dropdownOpen: boolean
|
||||
onMousedown: (e: MouseEvent) => void
|
||||
onMouseup: (e: MouseEvent) => void
|
||||
setDropdownMenuEl: (el: HTMLElement | null) => void
|
||||
}
|
||||
export type InjectedDropdownMenuContext = ComputedRef<DropdownMenuContext>
|
||||
|
||||
export interface DropdownMenuItemContext {
|
||||
uid: DropdownMenuContext['uid']
|
||||
typeAheadPointer: number
|
||||
setTypeAheadPointer: (index: number) => void
|
||||
isOptionDeselectable: (option: VueSelectOption) => boolean
|
||||
isOptionSelected: (option: VueSelectOption) => boolean
|
||||
onMousedown: (e: MouseEvent) => void
|
||||
onMouseup: (e: MouseEvent) => void
|
||||
getOptionKey: (option: VueSelectOption) => unknown
|
||||
filteredOptionKeys: VueSelectOptionKey[]
|
||||
select: (option: VueSelectOption) => void
|
||||
setDropdownMenuEl: (el: HTMLElement | null) => void
|
||||
registerSelectableEl: (el: HTMLElement | null) => void
|
||||
unRegisterSelectableEl: (el: HTMLElement | null) => void
|
||||
selectable: (option: VueSelectOption) => boolean
|
||||
}
|
||||
|
||||
export type InjectedVueSelectContext = ComputedRef<VueSelectContext>
|
||||
export type InjectedDropdownMenuItemContext =
|
||||
ComputedRef<DropdownMenuItemContext>
|
||||
|
||||
export type VueSelectOption = unknown
|
||||
export type VueSelectOptionKey = unknown
|
||||
|
||||
Reference in New Issue
Block a user