Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isWorklet function #4894

Merged
merged 6 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions src/reanimated2/PropAdapters.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
'use strict';
import { addWhitelistedNativeProps } from '../ConfigHelper';
import type { __AdapterWorkletFunction } from './commonTypes';
import type { AnimatedPropsAdapterFunction } from './helperTypes';
import type {
AnimatedPropsAdapterFunction,
AnimatedPropsAdapterWorklet,
} from './commonTypes';

// TODO TYPESCRIPT This is a temporary type to get rid of .d.ts file.
type createAnimatedPropAdapterType = (
// @ts-expect-error This overload is required by our API.
export function createAnimatedPropAdapter(
adapter: AnimatedPropsAdapterFunction,
nativeProps?: string[]
) => AnimatedPropsAdapterFunction;
): AnimatedPropsAdapterFunction;

export const createAnimatedPropAdapter = ((
adapter: __AdapterWorkletFunction,
export function createAnimatedPropAdapter(
adapter: AnimatedPropsAdapterWorklet,
nativeProps?: string[]
): __AdapterWorkletFunction => {
): AnimatedPropsAdapterWorklet {
const nativePropsToAdd: { [key: string]: boolean } = {};
nativeProps?.forEach((prop) => {
nativePropsToAdd[prop] = true;
});
addWhitelistedNativeProps(nativePropsToAdd);
return adapter;
}) as createAnimatedPropAdapterType;
}
68 changes: 34 additions & 34 deletions src/reanimated2/commonTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ export type MapperRegistry = {
stop: (mapperID: number) => void;
};

export type WorkletStackDetails = [
error: Error,
lineOffset: number,
columnOffset: number
];

type WorkletClosure = Record<string, unknown>;

interface WorkletInitDataCommon {
Expand All @@ -85,14 +91,41 @@ interface WorkletBaseRelease extends WorkletBaseCommon {

interface WorkletBaseDev extends WorkletBaseCommon {
__initData: WorkletInitDataDev;
__stackDetails: Error;
/**
* `__stackDetails` is removed after parsing.
*/
__stackDetails?: WorkletStackDetails;
}

export type WorkletFunction<
Args extends unknown[] = unknown[],
ReturnValue = unknown
> = ((...args: Args) => ReturnValue) & (WorkletBaseRelease | WorkletBaseDev);

/**
* This function works well on the JS thread performance-wise, since the JIT can inline it.
* However, on other threads it will not get optimized and we will get a function call overhead.
*/
export function isWorklet<
Args extends unknown[] = unknown[],
ReturnValue = unknown,
BuildType extends WorkletBaseDev | WorkletBaseRelease = WorkletBaseDev
>(value: unknown): value is WorkletFunction<Args, ReturnValue> & BuildType {
'worklet';
// Since host objects always return true for `in` operator, we have to use dot notation to check if the property exists.
// See https://github.com/facebook/hermes/blob/340726ef8cf666a7cce75bc60b02fa56b3e54560/lib/VM/JSObject.cpp#L1276.
return !!(value as Record<string, unknown>).__workletHash;
tjzel marked this conversation as resolved.
Show resolved Hide resolved
}

export type AnimatedPropsAdapterFunction = (
props: Record<string, unknown>
) => void;

export type AnimatedPropsAdapterWorklet = WorkletFunction<
[props: Record<string, unknown>],
void
>;

export interface NestedObject<T> {
[key: string]: NestedObjectValues<T>;
}
Expand Down Expand Up @@ -253,36 +286,3 @@ export enum ReduceMotion {
Always = 'always',
Never = 'never',
}

// THE LAND OF THE DEPRECATED

/**
* @deprecated don't use
*/
export interface __WorkletFunction {
__closure?: Record<string, unknown>;
__workletHash?: number;
}

/**
* @deprecated don't use
*/
export interface __BasicWorkletFunction<T> extends __WorkletFunction {
(): T;
}

/**
* @deprecated don't use
*/
export interface __ComplexWorkletFunction<A extends any[], R>
extends __WorkletFunction {
(...args: A): R;
__remoteFunction?: (...args: A) => R;
}

/**
* @deprecated don't use
*/
export interface __AdapterWorkletFunction extends __WorkletFunction {
(value: NestedObject<string | number | AnimationObject>): void;
}
6 changes: 3 additions & 3 deletions src/reanimated2/errors.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
'use strict';
type StackDetails = [Error, number, number];
import type { WorkletStackDetails } from './commonTypes';

const _workletStackDetails = new Map<number, StackDetails>();
const _workletStackDetails = new Map<number, WorkletStackDetails>();

export function registerWorkletStackDetails(
hash: number,
stackDetails: StackDetails
stackDetails: WorkletStackDetails
) {
_workletStackDetails.set(hash, stackDetails);
}
Expand Down
6 changes: 1 addition & 5 deletions src/reanimated2/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type {
MapperRegistry,
ShareableRef,
ShadowNodeWrapper,
__ComplexWorkletFunction,
FlatShareableRef,
} from './commonTypes';
import type { AnimatedStyle } from './helperTypes';
Expand Down Expand Up @@ -42,10 +41,7 @@ declare global {
var _notifyAboutEnd: (tag: number, removeView: boolean) => void;
var _setGestureState: (handlerTag: number, newState: number) => void;
var _makeShareableClone: <T>(value: T) => FlatShareableRef<T>;
var _scheduleOnJS: (
fun: __ComplexWorkletFunction<A, R>,
args?: unknown[]
) => void;
var _scheduleOnJS: (fun: (...args: A) => R, args?: A) => void;
var _scheduleOnRuntime: (
runtime: WorkletRuntime,
worklet: ShareableRef<() => void>
Expand Down
15 changes: 0 additions & 15 deletions src/reanimated2/helperTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import type {
} from './layoutReanimation/animationBuilder/commonTypes';
import type { ReanimatedKeyframe } from './layoutReanimation/animationBuilder/Keyframe';
import type { SharedTransition } from './layoutReanimation/sharedTransitions';
import type { DependencyList } from './hook/commonTypes';

export type TransformArrayItem = Extract<
TransformsStyle['transform'],
Expand Down Expand Up @@ -160,20 +159,6 @@ export type AnimatedProps<Props extends object> = RestProps<Props> &
animatedProps?: Partial<AnimatedPropsProp<Props>>;
};

export type AnimatedPropsAdapterFunction = (
props: Record<string, unknown>
) => void;

export type useAnimatedPropsType = <Props extends object>(
updater: () => Partial<Props>,
deps?: DependencyList | null,
adapters?:
| AnimatedPropsAdapterFunction
| AnimatedPropsAdapterFunction[]
| null,
isAnimatedProps?: boolean
) => Partial<Props>;

// THE LAND OF THE DEPRECATED

/**
Expand Down
17 changes: 16 additions & 1 deletion src/reanimated2/hook/commonTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
'use strict';
import type { Component, MutableRefObject } from 'react';
import type { ShadowNodeWrapper, SharedValue } from '../commonTypes';
import type {
AnimatedPropsAdapterFunction,
ShadowNodeWrapper,
SharedValue,
WorkletFunction,
} from '../commonTypes';
import type {
ImageStyle,
NativeSyntheticEvent,
Expand Down Expand Up @@ -92,3 +97,13 @@ export interface JestAnimatedStyleHandle<
> extends AnimatedStyleHandle<Style> {
jestAnimatedStyle: MutableRefObject<AnimatedStyle<Style>>;
}

export type UseAnimatedStyleInternal<Style extends DefaultStyle> = (
updater: WorkletFunction<[], Style> | (() => Style),
dependencies?: DependencyList | null,
adapters?:
| AnimatedPropsAdapterFunction
| AnimatedPropsAdapterFunction[]
| null,
isAnimatedProps?: boolean
) => AnimatedStyleHandle<Style> | JestAnimatedStyleHandle<Style>;
61 changes: 33 additions & 28 deletions src/reanimated2/hook/useAnimatedProps.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
'use strict';
import { useAnimatedStyle } from './useAnimatedStyle';
import type { DependencyList } from './commonTypes';
import type {
AnimatedPropsAdapterFunction,
useAnimatedPropsType,
} from '../helperTypes';
import type { DependencyList, UseAnimatedStyleInternal } from './commonTypes';
import { shouldBeUseWeb } from '../PlatformChecker';
import type { AnimatedPropsAdapterFunction } from '../commonTypes';

// TODO: we should make sure that when useAP is used we are not assigning styles
tjzel marked this conversation as resolved.
Show resolved Hide resolved
// when you need styles to animated you should always use useAS
// TODO TYPESCRIPT This is a temporary cast to get rid of .d.ts file.

type UseAnimatedProps = <Props extends object>(
updater: () => Partial<Props>,
dependencies?: DependencyList | null,
adapters?:
| AnimatedPropsAdapterFunction
| AnimatedPropsAdapterFunction[]
| null,
isAnimatedProps?: boolean
) => Partial<Props>;

function useAnimatedPropsJS<Props extends object>(
updater: () => Props,
deps?: DependencyList | null,
adapters?:
| AnimatedPropsAdapterFunction
| AnimatedPropsAdapterFunction[]
| null
) {
return (useAnimatedStyle as UseAnimatedStyleInternal<Props>)(
updater,
deps,
adapters,
true
);
}

const useAnimatedPropsNative = useAnimatedStyle;

/**
* Lets you create an animated props object which can be animated using shared values.
Expand All @@ -20,24 +43,6 @@ import { shouldBeUseWeb } from '../PlatformChecker';
* @returns An animated props object which has to be passed to `animatedProps` property of an Animated component that you want to animate.
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedProps
*/
export let useAnimatedProps: useAnimatedPropsType;

if (shouldBeUseWeb()) {
useAnimatedProps = function <T extends object>(
updater: () => Partial<T>,
deps?: DependencyList | null,
adapters?:
| AnimatedPropsAdapterFunction
| AnimatedPropsAdapterFunction[]
| null
) {
return (useAnimatedStyle as useAnimatedPropsType)(
updater,
deps,
adapters,
true
);
};
} else {
useAnimatedProps = useAnimatedStyle as useAnimatedPropsType;
}
export const useAnimatedProps: UseAnimatedProps = shouldBeUseWeb()
? (useAnimatedPropsJS as UseAnimatedProps)
: useAnimatedPropsNative;
21 changes: 12 additions & 9 deletions src/reanimated2/hook/useAnimatedStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import type {
NestedObjectValues,
SharedValue,
StyleProps,
__AdapterWorkletFunction,
__BasicWorkletFunction,
WorkletFunction,
AnimatedPropsAdapterFunction,
AnimatedPropsAdapterWorklet,
} from '../commonTypes';
import type { AnimatedStyle } from '../helperTypes';
import { isWorklet } from '../commonTypes';

const SHOULD_BE_USE_WEB = shouldBeUseWeb();

Expand Down Expand Up @@ -175,7 +176,7 @@ function runAnimations(

function styleUpdater(
viewDescriptors: SharedValue<Descriptor[]>,
updater: __BasicWorkletFunction<AnimatedStyle<any>>,
updater: WorkletFunction<[], AnimatedStyle<any>> | (() => AnimatedStyle<any>),
state: AnimatedState,
maybeViewRef: ViewRefSet<any> | undefined,
animationsActive: SharedValue<boolean>,
Expand Down Expand Up @@ -265,12 +266,12 @@ function styleUpdater(

function jestStyleUpdater(
viewDescriptors: SharedValue<Descriptor[]>,
updater: __BasicWorkletFunction<AnimatedStyle<any>>,
updater: WorkletFunction<[], AnimatedStyle<any>> | (() => AnimatedStyle<any>),
state: AnimatedState,
maybeViewRef: ViewRefSet<any> | undefined,
animationsActive: SharedValue<boolean>,
animatedStyle: MutableRefObject<AnimatedStyle<any>>,
adapters: __AdapterWorkletFunction[] = []
adapters: AnimatedPropsAdapterFunction[]
): void {
'worklet';
const animations: AnimatedStyle<any> = state.animations ?? {};
Expand Down Expand Up @@ -413,9 +414,11 @@ export function useAnimatedStyle<Style extends DefaultStyle>(
): Style;

export function useAnimatedStyle<Style extends DefaultStyle>(
updater: WorkletFunction<[], Style>,
updater:
| WorkletFunction<[], Style>
| ((() => Style) & Record<string, unknown>),
dependencies?: DependencyList | null,
adapters?: WorkletFunction | WorkletFunction[],
adapters?: AnimatedPropsAdapterWorklet | AnimatedPropsAdapterWorklet[] | null,
isAnimatedProps = false
): AnimatedStyleHandle<Style> | JestAnimatedStyleHandle<Style> {
const viewsRef: ViewRefSet<unknown> | undefined = useViewRefSet();
Expand All @@ -426,7 +429,7 @@ export function useAnimatedStyle<Style extends DefaultStyle>(
// let web work without a Babel plugin
inputs = dependencies;
}
if (__DEV__ && !inputs.length && !dependencies && !updater.__workletHash) {
if (__DEV__ && !inputs.length && !dependencies && !isWorklet(updater)) {
throw new Error(
`[Reanimated] \`useAnimatedStyle\` was used without a dependency array or Babel plugin. Please explicitly pass a dependency array, or enable the Babel plugin.
For more, see the docs: \`https://docs.swmansion.com/react-native-reanimated/docs/guides/web-support#web-without-the-babel-plugin\`.`
Expand Down Expand Up @@ -483,7 +486,7 @@ For more, see the docs: \`https://docs.swmansion.com/react-native-reanimated/doc
'worklet';
const newValues = updater();
adaptersArray.forEach((adapter) => {
adapter(newValues);
adapter(newValues as Record<string, unknown>);
});
return newValues;
}) as WorkletFunction<[], Style>;
Expand Down
9 changes: 6 additions & 3 deletions src/reanimated2/hook/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import type { WorkletFunction } from '../commonTypes';
import type { DependencyList } from './commonTypes';

// Builds one big hash from multiple worklets' hashes.
export function buildWorkletsHash(
worklets: Record<string, WorkletFunction> | WorkletFunction[]
export function buildWorkletsHash<Args extends unknown[], ReturnValue>(
worklets:
| Record<string, WorkletFunction<Args, ReturnValue>>
| WorkletFunction<Args, ReturnValue>[]
) {
// For arrays `Object.values` returns the array itself.
return Object.values(worklets).reduce(
(acc, worklet: WorkletFunction) => acc + worklet.__workletHash.toString(),
(acc, worklet: WorkletFunction<Args, ReturnValue>) =>
acc + worklet.__workletHash.toString(),
''
);
}
Expand Down
Loading