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 React from 'react';
import QuickSwitchModal from 'components/quick_switch_modal/quick_switch_modal'; 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'; import Constants from 'utils/constants';
describe('components/QuickSwitchModal', () => { 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(); this.focusTextbox();
}; };
private onHide = (): void => { private hideOnSelect = (): void => {
this.focusPostTextbox(); this.focusPostTextbox();
this.setState({ this.setState({
text: '', 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 => { private onChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({text: e.target.value, shouldShowLoadingSpinner: true}); 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) => { switchToChannel(selectedChannel).then((result: ActionResult) => {
if ('data' in result) { if ('data' in result) {
this.onHide(); this.hideOnSelect();
} }
}); });
} else { } else {
getHistory().push('/' + selected.name); getHistory().push('/' + selected.name);
this.onHide(); this.hideOnSelect();
} }
}; };
@ -188,7 +198,7 @@ export default class QuickSwitchModal extends React.PureComponent<Props, State>
<Modal <Modal
dialogClassName='a11y__modal channel-switcher' dialogClassName='a11y__modal channel-switcher'
show={true} show={true}
onHide={this.onHide} onHide={this.hideOnCancel}
enforceFocus={false} enforceFocus={false}
restoreFocus={false} restoreFocus={false}
role='dialog' role='dialog'

View File

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