Repository navigation
fix(plugin-detail): header highlights share the row's free width and truncate only when it runs out (objectui#11684) - #11719
Merged
objectstack-fleet[bot] merged 2 commits intoOct 6, 2026
Conversation
…truncate only when it runs out (objectui#11684) Each highlight chip was a fixed column (9rem / 16rem basis, no grow, 16rem / 24rem cap), so "QA Widget 1" read "QA Wid..." in the record drawer with most of the row empty. The basis is now the chip's floor (line breaking still reads it), `grow` hands the line's free width to the chips, and `max-w-max` caps each chip at its own content so the free width goes to the chips that still need it. Claude-Session: https://claude.ai/code/session_01FngvPpdrnhHMdHHq6vwwju Co-authored-by: Claude <noreply@anthropic.com>
…instead of an any cast (objectui#11684) Claude-Session: https://claude.ai/code/session_01FngvPpdrnhHMdHHq6vwwju Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
objectstack-fleet
Bot
deleted the
claude/issue-11684-highlight-share-row
branch
October 6, 2026 14:34
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.
Fixes #11684
Clause-②: no
What was wrong
HeaderHighlight(@object-ui/plugin-detail) laid each highlight chip out as a fixed column. The basis was 9rem (16rem for a wide display type or a column being edited), with nogrowand a 16rem / 24rem cap. The row isflex flex-wrapwithoverflow: visible, and the value is ablock min-w-0 truncatespan. So a chip never got wider than its basis, and a value wider than the chip's content box was cut, whatever the row had left.Measured in Chromium in the console's own drawer path at the default width. The scratch harness mounted the real
RecordDetailView embeddedinside the realNavigationOverlaydrawer, with the showcase Product object. The harness was deleted before commit. At 1440px the drawer is 864px and the highlight row is 767px. The three chips use 432px and leave 335px free. The Description chip holding "QA Widget 1" has a 79px value box for an 80px text, so it clips. The 79px is the 144px basis, minus 40px padding, a 1px divider and 24px for the hover pencil.The change
One class string on the chip column, plus its comment:
basis-[9rem]/basis-[16rem]stay. They are now the chip's floor, and line breaking still reads them, so which chips share a line does not change.growhands the line's free width to the chips.max-w-maxreplaces the 16rem / 24rem caps. Each chip is capped at its own content. A chip that fits stops growing, and the flex algorithm passes the rest of the free width to the chips that still need it.min-w-[min(9rem,100%)]/min-w-[min(16rem,100%)]replacemin-w-[7rem]. A short value keeps its 9rem column, and a column can still narrow to a row that is itself narrower than the floor.No new authored key, no prop and no export. The row container is unchanged.
Route: content cap, not the suggested share-of-row cap
The order suggested letting each column grow with its basis as the floor, under a cap that is a share of the row. I measured the alternatives against the card's Done-when and took a content cap. Reasons:
@object-ui/componentsCHANGELOG) set the caps to stop. By construction (not measured), it also moves the hover pencil, whichjustify-betweenplaces, to the far edge of a stretched chip. Under the content cap no chip is wider than its content, so a sparse strip still packs left and the pencil stays beside its value.What I kept from the old caps: their reason, namely that a highlight is never stretched beyond its content and a sparse strip packs left. What I dropped is the fixed 16rem / 24rem point where a long value was cut regardless of free width. A single highlight can now reach the full row width only when its own content is that long and its line has room.
Premise checks (the order's mechanism assumptions, measured at base
48c82c9)display: flex,flex-wrap: wrap,overflow: visible. Chipflex: 0 1 144px,max-width: 256px,min-width: 112px. Valuetruncate. The Description chip read 79 of 80px at every drawer width measured (table below). The SKU chip is the first chip, so it has no left padding and a 100px box. Its 100px text fit exactly in this container's fonts. The sweep's host clipped both, so the pin covers every chip that carries the measured text.deriveRecordSurfaceopens a drawer withoverlayWidthFor('auto', objectDef). Five fields give themdbucket,min(92vw, 720px). The shell treats that as a floor. The rendered drawer carries--ov-w: max(min(92vw, 720px), min(60vw, 880px)), which is 720 / 768 / 864 / 880px at 1024 / 1280 / 1440 / 1920. The publishedRecordDetailDrawerdefault (RECORD_OVERLAY_DEFAULT_WIDTH,min(960px, 60vw)) goes through the same shell expression. jsdom does not lay out, so the committed pin asserts the classes that decide the distribution. The browser reading is below and was not committed (see Acceptance notes).RecordDetailViewat full viewport width. That is wider than the console page shell, so it is the stress case for wide rows. Short values look exactly as in the drawer: the chips pack left and nothing stretches. A long value grows to its content and stops there.Browser reading (Chromium 1194, one-time, scratch harness deleted)
"col" is the chip column width and "box / text" is the value's clip box against its scroll width, in px.
Pins
packages/plugin-detail/src/__tests__/HeaderHighlight.shareRowWidth-11684.test.tsx, 6 cases. It renders the console's path,record:highlightsunder a record context, with the showcase Product field types.grow,max-w-max,basis-[9rem]andmin-w-[min(9rem,100%)], and none of the retiredmax-w-[16rem],max-w-[24rem]ormin-w-[7rem].truncate, with the whole value as its title.flex flex-wrap.The existing pins that read the basis classes stay green unchanged:
RecordHighlightsRenderer.phoneWidth-11659, andexpandableFamily.identity-5874's wide/narrow reading. TheRecordHighlightsRenderer.percentClipheader described the chip as "shrinking towardmin-w-[7rem]". It now describes the old fixed column in the past tense.Ablation (one-shot, from committed state
3923377)The distribution was reverted to the base class strings with
scripts/ablation-replace.mjsin wrap mode, which owns the EXIT/INT/TERM restore on the absolute path. The anchor went x1 to x0, the replacement x0 to x1, and the blob98d218122a4btoa293d79c18f5. During the mutation the on-disk counts were:max-w-max1 (the comment only; 2 when restored), the old cap string 1, andmin-w-[7rem]1.Tests 4 failed | 2 passed (6).98d218122a4b), andgit diff HEADis empty.../HeaderHighlightand../renderers/record-highlightsrelatively, so the subject issrcand nodistrebuild sat on the path.Gates
pnpm turbo run build --filter='@object-ui/plugin-detail^...' --concurrency=2(the dependency closure)3923377pnpm --filter @object-ui/plugin-detail build3923377(HeaderHighlight.tsxunchanged since)pnpm --filter @object-ui/plugin-detail type-check(tsc --noEmit && tsc -p tsconfig.test.json;--listFilesshows the test program reads the new pin)3923377; the test program re-run on the bytes committed asbc8daa3pnpm --filter @object-ui/plugin-detail lintbc8daa3pnpm exec vitest run packages/plugin-detail/bc8daa3pnpm check:new-line-citations·check:control-bytesbc8daa3pnpm check:changeset-claims·check:pending-changeset-literalsbc8daa3node scripts/check-changeset-fixed.mjs·check-changeset-no-major.mjs·check-changeset-presence.mjsbc8daa3pnpm check:test-path-roots·check:unreferenced-sourcesbc8daa3node scripts/check-governed-queue-guard.mjs --testover the four pathsbc8daa3Lint workflow
check:*families not listed here are CI's.scripts/pm/dispatch-gates.mjsis objectstack's and cannot derive objectui's families, so these were derived by hand from objectui'spackage.jsonfor this diff.Acceptance notes
e2e/record-header-title-width.spec.ts. That would mean real Tailwind compiled from the class strings read out ofHeaderHighlight.tsx, and "QA Widget 1" whole in a 767px row.e2e/is outside this claim's file surface, so I did not add it. The seat decides whether to add it as a follow-up.labeland the i18n bundle, and passes no object-schema label as the fallback. With no bundle, as in the stub harness, the label renders blank. On the real backend the sweep read "SKU" and "Description", and I did not measure a host where this shows. Carrier: none.Session:
https://claude.ai/code/session_01FngvPpdrnhHMdHHq6vwwjuGenerated by Claude Code