fix(core): justify-content honors min-resolved root main size (closes #165)#173
Open
zhijiewong wants to merge 9 commits into
Open
fix(core): justify-content honors min-resolved root main size (closes #165)#173zhijiewong wants to merge 9 commits into
zhijiewong wants to merge 9 commits into
Conversation
…tent (#165) Root cause + main-axis-only fix design: resolve a bare-auto root's main container size from clamp(content, min, max) at the positioning step so justify-content distributes against the resolved size instead of 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nt (#165) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ved root main size (#165) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…165) Code-review follow-up. Reverse directions reflect about innerMain in flipMainAxis (and the spineless applyReverseMainPos reflects about the same unresolved 0), so substituting a larger forward main size would desync the engines and rely on the autoSizeRootFromContent shift to mask negatives. Gate the substitution to !isReverse — reverse + bare-auto stays deferred and identical across engines. Also renames the inner `items` binding to `lineItems` to avoid shadowing the step-1 `items`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#165) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… fixtures (#165) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uzzer guard (#165) Final-review follow-up (two cross-engine gaps on the untouched flexWrap path): 1. The classic substitution gated on `lines.length === 1`, which is true for a single-child WRAP root (packIntoLines short-circuits at <=1 item), so classic applied the #165 fix to wrap roots while the spineless wrap path (evaluateWrappedChild) never does — kid.left 15 vs 0. Gate classic to no-wrap so both engines defer wrap identically. 2. Both differential fuzzers' imperative reference called `layoutChildren(root)` with the default rootMainAuto=false, no longer mirroring index.ts — so the fuzzer compared a fixed spineless side against an unfixed imperative side and would spuriously diverge (or silently stop guarding) the changed code. Mirror index.ts in both imperativeFloats helpers. Adds a multi-child space-between test and a wrap-deferral consistency test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
What
A bare-auto root container resolved its main-axis size from
min-width/min-heightafter positioning its children, so
justify-contentcollapsed them toflex-start at
0(root width became 50 but the child stayed atleft: 0).Yoga distributes within the resolved size.
Fix
At the positioning step only, for a single-line, forward-direction bare-auto
root main axis, both engines position against
max(innerMain, clamp(content, min, max) − pads):index.ts+main-axis.ts): threads arootMainAutoflag(via the now-exported
axisIsBareZero) into the flex pipeline; substitutes atpositionItemsInLine, gatedrootMainAuto && noWrap && !isReverse.flex-grammar.ts): feeds the root's min/max main fields intoemitJustifiedMainPosunder the existingrootAxisIsBareZerostructural gate(forward, no-wrap).
The
max(…)guard makes the change a no-op for every concrete-size container.The two engines are kept byte-identical; the differential fuzzer confirms it
(its imperative reference was also updated to pass
rootMainAuto, restoring itas a real guard for this code).
Tests
layout.test.ts(classic + spineless paths, multi-childspace-between, shrink-wrap regression, and a wrap-deferral consistency guard).
row-min-width-and-margin,column-min-height-and-margin.pnpm run cigreen (lint → build → typecheck → test 1770 → test:differential 976).Scope / follow-up
No-wrap, forward-direction main axis only. The cross-axis (
align-items) analogand the wrap-justify case are deferred and tracked in #172 — both kept
consistent across engines.
Closes #165.
🤖 Generated with Claude Code