mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-22 10:30:34 +03:00
allow open prop to control menu state
This commit is contained in:
+11
-29
@@ -1,22 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div class="flex items-center justify-center pt-40">
|
||||||
<ListBox
|
<ListBox
|
||||||
v-model="selected"
|
v-model="selected"
|
||||||
:open="open"
|
v-model:open="open"
|
||||||
class="px-2 text-left border border-gray-500 rounded w-64 relative bg-blue-100 h-12"
|
class="px-2 text-left border border-gray-500 rounded w-64 relative h-12"
|
||||||
>
|
>
|
||||||
{{ selected?.label }}
|
{{ selected?.label }}
|
||||||
|
|
||||||
<ListBoxMenu
|
<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
|
<ListBoxOption
|
||||||
@click="selected = country"
|
@click="selected = country"
|
||||||
v-for="country in config.options"
|
v-for="country in config.options"
|
||||||
:key="country.id"
|
: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>
|
</ListBoxOption>
|
||||||
</ListBoxMenu>
|
</ListBoxMenu>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
@@ -33,6 +37,7 @@ export default {
|
|||||||
components: { ListBoxOption, ListBoxMenu, ListBox },
|
components: { ListBoxOption, ListBoxMenu, ListBox },
|
||||||
data: () => ({
|
data: () => ({
|
||||||
selected: null,
|
selected: null,
|
||||||
|
open: false,
|
||||||
|
|
||||||
config: {
|
config: {
|
||||||
options: countries,
|
options: countries,
|
||||||
@@ -40,26 +45,3 @@ export default {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
</script>
|
</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
|
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.
|
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
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
#### Example: Open the dropdown when search text is present
|
#### Example: Open the dropdown when search text is present
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,25 +1,45 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ListBoxInjectionKey } from '@/keys.js'
|
import { ListBoxInjectionKey } from '@/keys'
|
||||||
import type { ComputedRef, PropType } from 'vue'
|
import type { ComputedRef, PropType } from 'vue'
|
||||||
import { provide, defineEmits, computed, ref } from 'vue'
|
import { provide, defineEmits, computed, reactive, watch } from 'vue'
|
||||||
|
|
||||||
export interface ListBoxProps {
|
export interface ListBoxProps {
|
||||||
modelValue: PropType<unknown>
|
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>(), {
|
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,
|
ListBoxInjectionKey,
|
||||||
computed<ListBoxProps>(() => ({
|
computed<ResolvedListBoxProps>(() => ({
|
||||||
open: props.open,
|
open: isOpen.value,
|
||||||
modelValue: props.modelValue,
|
modelValue: props.modelValue,
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
@@ -31,7 +51,7 @@ provide<ComputedListBoxInjectionProps>(
|
|||||||
type="button"
|
type="button"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
:aria-expanded="open"
|
:aria-expanded="open"
|
||||||
@click.exact="open = !open"
|
@click.exact="mutableState.open = !mutableState.open"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, inject } from 'vue'
|
import { defineProps, inject } from 'vue'
|
||||||
import { ListBoxInjectionKey } from '@/keys'
|
import { ListBoxInjectionKey } from '@/keys'
|
||||||
import type { ComputedListBoxInjectionProps } from '@/components/ListBox/ListBox.vue'
|
import type { InjectedListBoxProps } from '@/components/ListBox/ListBox.vue'
|
||||||
|
|
||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
@@ -12,11 +12,11 @@ withDefaults(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const listBoxProps = inject<ComputedListBoxInjectionProps>(ListBoxInjectionKey)
|
const listBoxProps = inject<InjectedListBoxProps>(ListBoxInjectionKey)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Component :is="as" v-show="listBoxProps?.open">
|
<Component :is="as" v-show="listBoxProps.open">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</Component>
|
</Component>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<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<{
|
defineProps<{
|
||||||
as?: string
|
as?: string
|
||||||
|
value: unknown
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
as: 'div',
|
as: 'div',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const listBoxProps = inject<InjectedListBoxProps>(ListBoxInjectionKey)
|
||||||
|
|
||||||
|
const isSelected = computed(() => {
|
||||||
|
return listBoxProps?.value.modelValue === props.value
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Component :is="as">
|
<Component :is="as">
|
||||||
<slot></slot>
|
<slot v-bind="{ isSelected }"></slot>
|
||||||
</Component>
|
</Component>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user