chore: update map
This commit is contained in:
+6
-76
@@ -1,81 +1,11 @@
|
||||
'use strict';
|
||||
import type { Extrapolate as _Extrapolate } from './reanimated2/interpolateColor';
|
||||
import type { SharedValue as _SharedValue } from './reanimated2/commonTypes';
|
||||
import type { DerivedValue as _DerivedValue } from './reanimated2/hook/useDerivedValue';
|
||||
import type {
|
||||
TransformStyleTypes as _TransformStyleTypes,
|
||||
Adaptable as _Adaptable,
|
||||
AdaptTransforms as _AdaptTransforms,
|
||||
AnimatedTransform as _AnimatedTransform,
|
||||
AnimateStyle as _AnimateStyle,
|
||||
StylesOrDefault as _StylesOrDefault,
|
||||
AnimateProps as _AnimateProps,
|
||||
} from './reanimated2/helperTypes';
|
||||
import type { EasingFunction as _EasingFunction } from './reanimated2/Easing';
|
||||
|
||||
import type { AnimatedScrollViewProps as _AnimatedScrollViewProps } from './reanimated2/component/ScrollView';
|
||||
import type { FlatListPropsWithLayout as _FlatListPropsWithLayout } from './reanimated2/component/FlatList';
|
||||
|
||||
export { createAnimatedComponent } from './createAnimatedComponent';
|
||||
export { AnimatedText as Text } from './reanimated2/component/Text';
|
||||
export { AnimatedView as View } from './reanimated2/component/View';
|
||||
export { AnimatedScrollView as ScrollView } from './reanimated2/component/ScrollView';
|
||||
export { AnimatedImage as Image } from './reanimated2/component/Image';
|
||||
export { ReanimatedFlatList as FlatList } from './reanimated2/component/FlatList';
|
||||
export { ReanimatedFlatList as FlatList } from './component/FlatList';
|
||||
export { AnimatedImage as Image } from './component/Image';
|
||||
export { AnimatedScrollView as ScrollView } from './component/ScrollView';
|
||||
export { AnimatedText as Text } from './component/Text';
|
||||
export { AnimatedView as View } from './component/View';
|
||||
export {
|
||||
addWhitelistedNativeProps,
|
||||
addWhitelistedUIProps,
|
||||
} from './ConfigHelper';
|
||||
/**
|
||||
* @deprecated Please import `Extrapolate` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
*/
|
||||
export type Extrapolate = typeof _Extrapolate;
|
||||
/**
|
||||
* @deprecated Please import `SharedValue` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
*/
|
||||
|
||||
export type SharedValue<T> = _SharedValue<T>;
|
||||
/**
|
||||
* @deprecated Please import `DerivedValue` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
*/
|
||||
export type DerivedValue<T> = _DerivedValue<T>;
|
||||
/**
|
||||
* @deprecated Please import `Adaptable` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
*/
|
||||
export type Adaptable<T> = _Adaptable<T>;
|
||||
/**
|
||||
* @deprecated Please import `TransformStyleTypes` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type TransformStyleTypes = _TransformStyleTypes;
|
||||
/**
|
||||
* @deprecated Please import `AdaptTransforms` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type AdaptTransforms<T> = _AdaptTransforms<T>;
|
||||
/**
|
||||
* @deprecated Please import `AnimatedTransform` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
*/
|
||||
export type AnimatedTransform = _AnimatedTransform;
|
||||
/**
|
||||
* @deprecated Please import `AnimateStyle` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type AnimateStyle<S> = _AnimateStyle<S>;
|
||||
/**
|
||||
* @deprecated Please import `StylesOrDefault` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type StylesOrDefault<S> = _StylesOrDefault<S>;
|
||||
/**
|
||||
* @deprecated Please import `AnimateProps` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type AnimateProps<P extends object> = _AnimateProps<P>;
|
||||
/**
|
||||
* @deprecated Please import `EasingFunction` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type EasingFunction = _EasingFunction;
|
||||
/**
|
||||
* @deprecated Please import `AnimatedScrollViewProps` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type AnimatedScrollViewProps = _AnimatedScrollViewProps;
|
||||
/**
|
||||
* @deprecated Please import `FlatListPropsWithLayout` directly from `react-native-reanimated` instead of `Animated` namespace.
|
||||
* */
|
||||
export type FlatListPropsWithLayout<T> = _FlatListPropsWithLayout<T>;
|
||||
export { createAnimatedComponent } from './createAnimatedComponent';
|
||||
|
||||
+28
-74
@@ -1,87 +1,41 @@
|
||||
'use strict';
|
||||
import { PropsAllowlists } from './propsAllowlists';
|
||||
import { jsiConfigureProps } from './reanimated2/core';
|
||||
function assertNoOverlapInLists() {
|
||||
for (const key in PropsAllowlists.NATIVE_THREAD_PROPS_WHITELIST) {
|
||||
if (key in PropsAllowlists.UI_THREAD_PROPS_WHITELIST) {
|
||||
throw new Error(
|
||||
`[Reanimated] Property \`${key}\` was whitelisted both as UI and native prop. Please remove it from one of the lists.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
import { executeOnUIRuntimeSync } from 'react-native-worklets';
|
||||
|
||||
function configureProps(): void {
|
||||
assertNoOverlapInLists();
|
||||
jsiConfigureProps(
|
||||
Object.keys(PropsAllowlists.UI_THREAD_PROPS_WHITELIST),
|
||||
Object.keys(PropsAllowlists.NATIVE_THREAD_PROPS_WHITELIST)
|
||||
);
|
||||
}
|
||||
import type { LoggerConfig } from './common';
|
||||
import {
|
||||
getLoggerConfig,
|
||||
SHOULD_BE_USE_WEB,
|
||||
updateLoggerConfig,
|
||||
} from './common';
|
||||
|
||||
/** @deprecated This function is a no-op in Reanimated 4. */
|
||||
export function addWhitelistedNativeProps(
|
||||
props: Record<string, boolean>
|
||||
_props: Record<string, boolean>
|
||||
): void {
|
||||
const oldSize = Object.keys(
|
||||
PropsAllowlists.NATIVE_THREAD_PROPS_WHITELIST
|
||||
).length;
|
||||
PropsAllowlists.NATIVE_THREAD_PROPS_WHITELIST = {
|
||||
...PropsAllowlists.NATIVE_THREAD_PROPS_WHITELIST,
|
||||
...props,
|
||||
};
|
||||
if (
|
||||
oldSize !==
|
||||
Object.keys(PropsAllowlists.NATIVE_THREAD_PROPS_WHITELIST).length
|
||||
) {
|
||||
configureProps();
|
||||
}
|
||||
// Do nothing. This is just for backward compatibility.
|
||||
}
|
||||
|
||||
export function addWhitelistedUIProps(props: Record<string, boolean>): void {
|
||||
const oldSize = Object.keys(PropsAllowlists.UI_THREAD_PROPS_WHITELIST).length;
|
||||
PropsAllowlists.UI_THREAD_PROPS_WHITELIST = {
|
||||
...PropsAllowlists.UI_THREAD_PROPS_WHITELIST,
|
||||
...props,
|
||||
};
|
||||
if (
|
||||
oldSize !== Object.keys(PropsAllowlists.UI_THREAD_PROPS_WHITELIST).length
|
||||
) {
|
||||
configureProps();
|
||||
}
|
||||
/** @deprecated This function is a no-op in Reanimated 4. */
|
||||
export function addWhitelistedUIProps(_props: Record<string, boolean>): void {
|
||||
// Do nothing. This is just for backward compatibility.
|
||||
}
|
||||
|
||||
const PROCESSED_VIEW_NAMES = new Set();
|
||||
|
||||
export interface ViewConfig {
|
||||
uiViewClassName: string;
|
||||
validAttributes: Record<string, unknown>;
|
||||
}
|
||||
/**
|
||||
* updates UI props whitelist for given view host instance
|
||||
* this will work just once for every view name
|
||||
* Updates Reanimated logger config with the user-provided configuration. Will
|
||||
* affect Reanimated code executed after call to this function so it should be
|
||||
* called before any Reanimated code is executed to take effect. Each call to
|
||||
* this function will override the previous configuration (it's recommended to
|
||||
* call it only once).
|
||||
*
|
||||
* @param config - The new logger configuration to apply.
|
||||
*/
|
||||
|
||||
export function adaptViewConfig(viewConfig: ViewConfig): void {
|
||||
const viewName = viewConfig.uiViewClassName;
|
||||
const props = viewConfig.validAttributes;
|
||||
|
||||
// update whitelist of UI props for this view name only once
|
||||
if (!PROCESSED_VIEW_NAMES.has(viewName)) {
|
||||
const propsToAdd: Record<string, boolean> = {};
|
||||
Object.keys(props).forEach((key) => {
|
||||
// we don't want to add native props as they affect layout
|
||||
// we also skip props which repeat here
|
||||
if (
|
||||
!(key in PropsAllowlists.NATIVE_THREAD_PROPS_WHITELIST) &&
|
||||
!(key in PropsAllowlists.UI_THREAD_PROPS_WHITELIST)
|
||||
) {
|
||||
propsToAdd[key] = true;
|
||||
}
|
||||
});
|
||||
addWhitelistedUIProps(propsToAdd);
|
||||
|
||||
PROCESSED_VIEW_NAMES.add(viewName);
|
||||
export function configureReanimatedLogger(config: LoggerConfig) {
|
||||
// Get the current config from the React runtime (to have a single source of truth)
|
||||
const currentConfig = getLoggerConfig();
|
||||
// Update the configuration object in the React runtime
|
||||
updateLoggerConfig(currentConfig, config);
|
||||
// Register the updated configuration in the UI runtime
|
||||
if (!SHOULD_BE_USE_WEB) {
|
||||
executeOnUIRuntimeSync(updateLoggerConfig)(currentConfig, config);
|
||||
}
|
||||
}
|
||||
|
||||
configureProps();
|
||||
|
||||
+59
-19
@@ -1,12 +1,14 @@
|
||||
'use strict';
|
||||
import { logger } from './common';
|
||||
import type {
|
||||
ILayoutAnimationBuilder,
|
||||
LayoutAnimationFunction,
|
||||
LayoutAnimationsValues,
|
||||
} from './reanimated2/layoutReanimation';
|
||||
import type { StyleProps } from './reanimated2/commonTypes';
|
||||
LayoutAnimationValues,
|
||||
StyleProps,
|
||||
} from './commonTypes';
|
||||
import type { NestedArray } from './createAnimatedComponent/commonTypes';
|
||||
|
||||
const mockTargetValues: LayoutAnimationsValues = {
|
||||
const mockTargetValues: LayoutAnimationValues = {
|
||||
targetOriginX: 0,
|
||||
targetOriginY: 0,
|
||||
targetWidth: 0,
|
||||
@@ -25,12 +27,57 @@ const mockTargetValues: LayoutAnimationsValues = {
|
||||
currentBorderRadius: 0,
|
||||
};
|
||||
|
||||
function getCommonProperties(
|
||||
layoutStyle: StyleProps,
|
||||
componentStyle: NestedArray<StyleProps>
|
||||
) {
|
||||
let componentStyleFlat = Array.isArray(componentStyle)
|
||||
? componentStyle.flat()
|
||||
: [componentStyle];
|
||||
|
||||
componentStyleFlat = componentStyleFlat.filter(Boolean);
|
||||
|
||||
componentStyleFlat = componentStyleFlat.map((style) =>
|
||||
'initial' in style
|
||||
? style.initial.value // Include properties of animated style
|
||||
: style
|
||||
);
|
||||
|
||||
const componentStylesKeys = componentStyleFlat.flatMap((style) =>
|
||||
Object.keys(style)
|
||||
);
|
||||
|
||||
const commonKeys = Object.keys(layoutStyle).filter((key) =>
|
||||
componentStylesKeys.includes(key)
|
||||
);
|
||||
|
||||
return commonKeys;
|
||||
}
|
||||
|
||||
function maybeReportOverwrittenProperties(
|
||||
layoutAnimationStyle: StyleProps,
|
||||
style: NestedArray<StyleProps>,
|
||||
displayName: string
|
||||
) {
|
||||
const commonProperties = getCommonProperties(layoutAnimationStyle, style);
|
||||
|
||||
if (commonProperties.length > 0) {
|
||||
logger.warn(
|
||||
`${
|
||||
commonProperties.length === 1 ? 'Property' : 'Properties'
|
||||
} "${commonProperties.join(
|
||||
', '
|
||||
)}" of ${displayName} may be overwritten by a layout animation. Please wrap your component with an animated view and apply the layout animation on the wrapper.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function maybeBuild(
|
||||
layoutAnimationOrBuilder:
|
||||
| ILayoutAnimationBuilder
|
||||
| LayoutAnimationFunction
|
||||
| Keyframe,
|
||||
style: StyleProps | undefined,
|
||||
style: NestedArray<StyleProps> | undefined,
|
||||
displayName: string
|
||||
): LayoutAnimationFunction | Keyframe {
|
||||
const isAnimationBuilder = (
|
||||
@@ -41,24 +88,17 @@ export function maybeBuild(
|
||||
|
||||
if (isAnimationBuilder(layoutAnimationOrBuilder)) {
|
||||
const animationFactory = layoutAnimationOrBuilder.build();
|
||||
const layoutAnimation = animationFactory(mockTargetValues);
|
||||
const animatedStyle = layoutAnimation.animations;
|
||||
|
||||
const getCommonProperties = (obj1: object, obj2: object) =>
|
||||
Object.keys(obj1).filter((key) =>
|
||||
Object.prototype.hasOwnProperty.call(obj2, key)
|
||||
);
|
||||
|
||||
const commonProperties = getCommonProperties(animatedStyle, style || {});
|
||||
if (commonProperties.length > 0) {
|
||||
console.warn(
|
||||
`[Reanimated] ${
|
||||
commonProperties.length === 1 ? 'Property' : 'Properties: '
|
||||
} "${commonProperties}" of ${displayName} may be overwritten with layout animation. Please create a wrapper with the layout animation you want to apply.`
|
||||
if (__DEV__ && style) {
|
||||
const layoutAnimation = animationFactory(mockTargetValues);
|
||||
maybeReportOverwrittenProperties(
|
||||
layoutAnimation.animations,
|
||||
style,
|
||||
displayName
|
||||
);
|
||||
}
|
||||
|
||||
return layoutAnimationOrBuilder.build();
|
||||
return animationFactory;
|
||||
} else {
|
||||
return layoutAnimationOrBuilder;
|
||||
}
|
||||
|
||||
frontend-admin/node_modules/react-native-reanimated/src/createAnimatedComponent/InlinePropManager.ts
Generated
Vendored
+32
-50
@@ -1,24 +1,17 @@
|
||||
'use strict';
|
||||
import type { StyleProps } from '../reanimated2';
|
||||
import type { StyleProps } from '../commonTypes';
|
||||
import { isSharedValue } from '../isSharedValue';
|
||||
import { startMapper, stopMapper } from '../mappers';
|
||||
import { updateProps } from '../updateProps';
|
||||
import type { ViewDescriptorsSet } from '../ViewDescriptorsSet';
|
||||
import { makeViewDescriptorsSet } from '../ViewDescriptorsSet';
|
||||
import type {
|
||||
IAnimatedComponentInternal,
|
||||
AnimatedComponentProps,
|
||||
AnimatedComponentType,
|
||||
IInlinePropManager,
|
||||
ViewInfo,
|
||||
} from './commonTypes';
|
||||
import { flattenArray } from './utils';
|
||||
import { makeViewDescriptorsSet } from '../reanimated2/ViewDescriptorsSet';
|
||||
import type {
|
||||
ViewDescriptorsSet,
|
||||
ViewRefSet,
|
||||
} from '../reanimated2/ViewDescriptorsSet';
|
||||
import { adaptViewConfig } from '../ConfigHelper';
|
||||
import updateProps from '../reanimated2/UpdateProps';
|
||||
import { stopMapper, startMapper } from '../reanimated2/mappers';
|
||||
import { isSharedValue } from '../reanimated2/isSharedValue';
|
||||
import { shouldBeUseWeb } from '../reanimated2/PlatformChecker';
|
||||
|
||||
const SHOULD_BE_USE_WEB = shouldBeUseWeb();
|
||||
|
||||
function isInlineStyleTransform(transform: unknown): boolean {
|
||||
if (!Array.isArray(transform)) {
|
||||
@@ -37,29 +30,30 @@ function inlinePropsHasChanged(
|
||||
}
|
||||
|
||||
for (const key of Object.keys(styles1)) {
|
||||
if (styles1[key] !== styles2[key]) return true;
|
||||
if (styles1[key] !== styles2[key]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getInlinePropsUpdate(inlineProps: Record<string, unknown>) {
|
||||
function getInlinePropsUpdate(styleValue: StyleProps): unknown {
|
||||
'worklet';
|
||||
const update: Record<string, unknown> = {};
|
||||
for (const [key, styleValue] of Object.entries(inlineProps)) {
|
||||
if (isSharedValue(styleValue)) {
|
||||
update[key] = styleValue.value;
|
||||
} else if (Array.isArray(styleValue)) {
|
||||
update[key] = styleValue.map((item) => {
|
||||
return getInlinePropsUpdate(item);
|
||||
});
|
||||
} else if (typeof styleValue === 'object') {
|
||||
update[key] = getInlinePropsUpdate(styleValue as Record<string, unknown>);
|
||||
} else {
|
||||
update[key] = styleValue;
|
||||
}
|
||||
if (isSharedValue(styleValue)) {
|
||||
return styleValue.value;
|
||||
}
|
||||
return update;
|
||||
if (Array.isArray(styleValue)) {
|
||||
return styleValue.map(getInlinePropsUpdate);
|
||||
}
|
||||
if (styleValue && typeof styleValue === 'object') {
|
||||
const update: Record<string, unknown> = {};
|
||||
for (const [key, value] of Object.entries(styleValue)) {
|
||||
update[key] = getInlinePropsUpdate(value);
|
||||
}
|
||||
return update;
|
||||
}
|
||||
return styleValue;
|
||||
}
|
||||
|
||||
function extractSharedValuesMapFromProps(
|
||||
@@ -77,14 +71,14 @@ function extractSharedValuesMapFromProps(
|
||||
if (!style) {
|
||||
return;
|
||||
}
|
||||
for (const [key, styleValue] of Object.entries(style)) {
|
||||
for (const [styleKey, styleValue] of Object.entries(style)) {
|
||||
if (isSharedValue(styleValue)) {
|
||||
inlineProps[key] = styleValue;
|
||||
inlineProps[styleKey] = styleValue;
|
||||
} else if (
|
||||
key === 'transform' &&
|
||||
styleKey === 'transform' &&
|
||||
isInlineStyleTransform(styleValue)
|
||||
) {
|
||||
inlineProps[key] = styleValue;
|
||||
inlineProps[styleKey] = styleValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -114,7 +108,7 @@ export function getInlineStyle(
|
||||
isFirstRender: boolean
|
||||
) {
|
||||
if (isFirstRender) {
|
||||
return getInlinePropsUpdate(style);
|
||||
return getInlinePropsUpdate(style) as Record<string, unknown>;
|
||||
}
|
||||
const newStyle: StyleProps = {};
|
||||
for (const [key, styleValue] of Object.entries(style)) {
|
||||
@@ -134,8 +128,7 @@ export class InlinePropManager implements IInlinePropManager {
|
||||
_inlineProps: StyleProps = {};
|
||||
|
||||
public attachInlineProps(
|
||||
animatedComponent: React.Component<unknown, unknown> &
|
||||
IAnimatedComponentInternal,
|
||||
animatedComponent: AnimatedComponentType,
|
||||
viewInfo: ViewInfo
|
||||
) {
|
||||
const newInlineProps: Record<string, unknown> =
|
||||
@@ -146,31 +139,20 @@ export class InlinePropManager implements IInlinePropManager {
|
||||
if (!this._inlinePropsViewDescriptors) {
|
||||
this._inlinePropsViewDescriptors = makeViewDescriptorsSet();
|
||||
|
||||
const { viewTag, viewName, shadowNodeWrapper, viewConfig } = viewInfo;
|
||||
|
||||
if (Object.keys(newInlineProps).length && viewConfig) {
|
||||
adaptViewConfig(viewConfig);
|
||||
}
|
||||
const { viewTag, shadowNodeWrapper } = viewInfo;
|
||||
|
||||
this._inlinePropsViewDescriptors.add({
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
tag: viewTag as number,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
name: viewName!,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
shadowNodeWrapper: shadowNodeWrapper!,
|
||||
});
|
||||
}
|
||||
const shareableViewDescriptors =
|
||||
this._inlinePropsViewDescriptors.shareableViewDescriptors;
|
||||
|
||||
const maybeViewRef = SHOULD_BE_USE_WEB
|
||||
? ({ items: new Set([animatedComponent]) } as ViewRefSet<unknown>) // see makeViewsRefSet
|
||||
: undefined;
|
||||
const updaterFunction = () => {
|
||||
'worklet';
|
||||
const update = getInlinePropsUpdate(newInlineProps);
|
||||
updateProps(shareableViewDescriptors, update, maybeViewRef);
|
||||
updateProps(shareableViewDescriptors, update);
|
||||
};
|
||||
this._inlineProps = newInlineProps;
|
||||
if (this._inlinePropsMapperId) {
|
||||
|
||||
Generated
Vendored
+42
-108
@@ -1,124 +1,55 @@
|
||||
'use strict';
|
||||
import {
|
||||
NativeEventEmitter,
|
||||
NativeModules,
|
||||
findNodeHandle,
|
||||
} from 'react-native';
|
||||
import { shouldBeUseWeb } from '../reanimated2/PlatformChecker';
|
||||
import type { StyleProps } from '../reanimated2';
|
||||
import { runOnJS, runOnUIImmediately } from '../reanimated2/threads';
|
||||
import { runOnUI } from 'react-native-worklets';
|
||||
|
||||
import { SHOULD_BE_USE_WEB } from '../common';
|
||||
import type {
|
||||
AnimatedComponentProps,
|
||||
AnimatedComponentType,
|
||||
IAnimatedComponentInternal,
|
||||
IJSPropsUpdater,
|
||||
InitialComponentProps,
|
||||
JSPropsOperation,
|
||||
} from './commonTypes';
|
||||
|
||||
interface ListenerData {
|
||||
viewTag: number;
|
||||
props: StyleProps;
|
||||
}
|
||||
class JSPropsUpdaterNative implements IJSPropsUpdater {
|
||||
private static _tagToComponentMapping = new Map<
|
||||
number,
|
||||
AnimatedComponentType
|
||||
>();
|
||||
|
||||
const SHOULD_BE_USE_WEB = shouldBeUseWeb();
|
||||
|
||||
class JSPropsUpdaterPaper implements IJSPropsUpdater {
|
||||
private static _tagToComponentMapping = new Map();
|
||||
private _reanimatedEventEmitter: NativeEventEmitter;
|
||||
|
||||
constructor() {
|
||||
this._reanimatedEventEmitter = new NativeEventEmitter(
|
||||
NativeModules.ReanimatedModule
|
||||
);
|
||||
}
|
||||
|
||||
public addOnJSPropsChangeListener(
|
||||
animatedComponent: React.Component<
|
||||
AnimatedComponentProps<InitialComponentProps>
|
||||
> &
|
||||
IAnimatedComponentInternal
|
||||
public registerComponent(
|
||||
animatedComponent: AnimatedComponentType,
|
||||
jsProps: string[]
|
||||
) {
|
||||
const viewTag = findNodeHandle(animatedComponent);
|
||||
JSPropsUpdaterPaper._tagToComponentMapping.set(viewTag, animatedComponent);
|
||||
if (JSPropsUpdaterPaper._tagToComponentMapping.size === 1) {
|
||||
const listener = (data: ListenerData) => {
|
||||
const component = JSPropsUpdaterPaper._tagToComponentMapping.get(
|
||||
data.viewTag
|
||||
);
|
||||
component?._updateFromNative(data.props);
|
||||
};
|
||||
this._reanimatedEventEmitter.addListener(
|
||||
'onReanimatedPropsChange',
|
||||
listener
|
||||
const viewTag = animatedComponent.getComponentViewTag();
|
||||
JSPropsUpdaterNative._tagToComponentMapping.set(viewTag, animatedComponent);
|
||||
|
||||
runOnUI(() => {
|
||||
global._tagToJSPropNamesMapping[viewTag] = Object.fromEntries(
|
||||
jsProps.map((propName) => [propName, true])
|
||||
);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
public removeOnJSPropsChangeListener(
|
||||
animatedComponent: React.Component<
|
||||
AnimatedComponentProps<InitialComponentProps>
|
||||
> &
|
||||
IAnimatedComponentInternal
|
||||
) {
|
||||
const viewTag = findNodeHandle(animatedComponent);
|
||||
JSPropsUpdaterPaper._tagToComponentMapping.delete(viewTag);
|
||||
if (JSPropsUpdaterPaper._tagToComponentMapping.size === 0) {
|
||||
this._reanimatedEventEmitter.removeAllListeners(
|
||||
'onReanimatedPropsChange'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
public unregisterComponent(animatedComponent: AnimatedComponentType) {
|
||||
const viewTag = animatedComponent.getComponentViewTag();
|
||||
JSPropsUpdaterNative._tagToComponentMapping.delete(viewTag);
|
||||
|
||||
class JSPropsUpdaterFabric implements IJSPropsUpdater {
|
||||
private static _tagToComponentMapping = new Map();
|
||||
private static isInitialized = false;
|
||||
|
||||
constructor() {
|
||||
if (!JSPropsUpdaterFabric.isInitialized) {
|
||||
const updater = (viewTag: number, props: unknown) => {
|
||||
const component =
|
||||
JSPropsUpdaterFabric._tagToComponentMapping.get(viewTag);
|
||||
component?._updateFromNative(props);
|
||||
};
|
||||
runOnUIImmediately(() => {
|
||||
'worklet';
|
||||
global.updateJSProps = (viewTag: number, props: unknown) => {
|
||||
runOnJS(updater)(viewTag, props);
|
||||
};
|
||||
})();
|
||||
JSPropsUpdaterFabric.isInitialized = true;
|
||||
}
|
||||
runOnUI(() => {
|
||||
delete global._tagToJSPropNamesMapping[viewTag];
|
||||
})();
|
||||
}
|
||||
|
||||
public addOnJSPropsChangeListener(
|
||||
animatedComponent: React.Component<
|
||||
AnimatedComponentProps<InitialComponentProps>
|
||||
> &
|
||||
IAnimatedComponentInternal
|
||||
) {
|
||||
if (!JSPropsUpdaterFabric.isInitialized) {
|
||||
return;
|
||||
}
|
||||
const viewTag = findNodeHandle(animatedComponent);
|
||||
JSPropsUpdaterFabric._tagToComponentMapping.set(viewTag, animatedComponent);
|
||||
}
|
||||
|
||||
public removeOnJSPropsChangeListener(
|
||||
animatedComponent: React.Component<
|
||||
AnimatedComponentProps<InitialComponentProps>
|
||||
> &
|
||||
IAnimatedComponentInternal
|
||||
) {
|
||||
if (!JSPropsUpdaterFabric.isInitialized) {
|
||||
return;
|
||||
}
|
||||
const viewTag = findNodeHandle(animatedComponent);
|
||||
JSPropsUpdaterFabric._tagToComponentMapping.delete(viewTag);
|
||||
public updateProps(operations: JSPropsOperation[]) {
|
||||
operations.forEach(({ tag, updates }) => {
|
||||
const component = JSPropsUpdaterNative._tagToComponentMapping.get(tag);
|
||||
component?.setNativeProps(updates);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class JSPropsUpdaterWeb implements IJSPropsUpdater {
|
||||
public addOnJSPropsChangeListener(
|
||||
public registerComponent(
|
||||
_animatedComponent: React.Component<
|
||||
AnimatedComponentProps<InitialComponentProps>
|
||||
> &
|
||||
@@ -127,7 +58,7 @@ class JSPropsUpdaterWeb implements IJSPropsUpdater {
|
||||
// noop
|
||||
}
|
||||
|
||||
public removeOnJSPropsChangeListener(
|
||||
public unregisterComponent(
|
||||
_animatedComponent: React.Component<
|
||||
AnimatedComponentProps<InitialComponentProps>
|
||||
> &
|
||||
@@ -135,20 +66,23 @@ class JSPropsUpdaterWeb implements IJSPropsUpdater {
|
||||
) {
|
||||
// noop
|
||||
}
|
||||
|
||||
public updateProps(_operations: JSPropsOperation[]) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
type JSPropsUpdaterOptions =
|
||||
| typeof JSPropsUpdaterWeb
|
||||
| typeof JSPropsUpdaterFabric
|
||||
| typeof JSPropsUpdaterPaper;
|
||||
| typeof JSPropsUpdaterNative;
|
||||
|
||||
let JSPropsUpdater: JSPropsUpdaterOptions;
|
||||
if (SHOULD_BE_USE_WEB) {
|
||||
JSPropsUpdater = JSPropsUpdaterWeb;
|
||||
} else if (global._IS_FABRIC) {
|
||||
JSPropsUpdater = JSPropsUpdaterFabric;
|
||||
} else {
|
||||
JSPropsUpdater = JSPropsUpdaterPaper;
|
||||
JSPropsUpdater = JSPropsUpdaterNative;
|
||||
}
|
||||
|
||||
export default JSPropsUpdater;
|
||||
const jsPropsUpdater = new JSPropsUpdater();
|
||||
|
||||
export default jsPropsUpdater;
|
||||
|
||||
Generated
Vendored
+50
-38
@@ -1,19 +1,19 @@
|
||||
'use strict';
|
||||
import type { StyleProps, SharedValue } from '../reanimated2';
|
||||
import { isSharedValue } from '../reanimated2';
|
||||
import { isChromeDebugger } from '../reanimated2/PlatformChecker';
|
||||
import WorkletEventHandler from '../reanimated2/WorkletEventHandler';
|
||||
import { initialUpdaterRun } from '../reanimated2/animation';
|
||||
import { hasInlineStyles, getInlineStyle } from './InlinePropManager';
|
||||
|
||||
import { initialUpdaterRun } from '../animation';
|
||||
import type { StyleProps } from '../commonTypes';
|
||||
import type { AnimatedStyleHandle } from '../hook/commonTypes';
|
||||
import { isSharedValue } from '../isSharedValue';
|
||||
import { WorkletEventHandler } from '../WorkletEventHandler';
|
||||
import type {
|
||||
AnimatedComponentProps,
|
||||
AnimatedComponentType,
|
||||
AnimatedProps,
|
||||
InitialComponentProps,
|
||||
IAnimatedComponentInternal,
|
||||
IPropsFilter,
|
||||
} from './commonTypes';
|
||||
import { getInlineStyle, hasInlineStyles } from './InlinePropManager';
|
||||
import { flattenArray, has } from './utils';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
function dummyListener() {
|
||||
// empty listener we use to assign to listener properties for which animated
|
||||
@@ -21,56 +21,68 @@ function dummyListener() {
|
||||
}
|
||||
|
||||
export class PropsFilter implements IPropsFilter {
|
||||
private _initialStyle = {};
|
||||
private _initialPropsMap = new Map<AnimatedStyleHandle, StyleProps>();
|
||||
|
||||
public filterNonAnimatedProps(
|
||||
component: React.Component<unknown, unknown> & IAnimatedComponentInternal
|
||||
component: AnimatedComponentType
|
||||
): Record<string, unknown> {
|
||||
const inputProps =
|
||||
component.props as AnimatedComponentProps<InitialComponentProps>;
|
||||
const props: Record<string, unknown> = {};
|
||||
|
||||
for (const key in inputProps) {
|
||||
const value = inputProps[key];
|
||||
if (key === 'style') {
|
||||
const styleProp = inputProps.style;
|
||||
const styles = flattenArray<StyleProps>(styleProp ?? []);
|
||||
const processedStyle: StyleProps = styles.map((style) => {
|
||||
if (style && style.viewDescriptors) {
|
||||
// this is how we recognize styles returned by useAnimatedStyle
|
||||
style.viewsRef.add(component);
|
||||
|
||||
const processedStyle: StyleProps[] = styles.map((style) => {
|
||||
if (style?.viewDescriptors) {
|
||||
const handle = style as AnimatedStyleHandle;
|
||||
|
||||
if (component._isFirstRender) {
|
||||
this._initialStyle = {
|
||||
...style.initial.value,
|
||||
...this._initialStyle,
|
||||
...initialUpdaterRun<StyleProps>(style.initial.updater),
|
||||
};
|
||||
this._initialPropsMap.set(handle, {
|
||||
...handle.initial.value,
|
||||
...initialUpdaterRun(handle.initial.updater),
|
||||
} as StyleProps);
|
||||
}
|
||||
return this._initialStyle;
|
||||
|
||||
return this._initialPropsMap.get(handle) ?? {};
|
||||
} else if (hasInlineStyles(style)) {
|
||||
return getInlineStyle(style, component._isFirstRender);
|
||||
} else {
|
||||
return style;
|
||||
}
|
||||
});
|
||||
props[key] = StyleSheet.flatten(processedStyle);
|
||||
// keep styles as they were passed by the user
|
||||
// it will help other libs to interpret styles correctly
|
||||
props[key] = processedStyle;
|
||||
} else if (key === 'animatedProps') {
|
||||
const animatedProp = inputProps.animatedProps as Partial<
|
||||
AnimatedComponentProps<AnimatedProps>
|
||||
>;
|
||||
if (animatedProp.initial !== undefined) {
|
||||
Object.keys(animatedProp.initial.value).forEach((key) => {
|
||||
props[key] = animatedProp.initial?.value[key];
|
||||
animatedProp.viewsRef?.add(component);
|
||||
});
|
||||
}
|
||||
const animatedPropsProp = inputProps.animatedProps;
|
||||
const animatedPropsArray = flattenArray<
|
||||
Partial<AnimatedComponentProps<AnimatedProps>>
|
||||
>(animatedPropsProp ?? []);
|
||||
|
||||
animatedPropsArray.forEach((animatedProps) => {
|
||||
if (animatedProps?.viewDescriptors && animatedProps.initial) {
|
||||
Object.keys(animatedProps.initial.value).forEach(
|
||||
(initialValueKey) => {
|
||||
props[initialValueKey] =
|
||||
animatedProps.initial?.value[initialValueKey];
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
} else if (
|
||||
has('current', value) &&
|
||||
value.current instanceof WorkletEventHandler
|
||||
has('workletEventHandler', value) &&
|
||||
value.workletEventHandler instanceof WorkletEventHandler
|
||||
) {
|
||||
if (value.current.eventNames.length > 0) {
|
||||
value.current.eventNames.forEach((eventName) => {
|
||||
props[eventName] = has('listeners', value.current)
|
||||
? (value.current.listeners as Record<string, unknown>)[eventName]
|
||||
if (value.workletEventHandler.eventNames.length > 0) {
|
||||
value.workletEventHandler.eventNames.forEach((eventName) => {
|
||||
props[eventName] = has('listeners', value.workletEventHandler)
|
||||
? (
|
||||
value.workletEventHandler.listeners as Record<string, unknown>
|
||||
)[eventName]
|
||||
: dummyListener;
|
||||
});
|
||||
} else {
|
||||
@@ -78,9 +90,9 @@ export class PropsFilter implements IPropsFilter {
|
||||
}
|
||||
} else if (isSharedValue(value)) {
|
||||
if (component._isFirstRender) {
|
||||
props[key] = (value as SharedValue<unknown>).value;
|
||||
props[key] = value.value;
|
||||
}
|
||||
} else if (key !== 'onGestureHandlerStateChange' || !isChromeDebugger()) {
|
||||
} else {
|
||||
props[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
Generated
Vendored
+92
-38
@@ -1,32 +1,35 @@
|
||||
'use strict';
|
||||
import type { Ref, Component } from 'react';
|
||||
import type { Component, Ref, RefObject } from 'react';
|
||||
|
||||
import type {
|
||||
StyleProps,
|
||||
BaseAnimationBuilder,
|
||||
ILayoutAnimationBuilder,
|
||||
AnimatedStyle,
|
||||
EntryExitAnimationFunction,
|
||||
SharedTransition,
|
||||
ILayoutAnimationBuilder,
|
||||
ShadowNodeWrapper,
|
||||
SharedValue,
|
||||
} from '../reanimated2';
|
||||
import type {
|
||||
ViewDescriptorsSet,
|
||||
ViewRefSet,
|
||||
} from '../reanimated2/ViewDescriptorsSet';
|
||||
import type { SkipEnteringContext } from '../reanimated2/component/LayoutAnimationConfig';
|
||||
import type { ShadowNodeWrapper } from '../reanimated2/commonTypes';
|
||||
import type { ViewConfig } from '../ConfigHelper';
|
||||
StyleProps,
|
||||
StyleUpdaterContainer,
|
||||
} from '../commonTypes';
|
||||
import type { SkipEnteringContext } from '../component/LayoutAnimationConfig';
|
||||
import type { BaseAnimationBuilder } from '../layoutReanimation';
|
||||
import type { ViewDescriptorsSet } from '../ViewDescriptorsSet';
|
||||
|
||||
export interface AnimatedProps extends Record<string, unknown> {
|
||||
viewDescriptors?: ViewDescriptorsSet;
|
||||
viewsRef?: ViewRefSet<unknown>;
|
||||
initial?: SharedValue<StyleProps>;
|
||||
styleUpdaterContainer?: StyleUpdaterContainer;
|
||||
}
|
||||
|
||||
export interface ViewInfo {
|
||||
viewTag: number | HTMLElement | null;
|
||||
viewName: string | null;
|
||||
viewTag: number | AnimatedComponentRef | HTMLElement | null;
|
||||
shadowNodeWrapper: ShadowNodeWrapper | null;
|
||||
viewConfig: ViewConfig;
|
||||
// This is a React host instance view name which might differ from the
|
||||
// Fabric component name. For clarity, we use the viewName property
|
||||
// here and componentName in C++ after converting react viewName to
|
||||
// Fabric component name.
|
||||
// (see react/renderer/componentregistry/componentNameByReactViewName.cpp)
|
||||
viewName?: string;
|
||||
DOMElement?: HTMLElement | null;
|
||||
}
|
||||
|
||||
export interface IInlinePropManager {
|
||||
@@ -37,31 +40,49 @@ export interface IInlinePropManager {
|
||||
detachInlineProps(): void;
|
||||
}
|
||||
|
||||
export type AnimatedComponentType = React.Component<unknown, unknown> &
|
||||
IAnimatedComponentInternal;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
export type PropUpdates = StyleProps | AnimatedStyle<any>;
|
||||
|
||||
export interface IPropsFilter {
|
||||
filterNonAnimatedProps: (
|
||||
component: React.Component<unknown, unknown> & IAnimatedComponentInternal
|
||||
component: AnimatedComponentType
|
||||
) => Record<string, unknown>;
|
||||
}
|
||||
|
||||
export type JSPropsOperation = {
|
||||
tag: number;
|
||||
updates: StyleProps;
|
||||
};
|
||||
|
||||
export interface IJSPropsUpdater {
|
||||
addOnJSPropsChangeListener(
|
||||
animatedComponent: React.Component<unknown, unknown> &
|
||||
IAnimatedComponentInternal
|
||||
): void;
|
||||
removeOnJSPropsChangeListener(
|
||||
animatedComponent: React.Component<unknown, unknown> &
|
||||
IAnimatedComponentInternal
|
||||
registerComponent(
|
||||
animatedComponent: AnimatedComponentType,
|
||||
jsProps: string[]
|
||||
): void;
|
||||
unregisterComponent(animatedComponent: AnimatedComponentType): void;
|
||||
updateProps(operations: JSPropsOperation[]): void;
|
||||
}
|
||||
|
||||
export interface INativeEventsManager {
|
||||
attachEvents(): void;
|
||||
detachEvents(): void;
|
||||
updateEvents(prevProps: AnimatedComponentProps<InitialComponentProps>): void;
|
||||
}
|
||||
|
||||
export type LayoutAnimationStaticContext = {
|
||||
presetName: string;
|
||||
};
|
||||
|
||||
export type AnimatedComponentProps<P extends Record<string, unknown>> = P & {
|
||||
forwardedRef?: Ref<Component>;
|
||||
export type AnimatedComponentProps<
|
||||
P extends Record<string, unknown> = Record<string, unknown>,
|
||||
> = P & {
|
||||
ref?: Ref<Component>;
|
||||
style?: NestedArray<StyleProps>;
|
||||
animatedProps?: Partial<AnimatedComponentProps<AnimatedProps>>;
|
||||
jestAnimatedValues?: RefObject<AnimatedProps>;
|
||||
animatedStyle?: StyleProps;
|
||||
layout?: (
|
||||
| BaseAnimationBuilder
|
||||
@@ -83,34 +104,67 @@ export type AnimatedComponentProps<P extends Record<string, unknown>> = P & {
|
||||
| Keyframe
|
||||
) &
|
||||
LayoutAnimationStaticContext;
|
||||
sharedTransitionTag?: string;
|
||||
sharedTransitionStyle?: SharedTransition;
|
||||
};
|
||||
|
||||
export type LayoutAnimationOrBuilder = (
|
||||
| BaseAnimationBuilder
|
||||
| typeof BaseAnimationBuilder
|
||||
| EntryExitAnimationFunction
|
||||
| Keyframe
|
||||
| ILayoutAnimationBuilder
|
||||
) &
|
||||
LayoutAnimationStaticContext;
|
||||
|
||||
export interface AnimatedComponentRef extends Component {
|
||||
setNativeProps?: (props: Record<string, unknown>) => void;
|
||||
getScrollableNode?: () => AnimatedComponentRef;
|
||||
getAnimatableRef?: () => AnimatedComponentRef;
|
||||
// Case for SVG components on Web
|
||||
elementRef?: React.RefObject<HTMLElement>;
|
||||
}
|
||||
|
||||
export interface IAnimatedComponentInternal {
|
||||
_styles: StyleProps[] | null;
|
||||
_animatedProps?: Partial<AnimatedComponentProps<AnimatedProps>>;
|
||||
_viewTag: number;
|
||||
export interface IAnimatedComponentInternalBase {
|
||||
ChildComponent: AnyComponent;
|
||||
_componentRef: AnimatedComponentRef | HTMLElement | null;
|
||||
_hasAnimatedRef: boolean;
|
||||
_viewInfo?: ViewInfo;
|
||||
|
||||
/**
|
||||
* Used for Layout Animations and Animated Styles. It is not related to event
|
||||
* handling.
|
||||
*/
|
||||
getComponentViewTag: () => number;
|
||||
}
|
||||
|
||||
export interface IAnimatedComponentInternal
|
||||
extends IAnimatedComponentInternalBase {
|
||||
_animatedStyles: StyleProps[];
|
||||
_prevAnimatedStyles: StyleProps[];
|
||||
_animatedProps: Partial<AnimatedComponentProps<AnimatedProps>>[];
|
||||
_prevAnimatedProps: Partial<AnimatedComponentProps<AnimatedProps>>[];
|
||||
_isFirstRender: boolean;
|
||||
animatedStyle: { value: StyleProps };
|
||||
_component: AnimatedComponentRef | HTMLElement | null;
|
||||
_sharedElementTransition: SharedTransition | null;
|
||||
_jsPropsUpdater: IJSPropsUpdater;
|
||||
jestInlineStyle: NestedArray<StyleProps> | undefined;
|
||||
jestAnimatedStyle: { value: StyleProps };
|
||||
jestAnimatedProps: { value: AnimatedProps };
|
||||
_InlinePropManager: IInlinePropManager;
|
||||
_PropsFilter: IPropsFilter;
|
||||
_viewInfo?: ViewInfo;
|
||||
/** Doesn't exist on web. */
|
||||
_NativeEventsManager?: INativeEventsManager;
|
||||
context: React.ContextType<typeof SkipEnteringContext>;
|
||||
setNativeProps: (props: StyleProps) => void;
|
||||
}
|
||||
|
||||
export type NestedArray<T> = T | NestedArray<T>[];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type AnyComponent = React.ComponentType<any>;
|
||||
|
||||
export interface InitialComponentProps extends Record<string, unknown> {
|
||||
ref?: Ref<Component>;
|
||||
collapsable?: boolean;
|
||||
}
|
||||
|
||||
export type ManagedAnimatedComponent = React.Component<
|
||||
AnimatedComponentProps<InitialComponentProps>
|
||||
> &
|
||||
IAnimatedComponentInternal;
|
||||
|
||||
Generated
Vendored
+59
-563
@@ -1,81 +1,24 @@
|
||||
'use strict';
|
||||
import type {
|
||||
Component,
|
||||
ComponentClass,
|
||||
ComponentType,
|
||||
FunctionComponent,
|
||||
MutableRefObject,
|
||||
Ref,
|
||||
} from 'react';
|
||||
import React from 'react';
|
||||
import { findNodeHandle, Platform } from 'react-native';
|
||||
import WorkletEventHandler from '../reanimated2/WorkletEventHandler';
|
||||
import '../reanimated2/layoutReanimation/animationsManager';
|
||||
import invariant from 'invariant';
|
||||
import { adaptViewConfig } from '../ConfigHelper';
|
||||
import { RNRenderer } from '../reanimated2/platform-specific/RNRenderer';
|
||||
import {
|
||||
configureLayoutAnimations,
|
||||
enableLayoutAnimations,
|
||||
} from '../reanimated2/core';
|
||||
import {
|
||||
SharedTransition,
|
||||
LayoutAnimationType,
|
||||
} from '../reanimated2/layoutReanimation';
|
||||
import type { StyleProps, ShadowNodeWrapper } from '../reanimated2/commonTypes';
|
||||
import { getShadowNodeWrapperFromRef } from '../reanimated2/fabricUtils';
|
||||
import { removeFromPropsRegistry } from '../reanimated2/PropsRegistry';
|
||||
import { getReduceMotionFromConfig } from '../reanimated2/animation/util';
|
||||
import { maybeBuild } from '../animationBuilder';
|
||||
import { SkipEnteringContext } from '../reanimated2/component/LayoutAnimationConfig';
|
||||
import type { AnimateProps } from '../reanimated2';
|
||||
import JSPropsUpdater from './JSPropsUpdater';
|
||||
import type {
|
||||
AnimatedComponentProps,
|
||||
AnimatedProps,
|
||||
InitialComponentProps,
|
||||
AnimatedComponentRef,
|
||||
IAnimatedComponentInternal,
|
||||
ViewInfo,
|
||||
} from './commonTypes';
|
||||
import { has, flattenArray } from './utils';
|
||||
import setAndForwardRef from './setAndForwardRef';
|
||||
import {
|
||||
isFabric,
|
||||
isJest,
|
||||
isWeb,
|
||||
shouldBeUseWeb,
|
||||
} from '../reanimated2/PlatformChecker';
|
||||
import { InlinePropManager } from './InlinePropManager';
|
||||
import { PropsFilter } from './PropsFilter';
|
||||
import {
|
||||
startWebLayoutAnimation,
|
||||
tryActivateLayoutTransition,
|
||||
configureWebLayoutAnimations,
|
||||
getReducedMotionFromConfig,
|
||||
} from '../reanimated2/layoutReanimation/web';
|
||||
import type { CustomConfig } from '../reanimated2/layoutReanimation/web/config';
|
||||
import type { FlatList, FlatListProps } from 'react-native';
|
||||
|
||||
const IS_WEB = isWeb();
|
||||
const IS_FABRIC = isFabric();
|
||||
import type { AnimatedProps } from '../helperTypes';
|
||||
import type { Options } from './AnimatedComponent';
|
||||
import AnimatedComponentImpl from './AnimatedComponent';
|
||||
import type {
|
||||
AnimatedComponentProps,
|
||||
InitialComponentProps,
|
||||
} from './commonTypes';
|
||||
|
||||
function onlyAnimatedStyles(styles: StyleProps[]): StyleProps[] {
|
||||
return styles.filter((style) => style?.viewDescriptors);
|
||||
}
|
||||
|
||||
function isSameAnimatedStyle(
|
||||
style1?: StyleProps,
|
||||
style2?: StyleProps
|
||||
): boolean {
|
||||
// We cannot use equality check to compare useAnimatedStyle outputs directly.
|
||||
// Instead, we can compare its viewsRefs.
|
||||
return style1?.viewsRef === style2?.viewsRef;
|
||||
}
|
||||
|
||||
const isSameAnimatedProps = isSameAnimatedStyle;
|
||||
|
||||
type Options<P> = {
|
||||
setNativeProps: (ref: AnimatedComponentRef, props: P) => void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type AnimatableComponent<C extends ComponentType<any>> = C & {
|
||||
jsProps?: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -86,517 +29,70 @@ type Options<P> = {
|
||||
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/createAnimatedComponent
|
||||
*/
|
||||
|
||||
// Don't change the order of overloads, since such a change breaks current behavior
|
||||
export function createAnimatedComponent<P extends object>(
|
||||
component: AnimatableComponent<FunctionComponent<P>>,
|
||||
options?: Options<P>
|
||||
): FunctionComponent<AnimatedProps<P>>;
|
||||
|
||||
export function createAnimatedComponent<P extends object>(
|
||||
component: AnimatableComponent<ComponentClass<P>>,
|
||||
options?: Options<P>
|
||||
): ComponentClass<AnimatedProps<P>>;
|
||||
|
||||
export function createAnimatedComponent<P extends object>(
|
||||
// Actually ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P> but we need this overload too
|
||||
// since some external components (like FastImage) are typed just as ComponentType
|
||||
component: AnimatableComponent<ComponentType<P>>,
|
||||
options?: Options<P>
|
||||
): FunctionComponent<AnimatedProps<P>> | ComponentClass<AnimatedProps<P>>;
|
||||
|
||||
/**
|
||||
* @deprecated Please use `Animated.FlatList` component instead of calling `Animated.createAnimatedComponent(FlatList)` manually.
|
||||
* @deprecated Please use `Animated.FlatList` component instead of calling
|
||||
* `Animated.createAnimatedComponent(FlatList)` manually.
|
||||
*/
|
||||
// @ts-ignore This is required to create this overload, since type of createAnimatedComponent is incorrect and doesn't include typeof FlatList
|
||||
export function createAnimatedComponent(
|
||||
component: typeof FlatList<unknown>,
|
||||
options?: Options<any>
|
||||
): ComponentClass<AnimateProps<FlatListProps<unknown>>>;
|
||||
|
||||
export function createAnimatedComponent<P extends object>(
|
||||
component: FunctionComponent<P>,
|
||||
options?: Options<P>
|
||||
): FunctionComponent<AnimateProps<P>>;
|
||||
|
||||
export function createAnimatedComponent<P extends object>(
|
||||
component: ComponentClass<P>,
|
||||
options?: Options<P>
|
||||
): ComponentClass<AnimateProps<P>>;
|
||||
component: AnimatableComponent<typeof FlatList<unknown>>,
|
||||
options?: Options<typeof FlatList<unknown>>
|
||||
): ComponentClass<AnimatedProps<FlatListProps<unknown>>>;
|
||||
|
||||
export function createAnimatedComponent(
|
||||
Component: ComponentType<InitialComponentProps>,
|
||||
Component: AnimatableComponent<ComponentType<InitialComponentProps>>,
|
||||
options?: Options<InitialComponentProps>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): any {
|
||||
invariant(
|
||||
typeof Component !== 'function' ||
|
||||
(Component.prototype && Component.prototype.isReactComponent),
|
||||
`Looks like you're passing a function component \`${Component.name}\` to \`createAnimatedComponent\` function which supports only class components. Please wrap your function component with \`React.forwardRef()\` or use a class component instead.`
|
||||
);
|
||||
|
||||
class AnimatedComponent
|
||||
extends React.Component<AnimatedComponentProps<InitialComponentProps>>
|
||||
implements IAnimatedComponentInternal
|
||||
{
|
||||
_styles: StyleProps[] | null = null;
|
||||
_animatedProps?: Partial<AnimatedComponentProps<AnimatedProps>>;
|
||||
_viewTag = -1;
|
||||
_isFirstRender = true;
|
||||
animatedStyle: { value: StyleProps } = { value: {} };
|
||||
_component: AnimatedComponentRef | HTMLElement | null = null;
|
||||
_sharedElementTransition: SharedTransition | null = null;
|
||||
_jsPropsUpdater = new JSPropsUpdater();
|
||||
_InlinePropManager = new InlinePropManager();
|
||||
_PropsFilter = new PropsFilter();
|
||||
_viewInfo?: ViewInfo;
|
||||
static displayName: string;
|
||||
static contextType = SkipEnteringContext;
|
||||
context!: React.ContextType<typeof SkipEnteringContext>;
|
||||
class AnimatedComponent extends AnimatedComponentImpl {
|
||||
static displayName = `AnimatedComponent(${
|
||||
Component.displayName || Component.name || 'Component'
|
||||
})`;
|
||||
|
||||
constructor(props: AnimatedComponentProps<InitialComponentProps>) {
|
||||
super(props);
|
||||
if (isJest()) {
|
||||
this.animatedStyle = { value: {} };
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._attachNativeEvents();
|
||||
this._jsPropsUpdater.addOnJSPropsChangeListener(this);
|
||||
this._attachAnimatedStyles();
|
||||
this._InlinePropManager.attachInlineProps(this, this._getViewInfo());
|
||||
|
||||
if (IS_WEB) {
|
||||
configureWebLayoutAnimations();
|
||||
|
||||
if (!this.props.entering) {
|
||||
this._isFirstRender = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (getReducedMotionFromConfig(this.props.entering as CustomConfig)) {
|
||||
this._isFirstRender = false;
|
||||
return;
|
||||
}
|
||||
|
||||
startWebLayoutAnimation(
|
||||
this.props,
|
||||
this._component as HTMLElement,
|
||||
LayoutAnimationType.ENTERING
|
||||
);
|
||||
}
|
||||
|
||||
this._isFirstRender = false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._detachNativeEvents();
|
||||
this._jsPropsUpdater.removeOnJSPropsChangeListener(this);
|
||||
this._detachStyles();
|
||||
this._InlinePropManager.detachInlineProps();
|
||||
this._sharedElementTransition?.unregisterTransition(this._viewTag);
|
||||
|
||||
if (
|
||||
IS_WEB &&
|
||||
this.props.exiting &&
|
||||
!getReducedMotionFromConfig(this.props.exiting as CustomConfig)
|
||||
) {
|
||||
startWebLayoutAnimation(
|
||||
this.props,
|
||||
this._component as HTMLElement,
|
||||
LayoutAnimationType.EXITING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_getEventViewRef() {
|
||||
// Make sure to get the scrollable node for components that implement
|
||||
// `ScrollResponder.Mixin`.
|
||||
return (this._component as AnimatedComponentRef)?.getScrollableNode
|
||||
? (this._component as AnimatedComponentRef).getScrollableNode?.()
|
||||
: this._component;
|
||||
}
|
||||
|
||||
_attachNativeEvents() {
|
||||
const node = this._getEventViewRef() as AnimatedComponentRef;
|
||||
let viewTag = null; // We set it only if needed
|
||||
|
||||
for (const key in this.props) {
|
||||
const prop = this.props[key];
|
||||
if (
|
||||
has('current', prop) &&
|
||||
prop.current instanceof WorkletEventHandler
|
||||
) {
|
||||
if (viewTag === null) {
|
||||
viewTag = findNodeHandle(options?.setNativeProps ? this : node);
|
||||
}
|
||||
prop.current.registerForEvents(viewTag as number, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_detachNativeEvents() {
|
||||
for (const key in this.props) {
|
||||
const prop = this.props[key];
|
||||
if (
|
||||
has('current', prop) &&
|
||||
prop.current instanceof WorkletEventHandler
|
||||
) {
|
||||
prop.current.unregisterFromEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_detachStyles() {
|
||||
if (IS_WEB && this._styles !== null) {
|
||||
for (const style of this._styles) {
|
||||
if (style?.viewsRef) {
|
||||
style.viewsRef.remove(this);
|
||||
}
|
||||
}
|
||||
} else if (this._viewTag !== -1 && this._styles !== null) {
|
||||
for (const style of this._styles) {
|
||||
style.viewDescriptors.remove(this._viewTag);
|
||||
}
|
||||
if (this.props.animatedProps?.viewDescriptors) {
|
||||
this.props.animatedProps.viewDescriptors.remove(this._viewTag);
|
||||
}
|
||||
if (IS_FABRIC) {
|
||||
removeFromPropsRegistry(this._viewTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_reattachNativeEvents(
|
||||
prevProps: AnimatedComponentProps<InitialComponentProps>
|
||||
) {
|
||||
for (const key in prevProps) {
|
||||
const prop = this.props[key];
|
||||
if (
|
||||
has('current', prop) &&
|
||||
prop.current instanceof WorkletEventHandler &&
|
||||
prop.current.reattachNeeded
|
||||
) {
|
||||
prop.current.unregisterFromEvents();
|
||||
}
|
||||
}
|
||||
|
||||
let viewTag = null;
|
||||
|
||||
for (const key in this.props) {
|
||||
const prop = this.props[key];
|
||||
if (
|
||||
has('current', prop) &&
|
||||
prop.current instanceof WorkletEventHandler &&
|
||||
prop.current.reattachNeeded
|
||||
) {
|
||||
if (viewTag === null) {
|
||||
const node = this._getEventViewRef() as AnimatedComponentRef;
|
||||
viewTag = findNodeHandle(options?.setNativeProps ? this : node);
|
||||
}
|
||||
prop.current.registerForEvents(viewTag as number, key);
|
||||
prop.current.reattachNeeded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_updateFromNative(props: StyleProps) {
|
||||
if (options?.setNativeProps) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
options.setNativeProps(this._component as AnimatedComponentRef, props);
|
||||
} else {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
(this._component as AnimatedComponentRef)?.setNativeProps?.(props);
|
||||
}
|
||||
}
|
||||
|
||||
_getViewInfo(): ViewInfo {
|
||||
if (this._viewInfo !== undefined) {
|
||||
return this._viewInfo;
|
||||
}
|
||||
|
||||
let viewTag: number | HTMLElement | null;
|
||||
let viewName: string | null;
|
||||
let shadowNodeWrapper: ShadowNodeWrapper | null = null;
|
||||
let viewConfig;
|
||||
// Component can specify ref which should be animated when animated version of the component is created.
|
||||
// Otherwise, we animate the component itself.
|
||||
const component = (this._component as AnimatedComponentRef)
|
||||
?.getAnimatableRef
|
||||
? (this._component as AnimatedComponentRef).getAnimatableRef?.()
|
||||
: this;
|
||||
|
||||
if (IS_WEB) {
|
||||
// At this point I assume that `_setComponentRef` was already called and `_component` is set.
|
||||
// `this._component` on web represents HTMLElement of our component, that's why we use casting
|
||||
viewTag = this._component as HTMLElement;
|
||||
viewName = null;
|
||||
shadowNodeWrapper = null;
|
||||
viewConfig = null;
|
||||
} else {
|
||||
// hostInstance can be null for a component that doesn't render anything (render function returns null). Example: svg Stop: https://github.com/react-native-svg/react-native-svg/blob/develop/src/elements/Stop.tsx
|
||||
const hostInstance = RNRenderer.findHostInstance_DEPRECATED(component);
|
||||
if (!hostInstance) {
|
||||
throw new Error(
|
||||
'[Reanimated] Cannot find host instance for this component. Maybe it renders nothing?'
|
||||
);
|
||||
}
|
||||
// we can access view tag in the same way it's accessed here https://github.com/facebook/react/blob/e3f4eb7272d4ca0ee49f27577156b57eeb07cf73/packages/react-native-renderer/src/ReactFabric.js#L146
|
||||
viewTag = hostInstance?._nativeTag;
|
||||
/**
|
||||
* RN uses viewConfig for components for storing different properties of the component(example: https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Components/ScrollView/ScrollViewNativeComponent.js#L24).
|
||||
* The name we're looking for is in the field named uiViewClassName.
|
||||
*/
|
||||
viewName = hostInstance?.viewConfig?.uiViewClassName;
|
||||
|
||||
viewConfig = hostInstance?.viewConfig;
|
||||
|
||||
if (IS_FABRIC) {
|
||||
shadowNodeWrapper = getShadowNodeWrapperFromRef(this);
|
||||
}
|
||||
}
|
||||
this._viewInfo = { viewTag, viewName, shadowNodeWrapper, viewConfig };
|
||||
return this._viewInfo;
|
||||
}
|
||||
|
||||
_attachAnimatedStyles() {
|
||||
const styles = this.props.style
|
||||
? onlyAnimatedStyles(flattenArray<StyleProps>(this.props.style))
|
||||
: [];
|
||||
const prevStyles = this._styles;
|
||||
this._styles = styles;
|
||||
|
||||
const prevAnimatedProps = this._animatedProps;
|
||||
this._animatedProps = this.props.animatedProps;
|
||||
|
||||
const { viewTag, viewName, shadowNodeWrapper, viewConfig } =
|
||||
this._getViewInfo();
|
||||
|
||||
// update UI props whitelist for this view
|
||||
const hasReanimated2Props =
|
||||
this.props.animatedProps?.viewDescriptors || styles.length;
|
||||
if (hasReanimated2Props && viewConfig) {
|
||||
adaptViewConfig(viewConfig);
|
||||
}
|
||||
|
||||
this._viewTag = viewTag as number;
|
||||
|
||||
// remove old styles
|
||||
if (prevStyles) {
|
||||
// in most of the cases, views have only a single animated style and it remains unchanged
|
||||
const hasOneSameStyle =
|
||||
styles.length === 1 &&
|
||||
prevStyles.length === 1 &&
|
||||
isSameAnimatedStyle(styles[0], prevStyles[0]);
|
||||
|
||||
if (!hasOneSameStyle) {
|
||||
// otherwise, remove each style that is not present in new styles
|
||||
for (const prevStyle of prevStyles) {
|
||||
const isPresent = styles.some((style) =>
|
||||
isSameAnimatedStyle(style, prevStyle)
|
||||
);
|
||||
if (!isPresent) {
|
||||
prevStyle.viewDescriptors.remove(viewTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
styles.forEach((style) => {
|
||||
style.viewDescriptors.add({
|
||||
tag: viewTag,
|
||||
name: viewName,
|
||||
shadowNodeWrapper,
|
||||
});
|
||||
if (isJest()) {
|
||||
/**
|
||||
* We need to connect Jest's TestObject instance whose contains just props object
|
||||
* with the updateProps() function where we update the properties of the component.
|
||||
* We can't update props object directly because TestObject contains a copy of props - look at render function:
|
||||
* const props = this._filterNonAnimatedProps(this.props);
|
||||
*/
|
||||
this.animatedStyle.value = {
|
||||
...this.animatedStyle.value,
|
||||
...style.initial.value,
|
||||
};
|
||||
style.animatedStyle.current = this.animatedStyle;
|
||||
}
|
||||
});
|
||||
|
||||
// detach old animatedProps
|
||||
if (
|
||||
prevAnimatedProps &&
|
||||
!isSameAnimatedProps(prevAnimatedProps, this.props.animatedProps)
|
||||
) {
|
||||
prevAnimatedProps.viewDescriptors!.remove(viewTag as number);
|
||||
}
|
||||
|
||||
// attach animatedProps property
|
||||
if (this.props.animatedProps?.viewDescriptors) {
|
||||
this.props.animatedProps.viewDescriptors.add({
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
tag: viewTag as number,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
name: viewName!,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
shadowNodeWrapper: shadowNodeWrapper!,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(
|
||||
prevProps: AnimatedComponentProps<InitialComponentProps>,
|
||||
_prevState: Readonly<unknown>,
|
||||
// This type comes straight from React
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
snapshot: DOMRect | null
|
||||
) {
|
||||
this._reattachNativeEvents(prevProps);
|
||||
this._attachAnimatedStyles();
|
||||
this._InlinePropManager.attachInlineProps(this, this._getViewInfo());
|
||||
|
||||
// Snapshot won't be undefined because it comes from getSnapshotBeforeUpdate method
|
||||
if (
|
||||
IS_WEB &&
|
||||
snapshot !== null &&
|
||||
this.props.layout &&
|
||||
!getReducedMotionFromConfig(this.props.layout as CustomConfig)
|
||||
) {
|
||||
tryActivateLayoutTransition(
|
||||
this.props,
|
||||
this._component as HTMLElement,
|
||||
snapshot
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_setComponentRef = setAndForwardRef<Component | HTMLElement>({
|
||||
getForwardedRef: () =>
|
||||
this.props.forwardedRef as MutableRefObject<
|
||||
Component<Record<string, unknown>, Record<string, unknown>, unknown>
|
||||
>,
|
||||
setLocalRef: (ref) => {
|
||||
// TODO update config
|
||||
|
||||
const tag = IS_WEB
|
||||
? (ref as HTMLElement)
|
||||
: findNodeHandle(ref as Component);
|
||||
|
||||
const { layout, entering, exiting, sharedTransitionTag } = this.props;
|
||||
if (
|
||||
(layout || entering || exiting || sharedTransitionTag) &&
|
||||
tag != null
|
||||
) {
|
||||
if (!shouldBeUseWeb()) {
|
||||
enableLayoutAnimations(true, false);
|
||||
}
|
||||
if (layout) {
|
||||
configureLayoutAnimations(
|
||||
tag,
|
||||
LayoutAnimationType.LAYOUT,
|
||||
maybeBuild(
|
||||
layout,
|
||||
undefined /* We don't have to warn user if style has common properties with animation for LAYOUT */,
|
||||
AnimatedComponent.displayName
|
||||
)
|
||||
);
|
||||
}
|
||||
const skipEntering = this.context?.current;
|
||||
if (entering && !skipEntering) {
|
||||
configureLayoutAnimations(
|
||||
tag,
|
||||
LayoutAnimationType.ENTERING,
|
||||
maybeBuild(
|
||||
entering,
|
||||
this.props?.style,
|
||||
AnimatedComponent.displayName
|
||||
)
|
||||
);
|
||||
}
|
||||
if (exiting) {
|
||||
const reduceMotionInExiting =
|
||||
'getReduceMotion' in exiting &&
|
||||
typeof exiting.getReduceMotion === 'function'
|
||||
? getReduceMotionFromConfig(exiting.getReduceMotion())
|
||||
: getReduceMotionFromConfig();
|
||||
if (!reduceMotionInExiting) {
|
||||
configureLayoutAnimations(
|
||||
tag,
|
||||
LayoutAnimationType.EXITING,
|
||||
maybeBuild(
|
||||
exiting,
|
||||
this.props?.style,
|
||||
AnimatedComponent.displayName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (sharedTransitionTag && !IS_WEB) {
|
||||
const sharedElementTransition =
|
||||
this.props.sharedTransitionStyle ?? new SharedTransition();
|
||||
const reduceMotionInTransition = getReduceMotionFromConfig(
|
||||
sharedElementTransition.getReduceMotion()
|
||||
);
|
||||
if (!reduceMotionInTransition) {
|
||||
sharedElementTransition.registerTransition(
|
||||
tag as number,
|
||||
sharedTransitionTag
|
||||
);
|
||||
this._sharedElementTransition = sharedElementTransition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ref !== this._component) {
|
||||
this._component = ref;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// This is a component lifecycle method from React, therefore we are not calling it directly.
|
||||
// It is called before the component gets rerendered. This way we can access components' position before it changed
|
||||
// and later on, in componentDidUpdate, calculate translation for layout transition.
|
||||
getSnapshotBeforeUpdate() {
|
||||
if (
|
||||
(this._component as HTMLElement).getBoundingClientRect !== undefined
|
||||
) {
|
||||
return (this._component as HTMLElement).getBoundingClientRect();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const props = this._PropsFilter.filterNonAnimatedProps(this);
|
||||
|
||||
if (isJest()) {
|
||||
props.animatedStyle = this.animatedStyle;
|
||||
}
|
||||
|
||||
// Layout animations on web are set inside `componentDidMount` method, which is called after first render.
|
||||
// Because of that we can encounter a situation in which component is visible for a short amount of time, and later on animation triggers.
|
||||
// I've tested that on various browsers and devices and it did not happen to me. To be sure that it won't happen to someone else,
|
||||
// I've decided to hide component at first render. Its visibility is reset in `componentDidMount`.
|
||||
if (
|
||||
this._isFirstRender &&
|
||||
IS_WEB &&
|
||||
props.entering &&
|
||||
!getReducedMotionFromConfig(props.entering as CustomConfig)
|
||||
) {
|
||||
props.style = {
|
||||
...(props.style ?? {}),
|
||||
visibility: 'hidden', // Hide component until `componentDidMount` triggers
|
||||
};
|
||||
}
|
||||
|
||||
const platformProps = Platform.select({
|
||||
web: {},
|
||||
default: { collapsable: false },
|
||||
});
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...props}
|
||||
// Casting is used here, because ref can be null - in that case it cannot be assigned to HTMLElement.
|
||||
// After spending some time trying to figure out what to do with this problem, we decided to leave it this way
|
||||
ref={this._setComponentRef as (ref: Component) => void}
|
||||
{...platformProps}
|
||||
/>
|
||||
);
|
||||
// User can override component-defined jsProps via options
|
||||
const jsProps = options?.jsProps ?? Component.jsProps;
|
||||
const modifiedOptions = jsProps?.length
|
||||
? { ...options, jsProps }
|
||||
: options;
|
||||
super(Component, props, AnimatedComponent.displayName, modifiedOptions);
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedComponent.displayName = `AnimatedComponent(${
|
||||
Component.displayName || Component.name || 'Component'
|
||||
})`;
|
||||
|
||||
return React.forwardRef<Component>((props, ref) => {
|
||||
const animatedComponent = (
|
||||
props: AnimatedComponentProps & { ref: Ref<AnimatedComponent> }
|
||||
) => {
|
||||
return (
|
||||
<AnimatedComponent
|
||||
{...props}
|
||||
{...(ref === null ? null : { forwardedRef: ref })}
|
||||
// Needed to prevent react from signing AnimatedComponent to the ref
|
||||
// (we want to handle the ref assignment in the AnimatedComponent)
|
||||
ref={null}
|
||||
{...(props.ref === null ? null : { forwardedRef: props.ref })}
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
animatedComponent.displayName =
|
||||
Component.displayName || Component.name || 'Component';
|
||||
|
||||
return animatedComponent;
|
||||
}
|
||||
|
||||
Generated
Vendored
+26
-1
@@ -1,4 +1,6 @@
|
||||
'use strict';
|
||||
import type { StyleProps } from '../commonTypes';
|
||||
import type { CSSStyle } from '../css';
|
||||
import type { NestedArray } from './commonTypes';
|
||||
|
||||
export function flattenArray<T>(array: NestedArray<T>): T[] {
|
||||
@@ -23,7 +25,7 @@ export function flattenArray<T>(array: NestedArray<T>): T[] {
|
||||
export const has = <K extends string>(
|
||||
key: K,
|
||||
x: unknown
|
||||
): x is typeof x & { [key in K]: unknown } => {
|
||||
): x is { [key in K]: unknown } => {
|
||||
if (typeof x === 'function' || typeof x === 'object') {
|
||||
if (x === null || x === undefined) {
|
||||
return false;
|
||||
@@ -33,3 +35,26 @@ export const has = <K extends string>(
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
type FilteredStyles = {
|
||||
cssStyle: CSSStyle | null;
|
||||
animatedStyles: StyleProps[];
|
||||
};
|
||||
|
||||
export function filterStyles(styles: StyleProps[] | undefined): FilteredStyles {
|
||||
if (!styles) {
|
||||
return { animatedStyles: [], cssStyle: null };
|
||||
}
|
||||
|
||||
return styles.reduce<FilteredStyles>(
|
||||
({ animatedStyles, cssStyle }, style) => {
|
||||
if (style?.viewDescriptors) {
|
||||
animatedStyles.push(style);
|
||||
} else {
|
||||
cssStyle = { ...cssStyle, ...style } as CSSStyle;
|
||||
}
|
||||
return { animatedStyles, cssStyle };
|
||||
},
|
||||
{ animatedStyles: [], cssStyle: null }
|
||||
);
|
||||
}
|
||||
|
||||
+296
-1
@@ -1,5 +1,300 @@
|
||||
'use strict';
|
||||
|
||||
import './publicGlobals';
|
||||
|
||||
import { initializeReanimatedModule } from './initializers';
|
||||
import { ReanimatedModule } from './ReanimatedModule';
|
||||
|
||||
// TODO: Specify the initialization pipeline since now there's no
|
||||
// universal source of truth for it.
|
||||
initializeReanimatedModule(ReanimatedModule);
|
||||
|
||||
// eslint-disable-next-line import/first
|
||||
import * as Animated from './Animated';
|
||||
|
||||
export * from './reanimated2';
|
||||
export default Animated;
|
||||
|
||||
export { createAnimatedComponent } from './Animated';
|
||||
export type {
|
||||
DecayAnimation,
|
||||
DelayAnimation,
|
||||
RepeatAnimation,
|
||||
SequenceAnimation,
|
||||
SpringAnimation,
|
||||
StyleLayoutAnimation,
|
||||
TimingAnimation,
|
||||
WithDecayConfig,
|
||||
WithSpringConfig,
|
||||
WithTimingConfig,
|
||||
} from './animation';
|
||||
export {
|
||||
cancelAnimation,
|
||||
defineAnimation,
|
||||
GentleSpringConfig,
|
||||
GentleSpringConfigWithDuration,
|
||||
Reanimated3DefaultSpringConfig,
|
||||
Reanimated3DefaultSpringConfigWithDuration,
|
||||
SnappySpringConfig,
|
||||
SnappySpringConfigWithDuration,
|
||||
WigglySpringConfig,
|
||||
WigglySpringConfigWithDuration,
|
||||
withClamp,
|
||||
withDecay,
|
||||
withDelay,
|
||||
withRepeat,
|
||||
withSequence,
|
||||
withSpring,
|
||||
withTiming,
|
||||
} from './animation';
|
||||
export type { ParsedColorArray } from './Colors';
|
||||
export { convertToRGBA, isColor } from './Colors';
|
||||
export { processColor, ReanimatedLogLevel } from './common';
|
||||
export type {
|
||||
AnimatableValue,
|
||||
AnimatableValueObject,
|
||||
AnimatedKeyboardInfo,
|
||||
AnimatedKeyboardOptions,
|
||||
AnimatedSensor,
|
||||
AnimatedStyle,
|
||||
AnimatedTransform,
|
||||
Animation,
|
||||
AnimationCallback,
|
||||
AnimationObject,
|
||||
BaseLayoutAnimationConfig,
|
||||
EasingFunction,
|
||||
EntryAnimationsValues,
|
||||
EntryExitAnimationFunction,
|
||||
ExitAnimationsValues,
|
||||
IEntryExitAnimationBuilder,
|
||||
ILayoutAnimationBuilder,
|
||||
KeyframeProps,
|
||||
LayoutAnimation,
|
||||
LayoutAnimationFunction,
|
||||
LayoutAnimationStartFunction,
|
||||
LayoutAnimationValues as LayoutAnimationsValues,
|
||||
LayoutAnimationType,
|
||||
MeasuredDimensions,
|
||||
SensorConfig,
|
||||
SharedValue,
|
||||
StyleProps,
|
||||
TransformArrayItem,
|
||||
Value3D,
|
||||
ValueRotation,
|
||||
} from './commonTypes';
|
||||
export {
|
||||
InterfaceOrientation,
|
||||
IOSReferenceFrame,
|
||||
KeyboardState,
|
||||
ReduceMotion,
|
||||
SensorType,
|
||||
} from './commonTypes';
|
||||
export type { FlatListPropsWithLayout } from './component/FlatList';
|
||||
export { LayoutAnimationConfig } from './component/LayoutAnimationConfig';
|
||||
export type { PerformanceMonitorProps } from './component/PerformanceMonitor';
|
||||
export { PerformanceMonitor } from './component/PerformanceMonitor';
|
||||
export { ReducedMotionConfig } from './component/ReducedMotionConfig';
|
||||
export type { AnimatedScrollViewProps } from './component/ScrollView';
|
||||
export { configureReanimatedLogger } from './ConfigHelper';
|
||||
export {
|
||||
enableLayoutAnimations,
|
||||
getViewProp,
|
||||
isConfigured,
|
||||
isReanimated3,
|
||||
makeMutable,
|
||||
} from './core';
|
||||
export * from './css';
|
||||
export type { EasingFunctionFactory } from './Easing';
|
||||
export { Easing } from './Easing';
|
||||
export { getStaticFeatureFlag, setDynamicFeatureFlag } from './featureFlags';
|
||||
export type { FrameInfo } from './frameCallback';
|
||||
export type { AnimatedProps, EntryOrExitLayoutType } from './helperTypes';
|
||||
export type {
|
||||
AnimatedRef,
|
||||
DerivedValue,
|
||||
EventHandler,
|
||||
EventHandlerProcessed,
|
||||
FrameCallback,
|
||||
ReanimatedEvent,
|
||||
ScrollEvent,
|
||||
ScrollHandler,
|
||||
ScrollHandlerProcessed,
|
||||
ScrollHandlers,
|
||||
UseHandlerContext,
|
||||
} from './hook';
|
||||
export {
|
||||
useAnimatedKeyboard,
|
||||
useAnimatedProps,
|
||||
useAnimatedReaction,
|
||||
useAnimatedRef,
|
||||
useAnimatedScrollHandler,
|
||||
useAnimatedSensor,
|
||||
useAnimatedStyle,
|
||||
useComposedEventHandler,
|
||||
useDerivedValue,
|
||||
useEvent,
|
||||
useFrameCallback,
|
||||
useHandler,
|
||||
useReducedMotion,
|
||||
useScrollOffset,
|
||||
/** @deprecated Please use {@link useScrollOffset} instead. */
|
||||
useScrollOffset as useScrollViewOffset,
|
||||
useSharedValue,
|
||||
} from './hook';
|
||||
export type {
|
||||
InterpolateConfig,
|
||||
InterpolateHSV,
|
||||
InterpolateRGB,
|
||||
InterpolationOptions,
|
||||
} from './interpolateColor';
|
||||
export {
|
||||
ColorSpace,
|
||||
/** @deprecated Please use {@link Extrapolation} instead. */
|
||||
Extrapolate,
|
||||
interpolateColor,
|
||||
useInterpolateConfig,
|
||||
} from './interpolateColor';
|
||||
export type { ExtrapolationConfig, ExtrapolationType } from './interpolation';
|
||||
export { clamp, Extrapolation, interpolate } from './interpolation';
|
||||
export { isSharedValue } from './isSharedValue';
|
||||
export {
|
||||
advanceAnimationByFrame,
|
||||
advanceAnimationByTime,
|
||||
getAnimatedStyle,
|
||||
setUpTests,
|
||||
withReanimatedTimer,
|
||||
} from './jestUtils';
|
||||
export type { ReanimatedKeyframe } from './layoutReanimation';
|
||||
export {
|
||||
BaseAnimationBuilder,
|
||||
// Bounce
|
||||
BounceIn,
|
||||
BounceInDown,
|
||||
BounceInLeft,
|
||||
BounceInRight,
|
||||
BounceInUp,
|
||||
BounceOut,
|
||||
BounceOutDown,
|
||||
BounceOutLeft,
|
||||
BounceOutRight,
|
||||
BounceOutUp,
|
||||
ComplexAnimationBuilder,
|
||||
CurvedTransition,
|
||||
EntryExitTransition,
|
||||
// Fade
|
||||
FadeIn,
|
||||
FadeInDown,
|
||||
FadeInLeft,
|
||||
FadeInRight,
|
||||
FadeInUp,
|
||||
FadeOut,
|
||||
FadeOutDown,
|
||||
FadeOutLeft,
|
||||
FadeOutRight,
|
||||
FadeOutUp,
|
||||
FadingTransition,
|
||||
FlipInEasyX,
|
||||
FlipInEasyY,
|
||||
FlipInXDown,
|
||||
// Flip
|
||||
FlipInXUp,
|
||||
FlipInYLeft,
|
||||
FlipInYRight,
|
||||
FlipOutEasyX,
|
||||
FlipOutEasyY,
|
||||
FlipOutXDown,
|
||||
FlipOutXUp,
|
||||
FlipOutYLeft,
|
||||
FlipOutYRight,
|
||||
JumpingTransition,
|
||||
Keyframe,
|
||||
// Transitions
|
||||
Layout,
|
||||
LightSpeedInLeft,
|
||||
// Lightspeed
|
||||
LightSpeedInRight,
|
||||
LightSpeedOutLeft,
|
||||
LightSpeedOutRight,
|
||||
LinearTransition,
|
||||
// Pinwheel
|
||||
PinwheelIn,
|
||||
PinwheelOut,
|
||||
// Roll
|
||||
RollInLeft,
|
||||
RollInRight,
|
||||
RollOutLeft,
|
||||
RollOutRight,
|
||||
// Rotate
|
||||
RotateInDownLeft,
|
||||
RotateInDownRight,
|
||||
RotateInUpLeft,
|
||||
RotateInUpRight,
|
||||
RotateOutDownLeft,
|
||||
RotateOutDownRight,
|
||||
RotateOutUpLeft,
|
||||
RotateOutUpRight,
|
||||
SequencedTransition,
|
||||
SlideInDown,
|
||||
SlideInLeft,
|
||||
// Slide
|
||||
SlideInRight,
|
||||
SlideInUp,
|
||||
SlideOutDown,
|
||||
SlideOutLeft,
|
||||
SlideOutRight,
|
||||
SlideOutUp,
|
||||
// Stretch
|
||||
StretchInX,
|
||||
StretchInY,
|
||||
StretchOutX,
|
||||
StretchOutY,
|
||||
// Zoom
|
||||
ZoomIn,
|
||||
ZoomInDown,
|
||||
ZoomInEasyDown,
|
||||
ZoomInEasyUp,
|
||||
ZoomInLeft,
|
||||
ZoomInRight,
|
||||
ZoomInRotate,
|
||||
ZoomInUp,
|
||||
ZoomOut,
|
||||
ZoomOutDown,
|
||||
ZoomOutEasyDown,
|
||||
ZoomOutEasyUp,
|
||||
ZoomOutLeft,
|
||||
ZoomOutRight,
|
||||
ZoomOutRotate,
|
||||
ZoomOutUp,
|
||||
} from './layoutReanimation';
|
||||
export { startMapper, stopMapper } from './mappers';
|
||||
export { jsVersion as reanimatedVersion } from './platform-specific/jsVersion';
|
||||
export type { ComponentCoords } from './platformFunctions';
|
||||
export {
|
||||
dispatchCommand,
|
||||
getRelativeCoords,
|
||||
measure,
|
||||
scrollTo,
|
||||
setGestureState,
|
||||
setNativeProps,
|
||||
} from './platformFunctions';
|
||||
export { getUseOfValueInStyleWarning } from './pluginUtils';
|
||||
export { createAnimatedPropAdapter } from './PropAdapters';
|
||||
export type {
|
||||
AnimatedScreenTransition,
|
||||
GoBackGesture,
|
||||
ScreenTransitionConfig,
|
||||
} from './screenTransition';
|
||||
export {
|
||||
finishScreenTransition,
|
||||
ScreenTransition,
|
||||
startScreenTransition,
|
||||
} from './screenTransition';
|
||||
export type { WorkletRuntime } from './workletFunctions';
|
||||
export {
|
||||
createWorkletRuntime,
|
||||
executeOnUIRuntimeSync,
|
||||
isWorkletFunction,
|
||||
makeShareableCloneRecursive,
|
||||
runOnJS,
|
||||
runOnRuntime,
|
||||
runOnUI,
|
||||
} from './workletFunctions';
|
||||
|
||||
Reference in New Issue
Block a user