MM-55280: When closing/dismissing the find channels modal via keyboard, set focus on originating button (#26641)

* Restore focus to sidebar button when channel navigator closes

* Add new onHide function to use on exit of modal

* Move import back to original spot

* Remove duplicate blank line

* Fix spacing and semicolon

* Address PR feedback

* Add test id for targeting in unit test

* Add unit test for accessibility

* Fix linting

* Fix imports
This commit is contained in:
Karim Aljandali 2024-04-12 07:15:30 -04:00 committed by GitHub
parent bb26e8685f
commit c76a58b4b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 4 deletions

View File

@ -5,7 +5,9 @@ import {shallow} from 'enzyme';
import React from 'react';
import QuickSwitchModal from 'components/quick_switch_modal/quick_switch_modal';
import ChannelNavigator from 'components/sidebar/channel_navigator/channel_navigator';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import Constants from 'utils/constants';
describe('components/QuickSwitchModal', () => {
@ -144,4 +146,28 @@ describe('components/QuickSwitchModal', () => {
});
});
});
describe('accessibility', () => {
it('should restore focus to button', () => {
const channelNavigatorProps = {
showUnreadsCategory: false,
isQuickSwitcherOpen: false,
actions: {
openModal: jest.fn(),
closeModal: jest.fn(),
},
};
renderWithContext(
<>
<ChannelNavigator {...channelNavigatorProps}/>
<QuickSwitchModal {...baseProps}/>
</>,
);
userEvent.click(screen.getByTestId('SidebarChannelNavigatorButton'));
userEvent.keyboard('{escape}');
expect(screen.getByTestId('SidebarChannelNavigatorButton')).toHaveFocus();
});
});
});

View File

@ -96,7 +96,7 @@ export default class QuickSwitchModal extends React.PureComponent<Props, State>
this.focusTextbox();
};
private onHide = (): void => {
private hideOnSelect = (): void => {
this.focusPostTextbox();
this.setState({
text: '',
@ -115,6 +115,16 @@ export default class QuickSwitchModal extends React.PureComponent<Props, State>
}
};
private hideOnCancel = () => {
this.props.onExited?.();
setTimeout(() => {
const modalButton = document.querySelector('.SidebarChannelNavigator_jumpToButton') as HTMLElement;
if (modalButton) {
modalButton.focus();
}
});
};
private onChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({text: e.target.value, shouldShowLoadingSpinner: true});
};
@ -137,12 +147,12 @@ export default class QuickSwitchModal extends React.PureComponent<Props, State>
}
switchToChannel(selectedChannel).then((result: ActionResult) => {
if ('data' in result) {
this.onHide();
this.hideOnSelect();
}
});
} else {
getHistory().push('/' + selected.name);
this.onHide();
this.hideOnSelect();
}
};
@ -188,7 +198,7 @@ export default class QuickSwitchModal extends React.PureComponent<Props, State>
<Modal
dialogClassName='a11y__modal channel-switcher'
show={true}
onHide={this.onHide}
onHide={this.hideOnCancel}
enforceFocus={false}
restoreFocus={false}
role='dialog'

View File

@ -93,6 +93,8 @@ export default class ChannelNavigator extends React.PureComponent<Props> {
className={'SidebarChannelNavigator_jumpToButton'}
onClick={this.openQuickSwitcher}
aria-label={Utils.localizeMessage('sidebar_left.channel_navigator.channelSwitcherLabel', 'Channel Switcher')}
aria-haspopup='dialog'
data-testid='SidebarChannelNavigatorButton'
>
<i className='icon icon-magnify'/>
<FormattedMessage