2.2 KiB
@bsky.app__expo-scroll-edge-effect.patch
Fixes the iOS 26 scroll edge effect (the blur under the status bar) failing to attach on the New Architecture (Fabric).
Why
The native view resolves the target scroll view by React tag:
scrollViewTag (published from JS when the scroll view mounts) ->
appContext.findView(withTag:) -> attach a UIScrollEdgeElementContainerInteraction.
On Paper this resolved on the first try, because view-by-tag registration was serialized through the single UIManager batch pipeline - by the time the tag prop reached native, the scroll view was already in the registry.
On Fabric there is no synchronous tag->view registry. The scroll view's
ComponentView is registered when its mount transaction is applied, which is
deferred relative to the JS commit that set the tag. So the one-shot
resolveScrollView runs before the view is mounted and returns nil, the
interaction never attaches, and the blur is lost. (The un-gated case happened to
work only because the header's didMoveToWindow provided a late second attempt;
a list mounted later - e.g. behind an isActive gate - had no such retry.)
What it does
Makes resolution event-driven and self-healing instead of one-shot:
- When
resolveScrollViewreturns nil, it bumps a bounded counter and callssetNeedsLayout();layoutSubviews()re-attempts as sibling views mount, so it retries exactly when the scroll view actually appears - no fixed timer. isAttachedstops re-running once resolved (no teardown/re-attach churn).resolveAttempts/maxResolveAttemptsbound the retries so a permanently-absent scroll view (list not rendered) cannot spin layout forever.- The budget is reset on every "fresh" trigger (prop change, entering the
window) via
scheduleResolve(), so each new tag gets a full retry budget.
Notes
- iOS only; gated behind
#available(iOS 26, *). - This mirrors how
react-native-screenshandles the same effect on Fabric (resolve from the live view hierarchy and re-apply on mount/layout lifecycle rather than a single tag lookup). A cleaner long-term fix would move resolution to the scroll-view side, but this is the minimal change to the existing tag-based design.