Skip to content

Commit fd9a2d2

Browse files
authored
Ensure interactability with Popover.Panel contents in static mode (#857)
* ensure interactability with Popover.Panel contents in static mode * update changelog
1 parent f9e0d30 commit fd9a2d2

File tree

4 files changed

+156
-2
lines changed

4 files changed

+156
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Stop the event from propagating in the `Popover` component ([#798](https://github.com/tailwindlabs/headlessui/pull/798))
1313
- Allow to click on elements inside a `Dialog.Overlay` ([#816](https://github.com/tailwindlabs/headlessui/pull/816))
14+
- Ensure interactability with `Popover.Panel` contents when using the `static` prop ([#857](https://github.com/tailwindlabs/headlessui/pull/857))
1415

1516
## [Unreleased - Vue]
1617

packages/@headlessui-react/src/components/popover/popover.test.tsx

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { createElement, useEffect, useRef } from 'react'
2-
import { render } from '@testing-library/react'
2+
import { render, screen } from '@testing-library/react'
33

44
import { Popover } from './popover'
55
import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs'
@@ -2125,4 +2125,78 @@ describe('Mouse interactions', () => {
21252125
assertActiveElement(getPopoverButton())
21262126
})
21272127
)
2128+
2129+
it(
2130+
'should not close the Popover when clicking on a focusable element inside a static Popover.Panel',
2131+
suppressConsoleLogs(async () => {
2132+
let clickFn = jest.fn()
2133+
2134+
render(
2135+
<Popover>
2136+
<Popover.Button>Open</Popover.Button>
2137+
<Popover.Panel static>
2138+
<button onClick={clickFn}>btn</button>
2139+
</Popover.Panel>
2140+
</Popover>
2141+
)
2142+
2143+
// Open the popover
2144+
await click(getPopoverButton())
2145+
2146+
// The button should not close the popover
2147+
await click(getByText('btn'))
2148+
2149+
// Verify it is still open
2150+
assertPopoverButton({ state: PopoverState.Visible })
2151+
2152+
// Verify we actually clicked the button
2153+
expect(clickFn).toHaveBeenCalledTimes(1)
2154+
})
2155+
)
2156+
2157+
it(
2158+
'should not close the Popover when clicking on a non-focusable element inside a static Popover.Panel',
2159+
suppressConsoleLogs(async () => {
2160+
render(
2161+
<Popover>
2162+
<Popover.Button>Open</Popover.Button>
2163+
<Popover.Panel static>
2164+
<span>element</span>
2165+
</Popover.Panel>
2166+
</Popover>
2167+
)
2168+
2169+
// Open the popover
2170+
await click(getPopoverButton())
2171+
2172+
// The element should not close the popover
2173+
await click(getByText('element'))
2174+
2175+
// Verify it is still open
2176+
assertPopoverButton({ state: PopoverState.Visible })
2177+
})
2178+
)
2179+
2180+
it(
2181+
'should close the Popover when clicking outside of a static Popover.Panel',
2182+
suppressConsoleLogs(async () => {
2183+
render(
2184+
<Popover>
2185+
<Popover.Button>Open</Popover.Button>
2186+
<Popover.Panel static>
2187+
<span>element</span>
2188+
</Popover.Panel>
2189+
</Popover>
2190+
)
2191+
2192+
// Open the popover
2193+
await click(getPopoverButton())
2194+
2195+
// The element should close the popover
2196+
await click(document.body)
2197+
2198+
// Verify it is still open
2199+
assertPopoverButton({ state: PopoverState.InvisibleHidden })
2200+
})
2201+
)
21282202
})

packages/@headlessui-react/src/components/popover/popover.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,10 +619,12 @@ let Panel = forwardRefWithAs(function Panel<TTag extends ElementType = typeof DE
619619

620620
// Unlink on "unmount" children
621621
useEffect(() => {
622+
if (props.static) return
623+
622624
if (state.popoverState === PopoverStates.Closed && (props.unmount ?? true)) {
623625
dispatch({ type: ActionTypes.SetPanel, panel: null })
624626
}
625-
}, [state.popoverState, props.unmount, dispatch])
627+
}, [state.popoverState, props.unmount, props.static, dispatch])
626628

627629
// Move focus within panel
628630
useEffect(() => {

packages/@headlessui-vue/src/components/popover/popover.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2323,4 +2323,81 @@ describe('Mouse interactions', () => {
23232323
assertActiveElement(getPopoverButton())
23242324
})
23252325
)
2326+
2327+
it(
2328+
'should not close the Popover when clicking on a focusable element inside a static PopoverPanel',
2329+
suppressConsoleLogs(async () => {
2330+
let clickFn = jest.fn()
2331+
2332+
renderTemplate({
2333+
template: html`
2334+
<Popover>
2335+
<PopoverButton>Open</PopoverButton>
2336+
<PopoverPanel static>
2337+
<button @click="clickFn">btn</button>
2338+
</PopoverPanel>
2339+
</Popover>
2340+
`,
2341+
setup: () => ({ clickFn }),
2342+
})
2343+
2344+
// Open the popover
2345+
await click(getPopoverButton())
2346+
2347+
// The button should not close the popover
2348+
await click(getByText('btn'))
2349+
2350+
// Verify it is still open
2351+
assertPopoverButton({ state: PopoverState.Visible })
2352+
2353+
// Verify we actually clicked the button
2354+
expect(clickFn).toHaveBeenCalledTimes(1)
2355+
})
2356+
)
2357+
2358+
it(
2359+
'should not close the Popover when clicking on a non-focusable element inside a static PopoverPanel',
2360+
suppressConsoleLogs(async () => {
2361+
renderTemplate(html`
2362+
<Popover>
2363+
<PopoverButton>Open</PopoverButton>
2364+
<PopoverPanel static>
2365+
<span>element</span>
2366+
</PopoverPanel>
2367+
</Popover>
2368+
`)
2369+
2370+
// Open the popover
2371+
await click(getPopoverButton())
2372+
2373+
// The element should not close the popover
2374+
await click(getByText('element'))
2375+
2376+
// Verify it is still open
2377+
assertPopoverButton({ state: PopoverState.Visible })
2378+
})
2379+
)
2380+
2381+
it(
2382+
'should close the Popover when clicking outside of a static PopoverPanel',
2383+
suppressConsoleLogs(async () => {
2384+
renderTemplate(html`
2385+
<Popover>
2386+
<PopoverButton>Open</PopoverButton>
2387+
<PopoverPanel static>
2388+
<span>element</span>
2389+
</PopoverPanel>
2390+
</Popover>
2391+
`)
2392+
2393+
// Open the popover
2394+
await click(getPopoverButton())
2395+
2396+
// The element should close the popover
2397+
await click(document.body)
2398+
2399+
// Verify it is still open
2400+
assertPopoverButton({ state: PopoverState.InvisibleHidden })
2401+
})
2402+
)
23262403
})

0 commit comments

Comments
 (0)