Skip to content

fix(ios): resync visual state after display:none and window changes#4

Merged
RamboWasReal merged 1 commit into
mainfrom
fix/visibility-resync-display-none
Apr 1, 2026
Merged

fix(ios): resync visual state after display:none and window changes#4
RamboWasReal merged 1 commit into
mainfrom
fix/visibility-resync-display-none

Conversation

@RamboWasReal
Copy link
Copy Markdown
Owner

@RamboWasReal RamboWasReal commented Apr 1, 2026

Summary

  • Fix GleamView staying stuck in shimmer state when loading transitions occur while an ancestor has display: 'none' (e.g. security lock overlay with React Query cache invalidation)
  • Fabric maps display: 'none' to UIView.hidden = YES — no bounds change, no removeFromSuperview, no layoutSubviews — so the v1.0.3 fix alone was insufficient
  • Three layered fixes covering all hiding mechanisms:
Vector Hook Coverage
display: 'none' (hidden=YES) _tickWithTime: without !self.window bail for transitions Transition completes in ≤transitionDuration even while hidden
Window loss (navigation, modal) didMoveToWindow Resyncs state on re-attachment
Bounds change layoutSubviews else-if Forces idle state when !loading && !transitioning

Context

  • Observed in production: PatientStoreLoading: true→false and PrescriptionsCarousel.isLoading: true→false during showLock: true
  • Lock screen implemented as same-tree sibling with display: 'none' on content subtree — not a navigation replacement
  • Supersedes the incomplete fix in v1.0.3 (fix(ios): sync visual state in layoutSubviews after display:none #3) which only covered layoutSubviews

Test plan

  • Wrap GleamView in a parent that toggles display: 'none' while cycling loading true→false
  • App background → foreground with security lock overlay active
  • Verify transition completes while view is hidden (shimmer gone when unhidden)
  • Verify normal visible transitions are not affected (no premature snap)
  • Verify onTransitionEnd fires correctly in all scenarios

🤖 Generated with Claude Code

Fabric maps display:'none' to UIView.hidden=YES — no bounds change,
no removeFromSuperview, no layoutSubviews. A loading transition that
starts while the view is hidden (e.g. React Query cache invalidation
during a security lock overlay) could leave the shimmer visible after
the subtree becomes visible again.

Three changes:

1. _tickWithTime: let transitions always complete even when self.window
   is nil or view is hidden. Cost is bounded (≤ transitionDuration) and
   operations are cheap property sets. Shimmer animation (unbounded,
   cosmetic) still skips when not visible.

2. didMoveToWindow: resync visual state on window re-attachment, mirroring
   Android's onAttachedToWindow path. Does not snap in-flight transitions
   — ticks drive those to completion naturally.

3. layoutSubviews else-if (from v1.0.3): force idle state when loading=NO
   and no transition is running, covering bounds-restoration scenarios.
@RamboWasReal RamboWasReal merged commit f485915 into main Apr 1, 2026
4 checks passed
@RamboWasReal RamboWasReal deleted the fix/visibility-resync-display-none branch April 1, 2026 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant