From bd1b491dcba26f8c33a611b7f5c01634e042b295 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sat, 31 Oct 2026 12:59:15 +0100 Subject: [PATCH] fix(app): keep layout sized to the window after rotation A style update racing a window resize could recommit old root constraints. Rebuild the style update from the current root on each commit attempt. --- patches/react-native-unistyles+3.2.4.patch | 56 ++++++++++++++++++++++ scripts/postinstall-patches.mjs | 3 ++ 2 files changed, 59 insertions(+) diff --git a/patches/react-native-unistyles+3.2.4.patch b/patches/react-native-unistyles+3.2.4.patch index af825a6afa..c3da63a8ac 100644 --- a/patches/react-native-unistyles+3.2.4.patch +++ b/patches/react-native-unistyles+3.2.4.patch @@ -705,3 +705,59 @@ index a9c1804..f5a3c20 100644 return Insets( this._insets.top / density, +diff --git a/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp b/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp +index 01026dc..3786ec4 100644 +--- a/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp ++++ b/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp +@@ -17,13 +17,16 @@ void shadow::ShadowTreeManager::updateShadowTree(jsi::Runtime& rt) { + } + + #if REACT_NATIVE_VERSION_MINOR >= 81 +- std::unordered_map tagToProps; ++ // Paseo backport of https://github.com/jpudysz/react-native-unistyles/pull/1357. ++ // UIManager::updateShadowTree commits a root cloned before the commit, so when a ++ // window-size commit (rotation, keyboard) lands in between, the retried Unistyles ++ // commit puts the previous layout constraints back and the app stays laid out for ++ // the old size. Commit here instead and clone from the root the commit hands us. ++ std::unordered_set affectedSurfaces; + + for (const auto& [family, props] : updates) { + auto safeProps = props.isObject() ? props : folly::dynamic::object(); + +- tagToProps.insert({family->getTag(), safeProps}); +- + auto* mutableFamily = const_cast(family); + + if (mutableFamily->nativeProps_DEPRECATED && mutableFamily->nativeProps_DEPRECATED->isObject()) { +@@ -31,9 +34,30 @@ void shadow::ShadowTreeManager::updateShadowTree(jsi::Runtime& rt) { + } else { + mutableFamily->nativeProps_DEPRECATED = std::make_unique(safeProps); + } ++ ++ affectedSurfaces.insert(family->getSurfaceId()); + } + +- UIManagerBinding::getBinding(rt)->getUIManager().updateShadowTree(std::move(tagToProps)); ++ const auto& shadowTreeRegistry = UIManagerBinding::getBinding(rt)->getUIManager().getShadowTreeRegistry(); ++ ++ shadowTreeRegistry.enumerate([&updates, &affectedSurfaces](const ShadowTree& shadowTree, bool&){ ++ if (!affectedSurfaces.contains(shadowTree.getSurfaceId())) { ++ return; ++ } ++ ++ auto transaction = [&updates](const RootShadowNode& oldRootShadowNode) -> RootShadowNode::Unshared { ++ auto affectedNodes = shadow::ShadowTreeManager::findAffectedNodes(oldRootShadowNode, updates); ++ ++ return std::static_pointer_cast(shadow::ShadowTreeManager::cloneShadowTree( ++ oldRootShadowNode, ++ updates, ++ affectedNodes ++ )); ++ }; ++ ++ // mountSynchronously: this is an update from C++, not React ++ shadowTree.commit(transaction, {false, true}); ++ }); + #else + const auto& shadowTreeRegistry = UIManagerBinding::getBinding(rt)->getUIManager().getShadowTreeRegistry(); + diff --git a/scripts/postinstall-patches.mjs b/scripts/postinstall-patches.mjs index fbf87241c7..3dbbeddcaf 100644 --- a/scripts/postinstall-patches.mjs +++ b/scripts/postinstall-patches.mjs @@ -28,6 +28,9 @@ const patchedPackages = [ // withUnistyles: also keep the uniProps filter until upstream consumes its control prop. // Android configuration: backport 3.5.3; remove the two NativePlatform hunks at >= 3.5.3. // https://github.com/jpudysz/react-native-unistyles/compare/v3.5.2...v3.5.3 + // Layout constraints: backport of https://github.com/jpudysz/react-native-unistyles/pull/1357 + // (commit from the root the commit hands us, so a concurrent window-size commit is kept). + // Remove the ShadowTreeManager hunk when the installed release includes that PR. { nodeModulesPath: "node_modules/react-native-unistyles", patchPrefix: "react-native-unistyles+",