Skip to content

fix(webkit): let the host decide surface, size and width in three components - #829

Merged
robsongajunior merged 11 commits into
mainfrom
fix/host-context-wins
Jul 30, 2026
Merged

fix(webkit): let the host decide surface, size and width in three components#829
robsongajunior merged 11 commits into
mainfrom
fix/host-context-wins

Conversation

@gabriel-lisboa-azion

@gabriel-lisboa-azion gabriel-lisboa-azion commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three components each hard-coded a decision that belongs to whatever hosts them. One commit per component:

StatusIndicator painted its own background. The root set bg-[var(--bg-surface)], so the indicator carried a card-coloured panel wherever it went — on a table cell, a raised card or an overlay that showed as a visible patch behind the label. It is a status label, not a card: it now paints nothing and reads on whatever it sits on. A consumer who wants a panel can still pass one.

Table.Search could not be resized. size="small" was bound after v-bind="$attrs", so it overwrote whatever the consumer passed. A search field could never join a toolbar row of large controls, and the workaround was to drop Table.Search and hand-roll the field. Moving it before $attrs keeps small as the default while letting the consumer win — what every other pass-through on this component already does.

The global header start region refused to shrink. GlobalHeader.Left — the brand plus whatever resource path sits beside it — was shrink-0, so with the centre and end regions also populated a long org/project path pushed the bar wider than the viewport instead of the region giving way. shrink lets it yield first; the min-w-0 already there keeps its own contents truncating.

⚠️ Read the GlobalHeader finding below before approving that third change — the baselines say it is not the clean win the diff suggests.

Tests

Full webkit suite green (83 files / 1693 passing, 6 skipped), eslint + vue-tsc clean, catalog:check in sync.

New coverage for the one behavioural change: Table.Search defaults to small and honours a consumer size="large". I confirmed the test has teeth by reverting the fix — it fails with expected 'small' to be 'large' and passes with it.

The other two are pure style deltas with no observable DOM change, so they get no unit test on purpose — an assertion on the class string would be exactly the refactor-trap the testing rule forbids. They are verified in the visual layer below.

Visual regression

Baselines are regenerated and committed (ubuntu-latest, via the app-storybook-generate-baseline dispatch). Final delta — 24 files, nothing outside these two components, no orphans:

  • 18 movedcomponents-feedback-statusindicator--*: the background is gone, so it composites onto the story canvas. Review question: does the label still read in both themes now?
  • 6 newcomponents-layout-globalheader--crowded*, the first visual coverage the start region's shrink behaviour has ever had.
  • unchanged — Table: small is still the default, so nothing about the rendered toolbar moves.

⚠️ Finding: the GlobalHeader change is not demonstrably a win

The first regeneration came back with zero GlobalHeader movement. The Default story leaves the centre and end regions empty, so nothing competes for width, the shrink-0 constraint never binds, and the screenshots were byte-identical either way. The fix had no coverage at all.

I added a Crowded story (all three regions populated, long path at the start) and regenerated. What it shows:

viewport result
1280 desktop lays out cleanly, path un-truncatedLeft never needs to shrink
768 tablet lays out cleanly, path un-truncatedLeft never needs to shrink
375 mobile content overlaps — text collides across regions

So the one width where Left must shrink is the one where shrinking isn't enough: Middle carries no truncation and Right is shrink-0, so once Left has yielded there is nothing left to give. On the evidence, shrink-0shrink does not improve any tested viewport.

I did not fix it. How the header should degrade below md (truncate the centre? collapse to a menu? drop the path?) is a design decision, not a drive-by edit inside a one-line change — and the committed mobile baseline now documents the gap instead of hiding it, per the repo's default-on 6-mode policy.

Reviewer's call on the third commit: ship it as a correct-but-latent constraint change, drop it and handle GlobalHeader's narrow-width behaviour properly in its own PR, or extend this PR deliberately. The other two commits are independent of it.

Notes

  • The status-indicator spec drops its surface token row to match.
  • Independent of the other five branches in this batch — no merge-order constraint.
  • No new dependency. No breaking change: no prop, event, slot or export is added, renamed or removed.

The root painted bg-[var(--bg-surface)], so the indicator carried a card
coloured panel wherever it was placed. On a surface of any other tone - a table
cell, a raised card, an overlay - that showed as a visible patch behind the
label. It is a status label, not a card: it now paints no background and reads
on whatever it sits on. Consumers that want a panel can still pass one.
size="small" was bound after v-bind="$attrs", so it overwrote whatever the
consumer passed - a search field could never join a toolbar row of large
controls, and the only workaround was to drop Table.Search and hand-roll the
field. Moving it before $attrs keeps small as the default while letting the
consumer win, which is what every other pass-through on this component already
does.
GlobalHeader.Left - the start region, which holds the brand and whatever
resource path sits beside it - was shrink-0. With the centre and end regions
also populated there is no slack, so a long org/project path pushed the bar
wider than the viewport instead of giving way. shrink lets it yield first; the
min-w-0 already present keeps its own contents truncating rather than
overflowing.

The Default story could not show this: its centre and end regions are empty, so
nothing ever competed for the width and the regenerated baselines did not move
at all. The new Crowded story populates all three regions with a long path at
the start, which is the case that decides the behaviour, and it is shot at 375
and 768 where there is no slack to absorb it. The test asserts the fixture
composes and stays axe-clean; the widths are the visual layer's job.
gabriel-lisboa-azion and others added 5 commits July 29, 2026 08:52
StatusIndicator's 18 snapshots move: it no longer paints --bg-surface, so it
composites onto the story canvas. The 6 new globalheader--crowded snapshots are
the first visual coverage of the start region's shrink behaviour.

Recorded honestly: at 375px the crowded header OVERLAPS rather than degrading.
Letting the start region shrink is not sufficient there, because Middle carries
no truncation and Right is shrink-0, so once Left has yielded there is still
nothing left to give. At 768px and above the same content lays out cleanly with
the path un-truncated - meaning Left never has to shrink at those widths either.

So this baseline documents a real GlobalHeader gap (no narrow-width strategy for
the three populated regions) rather than proving the one-line change good. Left
deliberately unfixed here: how the header should degrade below md is a design
decision, not a drive-by edit inside a shrink-0 -> shrink change.

Generated on ubuntu-latest via app-storybook-generate-baseline; nothing outside
statusindicator and globalheader moved, and no baseline was orphaned.

@robsongajunior robsongajunior left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@gab-az revisar

425219f3e0b8c11e45bc41ca1b21438dd4ce204caa8e9366e3e557ae3d816d16

apps/storybook/.storybook/test-visual/__image_snapshots__/linux/components-layout-globalheader--crowded--dark-mobile.png

The story populated all three header regions with a long resource path at
the start, to exercise the case where the start region has to give way. The
spec's Stories section lists only Default, so Crowded was an undeclared
addition.

Removes the story, the test that composed it, and the six linux baselines it
owned. The shrink fix in global-header-left.vue stays; it now ships without
the story that demonstrated it, since the Default story's centre and end
regions are empty and its baselines never moved.
@robsongajunior
robsongajunior merged commit 8d494d7 into main Jul 30, 2026
23 checks passed
@robsongajunior
robsongajunior deleted the fix/host-context-wins branch July 30, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants