fix(flexbox): keep a hidden node at the position it was laid out - #127
Merged
Merged
Conversation
Yoga zeroes the computed box of a display:none node. Emitting that layout dragged the node and its subtree to the origin, so an element parked off screen by a translate read as on screen to anything walking the scene graph — the Plex TV drawer's nav items showed up in the testID mirror at 0,0 while the drawer was closed. Populates the _hiddenElements set _getUpdatedStyles already consults, so a hidden node stops emitting updates until it is shown again.
DouweBos
marked this pull request as ready for review
September 23, 2026 14:11
RuudBurger
approved these changes
Sep 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Found from a Plex TV smoke-test regression on Lightning. Two Maestro flows started failing on
assertVisible: id: primary-navigation-account, focused— the page object treats the presence of that element as "the nav drawer is expanded", and it was suddenly always present while the drawer was closed.The app change that exposed it was innocent: the drawer now sets
display: 'none'once its close animation finishes, instead of being drawn off screen every frame. The drawer is parked off screen by atranslateX, and hiding it moved the whole subtree back to the origin. Nothing changed visually, but the testID mirror the renderer's inspector builds — which Maestro queries — reported the closed drawer as an on-screen element at 0,0.Discussion
Yoga zeroes the computed box of a
display: nonenode._getUpdatedStylesemits that zeroed box like any other layout, andLightningManager._applyUpdateswritesx/yunconditionally — only width/height are guarded against 0. So hiding a node is enough to move it, and any position it held from a translate is lost.YogaManageralready had the machinery for this:_getUpdatedStylesskips an element in_hiddenElements(unlessprocessHiddenNodesis set), but nothing ever populated that set. This fills it in —applyStyleadds the element when the node's display resolves toDISPLAY_NONEand removes it otherwise, andremoveNodeclears it. A hidden node stops emitting updates and keeps the geometry it had; showing it again re-lays it out as before.Reading
getDisplay()from the node rather than the incoming style keeps the resets/partial-push semantics ofapplyReactPropsToYogaauthoritative — a full push that omitsdisplayresets it to flex, and that is reflected. One FFI read per style application, not per frame.Steps to test
Two unit tests in
YogaManager.displayToggle.test.ts, red before the change for the right reason (expected { x: 0 } to match { x: -452 }):x: -452when it is hidden.Verified live against the Plex Lightning app on the emulator, reading the inspector mirror over CDP. With the drawer closed after a real open → close cycle,
primary-navigation-accountcomposes tox: -452, right: -130(entirely off screen) with this change, versusx: 0, width: 322without it. The drawer itself opens and closes unchanged.plugin-flexboxsuite: 211/211 pass, and the repo unit tests are green.