feat(ui): govern chat bubble/row shell onto @maka/ui chat primitives - #334
Merged
Conversation
PR1 of #332. Move the conversation-flow row/bubble *shell* onto a new `@maka/ui` `Message` + `Bubble` primitive pair (cva + data-slot), retiring the bespoke `.message.{role}` / `.maka-bubble-user` / `.maka-bubble-truncated` shell CSS with zero visual change. - packages/ui/src/primitives/chat.tsx: `Message` (row, role variants) keeps the authored `.maka-message-row` base and adds the role layout as utilities; `Bubble` (user/assistant) carries the user tint as utilities on the neutral `--chat-user-bg` token path (never primary/accent) and re-emits `.maka-bubble-assistant` so the Markdown prose (OUT of scope) is untouched. - Wire MessageBody, the committed user/system/assistant rows, the streaming row, and the streaming truncated pill onto the primitives. - Retire shell CSS: `.maka-bubble-user` (both rules, incl. the 640px width cap), `.message.user/.assistant/.system`, the dead `.message > span` role labels, `.maka-bubble-assistant-stack`, `.maka-bubble-truncated`. Re-anchor the still-hand-written turn lineage/footer + system `pre` rules (PR2) onto the `[data-slot="message"][data-role]` hook at identical specificity. Keep all `.maka-bubble-assistant` Markdown prose. - Add chat-primitive-cascade-contract.test.ts locking: shell selectors gone, prose preserved, turn layout re-anchored, neutral token path + 640px cap.
…le→variant Address review on #334: - User bubble shell uses literal arbitrary utilities (rounded-[10px], px-[14px] py-[10px]) instead of the semantic scale (rounded-lg, px-3.5). The retired .maka-bubble-user hardcoded these pixels, so the literal is the faithful translation, immune to scale/token re-tuning, and self-evidently equal to the old computed style — the source-string contract becomes a complete proof without a render harness. (rounded-lg already resolves to 10px here via @theme inline --radius-lg, so this is not a regression fix — it removes the ambiguity the review flagged.) - Rename the Message `role` prop to `variant` so it never shadows the native HTML/ARIA `role` (still emitted to the DOM as data-role for the re-anchored turn rules); symmetric with Bubble's `variant`. - Strengthen the contract test to pin the literal radius/padding/leading/ width/token values and reject the semantic scale.
…user-bubble contract Address P3 review feedback on the #332 PR1 chat primitives (non-blocking robustness + governance precision): - Spread {...props} before the fixed data-slot/data-role/data-variant in Message/Bubble so the structural hooks the re-anchored selectors depend on always land last and can't be clobbered by a consumer. - Drop the unreachable defaultVariants from messageVariants/bubbleVariants (variant is a required prop; every call site passes it explicitly). - Tighten the user-bubble contract from contains-each-literal to an exact match on the whole variant class string, so a stray extra utility that would silently override the shell now fails the test. - Add a hook-free render-prop assertion in @maka/ui proving the primitives keep their own data-* over conflicting props.
This was referenced Jun 28, 2026
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.
Summary
PR1 of #332 — migrate the conversation-flow row/bubble shell onto a new
@maka/uiMessage+Bubbleprimitive pair (cva +data-slot), retiring the bespoke.message.{role}/.maka-bubble-user/.maka-bubble-truncatedshell CSS with zero visual change. The Markdown prose and the turn machinery (summary / lineage / footer / markers — PR2) are untouched.Why
Part of #332. The chat conversation-flow display was the last bespoke island after the rest of
packages/ui/src/primitives/*moved onto the shadcn Base UI + Tailwind substrate. This is governance — one substrate + a test net — not a redesign; the visual refresh is a separate follow-up.Scope
Changed:
packages/ui/src/primitives/chat.tsx(new), exported frompackages/ui/src/index.ts:Message— per-turn row (roleuser/assistant/system). Keeps the authored.maka-message-rowbase (centered column + entrance fade/animation + thedata-maka-visual-smokedisable); role layout moves to utilities..maka-message-rowlives in maka-tokens'@layer components, so the utilities (utilities layer) win — the assistant/system left-anchor (ml-0 mr-auto) overrides the row's centering exactly as the old.message.assistantdid.Bubble—variant="user"carries the tint as utilities on the neutral--chat-user-bgtoken path (neverprimary/accent);variant="assistant"re-emits.maka-bubble-assistantso the prose stays authored.packages/ui/src/components.tsx— wireMessageBody, the committed user/system/assistant rows, the streaming row, and the streaming "已截断" pill onto the primitives (net −66 lines; no new responsibility added to the sink)..maka-bubble-user(both rules, incl. the effectivemin(100%,640px)width cap from the second rule),.message.user/.assistant/.system, the dead.message > spanrole labels,.maka-bubble-assistant-stack,.maka-bubble-truncated.<pre>reset/pill ride[data-slot="message"][data-role=…]at identical specificity, so their layout is pixel-stable until PR2 migrates them.apps/desktop/src/main/__tests__/chat-primitive-cascade-contract.test.ts(new).Not included:
.maka-bubble-assistantMarkdown prose (task lists, code blocks, tables, blockquotes, links) — preserved verbatim..messagesscroll container, runtime, streaming, Markdown rendering, permission, turn model, tool output, or attachment IPC.Verification
chat-primitive-cascade-contract.test.tslocks: retired shell selectors gone, prose preserved, turn layout re-anchored onto the primitive, user bubble on--chat-user-bgwith the 640px cap and neverprimary/accent.@maka/desktoptypecheck clean; 1582/1582 desktop tests pass (incl. the renderer cascade + dead-CSS pruning contracts); 4/4@maka/uitests;node scripts/check-dead-css.mjs --check→ no dead classes.turn-narrativescenario on this branch: user bubble tinted/rounded/right-anchored with the meta row beneath; assistant summary, tools, prose, and footer all left-anchored at the same measure column. The repo screenshot harness is a presence/dimension sanity gate, not a pixel diff (font drift makes byte-diff too noisy), so visual parity is held by the contract test + the capture rather than an automated before/after diff.User-facing impact
None — zero visual change by design. No
CHANGELOG.md, docs, breaking changes, or migrations.Reviewer notes
.maka-bubble-userhad two rules; the second overridesmax-widthtomin(100%,640px)(not the first rule's78%). The primitive uses 640px, locked by the contract test..message.assistantwas the ancestor selector for the PR2 lineage/footer measure rule. Deleting it required re-anchoring those (and the system<pre>rules) onto[data-slot="message"][data-role]at identical specificity, so PR2 elements stay pixel-stable.