Skip to content

Commit 67a7b11

Browse files
fix(NavigationMenu): ignore inactive content dismiss (#2637)
* fix(NavigationMenu): ignore inactive content dismiss * test(NavigationMenu): fully cover the multi-content bug scenario. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent f2b0d8f commit 67a7b11

3 files changed

Lines changed: 77 additions & 1 deletion

File tree

packages/core/src/NavigationMenu/NavigationMenu.test.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
77
import { axe } from 'vitest-axe'
88
import { nextTick } from 'vue'
99
import { sleep } from '@/test'
10-
import NavigationMenuItem from './NavigationMenuItem.vue'
10+
import NavigationMenuUnmountOnHideFalse from './__test__/NavigationMenuUnmountOnHideFalse.vue'
1111

12+
import NavigationMenuItem from './NavigationMenuItem.vue'
1213
import NavigationMenu from './story/_NavigationMenu.vue'
1314

1415
vi.mock('@vueuse/core', async () => {
@@ -102,6 +103,33 @@ describe('given default NavigationMenu', () => {
102103
// })
103104
})
104105

106+
it('keeps active content open when clicking inside with unmountOnHide disabled', async () => {
107+
const wrapper = mount(NavigationMenuUnmountOnHideFalse, { attachTo: document.body })
108+
109+
await wrapper.find('[data-testid="trigger-one"]').trigger('click')
110+
await wrapper.vm.$nextTick()
111+
await sleep(0)
112+
113+
expect(wrapper.find('[data-testid="model-value"]').text()).toBe('one')
114+
115+
// Open second content; first stays mounted but becomes inactive
116+
await wrapper.find('[data-testid="trigger-two"]').trigger('click')
117+
await wrapper.vm.$nextTick()
118+
await sleep(0)
119+
120+
expect(wrapper.find('[data-testid="model-value"]').text()).toBe('two')
121+
122+
// Click inside active content-two; inactive content-one should not interfere
123+
await fireEvent.pointerDown(wrapper.find('[data-testid="inside-two"]').element)
124+
await wrapper.vm.$nextTick()
125+
await sleep(0)
126+
127+
// Content-two should remain open (content-one's dismiss handler returned early)
128+
expect(wrapper.find('[data-testid="model-value"]').text()).toBe('two')
129+
130+
wrapper.unmount()
131+
})
132+
105133
describe('menu triggers', () => {
106134
const findMenuItem = () => wrapper.findComponent(NavigationMenuItem)
107135

packages/core/src/NavigationMenu/NavigationMenuContentImpl.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ function handleKeydown(ev: KeyboardEvent) {
180180
}
181181
182182
function handleDismiss() {
183+
if (menuContext.modelValue.value !== itemContext.value)
184+
return
185+
183186
const rootContentDismissEvent = new Event(EVENT_ROOT_CONTENT_DISMISS, {
184187
bubbles: true,
185188
cancelable: true,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
import {
4+
NavigationMenuContent,
5+
NavigationMenuItem,
6+
NavigationMenuList,
7+
NavigationMenuRoot,
8+
NavigationMenuTrigger,
9+
} from '..'
10+
11+
const modelValue = ref('')
12+
</script>
13+
14+
<template>
15+
<NavigationMenuRoot
16+
v-model="modelValue"
17+
:unmount-on-hide="false"
18+
:disable-hover-trigger="true"
19+
>
20+
<span data-testid="model-value">{{ modelValue }}</span>
21+
<NavigationMenuList>
22+
<NavigationMenuItem value="one">
23+
<NavigationMenuTrigger data-testid="trigger-one">
24+
One
25+
</NavigationMenuTrigger>
26+
<NavigationMenuContent data-testid="content-one">
27+
<button data-testid="inside-one">
28+
Inside one
29+
</button>
30+
</NavigationMenuContent>
31+
</NavigationMenuItem>
32+
33+
<NavigationMenuItem value="two">
34+
<NavigationMenuTrigger data-testid="trigger-two">
35+
Two
36+
</NavigationMenuTrigger>
37+
<NavigationMenuContent data-testid="content-two">
38+
<button data-testid="inside-two">
39+
Inside two
40+
</button>
41+
</NavigationMenuContent>
42+
</NavigationMenuItem>
43+
</NavigationMenuList>
44+
</NavigationMenuRoot>
45+
</template>

0 commit comments

Comments
 (0)