Skip to content

Commit

Permalink
[Web LA] Remove existingTransform (#6060)
Browse files Browse the repository at this point in the history
## Summary

A while ago I've noticed that layout animations on mobile throw warning
if one tries to add animation into `View` that has `transform` property.
Now, while working on #5277 I've decided to remove code responsible for
applying existing transform on web. Here are the reasons why I believe
it is good idea:

1. It unifies behavior with mobile platforms, which are main target of
`reanimated`.
2. Some of `transforms` were not applied correctly and required
additional calculations to be implemented (like `skew`).
3. Removing existing transforms means removing a lot of `ifs` and
unnecessary code.

## Test plan

Tested on example app on `LA` examples.
  • Loading branch information
m-bert authored May 29, 2024
1 parent 4cd7505 commit 98646b3
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 196 deletions.
32 changes: 0 additions & 32 deletions src/reanimated2/layoutReanimation/web/animationParser.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use strict';

import type { TransformsStyle } from 'react-native';

export interface ReanimatedWebTransformProperties {
translateX?: string;
translateY?: string;
Expand Down Expand Up @@ -67,33 +65,3 @@ export function convertAnimationObjectToKeyframes(

return keyframe;
}

export function convertTransformToString(
transform: NonNullable<TransformsStyle['transform']> | undefined
) {
if (!transform) {
return '';
}

type RNTransformProp = (typeof transform)[number];

let transformString = '';

// @ts-ignore `transform` cannot be string because in that case
// we throw error in `extractTransformFromStyle`
transform.forEach((transformObject: RNTransformProp) => {
for (const [key, value] of Object.entries(transformObject)) {
if (key === 'reversed') {
continue;
}

if (key.indexOf('translate') < 0) {
transformString += `${key}(${value}) `;
} else {
transformString += `${key}(${value}px) `;
}
}
});

return transformString;
}
48 changes: 11 additions & 37 deletions src/reanimated2/layoutReanimation/web/animationsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,13 @@ import type {
LayoutAnimationStaticContext,
} from '../../../createAnimatedComponent/commonTypes';
import { LayoutAnimationType } from '../animationBuilder/commonTypes';
import type { StyleProps } from '../../commonTypes';
import { createAnimationWithExistingTransform } from './createAnimation';
import {
extractTransformFromStyle,
getProcessedConfig,
handleExitingAnimation,
handleLayoutTransition,
setElementAnimation,
} from './componentUtils';
import { areDOMRectsEqual } from './domUtils';
import type { TransformsStyle } from 'react-native';
import type { TransitionData } from './animationParser';
import { makeElementVisible } from './componentStyle';

Expand Down Expand Up @@ -58,32 +54,23 @@ function chooseAction(
animationType: LayoutAnimationType,
animationConfig: AnimationConfig,
element: HTMLElement,
transitionData: TransitionData,
transform: TransformsStyle['transform'] | undefined
transitionData: TransitionData
) {
switch (animationType) {
case LayoutAnimationType.ENTERING:
setElementAnimation(element, animationConfig, transform);
setElementAnimation(element, animationConfig);
break;
case LayoutAnimationType.LAYOUT:
transitionData.reversed = animationConfig.reversed;

handleLayoutTransition(
element,
animationConfig,
transitionData,
transform
);
handleLayoutTransition(element, animationConfig, transitionData);
break;
case LayoutAnimationType.EXITING:
handleExitingAnimation(element, animationConfig);
break;
}
}

function tryGetAnimationConfigWithTransform<
ComponentProps extends Record<string, unknown>
>(
function tryGetAnimationConfig<ComponentProps extends Record<string, unknown>>(
props: Readonly<AnimatedComponentProps<ComponentProps>>,
animationType: LayoutAnimationType
) {
Expand All @@ -96,35 +83,28 @@ function tryGetAnimationConfigWithTransform<
typeof config.constructor;

const isLayoutTransition = animationType === LayoutAnimationType.LAYOUT;
const initialAnimationName =
const animationName =
typeof config === 'function'
? config.presetName
: (config.constructor as ConstructorWithStaticContext).presetName;

const shouldFail = checkUndefinedAnimationFail(
initialAnimationName,
animationName,
isLayoutTransition
);

if (shouldFail) {
return null;
}

const transform = extractTransformFromStyle(props.style as StyleProps);

const animationName =
transform && animationType !== LayoutAnimationType.EXITING
? createAnimationWithExistingTransform(initialAnimationName, transform)
: initialAnimationName;

const animationConfig = getProcessedConfig(
animationName,
animationType,
config as CustomConfig,
initialAnimationName as AnimationNames
animationName as AnimationNames
);

return { animationConfig, transform };
return animationConfig;
}

export function startWebLayoutAnimation<
Expand All @@ -135,20 +115,14 @@ export function startWebLayoutAnimation<
animationType: LayoutAnimationType,
transitionData?: TransitionData
) {
const maybeAnimationConfigWithTransform = tryGetAnimationConfigWithTransform(
props,
animationType
);

if (maybeAnimationConfigWithTransform) {
const { animationConfig, transform } = maybeAnimationConfigWithTransform;
const animationConfig = tryGetAnimationConfig(props, animationType);

if (animationConfig) {
chooseAction(
animationType,
animationConfig,
element,
transitionData as TransitionData,
transform
transitionData as TransitionData
);
} else {
makeElementVisible(element, 0);
Expand Down
45 changes: 4 additions & 41 deletions src/reanimated2/layoutReanimation/web/componentUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';

import type { TransformsStyle } from 'react-native';
import { Animations, TransitionType, WebEasings } from './config';
import type {
AnimationCallback,
Expand All @@ -9,14 +8,12 @@ import type {
CustomConfig,
WebEasingsNames,
} from './config';
import { convertTransformToString } from './animationParser';
import type { TransitionData } from './animationParser';
import { TransitionGenerator } from './createAnimation';
import { scheduleAnimationCleanup } from './domUtils';
import { _updatePropsJS } from '../../js-reanimated';
import type { ReanimatedHTMLElement } from '../../js-reanimated';
import { ReduceMotion } from '../../commonTypes';
import type { StyleProps } from '../../commonTypes';
import { isReducedMotion } from '../../PlatformChecker';
import { LayoutAnimationType } from '../animationBuilder/commonTypes';
import type { ReanimatedSnapshot, ScrollOffsets } from './componentStyle';
Expand Down Expand Up @@ -86,27 +83,6 @@ function getReversedFromConfig(config: CustomConfig) {
return !!config.reversed;
}

export function extractTransformFromStyle(style: StyleProps) {
if (!style) {
return;
}

if (typeof style.transform === 'string') {
throw new Error('[Reanimated] String transform is currently unsupported.');
}

if (!Array.isArray(style)) {
return style.transform;
}

// Only last transform should be considered
for (let i = style.length - 1; i >= 0; --i) {
if (style[i]?.transform) {
return style[i].transform;
}
}
}

export function getProcessedConfig(
animationName: string,
animationType: LayoutAnimationType,
Expand Down Expand Up @@ -144,8 +120,7 @@ export function saveSnapshot(element: HTMLElement) {

export function setElementAnimation(
element: HTMLElement,
animationConfig: AnimationConfig,
existingTransform?: TransformsStyle['transform']
animationConfig: AnimationConfig
) {
const { animationName, duration, delay, easing } = animationConfig;

Expand Down Expand Up @@ -174,7 +149,6 @@ export function setElementAnimation(
}

element.addEventListener('animationcancel', animationCancelHandler);
element.style.transform = convertTransformToString(existingTransform);
};

if (!(animationName in Animations)) {
Expand All @@ -185,8 +159,7 @@ export function setElementAnimation(
export function handleLayoutTransition(
element: HTMLElement,
animationConfig: AnimationConfig,
transitionData: TransitionData,
existingTransform: TransformsStyle['transform'] | undefined
transitionData: TransitionData
) {
const { animationName } = animationConfig;

Expand All @@ -209,20 +182,10 @@ export function handleLayoutTransition(

animationConfig.animationName = TransitionGenerator(
animationType,
transitionData,
existingTransform
transitionData
);

const transformCopy = existingTransform
? structuredClone(existingTransform)
: [];

// @ts-ignore `existingTransform` cannot be string because in that case
// we throw error in `extractTransformFromStyle`
transformCopy.push(transitionData);
element.style.transform = convertTransformToString(transformCopy);

setElementAnimation(element, animationConfig, existingTransform);
setElementAnimation(element, animationConfig);
}

function getElementScrollValue(element: HTMLElement): ScrollOffsets {
Expand Down
Loading

0 comments on commit 98646b3

Please sign in to comment.