2
0
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:
Jeff Sagal
2022-12-01 12:20:11 -08:00
parent eaced8caf1
commit f32ef69e3d
5 changed files with 78 additions and 84 deletions
+11 -27
View File
@@ -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>
+14 -17
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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