mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-07 07:12:23 +03:00
allow open prop to control menu state
This commit is contained in:
+11
-29
@@ -1,22 +1,26 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div class="flex items-center justify-center pt-40">
|
||||
<ListBox
|
||||
v-model="selected"
|
||||
:open="open"
|
||||
class="px-2 text-left border border-gray-500 rounded w-64 relative bg-blue-100 h-12"
|
||||
v-model:open="open"
|
||||
class="px-2 text-left border border-gray-500 rounded w-64 relative h-12"
|
||||
>
|
||||
{{ selected?.label }}
|
||||
|
||||
<ListBoxMenu
|
||||
class="absolute inset-0 top-12 w-full h-64 overflow-y-scroll bg-red-100 space-y-1"
|
||||
class="absolute inset-0 top-12 w-full h-64 overflow-y-scroll space-y-1 border rounded"
|
||||
>
|
||||
<ListBoxOption
|
||||
@click="selected = country"
|
||||
v-for="country in config.options"
|
||||
:key="country.id"
|
||||
class="px-2 py-1"
|
||||
:class="['px-2 py-1']"
|
||||
:value="country"
|
||||
#default="{ isSelected }"
|
||||
>
|
||||
{{ country.label }}
|
||||
<span :class="{ 'text-indigo-600': isSelected }">
|
||||
{{ country.label }}
|
||||
</span>
|
||||
</ListBoxOption>
|
||||
</ListBoxMenu>
|
||||
</ListBox>
|
||||
@@ -33,6 +37,7 @@ export default {
|
||||
components: { ListBoxOption, ListBoxMenu, ListBox },
|
||||
data: () => ({
|
||||
selected: null,
|
||||
open: false,
|
||||
|
||||
config: {
|
||||
options: countries,
|
||||
@@ -40,26 +45,3 @@ export default {
|
||||
}),
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-family: -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
max-width: 20rem;
|
||||
margin: 10rem auto 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-bottom: 1px solid #cacaca;
|
||||
margin-bottom: 1em;
|
||||
padding-top: 1em;
|
||||
width: 90%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,12 +3,9 @@
|
||||
By default, the dropdown will open anytime the underlying search input has focus. The dropdown will
|
||||
open when clicked, or when it has received focus when tabbing through inputs.
|
||||
|
||||
## Customizing Dropdown Behaviour <Badge text="v3.12.0+" />
|
||||
## Customizing Dropdown Behaviour <Badge text="v4+" />
|
||||
|
||||
The `dropdownShouldOpen` prop allows for full customization of the open/close behaviour. The prop
|
||||
accepts a `function` that should return a `boolean` value. The returned boolean value will be used
|
||||
to determine if the dropdown should be `open`/`true` or `false`/`closed`. The function receives the
|
||||
instance of the component as the only argument.
|
||||
The `open` prop can control showing and hiding the dropdown menu from a parent component. If this prop is set, the component will always use the value of `props.open` to handle showing and hiding the dropdown. Vue Select will emit the `update:open` when the prop value should change, so you can use `<VueSelect v-model:open="open" />` to have control over the `open` state while preserving default behaviour.
|
||||
|
||||
#### Example: Open the dropdown when search text is present
|
||||
---
|
||||
|
||||
@@ -1,25 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
import { ListBoxInjectionKey } from '@/keys.js'
|
||||
import { ListBoxInjectionKey } from '@/keys'
|
||||
import type { ComputedRef, PropType } from 'vue'
|
||||
import { provide, defineEmits, computed, ref } from 'vue'
|
||||
import { provide, defineEmits, computed, reactive, watch } from 'vue'
|
||||
|
||||
export interface ListBoxProps {
|
||||
modelValue: PropType<unknown>
|
||||
open?: boolean
|
||||
open?: boolean | undefined
|
||||
}
|
||||
export interface ResolvedListBoxProps extends Omit<ListBoxProps, 'open'> {
|
||||
open: boolean
|
||||
}
|
||||
export type InjectedListBoxProps = ComputedRef<ResolvedListBoxProps>
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const emit = defineEmits(['update:modelValue', 'update:open', 'open', 'close'])
|
||||
|
||||
const props = withDefaults(defineProps<ListBoxProps>(), {
|
||||
open: false,
|
||||
open: undefined,
|
||||
})
|
||||
|
||||
export type ComputedListBoxInjectionProps = ComputedRef<ListBoxProps>
|
||||
const mutableState = reactive<{
|
||||
open: boolean
|
||||
}>({
|
||||
open: props.open === undefined ? false : props.open,
|
||||
})
|
||||
|
||||
provide<ComputedListBoxInjectionProps>(
|
||||
watch(
|
||||
() => mutableState.open,
|
||||
(open) => emit('update:open', open)
|
||||
)
|
||||
|
||||
const isOpen = computed<boolean>(() => {
|
||||
if (props.open !== undefined) {
|
||||
return props.open
|
||||
}
|
||||
return mutableState.open
|
||||
})
|
||||
|
||||
provide<InjectedListBoxProps>(
|
||||
ListBoxInjectionKey,
|
||||
computed<ListBoxProps>(() => ({
|
||||
open: props.open,
|
||||
computed<ResolvedListBoxProps>(() => ({
|
||||
open: isOpen.value,
|
||||
modelValue: props.modelValue,
|
||||
}))
|
||||
)
|
||||
@@ -31,7 +51,7 @@ provide<ComputedListBoxInjectionProps>(
|
||||
type="button"
|
||||
aria-haspopup="true"
|
||||
:aria-expanded="open"
|
||||
@click.exact="open = !open"
|
||||
@click.exact="mutableState.open = !mutableState.open"
|
||||
>
|
||||
<slot></slot>
|
||||
</button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps, inject } from 'vue'
|
||||
import { ListBoxInjectionKey } from '@/keys'
|
||||
import type { ComputedListBoxInjectionProps } from '@/components/ListBox/ListBox.vue'
|
||||
import type { InjectedListBoxProps } from '@/components/ListBox/ListBox.vue'
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
@@ -12,11 +12,11 @@ withDefaults(
|
||||
}
|
||||
)
|
||||
|
||||
const listBoxProps = inject<ComputedListBoxInjectionProps>(ListBoxInjectionKey)
|
||||
const listBoxProps = inject<InjectedListBoxProps>(ListBoxInjectionKey)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Component :is="as" v-show="listBoxProps?.open">
|
||||
<Component :is="as" v-show="listBoxProps.open">
|
||||
<slot></slot>
|
||||
</Component>
|
||||
</template>
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue'
|
||||
import { computed, defineProps, inject } from 'vue'
|
||||
import type { InjectedListBoxProps } from '@/components/ListBox/ListBox.vue'
|
||||
import { ListBoxInjectionKey } from '@/keys'
|
||||
|
||||
withDefaults(
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
as?: string
|
||||
value: unknown
|
||||
}>(),
|
||||
{
|
||||
as: 'div',
|
||||
}
|
||||
)
|
||||
|
||||
const listBoxProps = inject<InjectedListBoxProps>(ListBoxInjectionKey)
|
||||
|
||||
const isSelected = computed(() => {
|
||||
return listBoxProps?.value.modelValue === props.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Component :is="as">
|
||||
<slot></slot>
|
||||
<slot v-bind="{ isSelected }"></slot>
|
||||
</Component>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user