From 16911e30bad78b92fa9613de37ef363ee67fb199 Mon Sep 17 00:00:00 2001 From: atomiks Date: Fri, 22 Nov 2024 20:57:46 +1100 Subject: [PATCH 1/4] [Popover] Disable focus management when opened via hover --- packages/react/src/Popover/Popup/PopoverPopup.tsx | 3 ++- packages/react/src/Popover/Root/usePopoverRoot.ts | 12 +++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/react/src/Popover/Popup/PopoverPopup.tsx b/packages/react/src/Popover/Popup/PopoverPopup.tsx index dd3281fca..64f6679a9 100644 --- a/packages/react/src/Popover/Popup/PopoverPopup.tsx +++ b/packages/react/src/Popover/Popup/PopoverPopup.tsx @@ -54,6 +54,7 @@ const PopoverPopup = React.forwardRef(function PopoverPopup( descriptionId, popupRef, mounted, + openReason, } = usePopoverRootContext(); const positioner = usePopoverPositionerContext(); @@ -91,7 +92,7 @@ const PopoverPopup = React.forwardRef(function PopoverPopup( diff --git a/packages/react/src/Popover/Root/usePopoverRoot.ts b/packages/react/src/Popover/Root/usePopoverRoot.ts index bb69abb9f..e93110f2f 100644 --- a/packages/react/src/Popover/Root/usePopoverRoot.ts +++ b/packages/react/src/Popover/Root/usePopoverRoot.ts @@ -31,7 +31,6 @@ export function usePopoverRoot(params: usePopoverRoot.Parameters): usePopoverRoo open: externalOpen, onOpenChange: onOpenChangeProp = () => {}, defaultOpen = false, - keepMounted = false, delay, closeDelay, openOnHover = false, @@ -69,22 +68,21 @@ export function usePopoverRoot(params: usePopoverRoot.Parameters): usePopoverRoo (nextOpen: boolean, event?: Event, reason?: OpenChangeReason) => { onOpenChange(nextOpen, event, reason); setOpenUnwrapped(nextOpen); - if (!keepMounted && !nextOpen) { + + if (!nextOpen) { if (animated) { runOnceAnimationsFinish(() => { if (!openRef.current) { setMounted(false); + setOpenReason(null); } }); } else { setMounted(false); + setOpenReason(null); } - } - - if (nextOpen) { - setOpenReason(reason ?? null); } else { - setOpenReason(null); + setOpenReason(reason ?? null); } }, ); From b01c0430f528754fd0b62afbe68e9ef6c6fe883b Mon Sep 17 00:00:00 2001 From: atomiks Date: Fri, 22 Nov 2024 20:58:56 +1100 Subject: [PATCH 2/4] Test --- .../src/Popover/Root/PopoverRoot.test.tsx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/react/src/Popover/Root/PopoverRoot.test.tsx b/packages/react/src/Popover/Root/PopoverRoot.test.tsx index 0f47eff5f..534520678 100644 --- a/packages/react/src/Popover/Root/PopoverRoot.test.tsx +++ b/packages/react/src/Popover/Root/PopoverRoot.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Popover } from '@base-ui-components/react/Popover'; -import { fireEvent, flushMicrotasks, screen, waitFor } from '@mui/internal-test-utils'; +import { act, fireEvent, flushMicrotasks, screen, waitFor } from '@mui/internal-test-utils'; import userEvent from '@testing-library/user-event'; import { expect } from 'chai'; import { spy } from 'sinon'; @@ -333,4 +333,27 @@ describe('', () => { { timeout: 1500 }, ); }); + + it('does not move focus to the popover when opened with hover', async () => { + await render( + + Toggle + + + Close + + + , + ); + + const toggle = screen.getByRole('button', { name: 'Toggle' }); + + act(() => toggle.focus()); + + await user.hover(toggle); + await flushMicrotasks(); + + expect(screen.queryByRole('button', { name: 'Close' })).not.to.equal(null); + expect(screen.queryByRole('button', { name: 'Close' })).not.to.toHaveFocus(); + }); }); From a67bc6c460a526750c759db1025a50c8ac3842bb Mon Sep 17 00:00:00 2001 From: atomiks Date: Fri, 22 Nov 2024 20:59:43 +1100 Subject: [PATCH 3/4] Refactor test --- packages/react/src/Popover/Root/PopoverRoot.test.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react/src/Popover/Root/PopoverRoot.test.tsx b/packages/react/src/Popover/Root/PopoverRoot.test.tsx index 534520678..06f3a1fc5 100644 --- a/packages/react/src/Popover/Root/PopoverRoot.test.tsx +++ b/packages/react/src/Popover/Root/PopoverRoot.test.tsx @@ -353,7 +353,9 @@ describe('', () => { await user.hover(toggle); await flushMicrotasks(); - expect(screen.queryByRole('button', { name: 'Close' })).not.to.equal(null); - expect(screen.queryByRole('button', { name: 'Close' })).not.to.toHaveFocus(); + const close = screen.getByRole('button', { name: 'Close' }); + + expect(close).not.to.equal(null); + expect(close).not.to.toHaveFocus(); }); }); From 720db6076fe93f1f33c45ca493c27d8fa04f4bcb Mon Sep 17 00:00:00 2001 From: atomiks Date: Fri, 22 Nov 2024 21:05:15 +1100 Subject: [PATCH 4/4] Remove keepMounted prop --- packages/react/src/Popover/Root/usePopoverRoot.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/react/src/Popover/Root/usePopoverRoot.ts b/packages/react/src/Popover/Root/usePopoverRoot.ts index e93110f2f..157863b19 100644 --- a/packages/react/src/Popover/Root/usePopoverRoot.ts +++ b/packages/react/src/Popover/Root/usePopoverRoot.ts @@ -207,11 +207,6 @@ export namespace usePopoverRoot { * @default 0 */ closeDelay?: number; - /** - * Whether the popover popup element stays mounted in the DOM when closed. - * @default false - */ - keepMounted?: boolean; /** * Whether the popover can animate, adding animation-related attributes and allowing for exit * animations to play. Useful to disable in tests to remove async behavior.