// Copyright 2018-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { KeyboardEvent } from 'react'; import React, { 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 type { LocalizerType } from '../types/Util'; import { useRefMerger } from '../hooks/useRefMerger'; import { handleOutsideClick } from '../util/handleOutsideClick'; 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 ); const buttonRef = React.useRef(null); const refMerger = useRefMerger(); const handleClick = () => { setMenuShowing(true); }; 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); return () => { document.body.removeChild(root); setPopperRoot(null); }; } return noop; }, [menuShowing, setPopperRoot, handleClose]); useEffect(() => { if (!menuShowing) { return noop; } return handleOutsideClick( () => { handleClose(); return true; }, { containerElements: [popperRoot, buttonRef], name: 'MediaQualitySelector', } ); }, [menuShowing, popperRoot, handleClose]); return ( {({ ref }) => ( )} , popperRoot ) : null} ); };