react-native-reanimated 3.15.2 → 3.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Common/cpp/reanimated/Fabric/PropsRegistry.h +15 -12
- package/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.cpp +7 -8
- package/Common/cpp/reanimated/Fabric/ReanimatedCommitShadowNode.h +16 -1
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp +82 -0
- package/Common/cpp/reanimated/Fabric/ReanimatedMountHook.h +33 -0
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy.cpp +76 -36
- package/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsUtils.h +4 -0
- package/Common/cpp/reanimated/NativeModules/NativeReanimatedModule.cpp +53 -40
- package/Common/cpp/reanimated/NativeModules/NativeReanimatedModule.h +2 -0
- package/lib/module/initializers.js +37 -3
- package/lib/module/initializers.js.map +1 -1
- package/lib/module/platform-specific/jsVersion.js +1 -1
- package/lib/module/platform-specific/jsVersion.js.map +1 -1
- package/lib/typescript/platform-specific/jsVersion.d.ts +1 -1
- package/package.json +1 -1
- package/src/initializers.ts +40 -1
- package/src/platform-specific/jsVersion.ts +1 -1
|
@@ -25,22 +25,24 @@ class PropsRegistry {
|
|
|
25
25
|
|
|
26
26
|
void remove(const Tag tag);
|
|
27
27
|
|
|
28
|
-
void
|
|
29
|
-
|
|
28
|
+
void pauseReanimatedCommits() {
|
|
29
|
+
isPaused_ = true;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
bool shouldReanimatedSkipCommit() {
|
|
33
|
-
|
|
34
|
-
// In RN 0.73+ we have a mount hook that will properly unset this flag
|
|
35
|
-
// after a non-Reanimated commit.
|
|
36
|
-
return shouldReanimatedSkipCommit_;
|
|
37
|
-
#else
|
|
38
|
-
return shouldReanimatedSkipCommit_.exchange(false);
|
|
39
|
-
#endif
|
|
33
|
+
return isPaused_;
|
|
40
34
|
}
|
|
41
35
|
|
|
42
|
-
void
|
|
43
|
-
|
|
36
|
+
void unpauseReanimatedCommits() {
|
|
37
|
+
isPaused_ = false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void pleaseCommitAfterPause() {
|
|
41
|
+
shouldCommitAfterPause_ = true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
bool shouldCommitAfterPause() {
|
|
45
|
+
return shouldCommitAfterPause_.exchange(false);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
private:
|
|
@@ -48,7 +50,8 @@ class PropsRegistry {
|
|
|
48
50
|
|
|
49
51
|
mutable std::mutex mutex_; // Protects `map_`.
|
|
50
52
|
|
|
51
|
-
std::atomic<bool>
|
|
53
|
+
std::atomic<bool> isPaused_;
|
|
54
|
+
std::atomic<bool> shouldCommitAfterPause_;
|
|
52
55
|
};
|
|
53
56
|
|
|
54
57
|
} // namespace reanimated
|
|
@@ -26,12 +26,7 @@ ReanimatedCommitHook::~ReanimatedCommitHook() noexcept {
|
|
|
26
26
|
RootShadowNode::Unshared ReanimatedCommitHook::shadowTreeWillCommit(
|
|
27
27
|
ShadowTree const &,
|
|
28
28
|
RootShadowNode::Shared const &,
|
|
29
|
-
#if REACT_NATIVE_MINOR_VERSION >= 73
|
|
30
29
|
RootShadowNode::Unshared const &newRootShadowNode) noexcept {
|
|
31
|
-
#else
|
|
32
|
-
RootShadowNode::Unshared const &newRootShadowNode) const noexcept {
|
|
33
|
-
#endif
|
|
34
|
-
|
|
35
30
|
auto reaShadowNode =
|
|
36
31
|
std::reinterpret_pointer_cast<ReanimatedCommitShadowNode>(
|
|
37
32
|
newRootShadowNode);
|
|
@@ -40,11 +35,12 @@ RootShadowNode::Unshared ReanimatedCommitHook::shadowTreeWillCommit(
|
|
|
40
35
|
// ShadowTree commited by Reanimated, no need to apply updates from
|
|
41
36
|
// PropsRegistry
|
|
42
37
|
reaShadowNode->unsetReanimatedCommitTrait();
|
|
38
|
+
reaShadowNode->setReanimatedMountTrait();
|
|
43
39
|
return newRootShadowNode;
|
|
44
40
|
}
|
|
45
41
|
|
|
46
42
|
// ShadowTree not commited by Reanimated, apply updates from PropsRegistry
|
|
47
|
-
|
|
43
|
+
reaShadowNode->unsetReanimatedMountTrait();
|
|
48
44
|
RootShadowNode::Unshared rootNode = newRootShadowNode;
|
|
49
45
|
PropsMap propsMap;
|
|
50
46
|
|
|
@@ -58,12 +54,15 @@ RootShadowNode::Unshared ReanimatedCommitHook::shadowTreeWillCommit(
|
|
|
58
54
|
|
|
59
55
|
rootNode = cloneShadowTreeWithNewProps(*rootNode, propsMap);
|
|
60
56
|
|
|
61
|
-
// If the commit comes from React Native then
|
|
57
|
+
// If the commit comes from React Native then pause commits from
|
|
62
58
|
// Reanimated since the ShadowTree to be committed by Reanimated may not
|
|
63
59
|
// include the new changes from React Native yet and all changes of animated
|
|
64
60
|
// props will be applied in ReanimatedCommitHook by iterating over
|
|
65
61
|
// PropsRegistry.
|
|
66
|
-
|
|
62
|
+
// This is very important, since if we didn't pause Reanimated commits,
|
|
63
|
+
// it could lead to RN commits being delayed until the animation is finished
|
|
64
|
+
// (very bad).
|
|
65
|
+
propsRegistry_->pauseReanimatedCommits();
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
return rootNode;
|
|
@@ -9,8 +9,14 @@ namespace reanimated {
|
|
|
9
9
|
// We need this information to skip unnecessary updates in
|
|
10
10
|
// the commit hook.
|
|
11
11
|
// Currently RN traits go up to 10, so hopefully
|
|
12
|
-
// the arbitrarily chosen
|
|
12
|
+
// the arbitrarily chosen numbers 27 and 28 will be safe :)
|
|
13
|
+
|
|
14
|
+
// We have to use 2 traits, because we want to distinguish reanimated
|
|
15
|
+
// commits both in the commit hook and mount hook. If we only had one trait
|
|
16
|
+
// and didn't remove it in the commit hook, then any node that would clone
|
|
17
|
+
// this node would also have our commit trait, rendering this trait useless.
|
|
13
18
|
constexpr ShadowNodeTraits::Trait ReanimatedCommitTrait{1 << 27};
|
|
19
|
+
constexpr ShadowNodeTraits::Trait ReanimatedMountTrait{1 << 28};
|
|
14
20
|
|
|
15
21
|
class ReanimatedCommitShadowNode : public ShadowNode {
|
|
16
22
|
public:
|
|
@@ -23,6 +29,15 @@ class ReanimatedCommitShadowNode : public ShadowNode {
|
|
|
23
29
|
inline bool hasReanimatedCommitTrait() {
|
|
24
30
|
return traits_.check(ReanimatedCommitTrait);
|
|
25
31
|
}
|
|
32
|
+
inline void setReanimatedMountTrait() {
|
|
33
|
+
traits_.set(ReanimatedMountTrait);
|
|
34
|
+
}
|
|
35
|
+
inline void unsetReanimatedMountTrait() {
|
|
36
|
+
traits_.unset(ReanimatedMountTrait);
|
|
37
|
+
}
|
|
38
|
+
inline bool hasReanimatedMountTrait() {
|
|
39
|
+
return traits_.check(ReanimatedMountTrait);
|
|
40
|
+
}
|
|
26
41
|
};
|
|
27
42
|
|
|
28
43
|
} // namespace reanimated
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
2
|
+
|
|
3
|
+
#include "ReanimatedMountHook.h"
|
|
4
|
+
#include "ReanimatedCommitShadowNode.h"
|
|
5
|
+
|
|
6
|
+
namespace reanimated {
|
|
7
|
+
|
|
8
|
+
ReanimatedMountHook::ReanimatedMountHook(
|
|
9
|
+
const std::shared_ptr<PropsRegistry> &propsRegistry,
|
|
10
|
+
const std::shared_ptr<UIManager> &uiManager)
|
|
11
|
+
: propsRegistry_(propsRegistry), uiManager_(uiManager) {
|
|
12
|
+
uiManager_->registerMountHook(*this);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
ReanimatedMountHook::~ReanimatedMountHook() noexcept {
|
|
16
|
+
uiManager_->unregisterMountHook(*this);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void ReanimatedMountHook::shadowTreeDidMount(
|
|
20
|
+
RootShadowNode::Shared const &rootShadowNode,
|
|
21
|
+
double) noexcept {
|
|
22
|
+
auto reaShadowNode =
|
|
23
|
+
std::reinterpret_pointer_cast<ReanimatedCommitShadowNode>(
|
|
24
|
+
std::const_pointer_cast<RootShadowNode>(rootShadowNode));
|
|
25
|
+
|
|
26
|
+
if (reaShadowNode->hasReanimatedMountTrait()) {
|
|
27
|
+
// We mark reanimated commits with ReanimatedMountTrait. We don't want other
|
|
28
|
+
// shadow nodes to use this trait, but since this rootShadowNode is Shared,
|
|
29
|
+
// we don't have that guarantee. That's why we also unset this trait in the
|
|
30
|
+
// commit hook. We remove it here mainly for the sake of cleanliness.
|
|
31
|
+
reaShadowNode->unsetReanimatedMountTrait();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// When commit from React Native has finished, we reset the skip commit flag
|
|
36
|
+
// in order to allow Reanimated to commit its tree
|
|
37
|
+
propsRegistry_->unpauseReanimatedCommits();
|
|
38
|
+
if (!propsRegistry_->shouldCommitAfterPause()) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const auto &shadowTreeRegistry = uiManager_->getShadowTreeRegistry();
|
|
43
|
+
shadowTreeRegistry.visit(
|
|
44
|
+
rootShadowNode->getSurfaceId(), [&](ShadowTree const &shadowTree) {
|
|
45
|
+
shadowTree.commit(
|
|
46
|
+
[&](RootShadowNode const &oldRootShadowNode)
|
|
47
|
+
-> RootShadowNode::Unshared {
|
|
48
|
+
PropsMap propsMap;
|
|
49
|
+
|
|
50
|
+
RootShadowNode::Unshared rootNode =
|
|
51
|
+
std::static_pointer_cast<RootShadowNode>(
|
|
52
|
+
oldRootShadowNode.ShadowNode::clone({}));
|
|
53
|
+
{
|
|
54
|
+
auto lock = propsRegistry_->createLock();
|
|
55
|
+
|
|
56
|
+
propsRegistry_->for_each([&](const ShadowNodeFamily &family,
|
|
57
|
+
const folly::dynamic &props) {
|
|
58
|
+
propsMap[&family].emplace_back(props);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
rootNode =
|
|
62
|
+
cloneShadowTreeWithNewProps(oldRootShadowNode, propsMap);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Mark the commit as Reanimated commit so that we can
|
|
66
|
+
// distinguish it in ReanimatedCommitHook.
|
|
67
|
+
auto reaShadowNode =
|
|
68
|
+
std::reinterpret_pointer_cast<ReanimatedCommitShadowNode>(
|
|
69
|
+
rootNode);
|
|
70
|
+
reaShadowNode->setReanimatedCommitTrait();
|
|
71
|
+
|
|
72
|
+
return rootNode;
|
|
73
|
+
},
|
|
74
|
+
{/* .enableStateReconciliation = */
|
|
75
|
+
false,
|
|
76
|
+
/* .mountSynchronously = */ true});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
} // namespace reanimated
|
|
81
|
+
|
|
82
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
3
|
+
|
|
4
|
+
#include "PropsRegistry.h"
|
|
5
|
+
|
|
6
|
+
#include <react/renderer/uimanager/UIManagerMountHook.h>
|
|
7
|
+
#include "ShadowTreeCloner.h"
|
|
8
|
+
|
|
9
|
+
#include <memory>
|
|
10
|
+
|
|
11
|
+
namespace reanimated {
|
|
12
|
+
|
|
13
|
+
using namespace facebook::react;
|
|
14
|
+
|
|
15
|
+
class ReanimatedMountHook : public UIManagerMountHook {
|
|
16
|
+
public:
|
|
17
|
+
ReanimatedMountHook(
|
|
18
|
+
const std::shared_ptr<PropsRegistry> &propsRegistry,
|
|
19
|
+
const std::shared_ptr<UIManager> &uiManager);
|
|
20
|
+
~ReanimatedMountHook() noexcept override;
|
|
21
|
+
|
|
22
|
+
void shadowTreeDidMount(
|
|
23
|
+
RootShadowNode::Shared const &rootShadowNode,
|
|
24
|
+
double mountTime) noexcept override;
|
|
25
|
+
|
|
26
|
+
private:
|
|
27
|
+
const std::shared_ptr<PropsRegistry> propsRegistry_;
|
|
28
|
+
const std::shared_ptr<UIManager> uiManager_;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
} // namespace reanimated
|
|
32
|
+
|
|
33
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
@@ -22,7 +22,8 @@ std::optional<MountingTransaction> LayoutAnimationsProxy::pullTransaction(
|
|
|
22
22
|
const TransactionTelemetry &telemetry,
|
|
23
23
|
ShadowViewMutationList mutations) const {
|
|
24
24
|
#ifdef LAYOUT_ANIMATIONS_LOGS
|
|
25
|
-
LOG(INFO) <<
|
|
25
|
+
LOG(INFO) << std::endl;
|
|
26
|
+
LOG(INFO) << "pullTransaction " << std::this_thread::get_id() << " "
|
|
26
27
|
<< surfaceId << std::endl;
|
|
27
28
|
#endif
|
|
28
29
|
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
|
|
@@ -240,15 +241,15 @@ void LayoutAnimationsProxy::handleRemovals(
|
|
|
240
241
|
if (!startAnimationsRecursively(
|
|
241
242
|
node, true, true, false, filteredMutations)) {
|
|
242
243
|
filteredMutations.push_back(node->mutation);
|
|
243
|
-
nodeForTag_.erase(node->tag);
|
|
244
244
|
node->unflattenedParent->removeChildFromUnflattenedTree(node); //???
|
|
245
|
-
#ifdef LAYOUT_ANIMATIONS_LOGS
|
|
246
|
-
LOG(INFO) << "delete " << node->tag << std::endl;
|
|
247
|
-
#endif
|
|
248
245
|
if (node->state != MOVED) {
|
|
249
246
|
maybeCancelAnimation(node->tag);
|
|
250
247
|
filteredMutations.push_back(ShadowViewMutation::DeleteMutation(
|
|
251
248
|
node->mutation.oldChildShadowView));
|
|
249
|
+
nodeForTag_.erase(node->tag);
|
|
250
|
+
#ifdef LAYOUT_ANIMATIONS_LOGS
|
|
251
|
+
LOG(INFO) << "delete " << node->tag << std::endl;
|
|
252
|
+
#endif
|
|
252
253
|
}
|
|
253
254
|
}
|
|
254
255
|
}
|
|
@@ -268,6 +269,7 @@ void LayoutAnimationsProxy::handleUpdatesAndEnterings(
|
|
|
268
269
|
ShadowViewMutationList &mutations,
|
|
269
270
|
const PropsParserContext &propsParserContext,
|
|
270
271
|
SurfaceId surfaceId) const {
|
|
272
|
+
std::unordered_map<Tag, ShadowView> oldShadowViewsForReparentings;
|
|
271
273
|
for (auto &mutation : mutations) {
|
|
272
274
|
maybeUpdateWindowDimensions(mutation, surfaceId);
|
|
273
275
|
|
|
@@ -291,7 +293,14 @@ void LayoutAnimationsProxy::handleUpdatesAndEnterings(
|
|
|
291
293
|
if (movedViews.contains(tag)) {
|
|
292
294
|
auto layoutAnimationIt = layoutAnimations_.find(tag);
|
|
293
295
|
if (layoutAnimationIt == layoutAnimations_.end()) {
|
|
294
|
-
|
|
296
|
+
if (oldShadowViewsForReparentings.contains(tag)) {
|
|
297
|
+
filteredMutations.push_back(ShadowViewMutation::InsertMutation(
|
|
298
|
+
mutation.parentShadowView,
|
|
299
|
+
oldShadowViewsForReparentings[tag],
|
|
300
|
+
mutation.index));
|
|
301
|
+
} else {
|
|
302
|
+
filteredMutations.push_back(mutation);
|
|
303
|
+
}
|
|
295
304
|
continue;
|
|
296
305
|
}
|
|
297
306
|
|
|
@@ -338,6 +347,10 @@ void LayoutAnimationsProxy::handleUpdatesAndEnterings(
|
|
|
338
347
|
updateOngoingAnimationTarget(tag, mutation);
|
|
339
348
|
continue;
|
|
340
349
|
}
|
|
350
|
+
|
|
351
|
+
// store the oldChildShadowView, so that we can use this ShadowView when
|
|
352
|
+
// the view is inserted
|
|
353
|
+
oldShadowViewsForReparentings[tag] = mutation.oldChildShadowView;
|
|
341
354
|
startLayoutAnimation(tag, mutation);
|
|
342
355
|
break;
|
|
343
356
|
}
|
|
@@ -471,6 +484,7 @@ bool LayoutAnimationsProxy::startAnimationsRecursively(
|
|
|
471
484
|
hasAnimatedChildren = true;
|
|
472
485
|
} else {
|
|
473
486
|
endAnimationsRecursively(subNode, mutations);
|
|
487
|
+
toBeRemoved.push_back(subNode);
|
|
474
488
|
}
|
|
475
489
|
} else if (startAnimationsRecursively(
|
|
476
490
|
subNode,
|
|
@@ -486,7 +500,7 @@ bool LayoutAnimationsProxy::startAnimationsRecursively(
|
|
|
486
500
|
hasAnimatedChildren = true;
|
|
487
501
|
} else if (subNode->state == MOVED) {
|
|
488
502
|
mutations.push_back(subNode->mutation);
|
|
489
|
-
|
|
503
|
+
toBeRemoved.push_back(subNode);
|
|
490
504
|
} else if (shouldRemoveSubviewsWithoutAnimations) {
|
|
491
505
|
maybeCancelAnimation(subNode->tag);
|
|
492
506
|
mutations.push_back(subNode->mutation);
|
|
@@ -508,6 +522,14 @@ bool LayoutAnimationsProxy::startAnimationsRecursively(
|
|
|
508
522
|
}
|
|
509
523
|
|
|
510
524
|
if (node->state == MOVED) {
|
|
525
|
+
auto replacement = std::make_shared<Node>(*node);
|
|
526
|
+
for (auto subNode : node->children) {
|
|
527
|
+
subNode->parent = replacement;
|
|
528
|
+
}
|
|
529
|
+
for (auto subNode : node->unflattenedChildren) {
|
|
530
|
+
subNode->unflattenedParent = replacement;
|
|
531
|
+
}
|
|
532
|
+
nodeForTag_[replacement->tag] = replacement;
|
|
511
533
|
return false;
|
|
512
534
|
}
|
|
513
535
|
|
|
@@ -594,30 +616,37 @@ void LayoutAnimationsProxy::startEnteringAnimation(
|
|
|
594
616
|
LOG(INFO) << "start entering animation for tag " << tag << std::endl;
|
|
595
617
|
#endif
|
|
596
618
|
auto finalView = std::make_shared<ShadowView>(mutation.newChildShadowView);
|
|
597
|
-
auto current = std::make_shared<ShadowView>(mutation.
|
|
619
|
+
auto current = std::make_shared<ShadowView>(mutation.newChildShadowView);
|
|
598
620
|
auto parent = std::make_shared<ShadowView>(mutation.parentShadowView);
|
|
599
621
|
|
|
600
622
|
auto &viewProps =
|
|
601
623
|
static_cast<const ViewProps &>(*mutation.newChildShadowView.props);
|
|
602
|
-
|
|
603
|
-
|
|
624
|
+
auto opacity = viewProps.opacity;
|
|
625
|
+
|
|
626
|
+
uiScheduler_->scheduleOnUI(
|
|
627
|
+
[finalView, current, parent, mutation, opacity, this, tag]() {
|
|
628
|
+
Rect window{};
|
|
629
|
+
{
|
|
630
|
+
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
|
|
631
|
+
layoutAnimations_.insert_or_assign(
|
|
632
|
+
tag, LayoutAnimation{finalView, current, parent, opacity});
|
|
633
|
+
window =
|
|
634
|
+
surfaceManager.getWindow(mutation.newChildShadowView.surfaceId);
|
|
635
|
+
}
|
|
604
636
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
layoutAnimationsManager_->startLayoutAnimation(
|
|
619
|
-
uiRuntime_, tag, LayoutAnimationType::ENTERING, yogaValues);
|
|
620
|
-
});
|
|
637
|
+
Snapshot values(mutation.newChildShadowView, window);
|
|
638
|
+
jsi::Object yogaValues(uiRuntime_);
|
|
639
|
+
yogaValues.setProperty(uiRuntime_, "targetOriginX", values.x);
|
|
640
|
+
yogaValues.setProperty(uiRuntime_, "targetGlobalOriginX", values.x);
|
|
641
|
+
yogaValues.setProperty(uiRuntime_, "targetOriginY", values.y);
|
|
642
|
+
yogaValues.setProperty(uiRuntime_, "targetGlobalOriginY", values.y);
|
|
643
|
+
yogaValues.setProperty(uiRuntime_, "targetWidth", values.width);
|
|
644
|
+
yogaValues.setProperty(uiRuntime_, "targetHeight", values.height);
|
|
645
|
+
yogaValues.setProperty(uiRuntime_, "windowWidth", values.windowWidth);
|
|
646
|
+
yogaValues.setProperty(uiRuntime_, "windowHeight", values.windowHeight);
|
|
647
|
+
layoutAnimationsManager_->startLayoutAnimation(
|
|
648
|
+
uiRuntime_, tag, LayoutAnimationType::ENTERING, yogaValues);
|
|
649
|
+
});
|
|
621
650
|
}
|
|
622
651
|
|
|
623
652
|
void LayoutAnimationsProxy::startExitingAnimation(
|
|
@@ -627,12 +656,18 @@ void LayoutAnimationsProxy::startExitingAnimation(
|
|
|
627
656
|
LOG(INFO) << "start exiting animation for tag " << tag << std::endl;
|
|
628
657
|
#endif
|
|
629
658
|
auto surfaceId = mutation.oldChildShadowView.surfaceId;
|
|
630
|
-
auto oldView = mutation.oldChildShadowView;
|
|
631
|
-
createLayoutAnimation(mutation, oldView, surfaceId, tag);
|
|
632
659
|
|
|
633
|
-
|
|
660
|
+
uiScheduler_->scheduleOnUI([this, tag, mutation, surfaceId]() {
|
|
661
|
+
auto oldView = mutation.oldChildShadowView;
|
|
662
|
+
Rect window{};
|
|
663
|
+
{
|
|
664
|
+
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
|
|
665
|
+
createLayoutAnimation(mutation, oldView, surfaceId, tag);
|
|
666
|
+
window = surfaceManager.getWindow(surfaceId);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
Snapshot values(oldView, window);
|
|
634
670
|
|
|
635
|
-
uiScheduler_->scheduleOnUI([values, this, tag]() {
|
|
636
671
|
jsi::Object yogaValues(uiRuntime_);
|
|
637
672
|
yogaValues.setProperty(uiRuntime_, "currentOriginX", values.x);
|
|
638
673
|
yogaValues.setProperty(uiRuntime_, "currentGlobalOriginX", values.x);
|
|
@@ -655,14 +690,19 @@ void LayoutAnimationsProxy::startLayoutAnimation(
|
|
|
655
690
|
LOG(INFO) << "start layout animation for tag " << tag << std::endl;
|
|
656
691
|
#endif
|
|
657
692
|
auto surfaceId = mutation.oldChildShadowView.surfaceId;
|
|
658
|
-
auto oldView = mutation.oldChildShadowView;
|
|
659
|
-
createLayoutAnimation(mutation, oldView, surfaceId, tag);
|
|
660
693
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
694
|
+
uiScheduler_->scheduleOnUI([this, mutation, surfaceId, tag]() {
|
|
695
|
+
auto oldView = mutation.oldChildShadowView;
|
|
696
|
+
Rect window{};
|
|
697
|
+
{
|
|
698
|
+
auto lock = std::unique_lock<std::recursive_mutex>(mutex);
|
|
699
|
+
createLayoutAnimation(mutation, oldView, surfaceId, tag);
|
|
700
|
+
window = surfaceManager.getWindow(surfaceId);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
Snapshot currentValues(oldView, window);
|
|
704
|
+
Snapshot targetValues(mutation.newChildShadowView, window);
|
|
664
705
|
|
|
665
|
-
uiScheduler_->scheduleOnUI([currentValues, targetValues, this, tag]() {
|
|
666
706
|
jsi::Object yogaValues(uiRuntime_);
|
|
667
707
|
yogaValues.setProperty(uiRuntime_, "currentOriginX", currentValues.x);
|
|
668
708
|
yogaValues.setProperty(uiRuntime_, "currentGlobalOriginX", currentValues.x);
|
|
@@ -83,6 +83,10 @@ struct Node {
|
|
|
83
83
|
: children(std::move(node.children)),
|
|
84
84
|
unflattenedChildren(std::move(node.unflattenedChildren)),
|
|
85
85
|
tag(node.tag) {}
|
|
86
|
+
Node(Node &node)
|
|
87
|
+
: children(node.children),
|
|
88
|
+
unflattenedChildren(node.unflattenedChildren),
|
|
89
|
+
tag(node.tag) {}
|
|
86
90
|
virtual ~Node() = default;
|
|
87
91
|
};
|
|
88
92
|
|
|
@@ -32,6 +32,18 @@
|
|
|
32
32
|
#include <fbjni/fbjni.h>
|
|
33
33
|
#endif
|
|
34
34
|
|
|
35
|
+
// Standard `__cplusplus` macro reference:
|
|
36
|
+
// https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros
|
|
37
|
+
#if REACT_NATIVE_MINOR_VERSION >= 75 || __cplusplus >= 20202L
|
|
38
|
+
// Implicit copy capture of `this` is deprecated in NDK27, which uses C++20.
|
|
39
|
+
#define COPY_CAPTURE_WITH_THIS [ =, this ] // NOLINT (whitespace/braces)
|
|
40
|
+
#else
|
|
41
|
+
// React Native 0.75 is the last one which allows NDK23. NDK23 uses C++17 and
|
|
42
|
+
// explicitly disallows C++20 features, including the syntax above. Therefore we
|
|
43
|
+
// fallback to the deprecated syntax here.
|
|
44
|
+
#define COPY_CAPTURE_WITH_THIS [=] // NOLINT (whitespace/braces)
|
|
45
|
+
#endif // REACT_NATIVE_MINOR_VERSION >= 75 || __cplusplus >= 20202L
|
|
46
|
+
|
|
35
47
|
using namespace facebook;
|
|
36
48
|
|
|
37
49
|
#if REACT_NATIVE_MINOR_VERSION == 73 && defined(RCT_NEW_ARCH_ENABLED)
|
|
@@ -195,13 +207,13 @@ void NativeReanimatedModule::scheduleOnUI(
|
|
|
195
207
|
const jsi::Value &worklet) {
|
|
196
208
|
auto shareableWorklet = extractShareableOrThrow<ShareableWorklet>(
|
|
197
209
|
rt, worklet, "[Reanimated] Only worklets can be scheduled to run on UI.");
|
|
198
|
-
uiScheduler_->scheduleOnUI(
|
|
210
|
+
uiScheduler_->scheduleOnUI(COPY_CAPTURE_WITH_THIS {
|
|
199
211
|
#if JS_RUNTIME_HERMES
|
|
200
|
-
// JSI's scope defined here allows for JSI-objects to be cleared up
|
|
201
|
-
// each runtime loop. Within these loops we typically create some
|
|
202
|
-
// JSI objects and hence it allows for such objects to be
|
|
203
|
-
// much sooner.
|
|
204
|
-
//
|
|
212
|
+
// JSI's scope defined here allows for JSI-objects to be cleared up
|
|
213
|
+
// after each runtime loop. Within these loops we typically create some
|
|
214
|
+
// temporary JSI objects and hence it allows for such objects to be
|
|
215
|
+
// garbage collected much sooner. Apparently the scope API is only
|
|
216
|
+
// supported on Hermes at the moment.
|
|
205
217
|
const auto scope = jsi::Scope(uiWorkletRuntime_->getJSIRuntime());
|
|
206
218
|
#endif
|
|
207
219
|
uiWorkletRuntime_->runGuarded(shareableWorklet);
|
|
@@ -261,7 +273,7 @@ jsi::Value NativeReanimatedModule::registerEventHandler(
|
|
|
261
273
|
rt, worklet, "[Reanimated] Event handler must be a worklet.");
|
|
262
274
|
int emitterReactTagInt = emitterReactTag.asNumber();
|
|
263
275
|
|
|
264
|
-
uiScheduler_->scheduleOnUI(
|
|
276
|
+
uiScheduler_->scheduleOnUI(COPY_CAPTURE_WITH_THIS {
|
|
265
277
|
auto handler = std::make_shared<WorkletEventHandler>(
|
|
266
278
|
newRegistrationId, eventNameStr, emitterReactTagInt, handlerShareable);
|
|
267
279
|
eventHandlerRegistry_->registerEventHandler(std::move(handler));
|
|
@@ -275,7 +287,9 @@ void NativeReanimatedModule::unregisterEventHandler(
|
|
|
275
287
|
const jsi::Value ®istrationId) {
|
|
276
288
|
uint64_t id = registrationId.asNumber();
|
|
277
289
|
uiScheduler_->scheduleOnUI(
|
|
278
|
-
|
|
290
|
+
COPY_CAPTURE_WITH_THIS
|
|
291
|
+
|
|
292
|
+
{ eventHandlerRegistry_->unregisterEventHandler(id); });
|
|
279
293
|
}
|
|
280
294
|
|
|
281
295
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
@@ -371,20 +385,23 @@ jsi::Value NativeReanimatedModule::getViewProp(
|
|
|
371
385
|
|
|
372
386
|
const int viewTagInt = viewTag.asNumber();
|
|
373
387
|
|
|
374
|
-
uiScheduler_->scheduleOnUI(
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
+
uiScheduler_->scheduleOnUI(
|
|
389
|
+
COPY_CAPTURE_WITH_THIS
|
|
390
|
+
|
|
391
|
+
() {
|
|
392
|
+
jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
|
|
393
|
+
const jsi::Value propNameValue =
|
|
394
|
+
jsi::String::createFromUtf8(uiRuntime, propNameStr);
|
|
395
|
+
const auto resultValue =
|
|
396
|
+
obtainPropFunction_(uiRuntime, viewTagInt, propNameValue);
|
|
397
|
+
const auto resultStr = resultValue.asString(uiRuntime).utf8(uiRuntime);
|
|
398
|
+
|
|
399
|
+
jsScheduler_->scheduleOnJS([=](jsi::Runtime &rnRuntime) {
|
|
400
|
+
const auto resultValue =
|
|
401
|
+
jsi::String::createFromUtf8(rnRuntime, resultStr);
|
|
402
|
+
funPtr->call(rnRuntime, resultValue);
|
|
403
|
+
});
|
|
404
|
+
});
|
|
388
405
|
return jsi::Value::undefined();
|
|
389
406
|
}
|
|
390
407
|
|
|
@@ -644,8 +661,9 @@ void NativeReanimatedModule::performOperations() {
|
|
|
644
661
|
{
|
|
645
662
|
auto lock = propsRegistry_->createLock();
|
|
646
663
|
|
|
647
|
-
if (copiedOperationsQueue.size() > 0
|
|
648
|
-
|
|
664
|
+
if (copiedOperationsQueue.size() > 0 &&
|
|
665
|
+
propsRegistry_->shouldReanimatedSkipCommit()) {
|
|
666
|
+
propsRegistry_->pleaseCommitAfterPause();
|
|
649
667
|
}
|
|
650
668
|
|
|
651
669
|
// remove recently unmounted ShadowNodes from PropsRegistry
|
|
@@ -722,15 +740,9 @@ void NativeReanimatedModule::performOperations() {
|
|
|
722
740
|
react_native_assert(family->getSurfaceId() == surfaceId_);
|
|
723
741
|
propsMap[family].emplace_back(rt, std::move(*props));
|
|
724
742
|
|
|
725
|
-
#if REACT_NATIVE_MINOR_VERSION >= 73
|
|
726
|
-
// Fix for catching nullptr returned from commit hook was
|
|
727
|
-
// introduced in 0.72.4 but we have only check for minor version
|
|
728
|
-
// of React Native so enable that optimization in React Native >=
|
|
729
|
-
// 0.73
|
|
730
743
|
if (propsRegistry_->shouldReanimatedSkipCommit()) {
|
|
731
744
|
return nullptr;
|
|
732
745
|
}
|
|
733
|
-
#endif
|
|
734
746
|
}
|
|
735
747
|
|
|
736
748
|
auto rootNode =
|
|
@@ -746,15 +758,12 @@ void NativeReanimatedModule::performOperations() {
|
|
|
746
758
|
|
|
747
759
|
return rootNode;
|
|
748
760
|
},
|
|
749
|
-
{
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
return propsRegistry_->shouldReanimatedSkipCommit();
|
|
756
|
-
}
|
|
757
|
-
});
|
|
761
|
+
{/* .enableStateReconciliation = */
|
|
762
|
+
false,
|
|
763
|
+
/* .mountSynchronously = */ true,
|
|
764
|
+
/* .shouldYield = */ [this]() {
|
|
765
|
+
return propsRegistry_->shouldReanimatedSkipCommit();
|
|
766
|
+
}});
|
|
758
767
|
});
|
|
759
768
|
}
|
|
760
769
|
|
|
@@ -840,6 +849,8 @@ void NativeReanimatedModule::initializeFabric(
|
|
|
840
849
|
|
|
841
850
|
initializeLayoutAnimations();
|
|
842
851
|
|
|
852
|
+
mountHook_ =
|
|
853
|
+
std::make_shared<ReanimatedMountHook>(propsRegistry_, uiManager_);
|
|
843
854
|
commitHook_ =
|
|
844
855
|
std::make_shared<ReanimatedCommitHook>(propsRegistry_, uiManager_);
|
|
845
856
|
}
|
|
@@ -878,7 +889,9 @@ jsi::Value NativeReanimatedModule::subscribeForKeyboardEvents(
|
|
|
878
889
|
handlerWorklet,
|
|
879
890
|
"[Reanimated] Keyboard event handler must be a worklet.");
|
|
880
891
|
return subscribeForKeyboardEventsFunction_(
|
|
881
|
-
|
|
892
|
+
COPY_CAPTURE_WITH_THIS
|
|
893
|
+
|
|
894
|
+
(int keyboardState, int height) {
|
|
882
895
|
uiWorkletRuntime_->runGuarded(
|
|
883
896
|
shareableHandler, jsi::Value(keyboardState), jsi::Value(height));
|
|
884
897
|
},
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
#include "LayoutAnimationsProxy.h"
|
|
24
24
|
#include "PropsRegistry.h"
|
|
25
25
|
#include "ReanimatedCommitHook.h"
|
|
26
|
+
#include "ReanimatedMountHook.h"
|
|
26
27
|
#endif
|
|
27
28
|
|
|
28
29
|
namespace reanimated {
|
|
@@ -218,6 +219,7 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec {
|
|
|
218
219
|
|
|
219
220
|
std::shared_ptr<PropsRegistry> propsRegistry_;
|
|
220
221
|
std::shared_ptr<ReanimatedCommitHook> commitHook_;
|
|
222
|
+
std::shared_ptr<ReanimatedMountHook> mountHook_;
|
|
221
223
|
|
|
222
224
|
std::vector<Tag> tagsToRemove_; // from `propsRegistry_`
|
|
223
225
|
#else
|
|
@@ -36,11 +36,45 @@ export function setupCallGuard() {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Currently there seems to be a bug in the JSI layer which causes a crash when
|
|
41
|
+
* we try to copy some of the console methods, i.e. `clear` or `dirxml`.
|
|
42
|
+
*
|
|
43
|
+
* The crash happens only in React Native 0.75. It's not reproducible in neither
|
|
44
|
+
* 0.76 nor 0.74. It also happens only in the configuration of a debug app and
|
|
45
|
+
* production bundle.
|
|
46
|
+
*
|
|
47
|
+
* I haven't yet discovered what exactly causes the crash. It's tied to the
|
|
48
|
+
* console methods sometimes being `HostFunction`s. Therefore, as a workaround
|
|
49
|
+
* we don't copy the methods as they are in the original console object, we copy
|
|
50
|
+
* JavaScript wrappers instead.
|
|
51
|
+
*/
|
|
52
|
+
function createMemorySafeCapturableConsole() {
|
|
53
|
+
const consoleCopy = Object.fromEntries(Object.entries(console).map(([methodName, method]) => {
|
|
54
|
+
const methodWrapper = function methodWrapper(...args) {
|
|
55
|
+
return method(...args);
|
|
56
|
+
};
|
|
57
|
+
if (method.name) {
|
|
58
|
+
/**
|
|
59
|
+
* Set the original method name as the wrapper name if available.
|
|
60
|
+
*
|
|
61
|
+
* It might be unnecessary but if we want to fully mimic the console
|
|
62
|
+
* object we should take into the account the fact some code might rely
|
|
63
|
+
* on the method name.
|
|
64
|
+
*/
|
|
65
|
+
Object.defineProperty(methodWrapper, 'name', {
|
|
66
|
+
value: method.name,
|
|
67
|
+
writable: false
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return [methodName, methodWrapper];
|
|
71
|
+
}));
|
|
72
|
+
return consoleCopy;
|
|
73
|
+
}
|
|
74
|
+
|
|
39
75
|
// We really have to create a copy of console here. Function runOnJS we use on elements inside
|
|
40
76
|
// this object makes it not configurable
|
|
41
|
-
const capturableConsole =
|
|
42
|
-
...console
|
|
43
|
-
};
|
|
77
|
+
const capturableConsole = createMemorySafeCapturableConsole();
|
|
44
78
|
export function setupConsole() {
|
|
45
79
|
'worklet';
|
|
46
80
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["reportFatalErrorOnJS","isChromeDebugger","isJest","shouldBeUseWeb","runOnJS","setupMicrotasks","callMicrotasks","runOnUIImmediately","mockedRequestAnimationFrame","IS_JEST","SHOULD_BE_USE_WEB","IS_CHROME_DEBUGGER","callGuardDEV","fn","args","e","global","__ErrorUtils","reportFatalError","setupCallGuard","__callGuardDEV","error","message","stack","
|
|
1
|
+
{"version":3,"names":["reportFatalErrorOnJS","isChromeDebugger","isJest","shouldBeUseWeb","runOnJS","setupMicrotasks","callMicrotasks","runOnUIImmediately","mockedRequestAnimationFrame","IS_JEST","SHOULD_BE_USE_WEB","IS_CHROME_DEBUGGER","callGuardDEV","fn","args","e","global","__ErrorUtils","reportFatalError","setupCallGuard","__callGuardDEV","error","message","stack","createMemorySafeCapturableConsole","consoleCopy","Object","fromEntries","entries","console","map","methodName","method","methodWrapper","name","defineProperty","value","writable","capturableConsole","setupConsole","assert","debug","log","warn","info","setupRequestAnimationFrame","nativeRequestAnimationFrame","requestAnimationFrame","animationFrameCallbacks","flushRequested","__flushAnimationFrame","frameTimestamp","currentCallbacks","forEach","f","callback","push","timestamp","__frameTimestamp","undefined","initializeUIRuntime","globalThis"],"sources":["initializers.ts"],"sourcesContent":["'use strict';\nimport { reportFatalErrorOnJS } from './errors';\nimport { isChromeDebugger, isJest, shouldBeUseWeb } from './PlatformChecker';\nimport {\n runOnJS,\n setupMicrotasks,\n callMicrotasks,\n runOnUIImmediately,\n} from './threads';\nimport { mockedRequestAnimationFrame } from './mockedRequestAnimationFrame';\n\nconst IS_JEST = isJest();\nconst SHOULD_BE_USE_WEB = shouldBeUseWeb();\nconst IS_CHROME_DEBUGGER = isChromeDebugger();\n\n// callGuard is only used with debug builds\nexport function callGuardDEV<Args extends unknown[], ReturnValue>(\n fn: (...args: Args) => ReturnValue,\n ...args: Args\n): ReturnValue | void {\n 'worklet';\n try {\n return fn(...args);\n } catch (e) {\n if (global.__ErrorUtils) {\n global.__ErrorUtils.reportFatalError(e as Error);\n } else {\n throw e;\n }\n }\n}\n\nexport function setupCallGuard() {\n 'worklet';\n global.__callGuardDEV = callGuardDEV;\n global.__ErrorUtils = {\n reportFatalError: (error: Error) => {\n runOnJS(reportFatalErrorOnJS)({\n message: error.message,\n stack: error.stack,\n });\n },\n };\n}\n\n/**\n * Currently there seems to be a bug in the JSI layer which causes a crash when\n * we try to copy some of the console methods, i.e. `clear` or `dirxml`.\n *\n * The crash happens only in React Native 0.75. It's not reproducible in neither\n * 0.76 nor 0.74. It also happens only in the configuration of a debug app and\n * production bundle.\n *\n * I haven't yet discovered what exactly causes the crash. It's tied to the\n * console methods sometimes being `HostFunction`s. Therefore, as a workaround\n * we don't copy the methods as they are in the original console object, we copy\n * JavaScript wrappers instead.\n */\nfunction createMemorySafeCapturableConsole(): typeof console {\n const consoleCopy = Object.fromEntries(\n Object.entries(console).map(([methodName, method]) => {\n const methodWrapper = function methodWrapper(...args: unknown[]) {\n return method(...args);\n };\n if (method.name) {\n /**\n * Set the original method name as the wrapper name if available.\n *\n * It might be unnecessary but if we want to fully mimic the console\n * object we should take into the account the fact some code might rely\n * on the method name.\n */\n Object.defineProperty(methodWrapper, 'name', {\n value: method.name,\n writable: false,\n });\n }\n return [methodName, methodWrapper];\n })\n );\n\n return consoleCopy as unknown as typeof console;\n}\n\n// We really have to create a copy of console here. Function runOnJS we use on elements inside\n// this object makes it not configurable\nconst capturableConsole = createMemorySafeCapturableConsole();\n\nexport function setupConsole() {\n 'worklet';\n if (!IS_CHROME_DEBUGGER) {\n // @ts-ignore TypeScript doesn't like that there are missing methods in console object, but we don't provide all the methods for the UI runtime console version\n global.console = {\n /* eslint-disable @typescript-eslint/unbound-method */\n assert: runOnJS(capturableConsole.assert),\n debug: runOnJS(capturableConsole.debug),\n log: runOnJS(capturableConsole.log),\n warn: runOnJS(capturableConsole.warn),\n error: runOnJS(capturableConsole.error),\n info: runOnJS(capturableConsole.info),\n /* eslint-enable @typescript-eslint/unbound-method */\n };\n }\n}\n\nfunction setupRequestAnimationFrame() {\n 'worklet';\n\n // Jest mocks requestAnimationFrame API and it does not like if that mock gets overridden\n // so we avoid doing requestAnimationFrame batching in Jest environment.\n const nativeRequestAnimationFrame = global.requestAnimationFrame;\n\n let animationFrameCallbacks: Array<(timestamp: number) => void> = [];\n let flushRequested = false;\n\n global.__flushAnimationFrame = (frameTimestamp: number) => {\n const currentCallbacks = animationFrameCallbacks;\n animationFrameCallbacks = [];\n currentCallbacks.forEach((f) => f(frameTimestamp));\n callMicrotasks();\n };\n\n global.requestAnimationFrame = (\n callback: (timestamp: number) => void\n ): number => {\n animationFrameCallbacks.push(callback);\n if (!flushRequested) {\n flushRequested = true;\n nativeRequestAnimationFrame((timestamp) => {\n flushRequested = false;\n global.__frameTimestamp = timestamp;\n global.__flushAnimationFrame(timestamp);\n global.__frameTimestamp = undefined;\n });\n }\n // Reanimated currently does not support cancelling callbacks requested with\n // requestAnimationFrame. We return -1 as identifier which isn't in line\n // with the spec but it should give users better clue in case they actually\n // attempt to store the value returned from rAF and use it for cancelling.\n return -1;\n };\n}\n\nexport function initializeUIRuntime() {\n if (IS_JEST) {\n // requestAnimationFrame react-native jest's setup is incorrect as it polyfills\n // the method directly using setTimeout, therefore the callback doesn't get the\n // expected timestamp as the only argument: https://github.com/facebook/react-native/blob/main/packages/react-native/jest/setup.js#L28\n // We override this setup here to make sure that callbacks get the proper timestamps\n // when executed. For non-jest environments we define requestAnimationFrame in setupRequestAnimationFrame\n // @ts-ignore TypeScript uses Node definition for rAF, setTimeout, etc which returns a Timeout object rather than a number\n globalThis.requestAnimationFrame = mockedRequestAnimationFrame;\n }\n\n runOnUIImmediately(() => {\n 'worklet';\n setupCallGuard();\n setupConsole();\n if (!SHOULD_BE_USE_WEB) {\n setupMicrotasks();\n setupRequestAnimationFrame();\n }\n })();\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* with the version used to build the native part of the library in runtime.
|
|
6
6
|
* Remember to keep this in sync with the version declared in `package.json`
|
|
7
7
|
*/
|
|
8
|
-
export const jsVersion = '3.15.
|
|
8
|
+
export const jsVersion = '3.15.4';
|
|
9
9
|
//# sourceMappingURL=jsVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["jsVersion"],"sources":["jsVersion.ts"],"sourcesContent":["'use strict';\n/**\n * We hardcode the version of Reanimated here in order to compare it\n * with the version used to build the native part of the library in runtime.\n * Remember to keep this in sync with the version declared in `package.json`\n */\nexport const jsVersion = '3.15.
|
|
1
|
+
{"version":3,"names":["jsVersion"],"sources":["jsVersion.ts"],"sourcesContent":["'use strict';\n/**\n * We hardcode the version of Reanimated here in order to compare it\n * with the version used to build the native part of the library in runtime.\n * Remember to keep this in sync with the version declared in `package.json`\n */\nexport const jsVersion = '3.15.4';\n"],"mappings":"AAAA,YAAY;;AACZ;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,SAAS,GAAG,QAAQ","ignoreList":[]}
|
package/package.json
CHANGED
package/src/initializers.ts
CHANGED
|
@@ -43,9 +43,48 @@ export function setupCallGuard() {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Currently there seems to be a bug in the JSI layer which causes a crash when
|
|
48
|
+
* we try to copy some of the console methods, i.e. `clear` or `dirxml`.
|
|
49
|
+
*
|
|
50
|
+
* The crash happens only in React Native 0.75. It's not reproducible in neither
|
|
51
|
+
* 0.76 nor 0.74. It also happens only in the configuration of a debug app and
|
|
52
|
+
* production bundle.
|
|
53
|
+
*
|
|
54
|
+
* I haven't yet discovered what exactly causes the crash. It's tied to the
|
|
55
|
+
* console methods sometimes being `HostFunction`s. Therefore, as a workaround
|
|
56
|
+
* we don't copy the methods as they are in the original console object, we copy
|
|
57
|
+
* JavaScript wrappers instead.
|
|
58
|
+
*/
|
|
59
|
+
function createMemorySafeCapturableConsole(): typeof console {
|
|
60
|
+
const consoleCopy = Object.fromEntries(
|
|
61
|
+
Object.entries(console).map(([methodName, method]) => {
|
|
62
|
+
const methodWrapper = function methodWrapper(...args: unknown[]) {
|
|
63
|
+
return method(...args);
|
|
64
|
+
};
|
|
65
|
+
if (method.name) {
|
|
66
|
+
/**
|
|
67
|
+
* Set the original method name as the wrapper name if available.
|
|
68
|
+
*
|
|
69
|
+
* It might be unnecessary but if we want to fully mimic the console
|
|
70
|
+
* object we should take into the account the fact some code might rely
|
|
71
|
+
* on the method name.
|
|
72
|
+
*/
|
|
73
|
+
Object.defineProperty(methodWrapper, 'name', {
|
|
74
|
+
value: method.name,
|
|
75
|
+
writable: false,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return [methodName, methodWrapper];
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
return consoleCopy as unknown as typeof console;
|
|
83
|
+
}
|
|
84
|
+
|
|
46
85
|
// We really have to create a copy of console here. Function runOnJS we use on elements inside
|
|
47
86
|
// this object makes it not configurable
|
|
48
|
-
const capturableConsole =
|
|
87
|
+
const capturableConsole = createMemorySafeCapturableConsole();
|
|
49
88
|
|
|
50
89
|
export function setupConsole() {
|
|
51
90
|
'worklet';
|