Skip to content

Commit 957fddf

Browse files
authored
[Select][Menu] Avoid :focus-visible style appearing (#1846)
1 parent f79d080 commit 957fddf

File tree

14 files changed

+198
-43
lines changed

14 files changed

+198
-43
lines changed

packages/react/src/dialog/root/useDialogRoot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
import * as React from 'react';
33
import {
44
FloatingRootContext,
5-
useClick,
65
useDismiss,
76
useFloatingRootContext,
87
useInteractions,
98
useRole,
109
type OpenChangeReason as FloatingUIOpenChangeReason,
1110
} from '@floating-ui/react';
1211
import { getTarget } from '@floating-ui/react/utils';
12+
import { useClick } from '../../utils/floating-ui/useClick';
1313
import { useControlled } from '../../utils/useControlled';
1414
import { useEventCallback } from '../../utils/useEventCallback';
1515
import { useScrollLock } from '../../utils/useScrollLock';

packages/react/src/menu/backdrop/MenuBackdrop.test.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { Menu } from '@base-ui-components/react/menu';
33
import { createRenderer, describeConformance } from '#test-utils';
4-
import { screen } from '@mui/internal-test-utils';
4+
import { screen, waitFor } from '@mui/internal-test-utils';
55

66
describe('<Menu.Backdrop />', () => {
77
const { render } = createRenderer();
@@ -46,6 +46,8 @@ describe('<Menu.Backdrop />', () => {
4646

4747
await user.click(screen.getByText('Open'));
4848

49-
expect(screen.getByTestId('backdrop').style.pointerEvents).not.to.equal('none');
49+
await waitFor(() => {
50+
expect(screen.getByTestId('backdrop').style.pointerEvents).not.to.equal('none');
51+
});
5052
});
5153
});

packages/react/src/menu/positioner/MenuPositioner.test.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { expect } from 'chai';
33
import userEvent from '@testing-library/user-event';
4-
import { describeSkipIf, flushMicrotasks, screen } from '@mui/internal-test-utils';
4+
import { describeSkipIf, flushMicrotasks, screen, waitFor } from '@mui/internal-test-utils';
55
import { Menu } from '@base-ui-components/react/menu';
66
import { describeConformance, createRenderer, isJSDOM } from '#test-utils';
77

@@ -322,12 +322,18 @@ describe('<Menu.Positioner />', () => {
322322

323323
await user.click(trigger);
324324
await flushMicrotasks();
325-
expect(queryByRole('menu', { hidden: false })).not.to.equal(null);
325+
await waitFor(() => {
326+
expect(queryByRole('menu', { hidden: false })).not.to.equal(null);
327+
});
326328
expect(queryByRole('menu', { hidden: false })).not.toBeInaccessible();
327329

328330
await user.click(trigger);
329-
expect(queryByRole('menu', { hidden: true })).not.to.equal(null);
330-
expect(queryByRole('menu', { hidden: true })).toBeInaccessible();
331+
await waitFor(() => {
332+
expect(queryByRole('menu', { hidden: true })).not.to.equal(null);
333+
});
334+
await waitFor(() => {
335+
expect(queryByRole('menu', { hidden: true })).toBeInaccessible();
336+
});
331337
});
332338

333339
it('when keepMounted=false, should unmount the content when closed', async () => {
@@ -351,11 +357,15 @@ describe('<Menu.Positioner />', () => {
351357

352358
await user.click(trigger);
353359
await flushMicrotasks();
354-
expect(queryByRole('menu', { hidden: false })).not.to.equal(null);
360+
await waitFor(() => {
361+
expect(queryByRole('menu', { hidden: false })).not.to.equal(null);
362+
});
355363
expect(queryByRole('menu', { hidden: false })).not.toBeInaccessible();
356364

357365
await user.click(trigger);
358-
expect(queryByRole('menu', { hidden: true })).to.equal(null);
366+
await waitFor(() => {
367+
expect(queryByRole('menu', { hidden: true })).to.equal(null);
368+
});
359369
});
360370
});
361371

packages/react/src/menu/root/MenuRoot.test.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -488,11 +488,11 @@ describe('<Menu.Root />', () => {
488488
});
489489

490490
it('opens submenu on click when openOnHover is false', async () => {
491-
const { getByRole, queryByTestId, getByTestId } = await render(
491+
const { getByRole, queryByTestId, findByTestId } = await render(
492492
<Menu.Root>
493493
<Menu.Trigger>Open Main</Menu.Trigger>
494494
<Menu.Portal>
495-
<Menu.Positioner>
495+
<Menu.Positioner data-testid="menu">
496496
<Menu.Popup>
497497
<Menu.Item>Item 1</Menu.Item>
498498
<Menu.Root openOnHover={false}>
@@ -514,16 +514,14 @@ describe('<Menu.Root />', () => {
514514
const mainTrigger = getByRole('button', { name: 'Open Main' });
515515
await user.click(mainTrigger);
516516

517+
const submenu = await findByTestId('menu');
517518
expect(queryByTestId('submenu')).to.equal(null);
518519

519-
const submenuTrigger = getByTestId('submenu-trigger');
520+
const submenuTrigger = await findByTestId('submenu-trigger');
520521
await user.click(submenuTrigger);
521522

522-
await waitFor(() => {
523-
expect(getByTestId('submenu')).not.to.equal(null);
524-
});
525-
526-
expect(getByTestId('submenu-item')).to.have.text('Submenu Item');
523+
expect(submenu).not.to.equal(null);
524+
expect(await findByTestId('submenu-item')).to.have.text('Submenu Item');
527525
});
528526
});
529527

@@ -605,7 +603,7 @@ describe('<Menu.Root />', () => {
605603
});
606604

607605
it('focuses the trigger after the menu is closed', async () => {
608-
const { getByRole } = await render(
606+
const { getByRole, findByRole } = await render(
609607
<div>
610608
<input type="text" />
611609
<Menu.Root>
@@ -625,7 +623,7 @@ describe('<Menu.Root />', () => {
625623
const button = getByRole('button', { name: 'Toggle' });
626624
await user.click(button);
627625

628-
const menuItem = getByRole('menuitem');
626+
const menuItem = await findByRole('menuitem');
629627
await user.click(menuItem);
630628

631629
expect(button).toHaveFocus();
@@ -637,7 +635,7 @@ describe('<Menu.Root />', () => {
637635
skip();
638636
}
639637

640-
const { getByRole } = await render(
638+
const { getByRole, findByRole } = await render(
641639
<div>
642640
<input type="text" />
643641
<Menu.Root>
@@ -657,7 +655,7 @@ describe('<Menu.Root />', () => {
657655
const button = getByRole('button', { name: 'Toggle' });
658656
await user.click(button);
659657

660-
const menuItem = getByRole('menuitem');
658+
const menuItem = await findByRole('menuitem');
661659
await user.click(menuItem);
662660

663661
await waitFor(() => {
@@ -870,7 +868,12 @@ describe('<Menu.Root />', () => {
870868
expect(screen.queryByRole('menu')).not.to.equal(null);
871869
});
872870

873-
await act(async () => actionsRef.current.unmount());
871+
await act(async () => {
872+
await new Promise((resolve) => {
873+
requestAnimationFrame(resolve);
874+
});
875+
actionsRef.current.unmount();
876+
});
874877

875878
await waitFor(() => {
876879
expect(screen.queryByRole('menu')).to.equal(null);

packages/react/src/menu/root/useMenuRoot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import * as React from 'react';
33
import * as ReactDOM from 'react-dom';
44
import {
55
safePolygon,
6-
useClick,
76
useDismiss,
87
useFloatingRootContext,
98
useHover,
@@ -13,6 +12,7 @@ import {
1312
useTypeahead,
1413
type FloatingRootContext,
1514
} from '@floating-ui/react';
15+
import { useClick } from '../../utils/floating-ui/useClick';
1616
import { GenericHTMLProps } from '../../utils/types';
1717
import { useTransitionStatus, type TransitionStatus } from '../../utils/useTransitionStatus';
1818
import { useEventCallback } from '../../utils/useEventCallback';

packages/react/src/menu/trigger/MenuTrigger.test.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ describe('<Menu.Trigger />', () => {
4949
});
5050

5151
it('toggles the menu state when clicked', async () => {
52-
const { getByRole, queryByRole } = await render(
52+
const { getByRole, findByRole } = await render(
5353
<Menu.Root>
5454
<Menu.Trigger>Open</Menu.Trigger>
5555
<Menu.Portal>
@@ -63,9 +63,8 @@ describe('<Menu.Trigger />', () => {
6363
const button = getByRole('button', { name: 'Open' });
6464
await user.click(button);
6565

66-
const menuPopup = queryByRole('menu', { hidden: false });
66+
const menuPopup = await findByRole('menu', { hidden: false });
6767
expect(menuPopup).not.to.equal(null);
68-
6968
expect(menuPopup).to.have.attribute('data-open', '');
7069
});
7170

packages/react/src/popover/backdrop/PopoverBackdrop.test.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { Popover } from '@base-ui-components/react/popover';
33
import { createRenderer, describeConformance } from '#test-utils';
4-
import { screen } from '@mui/internal-test-utils';
4+
import { screen, waitFor } from '@mui/internal-test-utils';
55

66
describe('<Popover.Backdrop />', () => {
77
const { render } = createRenderer();
@@ -46,6 +46,8 @@ describe('<Popover.Backdrop />', () => {
4646

4747
await user.click(screen.getByText('Open'));
4848

49-
expect(screen.getByTestId('backdrop').style.pointerEvents).not.to.equal('none');
49+
await waitFor(() => {
50+
expect(screen.getByTestId('backdrop').style.pointerEvents).not.to.equal('none');
51+
});
5052
});
5153
});

packages/react/src/popover/root/usePopoverRoot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import * as React from 'react';
22
import * as ReactDOM from 'react-dom';
33
import {
44
safePolygon,
5-
useClick,
65
useDismiss,
76
useFloatingRootContext,
87
useHover,
98
useInteractions,
109
useRole,
1110
type FloatingRootContext,
1211
} from '@floating-ui/react';
12+
import { useClick } from '../../utils/floating-ui/useClick';
1313
import { useControlled } from '../../utils/useControlled';
1414
import { useEventCallback } from '../../utils/useEventCallback';
1515
import { useTransitionStatus } from '../../utils/useTransitionStatus';

packages/react/src/preview-card/root/usePreviewCardRoot.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
import { useControlled } from '../../utils/useControlled';
1212
import { useTransitionStatus } from '../../utils/useTransitionStatus';
1313
import { useEventCallback } from '../../utils/useEventCallback';
14-
import { useFocusExtended } from '../utils/useFocusExtended';
1514
import { OPEN_DELAY, CLOSE_DELAY } from '../utils/constants';
1615
import type { GenericHTMLProps } from '../../utils/types';
1716
import type { TransitionStatus } from '../../utils/useTransitionStatus';
@@ -20,6 +19,7 @@ import {
2019
type OpenChangeReason,
2120
} from '../../utils/translateOpenChangeReason';
2221
import { useOpenChangeComplete } from '../../utils/useOpenChangeComplete';
22+
import { useFocusWithDelay } from '../../utils/floating-ui/useFocusWithDelay';
2323

2424
export function usePreviewCardRoot(
2525
params: usePreviewCardRoot.Parameters,
@@ -119,7 +119,7 @@ export function usePreviewCardRoot(
119119
close: closeDelayWithDefault,
120120
},
121121
});
122-
const focus = useFocusExtended(context);
122+
const focus = useFocusWithDelay(context, { delay: OPEN_DELAY });
123123
const dismiss = useDismiss(context);
124124

125125
const { getReferenceProps: getRootTriggerProps, getFloatingProps: getRootPopupProps } =

packages/react/src/select/root/SelectRoot.test.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,9 @@ describe('<Select.Root />', () => {
262262
const trigger = screen.getByTestId('trigger');
263263

264264
await user.click(trigger);
265-
expect(handleOpenChange.callCount).to.equal(1);
265+
await waitFor(() => {
266+
expect(handleOpenChange.callCount).to.equal(1);
267+
});
266268
expect(handleOpenChange.args[0][0]).to.equal(true);
267269
});
268270
});
@@ -396,7 +398,12 @@ describe('<Select.Root />', () => {
396398
expect(screen.queryByRole('listbox')).not.to.equal(null);
397399
});
398400

399-
await act(async () => actionsRef.current.unmount());
401+
await act(async () => {
402+
await new Promise((resolve) => {
403+
requestAnimationFrame(resolve);
404+
});
405+
actionsRef.current.unmount();
406+
});
400407

401408
await waitFor(() => {
402409
expect(screen.queryByRole('listbox')).to.equal(null);
@@ -670,7 +677,9 @@ describe('<Select.Root />', () => {
670677
expect(trigger).toHaveFocus();
671678

672679
await user.click(trigger);
673-
expect(handleOpenChange.callCount).to.equal(1);
680+
await waitFor(() => {
681+
expect(handleOpenChange.callCount).to.equal(1);
682+
});
674683
});
675684
});
676685

packages/react/src/select/root/useSelectRoot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import * as React from 'react';
22
import {
3-
useClick,
43
useDismiss,
54
useFloatingRootContext,
65
useInteractions,
76
useListNavigation,
87
useRole,
98
useTypeahead,
109
} from '@floating-ui/react';
10+
import { useClick } from '../../utils/floating-ui/useClick';
1111
import { useFieldControlValidation } from '../../field/control/useFieldControlValidation';
1212
import { useFieldRootContext } from '../../field/root/FieldRootContext';
1313
import { useBaseUiId } from '../../utils/useBaseUiId';

0 commit comments

Comments
 (0)