yeet
This commit is contained in:
223
node_modules/react-native/Libraries/Animated/src/createAnimatedComponent.js
generated
vendored
Normal file
223
node_modules/react-native/Libraries/Animated/src/createAnimatedComponent.js
generated
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {AnimatedEvent} = require('./AnimatedEvent');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const React = require('react');
|
||||
|
||||
const invariant = require('invariant');
|
||||
const setAndForwardRef = require('../../Utilities/setAndForwardRef');
|
||||
|
||||
export type AnimatedComponentType<
|
||||
Props: {+[string]: mixed, ...},
|
||||
Instance,
|
||||
> = React.AbstractComponent<$ObjMap<Props, () => any>, Instance>;
|
||||
|
||||
function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
||||
Component: React.AbstractComponent<Props, Instance>,
|
||||
): AnimatedComponentType<Props, Instance> {
|
||||
invariant(
|
||||
typeof Component !== 'function' ||
|
||||
(Component.prototype && Component.prototype.isReactComponent),
|
||||
'`createAnimatedComponent` does not support stateless functional components; ' +
|
||||
'use a class component instead.',
|
||||
);
|
||||
|
||||
class AnimatedComponent extends React.Component<Object> {
|
||||
_component: any; // TODO T53738161: flow type this, and the whole file
|
||||
_invokeAnimatedPropsCallbackOnMount: boolean = false;
|
||||
_prevComponent: any;
|
||||
_propsAnimated: AnimatedProps;
|
||||
_eventDetachers: Array<Function> = [];
|
||||
|
||||
_attachNativeEvents() {
|
||||
// Make sure to get the scrollable node for components that implement
|
||||
// `ScrollResponder.Mixin`.
|
||||
const scrollableNode = this._component?.getScrollableNode
|
||||
? 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() {
|
||||
this._eventDetachers.forEach(remove => remove());
|
||||
this._eventDetachers = [];
|
||||
}
|
||||
|
||||
// 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.
|
||||
_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
|
||||
// eslint-disable-next-line dot-notation
|
||||
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 &&
|
||||
this._component.getScrollResponder().getNativeScrollRef != null &&
|
||||
this._component.getScrollResponder().getNativeScrollRef() != null &&
|
||||
this._component.getScrollResponder().getNativeScrollRef()[
|
||||
// eslint-disable-next-line dot-notation
|
||||
'_internalInstanceHandle'
|
||||
]?.stateNode?.canonical != null)
|
||||
) {
|
||||
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`',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
_attachProps(nextProps) {
|
||||
const oldPropsAnimated = this._propsAnimated;
|
||||
|
||||
this._propsAnimated = new AnimatedProps(
|
||||
nextProps,
|
||||
this._animatedPropsCallback,
|
||||
);
|
||||
|
||||
// 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.
|
||||
if (oldPropsAnimated) {
|
||||
oldPropsAnimated.__restoreDefaultValues();
|
||||
oldPropsAnimated.__detach();
|
||||
}
|
||||
}
|
||||
|
||||
_setComponentRef = setAndForwardRef({
|
||||
getForwardedRef: () => this.props.forwardedRef,
|
||||
setLocalRef: ref => {
|
||||
this._prevComponent = this._component;
|
||||
this._component = ref;
|
||||
|
||||
// TODO: Delete this in a future release.
|
||||
if (ref != null && ref.getNode == null) {
|
||||
ref.getNode = () => {
|
||||
console.warn(
|
||||
'%s: Calling `getNode()` on the ref of an Animated component ' +
|
||||
'is no longer necessary. You can now directly use the ref ' +
|
||||
'instead. This method will be removed in a future release.',
|
||||
ref.constructor.name ?? '<<anonymous>>',
|
||||
);
|
||||
return ref;
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
render() {
|
||||
const props = this._propsAnimated.__getValue();
|
||||
return (
|
||||
<Component
|
||||
{...props}
|
||||
ref={this._setComponentRef}
|
||||
// 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.
|
||||
collapsable={
|
||||
this._propsAnimated.__isNative ? false : props.collapsable
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this._attachProps(this.props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this._invokeAnimatedPropsCallbackOnMount) {
|
||||
this._invokeAnimatedPropsCallbackOnMount = false;
|
||||
this._animatedPropsCallback();
|
||||
}
|
||||
|
||||
this._propsAnimated.setNativeView(this._component);
|
||||
this._attachNativeEvents();
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps) {
|
||||
this._attachProps(newProps);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this._component !== this._prevComponent) {
|
||||
this._propsAnimated.setNativeView(this._component);
|
||||
}
|
||||
if (this._component !== this._prevComponent || prevProps !== this.props) {
|
||||
this._detachNativeEvents();
|
||||
this._attachNativeEvents();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._propsAnimated && this._propsAnimated.__detach();
|
||||
this._detachNativeEvents();
|
||||
}
|
||||
}
|
||||
|
||||
return React.forwardRef(function AnimatedComponentWrapper(props, ref) {
|
||||
return (
|
||||
<AnimatedComponent
|
||||
{...props}
|
||||
{...(ref == null ? null : {forwardedRef: ref})}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = createAnimatedComponent;
|
Reference in New Issue
Block a user