2017-08-23 03:57:38 +03:00
|
|
|
/**
|
2018-09-12 01:27:47 +03:00
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
2017-08-23 03:57:38 +03:00
|
|
|
*
|
2018-02-17 05:24:55 +03:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2017-08-23 03:57:38 +03:00
|
|
|
*
|
|
|
|
* @flow
|
|
|
|
* @format
|
|
|
|
*/
|
2019-10-16 20:03:47 +03:00
|
|
|
|
2017-08-23 03:57:38 +03:00
|
|
|
'use strict';
|
|
|
|
|
2021-06-03 08:34:41 +03:00
|
|
|
import * as createAnimatedComponentInjection from './createAnimatedComponentInjection';
|
|
|
|
|
2020-08-26 00:12:19 +03:00
|
|
|
const View = require('../Components/View/View');
|
2017-08-23 03:57:38 +03:00
|
|
|
const {AnimatedEvent} = require('./AnimatedEvent');
|
|
|
|
const AnimatedProps = require('./nodes/AnimatedProps');
|
2019-05-08 18:44:25 +03:00
|
|
|
const React = require('react');
|
2020-07-29 22:37:11 +03:00
|
|
|
const NativeAnimatedHelper = require('./NativeAnimatedHelper');
|
2017-08-23 03:57:38 +03:00
|
|
|
|
2018-12-03 10:49:12 +03:00
|
|
|
const invariant = require('invariant');
|
2020-08-26 00:12:19 +03:00
|
|
|
const setAndForwardRef = require('../Utilities/setAndForwardRef');
|
2018-02-14 18:51:52 +03:00
|
|
|
|
2020-07-29 22:37:11 +03:00
|
|
|
let animatedComponentNextId = 1;
|
|
|
|
|
2019-11-04 05:00:15 +03:00
|
|
|
export type AnimatedComponentType<
|
2019-11-21 20:38:13 +03:00
|
|
|
Props: {+[string]: mixed, ...},
|
2019-11-04 05:00:15 +03:00
|
|
|
Instance,
|
2020-06-10 02:30:56 +03:00
|
|
|
> = React.AbstractComponent<
|
|
|
|
$ObjMap<
|
|
|
|
Props &
|
|
|
|
$ReadOnly<{
|
|
|
|
passthroughAnimatedPropExplicitValues?: React.ElementConfig<
|
|
|
|
typeof View,
|
|
|
|
>,
|
|
|
|
}>,
|
|
|
|
() => any,
|
|
|
|
>,
|
|
|
|
Instance,
|
|
|
|
>;
|
2019-10-23 21:40:30 +03:00
|
|
|
|
Reduce re-rendering of Animated components in Fabric
Summary:
The `isFabric` method used in createAnimatedComponent is unreliable (another reason in a long list of reasons why you should not duplicate this code elsewhere, and why we want to delete it ASAP).
In particular, during the first render, the ref component has not been set yet, so we /cannot/ detect if the component is Fabric or non-Fabric and assume it's non-Fabric.
In Fabric, this causes `collapsable` and `nativeID` values to change after the first render.
To reduce this re-rendering, but not eliminate it for all components, I've introduced a flag that indicates if a component will /never/ be flattened. In particular, Image components, ScrollViews, Text cannot ever be flattened,
so we should always pass `collapsable:false` and the same nativeID prop for those components. For Animated <View>s and other components, the re-rendering issue is still a problem in Fabric for now.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D25720322
fbshipit-source-id: fe3234d8ae974911a2b5f82e4f6a093216f43d4b
2020-12-29 09:33:01 +03:00
|
|
|
type AnimatedComponentOptions = {
|
|
|
|
collapsable?: boolean,
|
|
|
|
};
|
|
|
|
|
2019-11-21 20:38:13 +03:00
|
|
|
function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
2019-10-23 21:40:30 +03:00
|
|
|
Component: React.AbstractComponent<Props, Instance>,
|
Reduce re-rendering of Animated components in Fabric
Summary:
The `isFabric` method used in createAnimatedComponent is unreliable (another reason in a long list of reasons why you should not duplicate this code elsewhere, and why we want to delete it ASAP).
In particular, during the first render, the ref component has not been set yet, so we /cannot/ detect if the component is Fabric or non-Fabric and assume it's non-Fabric.
In Fabric, this causes `collapsable` and `nativeID` values to change after the first render.
To reduce this re-rendering, but not eliminate it for all components, I've introduced a flag that indicates if a component will /never/ be flattened. In particular, Image components, ScrollViews, Text cannot ever be flattened,
so we should always pass `collapsable:false` and the same nativeID prop for those components. For Animated <View>s and other components, the re-rendering issue is still a problem in Fabric for now.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D25720322
fbshipit-source-id: fe3234d8ae974911a2b5f82e4f6a093216f43d4b
2020-12-29 09:33:01 +03:00
|
|
|
options?: AnimatedComponentOptions,
|
2019-10-23 21:40:30 +03:00
|
|
|
): AnimatedComponentType<Props, Instance> {
|
2018-02-14 18:51:52 +03:00
|
|
|
invariant(
|
2018-05-09 10:47:48 +03:00
|
|
|
typeof Component !== 'function' ||
|
2018-02-14 18:51:52 +03:00
|
|
|
(Component.prototype && Component.prototype.isReactComponent),
|
|
|
|
'`createAnimatedComponent` does not support stateless functional components; ' +
|
|
|
|
'use a class component instead.',
|
|
|
|
);
|
|
|
|
|
2017-08-23 03:57:38 +03:00
|
|
|
class AnimatedComponent extends React.Component<Object> {
|
2019-09-10 08:23:07 +03:00
|
|
|
_component: any; // TODO T53738161: flow type this, and the whole file
|
2017-10-31 21:08:19 +03:00
|
|
|
_invokeAnimatedPropsCallbackOnMount: boolean = false;
|
2017-08-23 03:57:38 +03:00
|
|
|
_prevComponent: any;
|
|
|
|
_propsAnimated: AnimatedProps;
|
|
|
|
_eventDetachers: Array<Function> = [];
|
|
|
|
|
2020-07-29 22:37:11 +03:00
|
|
|
// Only to be used in this file, and only in Fabric.
|
2020-10-27 08:12:09 +03:00
|
|
|
_animatedComponentId: string = `${animatedComponentNextId++}:animatedComponent`;
|
2020-07-29 22:37:11 +03:00
|
|
|
|
2017-08-23 03:57:38 +03:00
|
|
|
_attachNativeEvents() {
|
|
|
|
// Make sure to get the scrollable node for components that implement
|
|
|
|
// `ScrollResponder.Mixin`.
|
2019-08-13 06:40:59 +03:00
|
|
|
const scrollableNode = this._component?.getScrollableNode
|
2017-08-23 03:57:38 +03:00
|
|
|
? this._component.getScrollableNode()
|
|
|
|
: this._component;
|
|
|
|
|
|
|
|
for (const key in this.props) {
|
|
|
|
const prop = this.props[key];
|
|
|
|
if (prop instanceof AnimatedEvent && prop.__isNative) {
|
|
|
|
prop.__attach(scrollableNode, key);
|
|
|
|
this._eventDetachers.push(() => prop.__detach(scrollableNode, key));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_detachNativeEvents() {
|
2020-03-25 07:35:58 +03:00
|
|
|
this._eventDetachers.forEach(remove => remove());
|
2017-08-23 03:57:38 +03:00
|
|
|
this._eventDetachers = [];
|
|
|
|
}
|
|
|
|
|
2020-07-29 22:37:11 +03:00
|
|
|
_isFabric = (): boolean => {
|
Reduce re-rendering of Animated components in Fabric
Summary:
The `isFabric` method used in createAnimatedComponent is unreliable (another reason in a long list of reasons why you should not duplicate this code elsewhere, and why we want to delete it ASAP).
In particular, during the first render, the ref component has not been set yet, so we /cannot/ detect if the component is Fabric or non-Fabric and assume it's non-Fabric.
In Fabric, this causes `collapsable` and `nativeID` values to change after the first render.
To reduce this re-rendering, but not eliminate it for all components, I've introduced a flag that indicates if a component will /never/ be flattened. In particular, Image components, ScrollViews, Text cannot ever be flattened,
so we should always pass `collapsable:false` and the same nativeID prop for those components. For Animated <View>s and other components, the re-rendering issue is still a problem in Fabric for now.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D25720322
fbshipit-source-id: fe3234d8ae974911a2b5f82e4f6a093216f43d4b
2020-12-29 09:33:01 +03:00
|
|
|
// When called during the first render, `_component` is always null.
|
|
|
|
// Therefore, even if a component is rendered in Fabric, we can't detect
|
|
|
|
// that until ref is set, which happens sometime after the first render.
|
2021-02-25 03:34:42 +03:00
|
|
|
// In cases where this value switching between "false" and "true" on Fabric
|
|
|
|
// causes issues, add an additional check for _component nullity.
|
2017-10-31 21:08:19 +03:00
|
|
|
if (this._component == null) {
|
2020-07-29 22:37:11 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (
|
2019-09-10 08:23:07 +03:00
|
|
|
// eslint-disable-next-line dot-notation
|
2020-02-06 05:36:20 +03:00
|
|
|
this._component['_internalInstanceHandle']?.stateNode?.canonical !=
|
|
|
|
null ||
|
|
|
|
// Some components have a setNativeProps function but aren't a host component
|
|
|
|
// such as lists like FlatList and SectionList. These should also use
|
|
|
|
// forceUpdate in Fabric since setNativeProps doesn't exist on the underlying
|
|
|
|
// host component. This crazy hack is essentially special casing those lists and
|
|
|
|
// ScrollView itself to use forceUpdate in Fabric.
|
|
|
|
// If these components end up using forwardRef then these hacks can go away
|
|
|
|
// as this._component would actually be the underlying host component and the above check
|
|
|
|
// would be sufficient.
|
|
|
|
(this._component.getNativeScrollRef != null &&
|
|
|
|
this._component.getNativeScrollRef() != null &&
|
|
|
|
// eslint-disable-next-line dot-notation
|
|
|
|
this._component.getNativeScrollRef()['_internalInstanceHandle']
|
|
|
|
?.stateNode?.canonical != null) ||
|
|
|
|
(this._component.getScrollResponder != null &&
|
2020-08-04 11:39:31 +03:00
|
|
|
this._component.getScrollResponder() != null &&
|
2020-02-06 05:36:20 +03:00
|
|
|
this._component.getScrollResponder().getNativeScrollRef != null &&
|
|
|
|
this._component.getScrollResponder().getNativeScrollRef() != null &&
|
|
|
|
this._component.getScrollResponder().getNativeScrollRef()[
|
|
|
|
// eslint-disable-next-line dot-notation
|
|
|
|
'_internalInstanceHandle'
|
|
|
|
]?.stateNode?.canonical != null)
|
2020-07-29 22:37:11 +03:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
_waitForUpdate = (): void => {
|
2021-04-27 13:58:38 +03:00
|
|
|
if (this._isFabric()) {
|
|
|
|
NativeAnimatedHelper.API.setWaitingForIdentifier(
|
|
|
|
this._animatedComponentId,
|
|
|
|
);
|
|
|
|
}
|
2020-07-29 22:37:11 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
_markUpdateComplete = (): void => {
|
2021-04-27 13:58:38 +03:00
|
|
|
if (this._isFabric()) {
|
|
|
|
NativeAnimatedHelper.API.unsetWaitingForIdentifier(
|
|
|
|
this._animatedComponentId,
|
|
|
|
);
|
|
|
|
}
|
2020-07-29 22:37:11 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
// The system is best designed when setNativeProps is implemented. It is
|
|
|
|
// able to avoid re-rendering and directly set the attributes that changed.
|
|
|
|
// However, setNativeProps can only be implemented on leaf native
|
|
|
|
// components. If you want to animate a composite component, you need to
|
|
|
|
// re-render it. In this case, we have a fallback that uses forceUpdate.
|
|
|
|
// This fallback is also called in Fabric.
|
|
|
|
_animatedPropsCallback = () => {
|
|
|
|
if (this._component == null) {
|
|
|
|
// AnimatedProps is created in will-mount because it's used in render.
|
|
|
|
// But this callback may be invoked before mount in async mode,
|
|
|
|
// In which case we should defer the setNativeProps() call.
|
|
|
|
// React may throw away uncommitted work in async mode,
|
|
|
|
// So a deferred call won't always be invoked.
|
|
|
|
this._invokeAnimatedPropsCallbackOnMount = true;
|
|
|
|
} else if (
|
|
|
|
process.env.NODE_ENV === 'test' ||
|
|
|
|
// For animating properties of non-leaf/non-native components
|
|
|
|
typeof this._component.setNativeProps !== 'function' ||
|
|
|
|
// In Fabric, force animations to go through forceUpdate and skip setNativeProps
|
|
|
|
this._isFabric()
|
2017-10-31 21:08:19 +03:00
|
|
|
) {
|
|
|
|
this.forceUpdate();
|
|
|
|
} else if (!this._propsAnimated.__isNative) {
|
|
|
|
this._component.setNativeProps(
|
|
|
|
this._propsAnimated.__getAnimatedValue(),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new Error(
|
|
|
|
'Attempting to run JS driven animation on animated ' +
|
|
|
|
'node that has been moved to "native" earlier by starting an ' +
|
|
|
|
'animation with `useNativeDriver: true`',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-08-23 03:57:38 +03:00
|
|
|
_attachProps(nextProps) {
|
|
|
|
const oldPropsAnimated = this._propsAnimated;
|
|
|
|
|
2017-10-31 21:08:19 +03:00
|
|
|
this._propsAnimated = new AnimatedProps(
|
|
|
|
nextProps,
|
|
|
|
this._animatedPropsCallback,
|
|
|
|
);
|
2021-05-11 03:01:43 +03:00
|
|
|
this._propsAnimated.__attach();
|
2017-08-23 03:57:38 +03:00
|
|
|
|
|
|
|
// When you call detach, it removes the element from the parent list
|
|
|
|
// of children. If it goes to 0, then the parent also detaches itself
|
|
|
|
// and so on.
|
|
|
|
// An optimization is to attach the new elements and THEN detach the old
|
|
|
|
// ones instead of detaching and THEN attaching.
|
|
|
|
// This way the intermediate state isn't to go to 0 and trigger
|
|
|
|
// this expensive recursive detaching to then re-attach everything on
|
|
|
|
// the very next operation.
|
2019-11-05 02:37:45 +03:00
|
|
|
if (oldPropsAnimated) {
|
|
|
|
oldPropsAnimated.__restoreDefaultValues();
|
|
|
|
oldPropsAnimated.__detach();
|
|
|
|
}
|
2017-08-23 03:57:38 +03:00
|
|
|
}
|
|
|
|
|
2019-11-04 05:00:15 +03:00
|
|
|
_setComponentRef = setAndForwardRef({
|
|
|
|
getForwardedRef: () => this.props.forwardedRef,
|
2020-03-25 07:35:58 +03:00
|
|
|
setLocalRef: ref => {
|
2019-11-04 05:00:15 +03:00
|
|
|
this._prevComponent = this._component;
|
|
|
|
this._component = ref;
|
|
|
|
},
|
|
|
|
});
|
2017-08-23 03:57:38 +03:00
|
|
|
|
|
|
|
render() {
|
2020-06-10 02:30:56 +03:00
|
|
|
const {style = {}, ...props} = this._propsAnimated.__getValue() || {};
|
|
|
|
const {style: passthruStyle = {}, ...passthruProps} =
|
|
|
|
this.props.passthroughAnimatedPropExplicitValues || {};
|
|
|
|
const mergedStyle = {...style, ...passthruStyle};
|
2021-02-25 03:34:42 +03:00
|
|
|
|
|
|
|
// On Fabric, we always want to ensure the container Animated View is *not*
|
|
|
|
// flattened.
|
|
|
|
// Because we do not get a host component ref immediately and thus cannot
|
|
|
|
// do a proper Fabric vs non-Fabric detection immediately, we default to assuming
|
|
|
|
// that Fabric *is* enabled until we know otherwise.
|
|
|
|
// Thus, in Fabric, this view will never be flattened. In non-Fabric, the view will
|
|
|
|
// not be flattened during the initial render but may be flattened in the second render
|
|
|
|
// and onwards.
|
|
|
|
const forceNativeIdFabric =
|
|
|
|
(this._component == null &&
|
|
|
|
(options?.collapsable === false || props.collapsable !== true)) ||
|
|
|
|
this._isFabric();
|
|
|
|
|
Reduce re-rendering of Animated components in Fabric
Summary:
The `isFabric` method used in createAnimatedComponent is unreliable (another reason in a long list of reasons why you should not duplicate this code elsewhere, and why we want to delete it ASAP).
In particular, during the first render, the ref component has not been set yet, so we /cannot/ detect if the component is Fabric or non-Fabric and assume it's non-Fabric.
In Fabric, this causes `collapsable` and `nativeID` values to change after the first render.
To reduce this re-rendering, but not eliminate it for all components, I've introduced a flag that indicates if a component will /never/ be flattened. In particular, Image components, ScrollViews, Text cannot ever be flattened,
so we should always pass `collapsable:false` and the same nativeID prop for those components. For Animated <View>s and other components, the re-rendering issue is still a problem in Fabric for now.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D25720322
fbshipit-source-id: fe3234d8ae974911a2b5f82e4f6a093216f43d4b
2020-12-29 09:33:01 +03:00
|
|
|
const forceNativeId =
|
|
|
|
props.collapsable ??
|
|
|
|
(this._propsAnimated.__isNative ||
|
2021-02-25 03:34:42 +03:00
|
|
|
forceNativeIdFabric ||
|
Reduce re-rendering of Animated components in Fabric
Summary:
The `isFabric` method used in createAnimatedComponent is unreliable (another reason in a long list of reasons why you should not duplicate this code elsewhere, and why we want to delete it ASAP).
In particular, during the first render, the ref component has not been set yet, so we /cannot/ detect if the component is Fabric or non-Fabric and assume it's non-Fabric.
In Fabric, this causes `collapsable` and `nativeID` values to change after the first render.
To reduce this re-rendering, but not eliminate it for all components, I've introduced a flag that indicates if a component will /never/ be flattened. In particular, Image components, ScrollViews, Text cannot ever be flattened,
so we should always pass `collapsable:false` and the same nativeID prop for those components. For Animated <View>s and other components, the re-rendering issue is still a problem in Fabric for now.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D25720322
fbshipit-source-id: fe3234d8ae974911a2b5f82e4f6a093216f43d4b
2020-12-29 09:33:01 +03:00
|
|
|
options?.collapsable === false);
|
|
|
|
// The native driver updates views directly through the UI thread so we
|
|
|
|
// have to make sure the view doesn't get optimized away because it cannot
|
|
|
|
// go through the NativeViewHierarchyManager since it operates on the shadow
|
|
|
|
// thread. TODO: T68258846
|
|
|
|
const collapsableProps = forceNativeId
|
|
|
|
? {
|
|
|
|
nativeID: props.nativeID ?? 'animatedComponent',
|
|
|
|
collapsable: false,
|
|
|
|
}
|
|
|
|
: {};
|
2017-08-23 03:57:38 +03:00
|
|
|
return (
|
|
|
|
<Component
|
|
|
|
{...props}
|
2020-06-10 02:30:56 +03:00
|
|
|
{...passthruProps}
|
Reduce re-rendering of Animated components in Fabric
Summary:
The `isFabric` method used in createAnimatedComponent is unreliable (another reason in a long list of reasons why you should not duplicate this code elsewhere, and why we want to delete it ASAP).
In particular, during the first render, the ref component has not been set yet, so we /cannot/ detect if the component is Fabric or non-Fabric and assume it's non-Fabric.
In Fabric, this causes `collapsable` and `nativeID` values to change after the first render.
To reduce this re-rendering, but not eliminate it for all components, I've introduced a flag that indicates if a component will /never/ be flattened. In particular, Image components, ScrollViews, Text cannot ever be flattened,
so we should always pass `collapsable:false` and the same nativeID prop for those components. For Animated <View>s and other components, the re-rendering issue is still a problem in Fabric for now.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D25720322
fbshipit-source-id: fe3234d8ae974911a2b5f82e4f6a093216f43d4b
2020-12-29 09:33:01 +03:00
|
|
|
{...collapsableProps}
|
2020-06-10 02:30:56 +03:00
|
|
|
style={mergedStyle}
|
2017-08-23 03:57:38 +03:00
|
|
|
ref={this._setComponentRef}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-03-16 01:09:19 +03:00
|
|
|
UNSAFE_componentWillMount() {
|
|
|
|
this._waitForUpdate();
|
|
|
|
this._attachProps(this.props);
|
|
|
|
}
|
|
|
|
|
2019-11-03 22:57:59 +03:00
|
|
|
componentDidMount() {
|
|
|
|
if (this._invokeAnimatedPropsCallbackOnMount) {
|
|
|
|
this._invokeAnimatedPropsCallbackOnMount = false;
|
|
|
|
this._animatedPropsCallback();
|
|
|
|
}
|
|
|
|
|
|
|
|
this._propsAnimated.setNativeView(this._component);
|
|
|
|
this._attachNativeEvents();
|
2020-07-29 22:37:11 +03:00
|
|
|
this._markUpdateComplete();
|
2017-08-23 03:57:38 +03:00
|
|
|
}
|
|
|
|
|
2021-03-16 01:09:19 +03:00
|
|
|
UNSAFE_componentWillReceiveProps(newProps) {
|
|
|
|
this._waitForUpdate();
|
|
|
|
this._attachProps(newProps);
|
|
|
|
}
|
|
|
|
|
2019-11-03 22:57:59 +03:00
|
|
|
componentDidUpdate(prevProps) {
|
|
|
|
if (this._component !== this._prevComponent) {
|
|
|
|
this._propsAnimated.setNativeView(this._component);
|
2017-08-23 03:57:38 +03:00
|
|
|
}
|
2019-11-03 22:57:59 +03:00
|
|
|
if (this._component !== this._prevComponent || prevProps !== this.props) {
|
|
|
|
this._detachNativeEvents();
|
|
|
|
this._attachNativeEvents();
|
2017-08-23 03:57:38 +03:00
|
|
|
}
|
2020-07-29 22:37:11 +03:00
|
|
|
this._markUpdateComplete();
|
2019-11-03 22:57:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this._propsAnimated && this._propsAnimated.__detach();
|
|
|
|
this._detachNativeEvents();
|
2020-07-29 22:37:11 +03:00
|
|
|
this._markUpdateComplete();
|
2021-02-25 04:12:58 +03:00
|
|
|
this._component = null;
|
|
|
|
this._prevComponent = null;
|
2019-11-03 22:57:59 +03:00
|
|
|
}
|
|
|
|
}
|
2017-08-23 03:57:38 +03:00
|
|
|
|
2019-11-04 05:00:15 +03:00
|
|
|
return React.forwardRef(function AnimatedComponentWrapper(props, ref) {
|
|
|
|
return (
|
|
|
|
<AnimatedComponent
|
|
|
|
{...props}
|
|
|
|
{...(ref == null ? null : {forwardedRef: ref})}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
});
|
2017-08-23 03:57:38 +03:00
|
|
|
}
|
|
|
|
|
2021-06-03 08:34:41 +03:00
|
|
|
// $FlowIgnore[incompatible-cast] - Will be compatible after refactors.
|
|
|
|
module.exports = (createAnimatedComponentInjection.recordAndRetrieve() ??
|
|
|
|
createAnimatedComponent: typeof createAnimatedComponent);
|