Skip to content

Let the theme turn a page header inline, so its two halves cannot drift - #92

Merged
anilcancakir merged 2 commits into
mainfrom
fix/page-header-inline-actions-theme
Aug 16, 2026
Merged

Let the theme turn a page header inline, so its two halves cannot drift#92
anilcancakir merged 2 commits into
mainfrom
fix/page-header-inline-actions-theme

Conversation

@anilcancakir

Copy link
Copy Markdown
Contributor

The defect

MSPageHeader.inlineActions does two things at once:

  1. swaps containerClassName for containerInlineClassName, and
  2. gives the title row flex-1 min-w-0 instead of only sm:flex-1.

Those are two halves of one decision, and until now a consumer could set the first and not the second, because the container class is a theme string while the flex behaviour is a widget argument.

That combination silently overflows. An app that themes the container into a row at every width, so a phone header keeps its action beside the title rather than dropping it under the subtitle, leaves the title row without flex-1 below sm. The title column is flex flex-col gap-1 flex-initial min-w-0, and flex-initial is a loose fit, so the text takes its intrinsic width and runs past the actions.

line-clamp-2 on the title cannot save it, for the same reason truncate cannot without a constrained box: it sets the overflow behaviour and nothing about the width.

How it was found

In depools, whose main.dart overrides containerClassName to flex-row at every width with a comment that predicted this exactly:

The constraint this accepts: below sm the starter gives the title block sm:flex-1, so the title takes its intrinsic width and a genuinely long one could overflow rather than shrink. Every title in this app is one or two short words. A longer one is the signal to reach for inlineActions, which MSPageScaffold does not forward today.

The product screen reported A RenderFlex overflowed by 40 pixels on the right at 390 with the title "Dishwasher Tablets" and three icon buttons. Confirmed by measurement rather than by reading: reverting that one override to flex-col sm:flex-row removed the stripe and the exception entirely, and the icons dropped to their own line.

The fix

MSPageScaffold does not forward inlineActions at all, so a scaffold consumer had no way to reach the second half even knowing it existed. Rather than threading an argument through the scaffold and asking every screen to pass it, the flag moves to MagicStarterPageHeaderTheme, beside the container class that requires it. One place, stated once, and the two cannot drift apart.

MSPageHeader.inlineActions becomes bool? and falls back to MagicStarter.pageHeaderTheme.inlineActions, so an explicit argument still beats the theme and every existing caller is unchanged.

Verification

flutter analyze clean, 1253 tests pass, of which 4 are new.

The overflow is a test rather than a proxy for one. Reverting the title-row half turns two tests red, and the second names the defect itself:

inline mode gives the title row flex-1 so a long title shrinks
  Expected: not contains 'sm:flex-1'
    Actual: 'flex flex-row items-center gap-3 sm:flex-1 min-w-0'

a header does not overflow at phone width when themed inline
  Expected: null
    Actual: FlutterError:<A RenderFlex overflowed by 79 pixels on the right.>

(79 rather than 40 because the test uses three plain 44px icons and a slightly different title; the mechanism is the same.)

.claude/rules/widgets.md records the coupling, so the next person reading the flag learns that setting one half alone is what breaks.

`MSPageHeader.inlineActions` does two things at once: it swaps
`containerClassName` for `containerInlineClassName`, and it gives the title row
`flex-1 min-w-0` instead of only `sm:flex-1`. Those are two halves of one
decision, and until now a consumer could set the first and not the second,
because the container class is a theme string while the flex behaviour is a
widget argument.

**That combination silently overflows.** An app that themes the container into
a row at every width, so a phone header keeps its action beside the title
rather than dropping it under the subtitle, leaves the title row without
`flex-1` below `sm`. The title column is `flex-initial`, a loose fit, so the
text takes its intrinsic width and runs past the actions. Measured in depools
at 40 logical pixels on a 390px viewport with a two-word title and three icon
buttons, and reproduced here at 79. `line-clamp-2` on the title cannot save it,
for the same reason `truncate` cannot without a constrained box.

`MSPageScaffold` does not forward `inlineActions` at all, so a scaffold
consumer had no way to reach the second half even knowing it existed. Rather
than threading an argument through the scaffold and asking every screen to pass
it, the flag moves to `MagicStarterPageHeaderTheme`, beside the container class
that requires it: one place, stated once, and the two cannot drift apart.

`inlineActions` becomes `bool?` and falls back to the theme, so an explicit
argument still beats it and every existing caller is unchanged.

The overflow itself is a test. Reverting the title-row half turns it red with
`A RenderFlex overflowed by 79 pixels on the right`, which is the defect rather
than a proxy for it.
Copilot AI lite review requested due to automatic review settings August 16, 2026 14:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@anilcancakir
anilcancakir merged commit edeb4f5 into main Aug 16, 2026
2 checks passed
@anilcancakir
anilcancakir deleted the fix/page-header-inline-actions-theme branch August 16, 2026 14:36
anilcancakir added a commit that referenced this pull request Aug 16, 2026
…#93)

`CLAUDE.md` has a post-change checklist and I ran none of it: CHANGELOG under
`[Unreleased]`, README where the API changed, and the relevant `doc/` pages.
The code in #92 was right and the paper trail was missing, which for a released
package is half the change.

The CHANGELOG entry carries the measurement rather than only the fix: the
combination that overflows is a theme override plus the missing flag, seen at
40 logical pixels in a host app and reproduced at 79 in the suite.

`doc/architecture/manager.md` gains the case worth documenting, which is not
"here is a new field" but "setting the container alone overflows". Anybody
overriding `containerClassName` into a row is one paragraph away from the bug,
so the paragraph sits under the override rather than under the flag.

`doc/basics/components.md`'s one-line summary says the header stacks below `sm`
and what turns that off. README is deliberately untouched: its component table
is a name and a phrase, and the detail belongs in `doc/`, where it now is.
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.

2 participants