diff --git a/Common/cpp/Tools/RuntimeDecorator.cpp b/Common/cpp/Tools/RuntimeDecorator.cpp index de2eaeb8e9f..45ed603d7fd 100644 --- a/Common/cpp/Tools/RuntimeDecorator.cpp +++ b/Common/cpp/Tools/RuntimeDecorator.cpp @@ -139,6 +139,7 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt, rt.global().setProperty(rt, "_getCurrentTime", timeFun); rt.global().setProperty(rt, "_frameTimestamp", jsi::Value::undefined()); + rt.global().setProperty(rt, "_eventTimestamp", jsi::Value::undefined()); } } \ No newline at end of file diff --git a/Example/ios/Podfile.lock b/Example/ios/Podfile.lock index 271e6a459c2..45987b90bb1 100644 --- a/Example/ios/Podfile.lock +++ b/Example/ios/Podfile.lock @@ -195,8 +195,8 @@ PODS: - React-cxxreact (= 0.63.0) - React-jsi (= 0.63.0) - React-jsinspector (0.63.0) - - react-native-safe-area-context (3.1.1): - - React + - react-native-safe-area-context (3.1.8): + - React-Core - React-RCTActionSheet (0.63.0): - React-Core/RCTActionSheetHeaders (= 0.63.0) - React-RCTAnimation (0.63.0): @@ -270,7 +270,7 @@ PODS: - React - RNGestureHandler (1.8.0): - React - - RNReanimated (2.0.0-alpha.8): + - RNReanimated (2.0.0-alpha.9): - DoubleConversion - FBLazyVector - FBReactNativeSpec @@ -299,8 +299,8 @@ PODS: - React-RCTVibration - ReactCommon/turbomodule/core - Yoga - - RNScreens (2.9.0): - - React + - RNScreens (2.13.0): + - React-Core - RNSVG (12.1.0): - React - Yoga (1.14.0) @@ -433,7 +433,7 @@ SPEC CHECKSUMS: React-jsi: 254710f3a97e587427bfbf3011dacec2af66a1fc React-jsiexecutor: 0e0cb4e170ca72d4bb1179843d08dcbea3d100ac React-jsinspector: fc661eff8edbfb7e22119382c13f33bcadde0f3c - react-native-safe-area-context: 344b969c45af3d8464d36e8dea264942992ef033 + react-native-safe-area-context: 79fea126c6830c85f65947c223a5e3058a666937 React-RCTActionSheet: aadd91a1d6cbfae50dd41f140004f816e9e47ade React-RCTAnimation: 7fa2ef6c0ef1e3f0b7d2261c827ec94412deb5e6 React-RCTBlob: ccbbc70295aee3a76a70323b48f63fb7a7fcffd6 @@ -446,8 +446,8 @@ SPEC CHECKSUMS: ReactCommon: f63556ee9e41e9802257228237e5e660451a03cf RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f RNGestureHandler: 7a5833d0f788dbd107fbb913e09aa0c1ff333c39 - RNReanimated: 2041d58f790987a36052d777e34c1f82635c2ef3 - RNScreens: c526239bbe0e957b988dacc8d75ac94ec9cb19da + RNReanimated: 51c39025c22b505646c853544600b28f3172cdb5 + RNScreens: 13f23e5498fb4aa749d19a5eda7f8792fbb9d01f RNSVG: ce9d996113475209013317e48b05c21ee988d42e Yoga: 7d2edc5b410474191962e6dee88ee67f9b328b6b diff --git a/Example/src/SwipeableListExample.js b/Example/src/SwipeableListExample.js index cf09998f0a1..55bc530d9f8 100644 --- a/Example/src/SwipeableListExample.js +++ b/Example/src/SwipeableListExample.js @@ -7,6 +7,7 @@ import Animated, { withSpring, withTiming, Easing, + runOnJS, } from 'react-native-reanimated'; import { PanGestureHandler, @@ -112,7 +113,9 @@ function ListItem({ item, onRemove }) { const styles = useAnimatedStyle(() => { if (isRemoving.value) { return { - height: withTiming(0, timingConfig, onRemove), + height: withTiming(0, timingConfig, () => { + runOnJS(onRemove)(); + }), transform: [ { translateX: withTiming(-windowDimensions.width, timingConfig), diff --git a/package.json b/package.json index b81f9a11522..ebe0a41503d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-reanimated", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "description": "More powerful alternative to Animated library for React Native.", "scripts": { "start": "node node_modules/react-native/local-cli/cli.js start", diff --git a/src/createAnimatedComponent.js b/src/createAnimatedComponent.js index a6f4859f5f9..f9f6635153e 100644 --- a/src/createAnimatedComponent.js +++ b/src/createAnimatedComponent.js @@ -1,6 +1,5 @@ import React from 'react'; import { findNodeHandle, Platform, StyleSheet } from 'react-native'; -import ReactNative from 'react-native/Libraries/Renderer/shims/ReactNative'; import ReanimatedEventEmitter from './ReanimatedEventEmitter'; import AnimatedEvent from './core/AnimatedEvent'; @@ -11,6 +10,7 @@ import WorkletEventHandler from './reanimated2/WorkletEventHandler'; import invariant from 'fbjs/lib/invariant'; import { adaptViewConfig } from './ConfigHelper'; +import { RNRenderer } from './reanimated2/platform-specific/RNRenderer'; const setAndForwardRef = require('react-native/Libraries/Utilities/setAndForwardRef'); @@ -230,18 +230,23 @@ export default function createAnimatedComponent(Component) { ? this.props.style : [this.props.style]; styles = flattenArray(styles); - - const hostInstance = ReactNative.findHostInstance_DEPRECATED(this); - // 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 - const viewTag = hostInstance._nativeTag; - /** - * RN uses viewConfig for components for storing different properties of the component(example: https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/ScrollViewViewConfig.js#L16). - * The name we're looking for is in the field named uiViewClassName. - */ - const viewName = hostInstance.viewConfig?.uiViewClassName; - // update UI props whitelist for this view - if (this._hasReanimated2Props(styles)) { - adaptViewConfig(hostInstance.viewConfig); + let viewTag, viewName; + if (Platform.OS === 'web') { + viewTag = findNodeHandle(this); + viewName = null; + } else { + const hostInstance = RNRenderer.findHostInstance_DEPRECATED(this); + // 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/master/Libraries/Components/ScrollView/ScrollViewViewConfig.js#L16). + * The name we're looking for is in the field named uiViewClassName. + */ + viewName = hostInstance.viewConfig?.uiViewClassName; + // update UI props whitelist for this view + if (this._hasReanimated2Props(styles)) { + adaptViewConfig(hostInstance.viewConfig); + } } styles.forEach((style) => { diff --git a/src/reanimated2/Hooks.js b/src/reanimated2/Hooks.js index 3435296aaf6..698db9f6ad1 100644 --- a/src/reanimated2/Hooks.js +++ b/src/reanimated2/Hooks.js @@ -72,7 +72,10 @@ function prepareAnimation(animatedProp, lastAnimation, lastValue) { if (lastValue.value !== undefined) { // previously it was a shared value value = lastValue.value; - } else if (lastValue.onFrame !== undefined) { + } else if ( + lastValue.onFrame !== undefined && + lastAnimation?.current + ) { // it was an animation before, copy its state value = lastAnimation.current; } diff --git a/src/reanimated2/core.js b/src/reanimated2/core.js index fec387a7884..d46189837e3 100644 --- a/src/reanimated2/core.js +++ b/src/reanimated2/core.js @@ -1,6 +1,7 @@ /* global _WORKLET _getCurrentTime _frameTimestamp _eventTimestamp */ import NativeReanimated from './NativeReanimated'; +import { Platform } from 'react-native'; global.__reanimatedWorkletInit = function(worklet) { worklet.__worklet = true; @@ -44,7 +45,7 @@ export function getViewProp(viewTag, propName) { }); } -export function getTimestamp() { +function _getTimestamp() { 'worklet'; if (_frameTimestamp) { return _frameTimestamp; @@ -55,6 +56,14 @@ export function getTimestamp() { return _getCurrentTime(); } +export function getTimestamp() { + 'worklet'; + if (Platform.OS === 'web') { + return NativeReanimated.getTimestamp(); + } + return _getTimestamp(); +} + function workletValueSetter(value) { 'worklet'; const previousAnimation = this._animation; diff --git a/src/reanimated2/js-reanimated/JSReanimated.js b/src/reanimated2/js-reanimated/JSReanimated.js index 09dce3533b7..729368100b4 100644 --- a/src/reanimated2/js-reanimated/JSReanimated.js +++ b/src/reanimated2/js-reanimated/JSReanimated.js @@ -15,6 +15,10 @@ export default class JSReanimated { this.maybeRequestRender(); } + getTimestamp() { + return window.performance.now(); + } + maybeRequestRender() { if (!this._renderRequested) { this._renderRequested = true; @@ -22,7 +26,7 @@ export default class JSReanimated { requestAnimationFrame((timestampMs) => { this._renderRequested = false; - this._onRender(timestampMs); + this._onRender(this.getTimestamp()); }); } } diff --git a/src/reanimated2/js-reanimated/index.js b/src/reanimated2/js-reanimated/index.js index f701935aadc..ec2c7a45ec3 100644 --- a/src/reanimated2/js-reanimated/index.js +++ b/src/reanimated2/js-reanimated/index.js @@ -2,6 +2,8 @@ import JSReanimated from './JSReanimated'; const reanimatedJS = new JSReanimated(); +global._frameTimestamp = null; + global._updatePropsJS = (viewTag, viewName, updates, viewRef) => { if (viewRef.current && viewRef.current._component) { const [rawStyles] = Object.keys(updates).reduce( diff --git a/src/reanimated2/platform-specific/RNRenderer.js b/src/reanimated2/platform-specific/RNRenderer.js new file mode 100644 index 00000000000..f6a69777b6a --- /dev/null +++ b/src/reanimated2/platform-specific/RNRenderer.js @@ -0,0 +1,3 @@ +export { + default as RNRenderer, +} from 'react-native/Libraries/Renderer/shims/ReactNative'; diff --git a/src/reanimated2/platform-specific/RNRenderer.web.js b/src/reanimated2/platform-specific/RNRenderer.web.js new file mode 100644 index 00000000000..e69de29bb2d