From fd9a2d20b2ad34fbee5e2f4836b199857ab8ee9b Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 8 Oct 2021 15:53:24 +0200 Subject: [PATCH] Ensure interactability with Popover.Panel contents in static mode (#857) * ensure interactability with Popover.Panel contents in static mode * update changelog --- CHANGELOG.md | 1 + .../src/components/popover/popover.test.tsx | 76 +++++++++++++++++- .../src/components/popover/popover.tsx | 4 +- .../src/components/popover/popover.test.ts | 77 +++++++++++++++++++ 4 files changed, 156 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12f58dfbe2..03ffda3159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Stop the event from propagating in the `Popover` component ([#798](https://github.com/tailwindlabs/headlessui/pull/798)) - Allow to click on elements inside a `Dialog.Overlay` ([#816](https://github.com/tailwindlabs/headlessui/pull/816)) +- Ensure interactability with `Popover.Panel` contents when using the `static` prop ([#857](https://github.com/tailwindlabs/headlessui/pull/857)) ## [Unreleased - Vue] diff --git a/packages/@headlessui-react/src/components/popover/popover.test.tsx b/packages/@headlessui-react/src/components/popover/popover.test.tsx index 3df9c9b630..ef1b208e43 100644 --- a/packages/@headlessui-react/src/components/popover/popover.test.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.test.tsx @@ -1,5 +1,5 @@ import React, { createElement, useEffect, useRef } from 'react' -import { render } from '@testing-library/react' +import { render, screen } from '@testing-library/react' import { Popover } from './popover' import { suppressConsoleLogs } from '../../test-utils/suppress-console-logs' @@ -2125,4 +2125,78 @@ describe('Mouse interactions', () => { assertActiveElement(getPopoverButton()) }) ) + + it( + 'should not close the Popover when clicking on a focusable element inside a static Popover.Panel', + suppressConsoleLogs(async () => { + let clickFn = jest.fn() + + render( + + Open + + + + + ) + + // Open the popover + await click(getPopoverButton()) + + // The button should not close the popover + await click(getByText('btn')) + + // Verify it is still open + assertPopoverButton({ state: PopoverState.Visible }) + + // Verify we actually clicked the button + expect(clickFn).toHaveBeenCalledTimes(1) + }) + ) + + it( + 'should not close the Popover when clicking on a non-focusable element inside a static Popover.Panel', + suppressConsoleLogs(async () => { + render( + + Open + + element + + + ) + + // Open the popover + await click(getPopoverButton()) + + // The element should not close the popover + await click(getByText('element')) + + // Verify it is still open + assertPopoverButton({ state: PopoverState.Visible }) + }) + ) + + it( + 'should close the Popover when clicking outside of a static Popover.Panel', + suppressConsoleLogs(async () => { + render( + + Open + + element + + + ) + + // Open the popover + await click(getPopoverButton()) + + // The element should close the popover + await click(document.body) + + // Verify it is still open + assertPopoverButton({ state: PopoverState.InvisibleHidden }) + }) + ) }) diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx index 9ddbf11813..f0e7264543 100644 --- a/packages/@headlessui-react/src/components/popover/popover.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.tsx @@ -619,10 +619,12 @@ let Panel = forwardRefWithAs(function Panel { + if (props.static) return + if (state.popoverState === PopoverStates.Closed && (props.unmount ?? true)) { dispatch({ type: ActionTypes.SetPanel, panel: null }) } - }, [state.popoverState, props.unmount, dispatch]) + }, [state.popoverState, props.unmount, props.static, dispatch]) // Move focus within panel useEffect(() => { diff --git a/packages/@headlessui-vue/src/components/popover/popover.test.ts b/packages/@headlessui-vue/src/components/popover/popover.test.ts index bc872cc825..7ba73f697d 100644 --- a/packages/@headlessui-vue/src/components/popover/popover.test.ts +++ b/packages/@headlessui-vue/src/components/popover/popover.test.ts @@ -2323,4 +2323,81 @@ describe('Mouse interactions', () => { assertActiveElement(getPopoverButton()) }) ) + + it( + 'should not close the Popover when clicking on a focusable element inside a static PopoverPanel', + suppressConsoleLogs(async () => { + let clickFn = jest.fn() + + renderTemplate({ + template: html` + + Open + + + + + `, + setup: () => ({ clickFn }), + }) + + // Open the popover + await click(getPopoverButton()) + + // The button should not close the popover + await click(getByText('btn')) + + // Verify it is still open + assertPopoverButton({ state: PopoverState.Visible }) + + // Verify we actually clicked the button + expect(clickFn).toHaveBeenCalledTimes(1) + }) + ) + + it( + 'should not close the Popover when clicking on a non-focusable element inside a static PopoverPanel', + suppressConsoleLogs(async () => { + renderTemplate(html` + + Open + + element + + + `) + + // Open the popover + await click(getPopoverButton()) + + // The element should not close the popover + await click(getByText('element')) + + // Verify it is still open + assertPopoverButton({ state: PopoverState.Visible }) + }) + ) + + it( + 'should close the Popover when clicking outside of a static PopoverPanel', + suppressConsoleLogs(async () => { + renderTemplate(html` + + Open + + element + + + `) + + // Open the popover + await click(getPopoverButton()) + + // The element should close the popover + await click(document.body) + + // Verify it is still open + assertPopoverButton({ state: PopoverState.InvisibleHidden }) + }) + ) })