[MM-55278]: Fixed autofocus on submenu's first element (#29547)

This commit is contained in:
ayush-chauhan233 2025-02-11 11:34:42 +05:30 committed by GitHub
parent 169274b3aa
commit b2b956c043
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 61 additions and 54 deletions

View File

@ -129,12 +129,10 @@ test('Post actions tab support', async ({pw, axe}) => {
// # Press arrow right
await channelsPage.postDotMenu.remindMenuItem.press('ArrowRight');
// * Reminder menu should be visible and have focused
channelsPage.postReminderMenu.toBeVisible();
await expect(channelsPage.postReminderMenu.container).toBeFocused();
// * Reminder menu should be visible
expect(channelsPage.postReminderMenu.container).toBeVisible();
// * Should move focus to 30 mins after arrow down
await channelsPage.postReminderMenu.container.press('ArrowDown');
// * Should have focus on 30 mins after submenu opens
expect(await channelsPage.postReminderMenu.thirtyMinsMenuItem).toBeFocused();
// * Should move focus to 1 hour after arrow down

View File

@ -159,13 +159,16 @@ function PostReminderSubmenu(props: Props) {
leadingElement={<ClockOutlineIcon size={18}/>}
trailingElements={<span className={'dot-menu__item-trailing-icon'}><ChevronRightIcon size={16}/></span>}
menuId={`remind_post_${props.post.id}-menu`}
>
subMenuHeader={
<h5 className={'dot-menu__post-reminder-menu-header'}>
{formatMessage(
{id: 'post_info.post_reminder.sub_menu.header',
defaultMessage: 'Set a reminder for:'},
{
id: 'post_info.post_reminder.sub_menu.header',
defaultMessage: 'Set a reminder for:',
},
)}
</h5>
</h5>}
>
{postReminderSubMenuItems}
</Menu.SubMenu>
);

View File

@ -7,12 +7,13 @@
min-width: 114px;
max-width: 496px;
max-height: 80vh;
padding: 4px 0;
background-color: var(--center-channel-bg);
box-shadow: var(--elevation-4);
box-shadow: var(--elevation-4), 0 0 0 1px rgba(var(--center-channel-color-rgb), 0.12) inset;
}
&.AsSubMenu {
& .MuiPaper-root {
box-shadow: var(--elevation-5);
box-shadow: var(--elevation-5), 0 0 0 1px rgba(var(--center-channel-color-rgb), 0.12) inset;
}
}
}

View File

@ -140,7 +140,7 @@ describe('menu click handlers', () => {
expect(screen.getByText('Open modal from submenu')).toBeInTheDocument();
// Press the down arrow once to focus first submenu item and then twice more to select the one we want
userEvent.keyboard('{arrowdown}{arrowdown}{arrowdown}');
userEvent.keyboard('{arrowdown}{arrowdown}');
expect(screen.getByText('Open modal from submenu').closest('li')).toHaveFocus();

View File

@ -309,6 +309,7 @@ export const MenuItemStyled = styled(MuiMenuItem, {
flexWrap: 'nowrap',
justifyContent: 'flex-end',
color: isRegular ? 'rgba(var(--center-channel-color-rgb), 0.75)' : 'var(--error-text)',
marginInlineStart: '24px',
gap: '4px',
fontSize: '12px',
lineHeight: '16px',

View File

@ -1,8 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import MuiMenu from '@mui/material/Menu';
import MuiMenuList from '@mui/material/MenuList';
import MuiPopover from '@mui/material/Popover';
import type {PopoverOrigin} from '@mui/material/Popover';
import React, {
useState,
@ -33,6 +33,8 @@ import {SubMenuContext, useMenuContextValue} from './menu_context';
import {MenuItem} from './menu_item';
import type {Props as MenuItemProps} from './menu_item';
import './menu.scss';
interface Props {
id: MenuItemProps['id'];
leadingElement?: MenuItemProps['leadingElement'];
@ -47,6 +49,7 @@ interface Props {
menuAriaDescribedBy?: string;
forceOpenOnLeft?: boolean; // Most of the times this is not needed, since submenu position is calculated and placed
subMenuHeader?: ReactNode;
children: ReactNode;
}
@ -63,6 +66,7 @@ export function SubMenu(props: Props) {
menuAriaDescribedBy,
forceOpenOnLeft,
children,
subMenuHeader,
...rest
} = props;
@ -136,6 +140,7 @@ export function SubMenu(props: Props) {
menuId,
menuAriaLabel,
children,
subMenuHeader,
},
}));
}
@ -166,35 +171,30 @@ export function SubMenu(props: Props) {
onMouseLeave={handleMouseLeave}
onKeyDown={handleKeyDown}
>
<MuiMenu
<SubMenuContext.Provider value={providerValue}>
<MuiPopover
anchorEl={anchorElement}
open={isSubMenuOpen}
anchorOrigin={originOfAnchorAndTransform.anchorOrigin}
transformOrigin={originOfAnchorAndTransform.transformOrigin}
sx={{pointerEvents: 'none'}}
className='menu_menuStyled AsSubMenu'
>
{/* This component is needed here to re enable pointer events for the submenu items which we had to disable above as */}
{/* pointer turns to default as soon as it leaves the parent menu */}
{/* Notice we dont use the below component in menu.tsx */}
{subMenuHeader}
<MuiMenuList
id={menuId}
component='ul'
aria-label={menuAriaLabel}
aria-describedby={menuAriaDescribedBy}
className={A11yClassNames.POPUP}
onKeyDown={handleSubMenuKeyDown}
autoFocusItem={isSubMenuOpen}
sx={{
pointerEvents: 'auto', // reset pointer events to default from here on
paddingTop: 0,
paddingBottom: 0,
py: 0,
}}
>
<SubMenuContext.Provider value={providerValue}>
{children}
</SubMenuContext.Provider>
</MuiMenuList>
</MuiMenu>
</MuiPopover>
</SubMenuContext.Provider>
</MenuItem>
);
}
@ -203,6 +203,7 @@ interface SubMenuModalProps {
menuId: Props['menuId'];
menuAriaLabel?: Props['menuAriaLabel'];
children: Props['children'];
subMenuHeader?: ReactNode;
}
function SubMenuModal(props: SubMenuModalProps) {
@ -224,9 +225,11 @@ function SubMenuModal(props: SubMenuModalProps) {
className='menuModal'
>
<MuiMenuList
component={'div'}
aria-hidden={true}
onClick={handleModalClose}
>
{props.subMenuHeader}
{props.children}
</MuiMenuList>
</GenericModal>

View File

@ -4,7 +4,7 @@ exports[`UserAccountNameMenuItem should not break if no props are passed 1`] = `
<div>
<li
aria-haspopup="true"
class="MuiButtonBase-root-JvZdr dKFJFs MuiButtonBase-root MuiMenuItem-root MuiMenuItem-gutters MuiMenuItem-root-dXqYNm kIRdVO MuiMenuItem-root MuiMenuItem-gutters sc-gswNZR cUFZeQ userAccountMenu_nameMenuItem"
class="MuiButtonBase-root-JvZdr dKFJFs MuiButtonBase-root MuiMenuItem-root MuiMenuItem-gutters MuiMenuItem-root-dXqYNm kIRdVO MuiMenuItem-root MuiMenuItem-gutters sc-gswNZR jjvBbU userAccountMenu_nameMenuItem"
role="menuitem"
tabindex="-1"
>

View File

@ -196,10 +196,9 @@ export default function UserAccountDndMenuItem(props: Props) {
</span>
</>
}
role='menuitemradio' // Prevents menu item from closing, not a recommended solution
aria-checked={props.isStatusDnd}
trailingElements={trailingElement}
>
subMenuHeader={
<h5
id='userAccountMenu_dndSubMenuTitle'
className='userAccountMenu_dndMenuItem_subMenuTitle'
@ -210,6 +209,8 @@ export default function UserAccountDndMenuItem(props: Props) {
defaultMessage: 'Clear after:',
})}
</h5>
}
>
<Menu.Item
id={DND_SUB_MENU_ITEMS_IDS.DO_NOT_CLEAR}
labels={