From 85835a882ba3ea1dd9d8214f4f934930699fab05 Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Wed, 11 Mar 2026 18:49:27 +0100 Subject: [PATCH 1/3] fix: `useWindowDimensions` calculations for `Modal` with `formSheet` presentation --- .../Modal/RCTModalHostViewComponentView.mm | 11 ++++++++++- .../components/modal/ModalHostViewShadowNode.cpp | 5 +++++ .../components/modal/ModalHostViewShadowNode.h | 2 ++ .../renderer/components/modal/ModalHostViewState.cpp | 4 +++- .../renderer/components/modal/ModalHostViewState.h | 7 ++++++- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm index 7c09d9cf73ef..2f80e8d277ca 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm @@ -261,7 +261,16 @@ - (void)boundsDidChange:(CGRect)newBounds } if (_state != nullptr) { - auto newState = ModalHostViewState{RCTSizeFromCGSize(newBounds.size)}; + CGPoint viewportOffset = CGPointZero; + UIView *modalView = _viewController.view; + if (modalView && modalView.window) { + CGRect frameInWindow = [modalView convertRect:modalView.bounds toView:nil]; + viewportOffset = frameInWindow.origin; + } + auto newState = ModalHostViewState{ + RCTSizeFromCGSize(newBounds.size), + facebook::react::Point{(Float)viewportOffset.x, (Float)viewportOffset.y} + }; _state->updateState(std::move(newState)); } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.cpp index 3598549813af..bbdfe2ac73d0 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.cpp @@ -14,4 +14,9 @@ namespace facebook::react { extern const char ModalHostViewComponentName[] = "ModalHostView"; +Transform ModalHostViewShadowNode::getTransform() const { + auto viewportOffset = getStateData().viewportOffset; + return Transform::Translate(viewportOffset.x, viewportOffset.y, 0); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.h index 0b767161d136..8ff8ec2dae5c 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewShadowNode.h @@ -38,6 +38,8 @@ class ModalHostViewShadowNode final : public ConcreteViewShadowNode< traits.set(ShadowNodeTraits::Trait::Unstable_uncullableView); return traits; } + + Transform getTransform() const override; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp index 9f5bff0bfac8..948264e812d1 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp @@ -16,7 +16,9 @@ ModalHostViewState::ModalHostViewState() #ifdef RN_SERIALIZABLE_STATE folly::dynamic ModalHostViewState::getDynamic() const { return folly::dynamic::object("screenWidth", screenSize.width)( - "screenHeight", screenSize.height); + "screenHeight", screenSize.height)( + "viewportOffsetX", viewportOffset.x)( + "viewportOffsetY", viewportOffset.y); } #endif diff --git a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h index 8631094fd8d0..1549e79b1267 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h +++ b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h @@ -27,15 +27,20 @@ class ModalHostViewState final { ModalHostViewState(); ModalHostViewState(Size screenSize_) : screenSize(screenSize_) {}; + ModalHostViewState(Size screenSize_, Point viewportOffset_) + : screenSize(screenSize_), viewportOffset(viewportOffset_) {}; #ifdef RN_SERIALIZABLE_STATE ModalHostViewState(const ModalHostViewState &previousState, folly::dynamic data) : screenSize( - Size{.width = (Float)data["screenWidth"].getDouble(), .height = (Float)data["screenHeight"].getDouble()}) { + Size{.width = (Float)data["screenWidth"].getDouble(), .height = (Float)data["screenHeight"].getDouble()}), + viewportOffset( + Point{.x = (Float)data["viewportOffsetX"].getDouble(), .y = (Float)data["viewportOffsetY"].getDouble()}) { }; #endif const Size screenSize{}; + const Point viewportOffset{}; #ifdef RN_SERIALIZABLE_STATE folly::dynamic getDynamic() const; From a41cfc75bd1573f0d368024fd745e548dd35b10c Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Wed, 11 Mar 2026 19:33:20 +0100 Subject: [PATCH 2/3] fix: Android crash --- .../react/renderer/components/modal/ModalHostViewState.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h index 1549e79b1267..7fcdd761fd33 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h +++ b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h @@ -35,7 +35,8 @@ class ModalHostViewState final { : screenSize( Size{.width = (Float)data["screenWidth"].getDouble(), .height = (Float)data["screenHeight"].getDouble()}), viewportOffset( - Point{.x = (Float)data["viewportOffsetX"].getDouble(), .y = (Float)data["viewportOffsetY"].getDouble()}) { + Point{.x = data.count("viewportOffsetX") ? (Float)data["viewportOffsetX"].getDouble() : 0.0f, + .y = data.count("viewportOffsetY") ? (Float)data["viewportOffsetY"].getDouble() : 0.0f}) { }; #endif From eb9d25408949b52f749717c8e714457af0ee4a5d Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Thu, 15 Oct 2026 13:09:30 +0200 Subject: [PATCH 3/3] fix: formatting and C++ API snapshots --- .../ComponentViews/Modal/RCTModalHostViewComponentView.mm | 4 +--- .../react/renderer/components/modal/ModalHostViewState.cpp | 3 +-- .../react/renderer/components/modal/ModalHostViewState.h | 6 +++--- scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api | 3 +++ scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api | 3 +++ scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api | 3 +++ 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm index 2f80e8d277ca..22d461797ee7 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm @@ -268,9 +268,7 @@ - (void)boundsDidChange:(CGRect)newBounds viewportOffset = frameInWindow.origin; } auto newState = ModalHostViewState{ - RCTSizeFromCGSize(newBounds.size), - facebook::react::Point{(Float)viewportOffset.x, (Float)viewportOffset.y} - }; + RCTSizeFromCGSize(newBounds.size), facebook::react::Point{(Float)viewportOffset.x, (Float)viewportOffset.y}}; _state->updateState(std::move(newState)); } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp index 948264e812d1..b70e5cc57dc8 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.cpp @@ -16,8 +16,7 @@ ModalHostViewState::ModalHostViewState() #ifdef RN_SERIALIZABLE_STATE folly::dynamic ModalHostViewState::getDynamic() const { return folly::dynamic::object("screenWidth", screenSize.width)( - "screenHeight", screenSize.height)( - "viewportOffsetX", viewportOffset.x)( + "screenHeight", screenSize.height)("viewportOffsetX", viewportOffset.x)( "viewportOffsetY", viewportOffset.y); } #endif diff --git a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h index 7fcdd761fd33..f1b75be27399 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h +++ b/packages/react-native/ReactCommon/react/renderer/components/modal/ModalHostViewState.h @@ -35,9 +35,9 @@ class ModalHostViewState final { : screenSize( Size{.width = (Float)data["screenWidth"].getDouble(), .height = (Float)data["screenHeight"].getDouble()}), viewportOffset( - Point{.x = data.count("viewportOffsetX") ? (Float)data["viewportOffsetX"].getDouble() : 0.0f, - .y = data.count("viewportOffsetY") ? (Float)data["viewportOffsetY"].getDouble() : 0.0f}) { - }; + Point{ + .x = data.count("viewportOffsetX") ? (Float)data["viewportOffsetX"].getDouble() : 0.0f, + .y = data.count("viewportOffsetY") ? (Float)data["viewportOffsetY"].getDouble() : 0.0f}) {}; #endif const Size screenSize{}; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api index 011a67c223d2..14346926b147 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api @@ -2758,12 +2758,15 @@ class facebook::react::ModalHostViewShadowNode : public facebook::react::Concret public ModalHostViewShadowNode(const facebook::react::ShadowNode& sourceShadowNode, const facebook::react::ShadowNodeFragment& fragment); public ModalHostViewShadowNode(const facebook::react::ShadowNodeFragment& fragment, const facebook::react::ShadowNodeFamily::Shared& family, facebook::react::ShadowNodeTraits traits); public static facebook::react::ShadowNodeTraits BaseTraits(); + public virtual facebook::react::Transform getTransform() const override; } class facebook::react::ModalHostViewState { public ModalHostViewState(); public ModalHostViewState(const facebook::react::ModalHostViewState& previousState, folly::dynamic data); public ModalHostViewState(facebook::react::Size screenSize_); + public ModalHostViewState(facebook::react::Size screenSize_, facebook::react::Point viewportOffset_); + public const facebook::react::Point viewportOffset; public const facebook::react::Size screenSize; public folly::dynamic getDynamic() const; public using Shared = std::shared_ptr; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api index 4293fa4df491..46165866e9fd 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api @@ -4974,11 +4974,14 @@ class facebook::react::ModalHostViewShadowNode : public facebook::react::Concret public ModalHostViewShadowNode(const facebook::react::ShadowNode& sourceShadowNode, const facebook::react::ShadowNodeFragment& fragment); public ModalHostViewShadowNode(const facebook::react::ShadowNodeFragment& fragment, const facebook::react::ShadowNodeFamily::Shared& family, facebook::react::ShadowNodeTraits traits); public static facebook::react::ShadowNodeTraits BaseTraits(); + public virtual facebook::react::Transform getTransform() const override; } class facebook::react::ModalHostViewState { public ModalHostViewState(); public ModalHostViewState(facebook::react::Size screenSize_); + public ModalHostViewState(facebook::react::Size screenSize_, facebook::react::Point viewportOffset_); + public const facebook::react::Point viewportOffset; public const facebook::react::Size screenSize; public using Shared = std::shared_ptr; } diff --git a/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api index b3011c1fec07..696b0476ead2 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api @@ -1646,11 +1646,14 @@ class facebook::react::ModalHostViewShadowNode : public facebook::react::Concret public ModalHostViewShadowNode(const facebook::react::ShadowNode& sourceShadowNode, const facebook::react::ShadowNodeFragment& fragment); public ModalHostViewShadowNode(const facebook::react::ShadowNodeFragment& fragment, const facebook::react::ShadowNodeFamily::Shared& family, facebook::react::ShadowNodeTraits traits); public static facebook::react::ShadowNodeTraits BaseTraits(); + public virtual facebook::react::Transform getTransform() const override; } class facebook::react::ModalHostViewState { public ModalHostViewState(); public ModalHostViewState(facebook::react::Size screenSize_); + public ModalHostViewState(facebook::react::Size screenSize_, facebook::react::Point viewportOffset_); + public const facebook::react::Point viewportOffset; public const facebook::react::Size screenSize; public using Shared = std::shared_ptr; }