From 78913842b9202211aea28fb253e747b18e4975c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= Date: Mon, 22 Jul 2024 15:01:24 +0200 Subject: [PATCH] Set animation after position --- .../createAnimatedComponent.tsx | 7 +-- .../web/animationsManager.ts | 7 +-- .../layoutReanimation/web/componentUtils.ts | 44 ++++++++----------- .../web/transition/Curved.web.ts | 11 ++--- 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx b/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx index 577b4a74e61..039f06eeb3c 100644 --- a/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx +++ b/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx @@ -49,6 +49,7 @@ import type { FlatList, FlatListProps } from 'react-native'; import { addHTMLMutationObserver } from '../layoutReanimation/web/domUtils'; import { getViewInfo } from './getViewInfo'; import { NativeEventsManager } from './NativeEventsManager'; +import type { ReanimatedHTMLElement } from '../js-reanimated'; const IS_WEB = isWeb(); @@ -178,7 +179,7 @@ export function createAnimatedComponent( startWebLayoutAnimation( this.props, - this._component as HTMLElement, + this._component as ReanimatedHTMLElement, LayoutAnimationType.ENTERING ); } @@ -211,7 +212,7 @@ export function createAnimatedComponent( startWebLayoutAnimation( this.props, - this._component as HTMLElement, + this._component as ReanimatedHTMLElement, LayoutAnimationType.EXITING ); } else if (exiting && !IS_WEB && !isFabric()) { @@ -418,7 +419,7 @@ export function createAnimatedComponent( ) { tryActivateLayoutTransition( this.props, - this._component as HTMLElement, + this._component as ReanimatedHTMLElement, snapshot ); } diff --git a/packages/react-native-reanimated/src/layoutReanimation/web/animationsManager.ts b/packages/react-native-reanimated/src/layoutReanimation/web/animationsManager.ts index 6d95260b0b2..34a7d523054 100644 --- a/packages/react-native-reanimated/src/layoutReanimation/web/animationsManager.ts +++ b/packages/react-native-reanimated/src/layoutReanimation/web/animationsManager.ts @@ -29,6 +29,7 @@ import type { TransitionData } from './animationParser'; import { Keyframe } from '../animationBuilder'; import { makeElementVisible } from './componentStyle'; import { EasingNameSymbol } from '../../Easing'; +import type { ReanimatedHTMLElement } from '../../js-reanimated'; function chooseConfig>( animationType: LayoutAnimationType, @@ -94,7 +95,7 @@ function maybeReportOverwrittenProperties( function chooseAction( animationType: LayoutAnimationType, animationConfig: AnimationConfig, - element: HTMLElement, + element: ReanimatedHTMLElement, transitionData: TransitionData ) { switch (animationType) { @@ -183,7 +184,7 @@ export function startWebLayoutAnimation< ComponentProps extends Record >( props: Readonly>, - element: HTMLElement, + element: ReanimatedHTMLElement, animationType: LayoutAnimationType, transitionData?: TransitionData ) { @@ -214,7 +215,7 @@ export function tryActivateLayoutTransition< ComponentProps extends Record >( props: Readonly>, - element: HTMLElement, + element: ReanimatedHTMLElement, snapshot: DOMRect ) { if (!props.layout) { diff --git a/packages/react-native-reanimated/src/layoutReanimation/web/componentUtils.ts b/packages/react-native-reanimated/src/layoutReanimation/web/componentUtils.ts index 708bc6554c4..1038a43d78a 100644 --- a/packages/react-native-reanimated/src/layoutReanimation/web/componentUtils.ts +++ b/packages/react-native-reanimated/src/layoutReanimation/web/componentUtils.ts @@ -153,9 +153,10 @@ export function saveSnapshot(element: HTMLElement) { } export function setElementAnimation( - element: HTMLElement, + element: ReanimatedHTMLElement, animationConfig: AnimationConfig, - shouldSavePosition = false + shouldSavePosition = false, + parent: Element | null = null ) { const { animationName, duration, delay, easing } = animationConfig; @@ -179,22 +180,30 @@ export function setElementAnimation( saveSnapshot(element); } + if (parent?.contains(element)) { + element.removedAfterAnimation = true; + parent.removeChild(element); + } + animationConfig.callback?.(true); element.removeEventListener('animationcancel', animationCancelHandler); }; const animationCancelHandler = () => { animationConfig.callback?.(false); + + if (parent?.contains(element)) { + element.removedAfterAnimation = true; + parent.removeChild(element); + } + element.removeEventListener('animationcancel', animationCancelHandler); }; // Here we have to use `addEventListener` since element.onanimationcancel doesn't work on chrome element.onanimationstart = () => { if (animationConfig.animationType === LayoutAnimationType.ENTERING) { - _updatePropsJS( - { visibility: 'initial' }, - element as ReanimatedHTMLElement - ); + _updatePropsJS({ visibility: 'initial' }, element); } element.addEventListener('animationcancel', animationCancelHandler); @@ -210,7 +219,7 @@ export function setElementAnimation( } export function handleLayoutTransition( - element: HTMLElement, + element: ReanimatedHTMLElement, animationConfig: AnimationConfig, transitionData: TransitionData ) { @@ -292,6 +301,7 @@ export function handleExitingAnimation( dummy.reanimatedDummy = true; element.style.animationName = ''; + dummy.style.animationName = ''; // After cloning the element, we want to move all children from original element to its clone. This is because original element // will be unmounted, therefore when this code executes in child component, parent will be either empty or removed soon. @@ -302,7 +312,6 @@ export function handleExitingAnimation( dummy.appendChild(element.firstChild); } - setElementAnimation(dummy, animationConfig); parent?.appendChild(dummy); const snapshot = snapshots.get(element)!; @@ -332,22 +341,5 @@ export function handleExitingAnimation( setElementPosition(dummy, snapshot); - const originalOnAnimationEnd = dummy.onanimationend; - - dummy.onanimationend = function (event: AnimationEvent) { - if (parent?.contains(dummy)) { - dummy.removedAfterAnimation = true; - parent.removeChild(dummy); - } - - // Given that this function overrides onAnimationEnd, it won't be null - originalOnAnimationEnd?.call(this, event); - }; - - dummy.addEventListener('animationcancel', () => { - if (parent?.contains(dummy)) { - dummy.removedAfterAnimation = true; - parent.removeChild(dummy); - } - }); + setElementAnimation(dummy, animationConfig, false, parent); } diff --git a/packages/react-native-reanimated/src/layoutReanimation/web/transition/Curved.web.ts b/packages/react-native-reanimated/src/layoutReanimation/web/transition/Curved.web.ts index 454e63a6a0c..51a5c77287a 100644 --- a/packages/react-native-reanimated/src/layoutReanimation/web/transition/Curved.web.ts +++ b/packages/react-native-reanimated/src/layoutReanimation/web/transition/Curved.web.ts @@ -1,4 +1,5 @@ 'use strict'; +import type { ReanimatedHTMLElement } from '../../../js-reanimated'; import { LayoutAnimationType } from '../..'; import type { WebEasingsNames } from '../Easing.web'; import { getEasingByName } from '../Easing.web'; @@ -33,8 +34,8 @@ function showChildren( } function prepareParent( - element: HTMLElement, - dummy: HTMLElement, + element: ReanimatedHTMLElement, + dummy: ReanimatedHTMLElement, animationConfig: AnimationConfig, transitionData: TransitionData ) { @@ -76,7 +77,7 @@ function prepareParent( } function prepareDummy( - element: HTMLElement, + element: ReanimatedHTMLElement, animationConfig: AnimationConfig, transitionData: TransitionData, dummyTransitionKeyframeName: string @@ -91,14 +92,14 @@ function prepareDummy( reversed: false, }; - const dummy = element.cloneNode(true) as HTMLElement; + const dummy = element.cloneNode(true) as ReanimatedHTMLElement; resetStyle(dummy); return { dummy, dummyAnimationConfig }; } export function prepareCurvedTransition( - element: HTMLElement, + element: ReanimatedHTMLElement, animationConfig: AnimationConfig, transitionData: TransitionData, dummyTransitionKeyframeName: string