Skip to content

Fix Paywalls V2 root z-layer stacks not scrolling in bounded containers#6873

Merged
MonikaMateska merged 10 commits into
mainfrom
monika/fix/sticky-footer
Jun 1, 2026
Merged

Fix Paywalls V2 root z-layer stacks not scrolling in bounded containers#6873
MonikaMateska merged 10 commits into
mainfrom
monika/fix/sticky-footer

Conversation

@MonikaMateska

@MonikaMateska MonikaMateska commented Jun 1, 2026

Copy link
Copy Markdown
Member

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-android and hybrids

Motivation

Fixes an iPad layout bug where Paywalls V2 paywalls with a root z-layer stack (not a vertical stack wrapping a z-layer) could not scroll in bounded containers such as form sheets. Tall hero images pushed the sticky footer off-screen, while the same paywall worked on iPhone.

Previously, z-layer stacks never applied scrolling (case .zlayer: self), unlike vertical and horizontal stacks. This change enables scrolling for z-layer stacks when appropriate, using ViewThatFits so content fills the container when it fits and scrolls only when it overflows.

Resolves: https://revenuecat.slack.com/archives/C093NCRHZ0T/p1779954980296169

Before:
Simulator Screenshot - iPad Pro 11-inch (M5) - 2026-05-28 at 12 18 22

After:
Simulator Screenshot - iPad Pro 11-inch (M5) - 2026-06-01 at 13 00 29

Description

  • PaywallScrollEnvironment.swift — small helpers so views know “is this a root z-layer paywall?” and “is something already scrolling above me?”
  • PaywallZLayerScrollPolicy.swift — the rules for when a z-layer should scroll
  • RootView.swift — marks root z-layer paywalls so the scroll logic can kick in
  • StackComponentView.swift — actually applies scrolling to z-layer stacks using those rules
  • ViewExtensions.swift — marks scroll views so nested stacks don’t fight each other

I added unit tests, and ran paywall-rendering-validation locally against paywalls from paywall-preview-resources, looked all good, no obvious regressions.
Manually verified on iPad: tall hero scrolls, footer stays reachable


Note

Medium Risk
Changes Paywalls V2 SwiftUI layout and scroll behavior for z-layer stacks; risk is mitigated by explicit scroll policy, ancestor tracking, and new unit/snapshot tests, but paywall rendering regressions are still possible across devices.

Overview
Fixes Paywalls V2 layouts where the root stack is a z-layer (not a vertical stack wrapping a z-layer): tall content could not scroll inside bounded containers (e.g. iPad form sheets), so sticky footers were pushed off-screen.

The PR adds scroll policy and environment plumbing so z-layer stacks can use the same ViewThatFits / vertical scroll path as other stacks when appropriate. RootView publishes whether the root is a z-layer; scroll views mark vertical ancestor scrolling so nested z-layers do not add competing scrollers. StackComponentView applies vertical scrolling to z-layers when PaywallZLayerScrollPolicy allows it (root z-layer or stack scroll enabled, and no vertical scroll ancestor).

Coverage includes unit tests for the policy and snapshot tests for sticky-footer + root z-layer on iPad sheet and iPhone sizes.

Reviewed by Cursor Bugbot for commit 94bd840. Bugbot is set up for automated code reviews on this repo. Configure here.

@MonikaMateska MonikaMateska requested review from a team as code owners June 1, 2026 11:03
@MonikaMateska MonikaMateska added the pr:fix A bug fix label Jun 1, 2026
Comment thread RevenueCat.xcodeproj/project.pbxproj Outdated
@MonikaMateska MonikaMateska requested a review from alexrepty June 1, 2026 11:09

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9929edb. Configure here.

self
self.paywallMarkingVerticalScrollContainer(axis: axis) {
self
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

iOS 15 fallback omits ancestor-scroll environment propagation

Low Severity

The paywallMarkingVerticalScrollContainer call (which sets paywallAncestorScrollsVertically to true for descendants) is only added inside the if #available(iOS 16.0, ...) branches. The else fallback path (iOS 15) at lines 178–182 still creates a scroll view via .scrollable(if: true) but never propagates the environment flag. Before this PR z-layers never scrolled, so this was harmless. Now that PaywallZLayerScrollPolicy.shouldApplyScroll can enable z-layer scrolling, a nested z-layer on iOS 15 would see ancestorScrollsVertically == false and create its own conflicting vertical scroll view.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9929edb. Configure here.

@MonikaMateska MonikaMateska merged commit f9e76f1 into main Jun 1, 2026
43 checks passed
@MonikaMateska MonikaMateska deleted the monika/fix/sticky-footer branch June 1, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants