Repository navigation
fix(native): answer an ancestor chain as a path, not as a set of names - #463
Open
YevheniiKotyrlo wants to merge 1 commit into
Open
YevheniiKotyrlo wants to merge 1 commit into
YevheniiKotyrlo wants to merge 1 commit into
Conversation
Contributor
Author
A container is registered by name, and every compound of an ancestor chain was resolved in the element's own scope. So `.outer .inner .x` asked whether both names sit somewhere above the element, and it matched the reversed nesting too. A descendant combinator asks for an `.inner` ancestor that itself has an `.outer` ancestor (Selectors 4 §16.1). Each registration now carries the scope it registered in, beside its element and props. The chain is walked innermost first, each compound resolving in the scope of the one inside it. A single compound resolves as before. Guards stay on the element's own scope, the one it can re-read.
YevheniiKotyrlo
force-pushed
the
fix/ancestor-chain-order
branch
from
October 11, 2026 12:36
88f88cd to
ba1b8a0
Compare
This branch has not been deployed
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.


Problem
A container is registered by name, and every compound of an ancestor chain resolves in the element's own scope. So
.outer .inner .subjectasks whether both names sit somewhere above the element. A descendant combinator asks for an.innerancestor that itself has an.outerancestor (Selectors 4 §16.1). Measured onmainwith.outer .inner .subject { color: red }:mainouter›inner›subject{"color":"#f00"}inner›outer›subject{"color":"#f00"}subject{"color":"#f00"}innerbesideouter›subjectundefinedThe last row is why this is a defect rather than a missing feature: the set of names is answered correctly, and only the order is lost. Stacked group variants are what Tailwind emits.
Solution
A registration keeps the scope it registered in, beside the element and props it already carries.
testContainerQuerieswalks the chain innermost first, each compound resolving in the scope of the one inside it, so a single compound resolves exactly as before.The registration a container publishes on every render takes the scope it renders in, so the walk never reads a stale one. Guards stay on the element's own scope, the only one it can re-read, and still compare the registration rather than the element, so a container whose props change re-derives its descendants.
Tests
src/__tests__/native/grouping.test.tsxgains seven cases:[data-state]read from that container, and re-derived when it changes;On
main, 3 of the 11 cases in the file fail. Each of 6 mutations fails its own cases, among them comparing a guard on the element alone, which misses a container whose props change.Verification
On Windows with Node 26:
yarn lintcleanyarn typecheckcleanyarn test --coverage: every failure also fails onmainon this machine (the four babel cases)yarn buildcleanyarn example expo export --platform webexportedDevice evidence, before and after: #463 (comment)
Known limits
An unnamed query still resolves the nearest container that registered, not any ancestor. #462 states the same limit for a classless ancestor.
Merge order
#427 also edits
src/native/reactivity.ts, so whichever lands second rebases. Independent of #462, which decides a classless ancestor's condition in the compiler; they touch no common file.Base
Re-written on
main(a5002c5).