From a73d7b42cfd47fcfdb9fe1430dc817475fec02f5 Mon Sep 17 00:00:00 2001 From: Josh Perez <60019601+josh-signal@users.noreply.github.com> Date: Wed, 7 Jul 2021 13:05:03 -0400 Subject: [PATCH] Adds keyboard support to the media quality selector --- .../components/MediaQualitySelector.scss | 6 +++ ts/components/CompositionArea.stories.tsx | 15 ++++++- ts/components/MediaQualitySelector.tsx | 39 ++++++++++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/stylesheets/components/MediaQualitySelector.scss b/stylesheets/components/MediaQualitySelector.scss index 12152d6296..6d2cc78751 100644 --- a/stylesheets/components/MediaQualitySelector.scss +++ b/stylesheets/components/MediaQualitySelector.scss @@ -23,6 +23,11 @@ opacity: 0.5; width: 32px; + &:focus, + &:hover { + opacity: 1; + } + &::after { content: ''; display: block; @@ -106,6 +111,7 @@ } } + &--focused, &:focus, &:active { border-radius: 6px; diff --git a/ts/components/CompositionArea.stories.tsx b/ts/components/CompositionArea.stories.tsx index 82e5d17945..f90d4e703a 100644 --- a/ts/components/CompositionArea.stories.tsx +++ b/ts/components/CompositionArea.stories.tsx @@ -7,6 +7,7 @@ import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { boolean } from '@storybook/addon-knobs'; +import { IMAGE_JPEG } from '../types/MIME'; import { CompositionArea, Props } from './CompositionArea'; import { setup as setupI18n } from '../../js/modules/i18n'; import enMessages from '../../_locales/en/messages.json'; @@ -33,7 +34,7 @@ const createProps = (overrideProps: Partial = {}): Props => ({ micCellEl, onChooseAttachment: action('onChooseAttachment'), // AttachmentList - draftAttachments: [], + draftAttachments: overrideProps.draftAttachments || [], onAddAttachment: action('onAddAttachment'), onClearAttachments: action('onClearAttachments'), onClickAttachment: action('onClickAttachment'), @@ -144,3 +145,15 @@ story.add('SMS-only', () => { return ; }); + +story.add('Attachments', () => { + const props = createProps({ + draftAttachments: [ + { + contentType: IMAGE_JPEG, + }, + ], + }); + + return ; +}); diff --git a/ts/components/MediaQualitySelector.tsx b/ts/components/MediaQualitySelector.tsx index 838d6a76df..566c266b35 100644 --- a/ts/components/MediaQualitySelector.tsx +++ b/ts/components/MediaQualitySelector.tsx @@ -21,6 +21,9 @@ export const MediaQualitySelector = ({ }: PropsType): JSX.Element => { const [menuShowing, setMenuShowing] = useState(false); const [popperRoot, setPopperRoot] = useState(null); + const [focusedOption, setFocusedOption] = useState<0 | 1 | undefined>( + undefined + ); // We use regular MouseEvent below, and this one uses React.MouseEvent const handleClick = (ev: KeyboardEvent | React.MouseEvent) => { @@ -29,8 +32,31 @@ export const MediaQualitySelector = ({ 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(() => { setMenuShowing(false); + setFocusedOption(undefined); }, [setMenuShowing]); useEffect(() => { @@ -69,6 +95,7 @@ export const MediaQualitySelector = ({ 'MediaQualitySelector__button--active': menuShowing, })} onClick={handleClick} + onKeyDown={handleKeyDown} ref={ref} type="button" /> @@ -91,7 +118,11 @@ export const MediaQualitySelector = ({ aria-label={i18n( 'MediaQualitySelector--standard-quality-title' )} - className="MediaQualitySelector__option" + className={classNames({ + MediaQualitySelector__option: true, + 'MediaQualitySelector__option--focused': + focusedOption === 0, + })} type="button" onClick={() => { onSelectQuality(false); @@ -119,7 +150,11 @@ export const MediaQualitySelector = ({ aria-label={i18n( 'MediaQualitySelector--high-quality-title' )} - className="MediaQualitySelector__option" + className={classNames({ + MediaQualitySelector__option: true, + 'MediaQualitySelector__option--focused': + focusedOption === 1, + })} type="button" onClick={() => { onSelectQuality(true);