Skip to content

[Feature] Add Message component - #446

Merged
djalmaaraujo merged 5 commits into
mainfrom
feat/message-component
Jun 30, 2026
Merged

[Feature] Add Message component#446
djalmaaraujo merged 5 commits into
mainfrom
feat/message-component

Conversation

@djalmaaraujo

@djalmaaraujodjalmaaraujo commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Description

Ports the shadcn Message component to RubyUI — the higher-level chat layout that pairs an avatar with bubbles, headers, and footers.

Stacked on #445 (Bubble). Base is feat/bubble-component; this PR shows only the Message diff. Retarget to main once #445 merges.

Reference:

Closes#444.

What's included

  • Message — row container, align: (start/end); flips avatar/content via flex-row-reverse
  • MessageGroup — stacks messages
  • MessageAvatar — wraps the existing Avatar; anchors to the row bottom and lifts when a footer is present
  • MessageContent — column holding bubbles; drives bubble alignment via group-data-[align=end]/message
  • MessageHeader / MessageFooter — muted meta lines (name, timestamp, "Delivered")

Reuse — no new primitives

Bubble alignment inside a message is handled entirely by Message — Bubble is unchanged. dependencies.yml: message depends on Avatar + Bubble.

Notes

  • shadcn ships these styles as a custom cn-message-* CSS layer; this port translates every rule to Tailwind v4 utilities. No custom CSS, no JS.
  • Marker (the "is typing…" indicator) is a separate shadcn component, out of scope here; the demo uses plain footer text instead.

Testing

  • cd gem && bundle exec rake → tests + StandardRB green.
  • Docs page rendered locally at /docs/message: conversation, header/footer, alignment, and group all verified visually against the shadcn demo.

Screenshots

Add before/after screenshots of /docs/message.


Summary by cubic

Add a chat Message layout that pairs an avatar with bubbles, headers, and footers to build aligned, grouped conversations. Ships with Tailwind v4 utilities and a docs page; no custom CSS or JS.

  • New Features

    • Message with align: :start|:end; controls bubble alignment and flips rows.
    • Subcomponents: MessageGroup, MessageAvatar, MessageContent, MessageHeader, MessageFooter.
    • Docs at /docs/message with examples; routes, controller, nav, sitemap, and LLM docs maps updated.
    • Tests for slots, alignment, and grouping.
    • MCP registry updated with Message files, metadata, and examples.
  • Dependencies

    • Updated dependencies.yml: message depends on Avatar and Bubble; Bubble is unchanged.

Written for commit c9dd5e7. Summary will update on new commits.

Review in cubic

Port the shadcn Bubble component: a chat bubble surface with 7 variants
(default, secondary, muted, tinted, outline, ghost, destructive),
start/end alignment, grouping, and edge-anchored reactions.
- Translates shadcn's cn-bubble-* CSS layer to real Tailwind v4 utilities
and RubyUI theme tokens (no custom CSS shipped).
- BubbleContent is polymorphic via as: (:div/:a/:button) for link/button
bubbles — the idiomatic Phlex equivalent of shadcn's asChild.
- No JS. Composes with Tooltip/Popover (docs examples included).
Docs page, route, controller, menu entry and site_files updated.

@cubic-dev-aicubic-dev-aiBot 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.

No issues found across 17 files

Re-trigger cubic

@djalmaaraujo
djalmaaraujoforce-pushed the feat/message-component branch from 9e0d56b to 75db4cfCompareJune 30, 2026 15:30
Collapse the duplicated [&_button]/[&_a] pairs into [&:is(button,a)]
selectors targeting the content element itself (the polymorphic as:
:button/:a case), matching the variant hover selectors. Halves the
class string with identical behavior.
@djalmaaraujo
djalmaaraujoforce-pushed the feat/message-component branch from 75db4cf to 8173b90CompareJune 30, 2026 15:37
Port the shadcn Message component: the higher-level chat layout that pairs
an avatar with bubbles, headers, and footers. Built on top of Bubble (#445).
- 6 parts: Message (align start/end), MessageGroup, MessageAvatar,
MessageContent, MessageHeader, MessageFooter.
- Reuses the existing Avatar and the new Bubble components — no new
primitives. Bubble alignment inside a message is driven by Message via
group-data-[align=end]/message; Bubble itself is unchanged.
- Translates shadcn's cn-message-* CSS layer to Tailwind v4 utilities.
- dependencies.yml: message depends on Avatar + Bubble.
Closes#444.
Docs page, route, controller, menu entry and site_files updated.
@djalmaaraujo
djalmaaraujoforce-pushed the feat/message-component branch from 8173b90 to c9dd5e7CompareJune 30, 2026 15:45
Base automatically changed from feat/bubble-component to mainJune 30, 2026 16:53
@djalmaaraujo
djalmaaraujo merged commit 43a75db into mainJun 30, 2026
7 checks passed
@djalmaaraujo
djalmaaraujo deleted the feat/message-component branch June 30, 2026 20:04
djalmaaraujo added a commit that referenced this pull request Jun 30, 2026
Port the shadcn Message Scroller: a chat transcript scroller that follows
the live edge, anchors new turns near the top, and jumps to the latest
message. Built on top of Message (#446) and Bubble (#445).
shadcn delegates to a closed React primitive (@shadcn/react); this is a
from-scratch Stimulus controller (ruby-ui--message-scroller) — our own
code, no external lib:
- autoScroll follow-edge: pins to the bottom while the reader is there,
releases on wheel/touch/keyboard/scrollbar away, re-engages on jump.
- scrollAnchor: settles an appended turn near the top keeping a peek of
the previous item (previous_item_peek).
- defaultPosition: open at end / start / last-anchor.
- preserveOnPrepend: hold the visible row when history loads in above.
- Public API for streaming/ActionCable: scrollToEnd/scrollToStart/
scrollToMessage; new rows are picked up via MutationObserver.
- rAF-based smooth scrolling (native smooth is unreliable on a contained
viewport), honors prefers-reduced-motion.
- a11y: content role=log + aria-relevant, button sr-only label, button
removed from tab order while inert.
Parts: MessageScrollerProvider, MessageScroller, MessageScrollerViewport,
MessageScrollerContent, MessageScrollerItem, MessageScrollerButton.
dependencies.yml: message_scroller depends on Message + Bubble. MCP
registry, docs page, route, controller, menu and site_files updated.
djalmaaraujo added a commit that referenced this pull request Jun 30, 2026
Port the shadcn Message Scroller: a chat transcript scroller that follows
the live edge, anchors new turns near the top, and jumps to the latest
message. Built on top of Message (#446) and Bubble (#445).
shadcn delegates to a closed React primitive (@shadcn/react); this is a
from-scratch Stimulus controller (ruby-ui--message-scroller) — our own
code, no external lib:
- autoScroll follow-edge: pins to the bottom while the reader is there,
releases on wheel/touch/keyboard/scrollbar away, re-engages on jump.
- scrollAnchor: settles an appended turn near the top keeping a peek of
the previous item (previous_item_peek).
- defaultPosition: open at end / start / last-anchor.
- preserveOnPrepend: hold the visible row when history loads in above.
- Public API for streaming/ActionCable: scrollToEnd/scrollToStart/
scrollToMessage; new rows are picked up via MutationObserver.
- rAF-based smooth scrolling (native smooth is unreliable on a contained
viewport), honors prefers-reduced-motion.
- a11y: content role=log + aria-relevant, button sr-only label, button
removed from tab order while inert.
Parts: MessageScrollerProvider, MessageScroller, MessageScrollerViewport,
MessageScrollerContent, MessageScrollerItem, MessageScrollerButton.
dependencies.yml: message_scroller depends on Message + Bubble. MCP
registry, docs page, route, controller, menu and site_files updated.
cirdes pushed a commit that referenced this pull request Jun 30, 2026
* [Feature] Add Empty component
Port the shadcn Empty component: a centered empty-state surface for when
there is no data or content. Parts: Empty, EmptyHeader, EmptyMedia
(default/icon variants), EmptyTitle, EmptyDescription, EmptyContent.
Translates shadcn's cn-empty-* CSS layer to Tailwind v4 utilities. No JS.
Docs page, route, controller, menu, site_files and MCP registry updated.
* [Feature] Add Message Scroller component
Port the shadcn Message Scroller: a chat transcript scroller that follows
the live edge, anchors new turns near the top, and jumps to the latest
message. Built on top of Message (#446) and Bubble (#445).
shadcn delegates to a closed React primitive (@shadcn/react); this is a
from-scratch Stimulus controller (ruby-ui--message-scroller) — our own
code, no external lib:
- autoScroll follow-edge: pins to the bottom while the reader is there,
releases on wheel/touch/keyboard/scrollbar away, re-engages on jump.
- scrollAnchor: settles an appended turn near the top keeping a peek of
the previous item (previous_item_peek).
- defaultPosition: open at end / start / last-anchor.
- preserveOnPrepend: hold the visible row when history loads in above.
- Public API for streaming/ActionCable: scrollToEnd/scrollToStart/
scrollToMessage; new rows are picked up via MutationObserver.
- rAF-based smooth scrolling (native smooth is unreliable on a contained
viewport), honors prefers-reduced-motion.
- a11y: content role=log + aria-relevant, button sr-only label, button
removed from tab order while inert.
Parts: MessageScrollerProvider, MessageScroller, MessageScrollerViewport,
MessageScrollerContent, MessageScrollerItem, MessageScrollerButton.
dependencies.yml: message_scroller depends on Message + Bubble. MCP
registry, docs page, route, controller, menu and site_files updated.
* [Bug Fix] Message Scroller: address review feedback
- Gate anchored-turn scrolling behind autoScroll/following, so a new turn
never yanks a reader who scrolled up to older content (P1).
- Scroll button honors data-direction: a start-direction button now jumps
to the start instead of the end (renamed action jumpToEnd → jump) (P2).
- Guard last-anchor opening position with hasContentTarget; the Stimulus
target getter throws rather than returning undefined (P2).
- Include the flex row gap in prepend preservation so the visible row no
longer drifts down by one gap per history insertion (P2).
- Only treat direct content children as transcript rows; markup mutated
inside a message (subtree) is handled as streaming, not history (P2).
Rebuilt MCP registry.
* [Documentation] Message Scroller: faithful chat-window demo with Empty state
Add the shadcn-style chat window as the hero example: a Card with an Empty
state until the first message, then a scrolling transcript that follows the
live edge, plus an input footer. A docs-only Stimulus demo harness
(message-scroller-chat) clones server-rendered user/assistant templates on
send so the scroller's autoscroll/anchoring is demonstrated live — standing
in for a real ActionCable/streaming source. Uses the new Empty component.
* [Bug Fix] Message Scroller: direction-aware scroll button visibility
updateButton now derives each button's active state from its own
data-direction — an end button activates when away from the bottom, a
start button when away from the top — and iterates all button targets.
Previously a start-direction button used end logic, so it was inert at
the live edge and showed at the wrong end. (cubic P2)
@djalmaaraujodjalmaaraujo mentioned this pull request Jul 1, 2026
3 tasks
djalmaaraujo added a commit that referenced this pull request Jul 1, 2026
Bump RubyUI to 1.5.0 (minor: new components since v1.4.0).
- gem/lib/ruby_ui.rb → 1.5.0; regenerate gem/ and docs/ Gemfile.lock
- docs home hero badge → headline features (Bubble, Message, Empty)
- rebuild mcp/data/registry.json
Highlights since v1.4.0:
- New components: Bubble (#445), Message (#446), Message Scroller (#447), Empty (#448)
- Port hover_card & context_menu to Floating UI, drop Popper.js (#438)
- Bug fixes: Dialog closed-state + docs controller (#458), DropdownMenu z-index (#440)
djalmaaraujo added a commit that referenced this pull request Jul 1, 2026
Bump RubyUI to 1.5.0 (minor: new components since v1.4.0).
- gem/lib/ruby_ui.rb → 1.5.0; regenerate gem/ and docs/ Gemfile.lock
- docs home hero badge → headline features (Bubble, Message, Empty)
- rebuild mcp/data/registry.json
Highlights since v1.4.0:
- New components: Bubble (#445), Message (#446), Message Scroller (#447), Empty (#448)
- Port hover_card & context_menu to Floating UI, drop Popper.js (#438)
- Bug fixes: Dialog closed-state + docs controller (#458), DropdownMenu z-index (#440)
Sign up for freeto 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.

[Feature] Message component (chat message layout: avatar + bubble + header/footer)

2 participants

@djalmaaraujo@cirdes