From d0e8fbd5a637a8f9492c8aa07155dc0a694a6f23 Mon Sep 17 00:00:00 2001 From: Josh Perez <60019601+josh-signal@users.noreply.github.com> Date: Thu, 14 Oct 2021 12:52:42 -0400 Subject: [PATCH] Animates ModalHost overlay --- package.json | 2 +- stylesheets/_modules.scss | 16 +- ts/components/ConfirmationDialog.tsx | 22 +- ts/components/ForwardMessageModal.tsx | 370 +++++++++++++------------- ts/components/Lightbox.tsx | 6 + ts/components/Modal.tsx | 33 ++- ts/components/ModalHost.tsx | 40 ++- ts/hooks/useAnimated.tsx | 73 +++-- yarn.lock | 70 ++--- 9 files changed, 340 insertions(+), 292 deletions(-) diff --git a/package.json b/package.json index 70e6bc471e6..07d91613a93 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ }, "dependencies": { "@popperjs/core": "2.9.2", - "@react-spring/web": "9.2.4", + "@react-spring/web": "9.2.6", "@signalapp/signal-client": "0.9.5", "@sindresorhus/is": "0.8.0", "abort-controller": "3.0.0", diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index 084dd35dabe..f732bcf34b4 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -8725,22 +8725,26 @@ button.module-image__border-overlay:focus { .module-modal-host__overlay { background: $color-black-alpha-40; - position: absolute; - height: 100vh; - width: 100vw; - left: 0; + position: absolute; top: 0; - + width: 100vw; z-index: 2; +} +.module-modal-host__container { display: flex; flex-direction: column; + height: 100vh; justify-content: center; - + left: 0; overflow: hidden; padding: 20px; + position: absolute; + top: 0; + width: 100vw; + z-index: 2; } // Module: GroupV2 Join Dialog diff --git a/ts/components/ConfirmationDialog.tsx b/ts/components/ConfirmationDialog.tsx index 07e34c988e4..a598cd93f21 100644 --- a/ts/components/ConfirmationDialog.tsx +++ b/ts/components/ConfirmationDialog.tsx @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { MouseEvent, useCallback } from 'react'; +import { animated } from '@react-spring/web'; import { Button, ButtonVariant } from './Button'; import { LocalizerType } from '../types/Util'; import { ModalHost } from './ModalHost'; @@ -63,17 +64,10 @@ export const ConfirmationDialog = React.memo( title, hasXButton, }: Props) => { - const { close, renderAnimation } = useAnimated( - { - from: { opacity: 0, transform: 'scale(0.25)' }, - enter: { opacity: 1, transform: 'scale(1)' }, - leave: { opacity: 0, onRest: () => onClose() }, - config: { - duration: 150, - }, - }, - onClose - ); + const { close, overlayStyles, modalStyles } = useAnimated(onClose, { + getFrom: () => ({ opacity: 0, transform: 'scale(0.25)' }), + getTo: isOpen => ({ opacity: isOpen ? 1 : 0, transform: 'scale(1)' }), + }); const cancelAndClose = useCallback(() => { if (onCancel) { @@ -94,8 +88,8 @@ export const ConfirmationDialog = React.memo( const hasActions = Boolean(actions.length); return ( - <ModalHost onClose={close} theme={theme}> - {renderAnimation( + <ModalHost onClose={close} theme={theme} overlayStyles={overlayStyles}> + <animated.div style={modalStyles}> <ModalWindow hasXButton={hasXButton} i18n={i18n} @@ -129,7 +123,7 @@ export const ConfirmationDialog = React.memo( ))} </Modal.ButtonFooter> </ModalWindow> - )} + </animated.div> </ModalHost> ); } diff --git a/ts/components/ForwardMessageModal.tsx b/ts/components/ForwardMessageModal.tsx index 0de436740d7..4bbedd1c2ca 100644 --- a/ts/components/ForwardMessageModal.tsx +++ b/ts/components/ForwardMessageModal.tsx @@ -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> </> ); diff --git a/ts/components/Lightbox.tsx b/ts/components/Lightbox.tsx index a87d0248a59..1ff7d6482a8 100644 --- a/ts/components/Lightbox.tsx +++ b/ts/components/Lightbox.tsx @@ -47,6 +47,12 @@ const INITIAL_IMAGE_TRANSFORM = { scale: 1, translateX: 0, translateY: 0, + config: { + clamp: true, + friction: 20, + mass: 0.5, + tension: 350, + }, }; export function Lightbox({ diff --git a/ts/components/Modal.tsx b/ts/components/Modal.tsx index df16c44878d..29a014c4089 100644 --- a/ts/components/Modal.tsx +++ b/ts/components/Modal.tsx @@ -5,6 +5,7 @@ import React, { ReactElement, ReactNode, useRef, useState } from 'react'; import Measure, { ContentRect, MeasuredComponentProps } from 'react-measure'; import classNames from 'classnames'; import { noop } from 'lodash'; +import { animated } from '@react-spring/web'; import { LocalizerType } from '../types/Util'; import { ModalHost } from './ModalHost'; @@ -42,24 +43,22 @@ export function Modal({ title, theme, }: Readonly<ModalPropsType>): ReactElement { - 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)' }, + }); return ( - <ModalHost noMouseClose={noMouseClose} onClose={close} theme={theme}> - {renderAnimation( + <ModalHost + noMouseClose={noMouseClose} + onClose={close} + overlayStyles={overlayStyles} + theme={theme} + > + <animated.div style={modalStyles}> <ModalWindow hasStickyButtons={hasStickyButtons} hasXButton={hasXButton} @@ -70,7 +69,7 @@ export function Modal({ > {children} </ModalWindow> - )} + </animated.div> </ModalHost> ); } diff --git a/ts/components/ModalHost.tsx b/ts/components/ModalHost.tsx index 465a75becde..966dfffe151 100644 --- a/ts/components/ModalHost.tsx +++ b/ts/components/ModalHost.tsx @@ -5,20 +5,30 @@ import React, { useEffect } from 'react'; import classNames from 'classnames'; import { createPortal } from 'react-dom'; import FocusTrap from 'focus-trap-react'; +import { SpringValues, animated } from '@react-spring/web'; +import type { ModalConfigType } from '../hooks/useAnimated'; import { Theme, themeClassName } from '../util/theme'; import { useEscapeHandling } from '../hooks/useEscapeHandling'; export type PropsType = { - readonly noMouseClose?: boolean; - readonly onEscape?: () => unknown; - readonly onClose: () => unknown; readonly children: React.ReactElement; + readonly noMouseClose?: boolean; + readonly onClose: () => unknown; + readonly onEscape?: () => unknown; + readonly overlayStyles?: SpringValues<ModalConfigType>; readonly theme?: Theme; }; export const ModalHost = React.memo( - ({ onEscape, onClose, children, noMouseClose, theme }: PropsType) => { + ({ + children, + noMouseClose, + onClose, + onEscape, + theme, + overlayStyles, + }: PropsType) => { const [root, setRoot] = React.useState<HTMLElement | null>(null); const [isMouseDown, setIsMouseDown] = React.useState(false); @@ -64,16 +74,18 @@ export const ModalHost = React.memo( allowOutsideClick: false, }} > - <div - role="presentation" - className={classNames( - 'module-modal-host__overlay', - theme ? themeClassName(theme) : undefined - )} - onMouseDown={noMouseClose ? undefined : handleMouseDown} - onMouseUp={noMouseClose ? undefined : handleMouseUp} - > - {children} + <div> + <animated.div + role="presentation" + className={classNames( + 'module-modal-host__overlay', + theme ? themeClassName(theme) : undefined + )} + onMouseDown={noMouseClose ? undefined : handleMouseDown} + onMouseUp={noMouseClose ? undefined : handleMouseUp} + style={overlayStyles} + /> + <div className="module-modal-host__container">{children}</div> </div> </FocusTrap>, root diff --git a/ts/hooks/useAnimated.tsx b/ts/hooks/useAnimated.tsx index 48f484d20d2..e0d15df0962 100644 --- a/ts/hooks/useAnimated.tsx +++ b/ts/hooks/useAnimated.tsx @@ -1,37 +1,72 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React, { useState, ReactElement } from 'react'; -import { animated, useTransition, UseTransitionProps } from '@react-spring/web'; -import cubicBezier from 'bezier-easing'; +import { useState } from 'react'; +import { + SpringValues, + useChain, + useSpring, + useSpringRef, +} from '@react-spring/web'; -export function useAnimated<Props extends Record<string, unknown>>( - props: UseTransitionProps, - onClose: () => unknown +export type ModalConfigType = { + opacity: number; + transform?: string; +}; + +export function useAnimated( + onClose: () => unknown, + { + getFrom, + getTo, + }: { + getFrom: (isOpen: boolean) => ModalConfigType; + getTo: (isOpen: boolean) => ModalConfigType; + } ): { close: () => unknown; - renderAnimation: (children: ReactElement) => JSX.Element; + modalStyles: SpringValues<ModalConfigType>; + overlayStyles: SpringValues<ModalConfigType>; } { const [isOpen, setIsOpen] = useState(true); - const transitions = useTransition<boolean, Props>(isOpen, { - ...props, - leave: { - ...props.leave, - onRest: () => onClose(), + const modalRef = useSpringRef(); + + const modalStyles = useSpring({ + from: getFrom(isOpen), + to: getTo(isOpen), + onRest: () => { + if (!isOpen) { + onClose(); + } }, config: { - duration: 200, - easing: cubicBezier(0.17, 0.17, 0, 1), - ...props.config, + clamp: true, + friction: 20, + mass: 0.5, + tension: 350, }, + ref: modalRef, }); + const overlayRef = useSpringRef(); + + const overlayStyles = useSpring({ + from: { opacity: 0 }, + to: { opacity: isOpen ? 1 : 0 }, + config: { + clamp: true, + friction: 22, + tension: 360, + }, + ref: overlayRef, + }); + + useChain(isOpen ? [overlayRef, modalRef] : [modalRef, overlayRef]); + return { close: () => setIsOpen(false), - renderAnimation: children => - transitions((style, item) => - item ? <animated.div style={style}>{children}</animated.div> : null - ), + overlayStyles, + modalStyles, }; } diff --git a/yarn.lock b/yarn.lock index cf7b6535ee7..bdf01558a15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1671,50 +1671,50 @@ react-lifecycles-compat "^3.0.4" warning "^3.0.0" -"@react-spring/animated@~9.2.0": - version "9.2.4" - resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.2.4.tgz#062ecc0fdfef89f2541a42d8500428b70035f879" - integrity sha512-AfV6ZM8pCCAT29GY5C8/1bOPjZrv/7kD0vedjiE/tEYvNDwg9GlscrvsTViWR2XykJoYrDfdkYArrldWpsCJ5g== +"@react-spring/animated@~9.2.6-beta.0": + version "9.2.6" + resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.2.6.tgz#58f30fb75d8bfb7ccbc156cfd6b974a8f3dfd54e" + integrity sha512-xjL6nmixYNDvnpTs1FFMsMfSC0tURwPCU3b2jWNriYGLfwZ7c/TcyaEZA7yiNnmdFnuR3f3Z27AqIgaFC083Cw== dependencies: - "@react-spring/shared" "~9.2.0" - "@react-spring/types" "~9.2.0" + "@react-spring/shared" "~9.2.6-beta.0" + "@react-spring/types" "~9.2.6-beta.0" -"@react-spring/core@~9.2.0": - version "9.2.4" - resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.2.4.tgz#275a4a065e3a315a4f5fb28c9a6f62ce718c25d6" - integrity sha512-R+PwyfsjiuYCWqaTTfCpYpRmsP0h87RNm7uxC1Uxy7QAHUfHEm2sAHn+AdHPwq/MbVwDssVT8C5yf2WGcqiXGg== +"@react-spring/core@~9.2.6-beta.0": + version "9.2.6" + resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.2.6.tgz#ae22338fe55d070caf03abb4293b5519ba620d93" + integrity sha512-uPHUxmu+w6mHJrfQTMtmGJ8iZEwiVxz9kH7dRyk69bkZJt9z+w0Oj3UF4J3VcECZsbm3HRhN2ogXSAaqGjwhQw== dependencies: - "@react-spring/animated" "~9.2.0" - "@react-spring/shared" "~9.2.0" - "@react-spring/types" "~9.2.0" + "@react-spring/animated" "~9.2.6-beta.0" + "@react-spring/shared" "~9.2.6-beta.0" + "@react-spring/types" "~9.2.6-beta.0" -"@react-spring/rafz@~9.2.0": - version "9.2.4" - resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.2.4.tgz#44793e9adc14dd0dcd1573d094368af11a89d73a" - integrity sha512-SOKf9eue+vAX+DGo7kWYNl9i9J3gPUlQjifIcV9Bzw9h3i30wPOOP0TjS7iMG/kLp2cdHQYDNFte6nt23VAZkQ== +"@react-spring/rafz@~9.2.6-beta.0": + version "9.2.6" + resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.2.6.tgz#d97484003875bf5fb5e6ec22dee97cc208363e48" + integrity sha512-62SivLKEpo7EfHPkxO5J3g9Cr9LF6+1A1RVOMJhkcpEYtbdbmma/d63Xp8qpMPEpk7uuWxaTb6jjyxW33pW3sg== -"@react-spring/shared@~9.2.0": - version "9.2.4" - resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.2.4.tgz#f9cc66ac5308a77293330a18518e34121f4008c1" - integrity sha512-ZEr4l2BxmyFRUvRA2VCkPfCJii4E7cGkwbjmTBx1EmcGrOnde/V2eF5dxqCTY3k35QuCegkrWe0coRJVkh8q2Q== +"@react-spring/shared@~9.2.6-beta.0": + version "9.2.6" + resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.2.6.tgz#2c84e62cc0cfbbbbeb5546acd46c1f4b248bc562" + integrity sha512-Qrm9fopKG/RxZ3Rw+4euhrpnB3uXSyiON9skHbcBfmkkzagpkUR66MX1YLrhHw0UchcZuSDnXs0Lonzt1rpWag== dependencies: - "@react-spring/rafz" "~9.2.0" - "@react-spring/types" "~9.2.0" + "@react-spring/rafz" "~9.2.6-beta.0" + "@react-spring/types" "~9.2.6-beta.0" -"@react-spring/types@~9.2.0": - version "9.2.4" - resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.2.4.tgz#2365ce9d761f548a9adcb2cd68714bf26765a5de" - integrity sha512-zHUXrWO8nweUN/ISjrjqU7GgXXvoEbFca1CgiE0TY0H/dqJb3l+Rhx8ecPVNYimzFg3ZZ1/T0egpLop8SOv4aA== +"@react-spring/types@~9.2.6-beta.0": + version "9.2.6" + resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.2.6.tgz#f60722fcf9f8492ae16d0bdc47f0ea3c2a16d2cf" + integrity sha512-l7mCw182DtDMnCI8CB9orgTAEoFZRtdQ6aS6YeEAqYcy3nQZPmPggIHH9DxyLw7n7vBPRSzu9gCvUMgXKpTflg== -"@react-spring/web@9.2.4": - version "9.2.4" - resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.2.4.tgz#c6d5464a954bfd0d7bc90117050f796a95ebfa08" - integrity sha512-vtPvOalLFvuju/MDBtoSnCyt0xXSL6Amyv82fljOuWPl1yGd4M1WteijnYL9Zlriljl0a3oXcPunAVYTD9dbDQ== +"@react-spring/web@9.2.6": + version "9.2.6" + resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.2.6.tgz#c4fba69e1b1b43bd1d6a62346530cfb07f2be09b" + integrity sha512-0HkRsEYR/CO3Uw46FWDWaF2wg2rUXcWE2R9AoZXthEYLUn5w9uE1mf2Jel7BxBxWGQ73owkqSQv+klA1Hb+ViQ== dependencies: - "@react-spring/animated" "~9.2.0" - "@react-spring/core" "~9.2.0" - "@react-spring/shared" "~9.2.0" - "@react-spring/types" "~9.2.0" + "@react-spring/animated" "~9.2.6-beta.0" + "@react-spring/core" "~9.2.6-beta.0" + "@react-spring/shared" "~9.2.6-beta.0" + "@react-spring/types" "~9.2.6-beta.0" "@signalapp/signal-client@0.9.5": version "0.9.5"