Skip to content

[render preview] [Feature] Add Bubble component - #445

Merged
cirdes merged 3 commits into
mainfrom
feat/bubble-component
Jun 30, 2026
Merged

[render preview] [Feature] Add Bubble component#445
cirdes merged 3 commits into
mainfrom
feat/bubble-component

Conversation

@djalmaaraujo

@djalmaaraujodjalmaaraujo commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Description

Ports the shadcn Bubble component to RubyUI — a chat bubble surface for conversational content.

Reference:

What's included

  • Bubble — root, variant: (default, secondary, muted, tinted, outline, ghost, destructive) and align: (start/end)
  • BubbleContent — content wrapper; polymorphic via as: (:div default, :a, :button) for link/button bubbles — the idiomatic Phlex equivalent of shadcn's asChild
  • BubbleReactions — edge-anchored reactions pill, side: (top/bottom) + align: (start/end)
  • BubbleGroup — stacks bubbles with tight spacing

Notes

  • shadcn ships these styles as a custom cn-bubble-* CSS layer. This port translates every rule to real Tailwind v4 utilities + RubyUI theme tokens, so no custom CSS is shipped.
  • No JS (no Stimulus controller).
  • Composes with the existing Tooltip and Popover components — examples included in the docs page.
  • No dependencies.yml entry (Bubble has no gem/JS/component deps, like Avatar/Card).

Testing

  • cd gem && bundle exec rake → tests + StandardRB green.
  • Docs page rendered locally at /docs/bubble: all 7 variants, alignment, reactions (top/bottom × start/end), group, link/button hover states, and Tooltip/Popover integration verified visually.

Screenshots

Add before/after screenshots of /docs/bubble.


Summary by cubic

Add a chat Bubble component to RubyUI for conversational UIs with 7 variants, alignment, grouping, reactions, docs, tests, and mcp registry entries. Built with Tailwind v4 utilities and RubyUI tokens—no custom CSS or JS.

  • New Features

    • RubyUI::Bubble with variants: default, secondary, muted, tinted, outline, ghost, destructive; align: :start|:end.
    • RubyUI::BubbleContent polymorphic via as: :div|:a|:button for link/button bubbles.
    • RubyUI::BubbleReactions pill anchored to the bubble edge; side: :top|:bottom, align: :start|:end.
    • RubyUI::BubbleGroup to stack bubbles with tight spacing.
    • Docs at /docs/bubble with examples and Tooltip/Popover integration; routes, menu, sitemap, and LLMs maps updated.
    • Rebuilt mcp registry to include Bubble metadata and examples.
  • Bug Fixes

    • Simplified BubbleContent interactive selectors to &:is(button,a) to match variant hover rules and reduce class noise without changing behavior.

Written for commit 1ae9145. 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 14 files

Re-trigger cubic

djalmaaraujo added a commit that referenced this pull request Jun 30, 2026
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.
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 added a commit that referenced this pull request Jun 30, 2026
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.
@djalmaaraujodjalmaaraujo changed the title [Feature] Add Bubble component[render preview] [Feature] Add Bubble componentJun 30, 2026
@djalmaaraujo
djalmaaraujo temporarily deployed to feat/bubble-component - web-1 PR #445 June 30, 2026 15:45 — with Render Destroyed
djalmaaraujo added a commit that referenced this pull request Jun 30, 2026
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.
@cirdes
cirdes merged commit d95814f into mainJun 30, 2026
8 checks passed
@cirdes
cirdes deleted the feat/bubble-component branch June 30, 2026 16:53
djalmaaraujo added a commit that referenced this pull request Jun 30, 2026
* [Feature] Add Bubble component
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.
* [Bug Fix] Bubble: simplify BubbleContent interactive styles
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.
* [Feature] Bubble: rebuild MCP registry
* [Feature] Add Message component
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.
* [Feature] Message: rebuild MCP registry
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.

2 participants

@djalmaaraujo@cirdes