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
`ContainerContextValue` mapped a container name to the nearest element that registered it, and `testContainerQueries` resolved every compound of a selector in the element's own scope. So `.outer .inner .x` asked whether both names were somewhere above rather than whether the `.inner` ancestor itself had an `.outer` ancestor, and the rule matched under reversed nesting. A registration now carries the scope it was made in, and the walk goes innermost first, resolving each compound in the scope of the one inside it. A single-compound selector resolves exactly as before. Guards stay keyed on the element's own scope: it is the only one this element can re-read, and every name the walk reaches is inherited by it, so a change to any of them is observable there. Recording a guard against the scope a link was resolved in instead never agrees on re-check and re-renders the tree until React refuses.
Contributor
Author
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 ancestor compound is resolved in the subject's own scope, so a chain asks "are both names somewhere above me" rather than Selectors 4 §14.1's narrower question — and
.outer .inner .xtherefore matches the reversed nesting too.Measured on
mainwith.outer .inner .subject { color: red }:<outer><inner><subject>{"color":"#f00"}<inner><outer><subject>{"color":"#f00"}<inner/><outer><subject>undefinedThe third row is why this is a defect rather than a missing feature: the set is answered correctly and only the ORDER is lost. And it is the shipped
group-*path — stacked ancestor variants are what Tailwind emits.Solution
The scope a container registers in is already in hand at registration time; nothing was keeping it. Carry it, and the chain has something to walk:
testContainerQueriesthen walks innermost first, resolving each compound in the scope of the one inside it. A single-compound selector resolves exactly as before — everygroup-hover:/group-data-*:utility in use today.Worth stating, because the obvious guard shape does not work: a guard recorded against the scope THAT link resolved in makes
testGuards— which re-checks container guards against the ELEMENT's scope — disagree every pass, re-rendering until React refuses. Guards stay on the element's own scope, the only one it can re-read and where every chain name is inherited anyway.Tests
src/__tests__/native/ancestor-chain-order.test.tsx, 13 cases: two pin the compiled shape the walk depends on, eight drive the nesting (ordered, reversed, siblings, intervening elements, a three-deep chain with one pair swapped, both class names on one element), three pin what must not move (a single ancestor, an interaction condition on each compound, an idempotent re-render). The reversed case is the mutation proof — red onmainfor the reason above.Every ancestor test in the suite uses ONE ancestor, where a name lookup and a path walk cannot disagree. Nothing rendered two ancestors in both nestings.
Mutation-proved: reverting the
src/diff and re-running these files alone turns 3 of 13 red.Verification
yarn test1061 passed ·yarn typecheck0 ·yarn lint0. The three failures are two babel suites that fail identically on an untouchedmainworktree (Windows-only module-specifier rewrites) — this touches no babel file.Known limits
Residual, stated: an outer
.ashadowed by a nearer.athat is not an ancestor of.bcan leave a guard stale — narrower than today's behaviour, which is wrong for every reversed nesting.Independent of #462, which answers a classless ancestor's condition in the compiler; this answers the ORDER of any chain in the runtime. They touch no common file, so whichever lands last needs no rebase.
No existing issue tracks this — searched the tracker for
descendant combinator,container query order,group-andancestor nesting, zero hits.Base
Branched off
f70c402.mainhas since taken #451 (a5002c5). 3 of the 5 files this changes also moved there, and 3 genuinely conflict —src/native/conditions/container-query.ts,src/native/react/rules.ts,src/native/reactivity.ts. Every measurement above was taken onf70c402. Say the word and I will re-apply it onto currentmain.