Skip to content

Remove view flattening error for Text component #3338

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

Merged
merged 12 commits into from
Feb 4, 2025
Merged
33 changes: 21 additions & 12 deletions android/src/main/jni/cpp-adapter.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#include <jni.h>
#include <jsi/jsi.h>

#include <react/renderer/components/text/ParagraphShadowNode.h>
#include <react/renderer/components/text/TextShadowNode.h>
#include <react/renderer/uimanager/primitives.h>

using namespace facebook;
using namespace react;

void decorateRuntime(jsi::Runtime &runtime) {
auto isFormsStackingContext = jsi::Function::createFromHostFunction(
auto isViewFlatteningDisabled = jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "isFormsStackingContext"),
jsi::PropNameID::forAscii(runtime, "isViewFlatteningDisabled"),
1,
[](jsi::Runtime &runtime,
const jsi::Value &thisValue,
Expand All @@ -20,21 +22,28 @@ void decorateRuntime(jsi::Runtime &runtime) {
}

auto shadowNode = shadowNodeFromValue(runtime, arguments[0]);
bool isFormsStackingContext = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext);
bool isViewFlatteningDisabled = shadowNode->getTraits().check(
ShadowNodeTraits::FormsStackingContext);

return jsi::Value(isFormsStackingContext);
// This is done using component names instead of type checking because
// of duplicate symbols for RN types, which prevent RTTI from working.
const char *componentName = shadowNode->getComponentName();
bool isTextComponent = strcmp(componentName, "Paragraph") == 0 ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, does this happen in both cases or only for Text?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answered here

strcmp(componentName, "Text") == 0;

return jsi::Value(isViewFlatteningDisabled || isTextComponent);
});
runtime.global().setProperty(
runtime, "isFormsStackingContext", std::move(isFormsStackingContext));
runtime, "isViewFlatteningDisabled", std::move(isViewFlatteningDisabled));
}

extern "C" JNIEXPORT void JNICALL
Java_com_swmansion_gesturehandler_react_RNGestureHandlerModule_decorateRuntime(
JNIEnv *env,
jobject clazz,
jlong jsiPtr) {
jsi::Runtime *runtime = reinterpret_cast<jsi::Runtime *>(jsiPtr);
if (runtime) {
decorateRuntime(*runtime);
}
JNIEnv *env,
jobject clazz,
jlong jsiPtr) {
jsi::Runtime *runtime = reinterpret_cast<jsi::Runtime *>(jsiPtr);
if (runtime) {
decorateRuntime(*runtime);
}
}
22 changes: 17 additions & 5 deletions apple/RNGestureHandlerModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#import <ReactCommon/CallInvoker.h>
#import <ReactCommon/RCTTurboModule.h>

#import <react/renderer/components/text/ParagraphShadowNode.h>
#import <react/renderer/components/text/TextShadowNode.h>
#import <react/renderer/uimanager/primitives.h>
#endif // RCT_NEW_ARCH_ENABLED

Expand Down Expand Up @@ -91,19 +93,29 @@ - (dispatch_queue_t)methodQueue
#ifdef RCT_NEW_ARCH_ENABLED
void decorateRuntime(jsi::Runtime &runtime)
{
auto isFormsStackingContext = jsi::Function::createFromHostFunction(
auto isViewFlatteningDisabled = jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "isFormsStackingContext"),
jsi::PropNameID::forAscii(runtime, "isViewFlatteningDisabled"),
1,
[](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value {
if (!arguments[0].isObject()) {
return jsi::Value::null();
}
auto shadowNode = shadowNodeFromValue(runtime, arguments[0]);
bool isFormsStackingContext = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext);
return jsi::Value(isFormsStackingContext);

if (dynamic_pointer_cast<const ParagraphShadowNode>(shadowNode)) {
return jsi::Value(true);
}

if (dynamic_pointer_cast<const TextShadowNode>(shadowNode)) {
return jsi::Value(true);
}

bool isViewFlatteningDisabled = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext);

return jsi::Value(isViewFlatteningDisabled);
});
runtime.global().setProperty(runtime, "isFormsStackingContext", std::move(isFormsStackingContext));
runtime.global().setProperty(runtime, "isViewFlatteningDisabled", std::move(isViewFlatteningDisabled));
}
#endif // RCT_NEW_ARCH_ENABLED

Expand Down
6 changes: 3 additions & 3 deletions src/handlers/gestures/GestureDetector/useViewRefHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, { useCallback } from 'react';
import findNodeHandle from '../../../findNodeHandle';

declare const global: {
isFormsStackingContext: (node: unknown) => boolean | null; // JSI function
isViewFlatteningDisabled: (node: unknown) => boolean | null; // JSI function
};

// Ref handler for the Wrap component attached under the GestureDetector.
Expand Down Expand Up @@ -35,9 +35,9 @@ export function useViewRefHandler(
updateAttachedGestures(true);
}

if (__DEV__ && isFabric() && global.isFormsStackingContext) {
if (__DEV__ && isFabric() && global.isViewFlatteningDisabled) {
const node = getShadowNodeFromRef(ref);
if (global.isFormsStackingContext(node) === false) {
if (global.isViewFlatteningDisabled(node) === false) {
console.error(
tagMessage(
'GestureDetector has received a child that may get view-flattened. ' +
Expand Down
Loading