make sure dropdown/combobox lists stay visible during close animation to

avoid layout shifts
This commit is contained in:
Gregor Vostrak
2026-07-09 12:33:56 +02:00
parent 65fbb43aa6
commit 7c3f7e2b67
7 changed files with 47 additions and 22 deletions

View File

@@ -89,11 +89,17 @@ function selectMember(member: Member) {
</Button>
</template>
<template #content>
<!-- kept open so the list stays visible during the popover close animation -->
<ComboboxRoot
v-model:search-term="searchValue"
v-model:open="open"
:open="true"
class="relative"
:filter-function="(val: string[]) => val">
:filter-function="(val: string[]) => val"
@update:open="
(value: boolean) => {
if (!value) open = false;
}
">
<ComboboxAnchor>
<ComboboxInput
ref="searchInput"

View File

@@ -37,9 +37,7 @@ const emit = defineEmits(['update:modelValue', 'changed']);
const activeClients = computed(() => clients.value.filter((c) => !c.is_archived));
// The selected project is pinned when the dropdown opens so rows don't re-sort while
// the user interacts, but the project list itself stays reactive — projects may still
// be loading (fetchAllPages) when the dropdown opens.
// Pinned on open so rows don't re-sort while interacting; the project list itself stays reactive.
const pinnedProjectId = ref<string | null>(null);
const sortedProjects = computed(() => {
@@ -112,13 +110,19 @@ function updateValue(project: Project) {
</template>
<template #content>
<div v-if="open">
<!-- kept open so the list stays visible during the popover close animation -->
<div>
<ComboboxRoot
v-model:open="open"
:open="true"
:model-value="currentProject"
class="relative"
:ignore-filter="true"
@update:model-value="updateValue">
@update:model-value="updateValue"
@update:open="
(value: boolean) => {
if (!value) open = false;
}
">
<ComboboxAnchor>
<ComboboxInput
ref="searchInput"

View File

@@ -85,13 +85,18 @@ function updateValue(client: { id: string | null; name: string }) {
<slot name="trigger"></slot>
</template>
<template #content>
<div v-if="open">
<div>
<ComboboxRoot
v-model:open="open"
:open="true"
:model-value="currentClient"
class="relative"
:ignore-filter="true"
@update:model-value="updateValue">
@update:model-value="updateValue"
@update:open="
(value: boolean) => {
if (!value) open = false;
}
">
<ComboboxAnchor>
<ComboboxInput
ref="searchInput"

View File

@@ -33,9 +33,7 @@ const props = defineProps<{
const open = ref(false);
const searchValue = ref('');
// The selection is pinned when the dropdown opens so rows don't re-sort while the user
// toggles checkboxes, but the item list itself stays reactive — items may still be
// loading (fetchAllPages) when the dropdown opens.
// Pinned on open so rows don't re-sort while toggling; the item list itself stays reactive.
const pinnedSelection = ref<Set<string>>(new Set());
watch(open, (isOpen) => {
@@ -104,7 +102,16 @@ const emit = defineEmits(['update:modelValue', 'changed', 'submit']);
<slot name="trigger"></slot>
</template>
<template #content>
<ComboboxRoot v-model:open="open" class="p-2" :ignore-filter="true">
<!-- kept open so the list stays visible during the popover close animation -->
<ComboboxRoot
:open="true"
class="p-2"
:ignore-filter="true"
@update:open="
(value: boolean) => {
if (!value) open = false;
}
">
<ComboboxAnchor>
<ComboboxInput
v-model="searchValue"

View File

@@ -37,9 +37,7 @@ const model = defineModel<string[]>({
const open = ref(false);
const searchValue = ref('');
// The selection is pinned when the dropdown opens so rows don't re-sort while the user
// toggles tags, but the tag list itself stays reactive — tags may still be loading
// when the dropdown opens.
// Pinned on open so rows don't re-sort while toggling; the tag list itself stays reactive.
const pinnedSelection = ref<Set<string>>(new Set());
watch(open, (isOpen) => {

View File

@@ -594,7 +594,7 @@ const showCreateProject = ref(false);
</slot>
</template>
<template #content>
<div v-if="open">
<div>
<input
ref="searchInput"
:value="searchValue"