// Copyright 2018-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { KeyboardEvent, useCallback, useEffect, useState } from 'react'; import { noop } from 'lodash'; import { createPortal } from 'react-dom'; import classNames from 'classnames'; import { Manager, Popper, Reference } from 'react-popper'; import { LocalizerType } from '../types/Util'; export type PropsType = { i18n: LocalizerType; isHighQuality: boolean; onSelectQuality: (isHQ: boolean) => unknown; }; export const MediaQualitySelector = ({ i18n, isHighQuality, onSelectQuality, }: 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) => { setMenuShowing(true); ev.stopPropagation(); 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(() => { if (menuShowing) { const root = document.createElement('div'); setPopperRoot(root); document.body.appendChild(root); const handleOutsideClick = (event: MouseEvent) => { if (!root.contains(event.target as Node)) { handleClose(); event.stopPropagation(); event.preventDefault(); } }; document.addEventListener('click', handleOutsideClick); return () => { document.body.removeChild(root); document.removeEventListener('click', handleOutsideClick); setPopperRoot(null); }; } return noop; }, [menuShowing, setPopperRoot, handleClose]); return ( {({ ref }) => ( )} , popperRoot ) : null} ); };