diff --git a/ts/components/Toast.tsx b/ts/components/Toast.tsx index 44f5859ed8f..f33fdd3a759 100644 --- a/ts/components/Toast.tsx +++ b/ts/components/Toast.tsx @@ -1,10 +1,15 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React, { KeyboardEvent, MouseEvent, ReactNode, useEffect } from 'react'; +import React, { + KeyboardEvent, + MouseEvent, + ReactNode, + memo, + useEffect, +} from 'react'; import classNames from 'classnames'; import { createPortal } from 'react-dom'; -import { onTimeout, removeTimeout } from '../services/timers'; import { useRestoreFocus } from '../hooks/useRestoreFocus'; export type PropsType = { @@ -20,88 +25,90 @@ export type PropsType = { }; }; -export const Toast = ({ - autoDismissDisabled = false, - children, - className, - disableCloseOnClick = false, - onClose, - timeout = 8000, - toastAction, -}: PropsType): JSX.Element | null => { - const [root, setRoot] = React.useState(null); - const [focusRef] = useRestoreFocus(); +export const Toast = memo( + ({ + autoDismissDisabled = false, + children, + className, + disableCloseOnClick = false, + onClose, + timeout = 8000, + toastAction, + }: PropsType): JSX.Element | null => { + const [root, setRoot] = React.useState(null); + const [focusRef] = useRestoreFocus(); - useEffect(() => { - const div = document.createElement('div'); - document.body.appendChild(div); - setRoot(div); + useEffect(() => { + const div = document.createElement('div'); + document.body.appendChild(div); + setRoot(div); - return () => { - document.body.removeChild(div); - setRoot(null); - }; - }, []); + return () => { + document.body.removeChild(div); + setRoot(null); + }; + }, []); - useEffect(() => { - if (!root || autoDismissDisabled) { - return; - } + useEffect(() => { + if (!root || autoDismissDisabled) { + return; + } - const timeoutId = onTimeout(Date.now() + timeout, onClose); + const timeoutId = setTimeout(onClose, timeout); - return () => { - if (timeoutId) { - removeTimeout(timeoutId); - } - }; - }, [autoDismissDisabled, onClose, root, timeout]); + return () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + }; + }, [autoDismissDisabled, onClose, root, timeout]); - return root - ? createPortal( -
{ - if (!disableCloseOnClick) { - onClose(); - } - }} - onKeyDown={(ev: KeyboardEvent) => { - if (ev.key === 'Enter' || ev.key === ' ') { + return root + ? createPortal( +
{ if (!disableCloseOnClick) { onClose(); } - } - }} - role="button" - tabIndex={0} - > -
{children}
- {toastAction && ( -
) => { - ev.stopPropagation(); - ev.preventDefault(); - toastAction.onClick(); - }} - onKeyDown={(ev: KeyboardEvent) => { - if (ev.key === 'Enter' || ev.key === ' ') { + }} + onKeyDown={(ev: KeyboardEvent) => { + if (ev.key === 'Enter' || ev.key === ' ') { + if (!disableCloseOnClick) { + onClose(); + } + } + }} + role="button" + tabIndex={0} + > +
{children}
+ {toastAction && ( +
) => { ev.stopPropagation(); ev.preventDefault(); toastAction.onClick(); - } - }} - ref={focusRef} - role="button" - tabIndex={0} - > - {toastAction.label} -
- )} -
, - root - ) - : null; -}; + }} + onKeyDown={(ev: KeyboardEvent) => { + if (ev.key === 'Enter' || ev.key === ' ') { + ev.stopPropagation(); + ev.preventDefault(); + toastAction.onClick(); + } + }} + ref={focusRef} + role="button" + tabIndex={0} + > + {toastAction.label} +
+ )} +
, + root + ) + : null; + } +); diff --git a/ts/components/conversation/AudioCapture.tsx b/ts/components/conversation/AudioCapture.tsx index 83450c8a841..d7e2e32756b 100644 --- a/ts/components/conversation/AudioCapture.tsx +++ b/ts/components/conversation/AudioCapture.tsx @@ -134,9 +134,9 @@ export const AudioCapture = ({ completeRecording(conversationId, onSendAudioRecording); }, [conversationId, completeRecording, onSendAudioRecording]); - function closeToast() { + const closeToast = useCallback(() => { setToastType(undefined); - } + }, []); let toastElement: JSX.Element | undefined; if (toastType === ToastType.VoiceNoteLimit) {