Animates ModalHost overlay
This commit is contained in:
parent
cfc5407d03
commit
d0e8fbd5a6
9 changed files with 340 additions and 292 deletions
|
@ -11,6 +11,7 @@ import React, {
|
|||
} from 'react';
|
||||
import Measure, { MeasuredComponentProps } from 'react-measure';
|
||||
import { noop } from 'lodash';
|
||||
import { animated } from '@react-spring/web';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { AttachmentList } from './conversation/AttachmentList';
|
||||
|
@ -199,20 +200,16 @@ export const ForwardMessageModal: FunctionComponent<PropsType> = ({
|
|||
[contactLookup, selectedContacts, setSelectedContacts]
|
||||
);
|
||||
|
||||
const { close, renderAnimation } = useAnimated(
|
||||
{
|
||||
from: { opacity: 0, transform: 'translateY(48px)' },
|
||||
enter: { opacity: 1, transform: 'translateY(0px)' },
|
||||
leave: {
|
||||
opacity: 0,
|
||||
transform: 'translateY(48px)',
|
||||
},
|
||||
config: {
|
||||
duration: 200,
|
||||
},
|
||||
},
|
||||
onClose
|
||||
);
|
||||
const { close, modalStyles, overlayStyles } = useAnimated(onClose, {
|
||||
getFrom: () => ({ opacity: 0, transform: 'translateY(48px)' }),
|
||||
getTo: isOpen =>
|
||||
isOpen
|
||||
? { opacity: 1, transform: 'translateY(0px)' }
|
||||
: {
|
||||
opacity: 0,
|
||||
transform: 'translateY(48px)',
|
||||
},
|
||||
});
|
||||
|
||||
const handleBackOrClose = useCallback(() => {
|
||||
if (isEditingMessage) {
|
||||
|
@ -265,188 +262,189 @@ export const ForwardMessageModal: FunctionComponent<PropsType> = ({
|
|||
{i18n('GroupV2--cannot-send')}
|
||||
</ConfirmationDialog>
|
||||
)}
|
||||
<ModalHost onEscape={handleBackOrClose} onClose={close}>
|
||||
{renderAnimation(
|
||||
<div className="module-ForwardMessageModal">
|
||||
<div
|
||||
className={classNames('module-ForwardMessageModal__header', {
|
||||
'module-ForwardMessageModal__header--edit': isEditingMessage,
|
||||
})}
|
||||
>
|
||||
{isEditingMessage ? (
|
||||
<button
|
||||
aria-label={i18n('back')}
|
||||
className="module-ForwardMessageModal__header--back"
|
||||
onClick={() => setIsEditingMessage(false)}
|
||||
type="button"
|
||||
>
|
||||
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
aria-label={i18n('close')}
|
||||
className="module-ForwardMessageModal__header--close"
|
||||
onClick={close}
|
||||
type="button"
|
||||
/>
|
||||
)}
|
||||
<h1>{i18n('forwardMessage')}</h1>
|
||||
</div>
|
||||
<ModalHost
|
||||
onEscape={handleBackOrClose}
|
||||
onClose={close}
|
||||
overlayStyles={overlayStyles}
|
||||
>
|
||||
<animated.div
|
||||
className="module-ForwardMessageModal"
|
||||
style={modalStyles}
|
||||
>
|
||||
<div
|
||||
className={classNames('module-ForwardMessageModal__header', {
|
||||
'module-ForwardMessageModal__header--edit': isEditingMessage,
|
||||
})}
|
||||
>
|
||||
{isEditingMessage ? (
|
||||
<div className="module-ForwardMessageModal__main-body">
|
||||
{linkPreview ? (
|
||||
<div className="module-ForwardMessageModal--link-preview">
|
||||
<StagedLinkPreview
|
||||
date={linkPreview.date || null}
|
||||
description={linkPreview.description || ''}
|
||||
domain={linkPreview.url}
|
||||
i18n={i18n}
|
||||
image={linkPreview.image}
|
||||
onClose={() => removeLinkPreview()}
|
||||
title={linkPreview.title}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{attachmentsToForward && attachmentsToForward.length ? (
|
||||
<AttachmentList
|
||||
attachments={attachmentsToForward}
|
||||
<button
|
||||
aria-label={i18n('back')}
|
||||
className="module-ForwardMessageModal__header--back"
|
||||
onClick={() => setIsEditingMessage(false)}
|
||||
type="button"
|
||||
>
|
||||
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
aria-label={i18n('close')}
|
||||
className="module-ForwardMessageModal__header--close"
|
||||
onClick={close}
|
||||
type="button"
|
||||
/>
|
||||
)}
|
||||
<h1>{i18n('forwardMessage')}</h1>
|
||||
</div>
|
||||
{isEditingMessage ? (
|
||||
<div className="module-ForwardMessageModal__main-body">
|
||||
{linkPreview ? (
|
||||
<div className="module-ForwardMessageModal--link-preview">
|
||||
<StagedLinkPreview
|
||||
date={linkPreview.date || null}
|
||||
description={linkPreview.description || ''}
|
||||
domain={linkPreview.url}
|
||||
i18n={i18n}
|
||||
onCloseAttachment={(attachment: AttachmentType) => {
|
||||
const newAttachments = attachmentsToForward.filter(
|
||||
currentAttachment => currentAttachment !== attachment
|
||||
);
|
||||
setAttachmentsToForward(newAttachments);
|
||||
}}
|
||||
image={linkPreview.image}
|
||||
onClose={() => removeLinkPreview()}
|
||||
title={linkPreview.title}
|
||||
/>
|
||||
) : null}
|
||||
<div className="module-ForwardMessageModal__text-edit-area">
|
||||
<CompositionInput
|
||||
clearQuotedMessage={shouldNeverBeCalled}
|
||||
draftText={messageBodyText}
|
||||
getQuotedMessage={noop}
|
||||
</div>
|
||||
) : null}
|
||||
{attachmentsToForward && attachmentsToForward.length ? (
|
||||
<AttachmentList
|
||||
attachments={attachmentsToForward}
|
||||
i18n={i18n}
|
||||
onCloseAttachment={(attachment: AttachmentType) => {
|
||||
const newAttachments = attachmentsToForward.filter(
|
||||
currentAttachment => currentAttachment !== attachment
|
||||
);
|
||||
setAttachmentsToForward(newAttachments);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<div className="module-ForwardMessageModal__text-edit-area">
|
||||
<CompositionInput
|
||||
clearQuotedMessage={shouldNeverBeCalled}
|
||||
draftText={messageBodyText}
|
||||
getQuotedMessage={noop}
|
||||
i18n={i18n}
|
||||
inputApi={inputApiRef}
|
||||
large
|
||||
moduleClassName="module-ForwardMessageModal__input"
|
||||
onEditorStateChange={(
|
||||
messageText,
|
||||
bodyRanges,
|
||||
caretLocation
|
||||
) => {
|
||||
setMessageBodyText(messageText);
|
||||
onEditorStateChange(messageText, bodyRanges, caretLocation);
|
||||
}}
|
||||
onPickEmoji={onPickEmoji}
|
||||
onSubmit={forwardMessage}
|
||||
onTextTooLong={onTextTooLong}
|
||||
/>
|
||||
<div className="module-ForwardMessageModal__emoji">
|
||||
<EmojiButton
|
||||
i18n={i18n}
|
||||
inputApi={inputApiRef}
|
||||
large
|
||||
moduleClassName="module-ForwardMessageModal__input"
|
||||
onEditorStateChange={(
|
||||
messageText,
|
||||
bodyRanges,
|
||||
caretLocation
|
||||
) => {
|
||||
setMessageBodyText(messageText);
|
||||
onEditorStateChange(
|
||||
messageText,
|
||||
bodyRanges,
|
||||
caretLocation
|
||||
);
|
||||
}}
|
||||
onPickEmoji={onPickEmoji}
|
||||
onSubmit={forwardMessage}
|
||||
onTextTooLong={onTextTooLong}
|
||||
onClose={focusTextEditInput}
|
||||
onPickEmoji={insertEmoji}
|
||||
onSetSkinTone={onSetSkinTone}
|
||||
recentEmojis={recentEmojis}
|
||||
skinTone={skinTone}
|
||||
/>
|
||||
<div className="module-ForwardMessageModal__emoji">
|
||||
<EmojiButton
|
||||
i18n={i18n}
|
||||
onClose={focusTextEditInput}
|
||||
onPickEmoji={insertEmoji}
|
||||
onSetSkinTone={onSetSkinTone}
|
||||
recentEmojis={recentEmojis}
|
||||
skinTone={skinTone}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="module-ForwardMessageModal__main-body">
|
||||
<SearchInput
|
||||
disabled={candidateConversations.length === 0}
|
||||
placeholder={i18n('contactSearchPlaceholder')}
|
||||
onChange={event => {
|
||||
setSearchTerm(event.target.value);
|
||||
}}
|
||||
ref={inputRef}
|
||||
value={searchTerm}
|
||||
/>
|
||||
{candidateConversations.length ? (
|
||||
<Measure bounds>
|
||||
{({ contentRect, measureRef }: MeasuredComponentProps) => {
|
||||
// We disable this ESLint rule because we're capturing a bubbled
|
||||
// keydown event. See [this note in the jsx-a11y docs][0].
|
||||
//
|
||||
// [0]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/c275964f52c35775208bd00cb612c6f82e42e34f/docs/rules/no-static-element-interactions.md#case-the-event-handler-is-only-being-used-to-capture-bubbled-events
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
return (
|
||||
<div
|
||||
className="module-ForwardMessageModal__list-wrapper"
|
||||
ref={measureRef}
|
||||
>
|
||||
<ConversationList
|
||||
dimensions={contentRect.bounds}
|
||||
getRow={getRow}
|
||||
i18n={i18n}
|
||||
onClickArchiveButton={shouldNeverBeCalled}
|
||||
onClickContactCheckbox={(
|
||||
conversationId: string,
|
||||
disabledReason:
|
||||
| undefined
|
||||
| ContactCheckboxDisabledReason
|
||||
) => {
|
||||
if (
|
||||
disabledReason !==
|
||||
ContactCheckboxDisabledReason.MaximumContactsSelected
|
||||
) {
|
||||
toggleSelectedConversation(conversationId);
|
||||
}
|
||||
}}
|
||||
onSelectConversation={shouldNeverBeCalled}
|
||||
renderMessageSearchResult={() => {
|
||||
shouldNeverBeCalled();
|
||||
return <div />;
|
||||
}}
|
||||
rowCount={rowCount}
|
||||
shouldRecomputeRowHeights={false}
|
||||
showChooseGroupMembers={shouldNeverBeCalled}
|
||||
startNewConversationFromPhoneNumber={
|
||||
shouldNeverBeCalled
|
||||
</div>
|
||||
) : (
|
||||
<div className="module-ForwardMessageModal__main-body">
|
||||
<SearchInput
|
||||
disabled={candidateConversations.length === 0}
|
||||
placeholder={i18n('contactSearchPlaceholder')}
|
||||
onChange={event => {
|
||||
setSearchTerm(event.target.value);
|
||||
}}
|
||||
ref={inputRef}
|
||||
value={searchTerm}
|
||||
/>
|
||||
{candidateConversations.length ? (
|
||||
<Measure bounds>
|
||||
{({ contentRect, measureRef }: MeasuredComponentProps) => {
|
||||
// We disable this ESLint rule because we're capturing a bubbled
|
||||
// keydown event. See [this note in the jsx-a11y docs][0].
|
||||
//
|
||||
// [0]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/c275964f52c35775208bd00cb612c6f82e42e34f/docs/rules/no-static-element-interactions.md#case-the-event-handler-is-only-being-used-to-capture-bubbled-events
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
return (
|
||||
<div
|
||||
className="module-ForwardMessageModal__list-wrapper"
|
||||
ref={measureRef}
|
||||
>
|
||||
<ConversationList
|
||||
dimensions={contentRect.bounds}
|
||||
getRow={getRow}
|
||||
i18n={i18n}
|
||||
onClickArchiveButton={shouldNeverBeCalled}
|
||||
onClickContactCheckbox={(
|
||||
conversationId: string,
|
||||
disabledReason:
|
||||
| undefined
|
||||
| ContactCheckboxDisabledReason
|
||||
) => {
|
||||
if (
|
||||
disabledReason !==
|
||||
ContactCheckboxDisabledReason.MaximumContactsSelected
|
||||
) {
|
||||
toggleSelectedConversation(conversationId);
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
/* eslint-enable jsx-a11y/no-static-element-interactions */
|
||||
}}
|
||||
</Measure>
|
||||
) : (
|
||||
<div className="module-ForwardMessageModal__no-candidate-contacts">
|
||||
{i18n('noContactsFound')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="module-ForwardMessageModal__footer">
|
||||
<div>
|
||||
{Boolean(selectedContacts.length) &&
|
||||
selectedContacts.map(contact => contact.title).join(', ')}
|
||||
</div>
|
||||
<div>
|
||||
{isEditingMessage || !isMessageEditable ? (
|
||||
<Button
|
||||
aria-label={i18n('ForwardMessageModal--continue')}
|
||||
className="module-ForwardMessageModal__send-button module-ForwardMessageModal__send-button--forward"
|
||||
disabled={!canForwardMessage}
|
||||
onClick={forwardMessage}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
aria-label={i18n('forwardMessage')}
|
||||
className="module-ForwardMessageModal__send-button module-ForwardMessageModal__send-button--continue"
|
||||
disabled={!hasContactsSelected}
|
||||
onClick={() => setIsEditingMessage(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
}}
|
||||
onSelectConversation={shouldNeverBeCalled}
|
||||
renderMessageSearchResult={() => {
|
||||
shouldNeverBeCalled();
|
||||
return <div />;
|
||||
}}
|
||||
rowCount={rowCount}
|
||||
shouldRecomputeRowHeights={false}
|
||||
showChooseGroupMembers={shouldNeverBeCalled}
|
||||
startNewConversationFromPhoneNumber={
|
||||
shouldNeverBeCalled
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
/* eslint-enable jsx-a11y/no-static-element-interactions */
|
||||
}}
|
||||
</Measure>
|
||||
) : (
|
||||
<div className="module-ForwardMessageModal__no-candidate-contacts">
|
||||
{i18n('noContactsFound')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="module-ForwardMessageModal__footer">
|
||||
<div>
|
||||
{Boolean(selectedContacts.length) &&
|
||||
selectedContacts.map(contact => contact.title).join(', ')}
|
||||
</div>
|
||||
<div>
|
||||
{isEditingMessage || !isMessageEditable ? (
|
||||
<Button
|
||||
aria-label={i18n('ForwardMessageModal--continue')}
|
||||
className="module-ForwardMessageModal__send-button module-ForwardMessageModal__send-button--forward"
|
||||
disabled={!canForwardMessage}
|
||||
onClick={forwardMessage}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
aria-label={i18n('forwardMessage')}
|
||||
className="module-ForwardMessageModal__send-button module-ForwardMessageModal__send-button--continue"
|
||||
disabled={!hasContactsSelected}
|
||||
onClick={() => setIsEditingMessage(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</animated.div>
|
||||
</ModalHost>
|
||||
</>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue