Fix nested Popover components not opening (#2293)

* fix nested `Popover`s not working

* update changelog
This commit is contained in:
Robin Malfait
2023-02-17 23:05:14 +01:00
committed by GitHub
parent 10efaa921d
commit c7f6bc60ed
6 changed files with 135 additions and 1 deletions
+1
View File
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Ensure the main tree and parent `Dialog` components are marked as `inert` ([#2290](https://github.com/tailwindlabs/headlessui/pull/2290))
- Fix nested `Popover` components not opening ([#2293](https://github.com/tailwindlabs/headlessui/pull/2293))
## [1.7.11] - 2023-02-15
@@ -2481,3 +2481,64 @@ describe('Mouse interactions', () => {
})
)
})
describe('Nested popovers', () => {
it(
'should be possible to nest Popover components and control them individually',
suppressConsoleLogs(async () => {
render(
<Popover data-testid="popover-a">
<Popover.Button>Toggle A</Popover.Button>
<Popover.Panel>
<span>Contents A</span>
<Popover data-testid="popover-b">
<Popover.Button>Toggle B</Popover.Button>
<Popover.Panel>
<span>Contents B</span>
</Popover.Panel>
</Popover>
</Popover.Panel>
</Popover>
)
// Verify that Popover B is not there yet
expect(document.querySelector('[data-testid="popover-b"]')).toBeNull()
// Open Popover A
await click(getByText('Toggle A'))
// Ensure Popover A is visible
assertPopoverPanel(
{ state: PopoverState.Visible },
document.querySelector(
'[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
// Ensure Popover B is visible
assertPopoverPanel(
{ state: PopoverState.InvisibleUnmounted },
document.querySelector(
'[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
// Open Popover B
await click(getByText('Toggle B'))
// Ensure both popovers are open
assertPopoverPanel(
{ state: PopoverState.Visible },
document.querySelector(
'[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
assertPopoverPanel(
{ state: PopoverState.Visible },
document.querySelector(
'[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
})
)
})
@@ -393,7 +393,12 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
let closeOthers = groupContext?.closeOthers
let panelContext = usePopoverPanelContext()
let isWithinPanel = panelContext !== null
// A button inside a panel will just have "close" functionality, no "open" functionality. However,
// if a `Popover.Button` is rendered inside a `Popover` which in turn is rendered inside a
// `Popover.Panel` (aka nested popovers), then we need to make sure that the button is able to
// open the nested popover.
let isWithinPanel = panelContext === null ? false : panelContext === state.panelId
useEffect(() => {
if (isWithinPanel) return
+1
View File
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Ensure the main tree and parent `Dialog` components are marked as `inert` ([#2290](https://github.com/tailwindlabs/headlessui/pull/2290))
- Fix nested `Popover` components not opening ([#2293](https://github.com/tailwindlabs/headlessui/pull/2293))
## [1.7.10] - 2023-02-15
@@ -2574,3 +2574,64 @@ describe('Mouse interactions', () => {
})
)
})
describe('Nested popovers', () => {
it(
'should be possible to nest Popover components and control them individually',
suppressConsoleLogs(async () => {
renderTemplate(html`
<Popover data-testid="popover-a">
<PopoverButton>Toggle A</PopoverButton>
<PopoverPanel>
<span>Contents A</span>
<Popover data-testid="popover-b">
<PopoverButton>Toggle B</PopoverButton>
<PopoverPanel>
<span>Contents B</span>
</PopoverPanel>
</Popover>
</PopoverPanel>
</Popover>
`)
// Verify that Popover B is not there yet
expect(document.querySelector('[data-testid="popover-b"]')).toBeNull()
// Open Popover A
await click(getByText('Toggle A'))
// Ensure Popover A is visible
assertPopoverPanel(
{ state: PopoverState.Visible },
document.querySelector(
'[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
// Ensure Popover B is visible
assertPopoverPanel(
{ state: PopoverState.InvisibleUnmounted },
document.querySelector(
'[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
// Open Popover B
await click(getByText('Toggle B'))
// Ensure both popovers are open
assertPopoverPanel(
{ state: PopoverState.Visible },
document.querySelector(
'[data-testid="popover-a"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
assertPopoverPanel(
{ state: PopoverState.Visible },
document.querySelector(
'[data-testid="popover-b"] [id^="headlessui-popover-panel-"]'
) as HTMLElement
)
})
)
})
@@ -288,6 +288,11 @@ export let PopoverButton = defineComponent({
let closeOthers = groupContext?.closeOthers
let panelContext = usePopoverPanelContext()
// A button inside a panel will just have "close" functionality, no "open" functionality.
// However, if a `Popover.Button` is rendered inside a `Popover` which in turn is rendered
// inside a `Popover.Panel` (aka nested popovers), then we need to make sure that the button is
// able to open the nested popover.
let isWithinPanel = computed(() =>
panelContext === null ? false : panelContext.value === api.panelId.value
)