Adds keyboard support to the media quality selector

This commit is contained in:
Josh Perez 2021-07-07 13:05:03 -04:00 committed by GitHub
parent 3827f05db9
commit a73d7b42cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 3 deletions

View file

@ -23,6 +23,11 @@
opacity: 0.5; opacity: 0.5;
width: 32px; width: 32px;
&:focus,
&:hover {
opacity: 1;
}
&::after { &::after {
content: ''; content: '';
display: block; display: block;
@ -106,6 +111,7 @@
} }
} }
&--focused,
&:focus, &:focus,
&:active { &:active {
border-radius: 6px; border-radius: 6px;

View file

@ -7,6 +7,7 @@ import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { boolean } from '@storybook/addon-knobs'; import { boolean } from '@storybook/addon-knobs';
import { IMAGE_JPEG } from '../types/MIME';
import { CompositionArea, Props } from './CompositionArea'; import { CompositionArea, Props } from './CompositionArea';
import { setup as setupI18n } from '../../js/modules/i18n'; import { setup as setupI18n } from '../../js/modules/i18n';
import enMessages from '../../_locales/en/messages.json'; import enMessages from '../../_locales/en/messages.json';
@ -33,7 +34,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
micCellEl, micCellEl,
onChooseAttachment: action('onChooseAttachment'), onChooseAttachment: action('onChooseAttachment'),
// AttachmentList // AttachmentList
draftAttachments: [], draftAttachments: overrideProps.draftAttachments || [],
onAddAttachment: action('onAddAttachment'), onAddAttachment: action('onAddAttachment'),
onClearAttachments: action('onClearAttachments'), onClearAttachments: action('onClearAttachments'),
onClickAttachment: action('onClickAttachment'), onClickAttachment: action('onClickAttachment'),
@ -144,3 +145,15 @@ story.add('SMS-only', () => {
return <CompositionArea {...props} />; return <CompositionArea {...props} />;
}); });
story.add('Attachments', () => {
const props = createProps({
draftAttachments: [
{
contentType: IMAGE_JPEG,
},
],
});
return <CompositionArea {...props} />;
});

View file

@ -21,6 +21,9 @@ export const MediaQualitySelector = ({
}: PropsType): JSX.Element => { }: PropsType): JSX.Element => {
const [menuShowing, setMenuShowing] = useState(false); const [menuShowing, setMenuShowing] = useState(false);
const [popperRoot, setPopperRoot] = useState<HTMLElement | null>(null); const [popperRoot, setPopperRoot] = useState<HTMLElement | null>(null);
const [focusedOption, setFocusedOption] = useState<0 | 1 | undefined>(
undefined
);
// We use regular MouseEvent below, and this one uses React.MouseEvent // We use regular MouseEvent below, and this one uses React.MouseEvent
const handleClick = (ev: KeyboardEvent | React.MouseEvent) => { const handleClick = (ev: KeyboardEvent | React.MouseEvent) => {
@ -29,8 +32,31 @@ export const MediaQualitySelector = ({
ev.preventDefault(); ev.preventDefault();
}; };
const handleKeyDown = (ev: KeyboardEvent) => {
if (!popperRoot) {
if (ev.key === 'Enter') {
setFocusedOption(isHighQuality ? 1 : 0);
}
return;
}
if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp') {
setFocusedOption(oldFocusedOption => (oldFocusedOption === 1 ? 0 : 1));
ev.stopPropagation();
ev.preventDefault();
}
if (ev.key === 'Enter') {
onSelectQuality(Boolean(focusedOption));
setMenuShowing(false);
ev.stopPropagation();
ev.preventDefault();
}
};
const handleClose = useCallback(() => { const handleClose = useCallback(() => {
setMenuShowing(false); setMenuShowing(false);
setFocusedOption(undefined);
}, [setMenuShowing]); }, [setMenuShowing]);
useEffect(() => { useEffect(() => {
@ -69,6 +95,7 @@ export const MediaQualitySelector = ({
'MediaQualitySelector__button--active': menuShowing, 'MediaQualitySelector__button--active': menuShowing,
})} })}
onClick={handleClick} onClick={handleClick}
onKeyDown={handleKeyDown}
ref={ref} ref={ref}
type="button" type="button"
/> />
@ -91,7 +118,11 @@ export const MediaQualitySelector = ({
aria-label={i18n( aria-label={i18n(
'MediaQualitySelector--standard-quality-title' 'MediaQualitySelector--standard-quality-title'
)} )}
className="MediaQualitySelector__option" className={classNames({
MediaQualitySelector__option: true,
'MediaQualitySelector__option--focused':
focusedOption === 0,
})}
type="button" type="button"
onClick={() => { onClick={() => {
onSelectQuality(false); onSelectQuality(false);
@ -119,7 +150,11 @@ export const MediaQualitySelector = ({
aria-label={i18n( aria-label={i18n(
'MediaQualitySelector--high-quality-title' 'MediaQualitySelector--high-quality-title'
)} )}
className="MediaQualitySelector__option" className={classNames({
MediaQualitySelector__option: true,
'MediaQualitySelector__option--focused':
focusedOption === 1,
})}
type="button" type="button"
onClick={() => { onClick={() => {
onSelectQuality(true); onSelectQuality(true);