Skip to content

feat(ui): add StreamReactions component and overflow emoji chip#67

Merged
xsahil03x merged 12 commits intomain-design-systemfrom
feat/message-reactions
Mar 6, 2026
Merged

feat(ui): add StreamReactions component and overflow emoji chip#67
xsahil03x merged 12 commits intomain-design-systemfrom
feat/message-reactions

Conversation

@xsahil03x
Copy link
Member

@xsahil03x xsahil03x commented Mar 6, 2026

Description of the pull request

  • Add StreamReactions component supporting segmented and clustered layouts.
  • Add StreamEmojiChip.overflow for displaying +N reaction counts with consistent numeric styling.
  • Implement StreamReactionsTheme and StreamReactionsThemeData for layout customization (spacing, gap, overlap, and indent).
  • Add support for positioning reactions as headers or footers relative to a child widget.
  • Update StreamComponentFactory to include a custom builder for reactions.
  • Add comprehensive playground and showcase examples for reactions in the design system gallery.
  • Refactor StreamEmojiChip internals to share a common _RawEmojiChip shell.

Screenshots / Videos

Segmented Clustered Footer
Screenshot 2026-03-06 at 05 40 00 Screenshot 2026-03-06 at 05 40 29 Screenshot 2026-03-06 at 05 41 21

Summary by CodeRabbit

New Features

  • Introduced StreamFlex layout component with flexible arrangement and negative spacing support for overlapping elements
  • Added StreamReactions component with segmented and clustered display modes
  • Enhanced StreamEmojiChip with cluster and overflow support for flexible emoji representation

Documentation

  • Updated design system gallery with comprehensive examples and interactive playgrounds for new components

- Add `StreamReactions` component supporting segmented and clustered layouts.
- Add `StreamEmojiChip.overflow` for displaying `+N` reaction counts with consistent numeric styling.
- Implement `StreamReactionsTheme` and `StreamReactionsThemeData` for layout customization (spacing, gap, overlap, and indent).
- Add support for positioning reactions as headers or footers relative to a child widget.
- Update `StreamComponentFactory` to include a custom builder for reactions.
- Add comprehensive playground and showcase examples for reactions in the design system gallery.
- Refactor `StreamEmojiChip` internals to share a common `_RawEmojiChip` shell.
@xsahil03x xsahil03x requested a review from a team as a code owner March 6, 2026 00:13
@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

This pull request introduces StreamFlex, a new layout component with negative spacing support for overlapping elements, and StreamReactions, a new reactions component with segmented and clustered variants. It enhances StreamEmojiChip with multi-emoji and cluster/overflow support, integrates these into the theme system, and adds comprehensive gallery demonstrations.

Changes

Cohort / File(s) Summary
Core Layout Component
packages/stream_core_flutter/lib/src/components/common/stream_flex.dart
New StreamFlex, StreamRow, and StreamColumn widgets supporting negative spacing via custom RenderFlex override. Enables overlapping child layouts with proper painting order.
Avatar Stack Refactor
packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart
Simplified layout from positioned stack to StreamRow-based approach using negative spacing, removing explicit width calculations.
Core Reactions Component
packages/stream_core_flutter/lib/src/components/reaction/stream_reactions.dart
New StreamReactions widget with segmented and clustered named constructors, supporting configurable positioning, alignment, overlap, and overflow behavior.
EmojiChip Multi-Emoji Support
packages/stream_core_flutter/lib/src/components/controls/stream_emoji_chip.dart
Added cluster and overflow constructors, multi-emoji rendering, and new internal chip variants; refactored playground with expanded type variants and state matrix sections.
Component Factory Integration
packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart, ...factory.g.theme.dart
Added reactions builder field to StreamComponentBuilders with propagation through copyWith, lerp, and equality operations.
Reactions Theme System
packages/stream_core_flutter/lib/src/theme/components/stream_reactions_theme.dart, ...theme.g.theme.dart
New StreamReactionsTheme (InheritedTheme) with enums for type/position/alignment; generated utilities for lerp, copyWith, merge, and equality.
Core Theme Integration
packages/stream_core_flutter/lib/src/theme/stream_theme.dart, ...stream_theme.g.theme.dart, stream_theme_extensions.dart, theme.dart
Extended StreamTheme to include reactionsTheme field; added theme extension getter and export for reactions theme component.
Public API Exports
packages/stream_core_flutter/lib/src/components.dart
Added exports for stream_flex and stream_reactions (hiding DefaultStreamReactions internal class).
Gallery Configuration
apps/design_system_gallery/lib/app/gallery_app.directories.g.dart
Updated widgetbook catalog to register StreamFlex under Common and StreamReactions under new Reactions folder with Playground and Showcase variants.
StreamFlex Gallery
apps/design_system_gallery/lib/components/common/stream_flex.dart
New 685-line playground and showcase demonstrating spacing values, negative spacing overlaps, and real-world avatar/badge compositions.
StreamReactions Gallery
apps/design_system_gallery/lib/components/reaction/stream_reactions.dart
New 663-line playground and showcase featuring configurable segmented/clustered reactions with position, alignment, and overflow controls across sample chat bubbles.
EmojiChip Gallery Enhancements
apps/design_system_gallery/lib/components/controls/stream_emoji_chip.dart
Expanded playground with _ChipType enum selecting between Single, Cluster, Overflow, and Add Emoji variants; added cluster/overflow variant sections and refactored state matrix layout.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Flex and reactions leap and play,
Overlapping, clustering the design way,
With negative space and themes so bright,
Emojis cluster, badges align just right!
Stream components dance, the gallery shines—
What beautiful code these changes define! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description covers key features, implementation details, screenshots, but is missing required template sections like Linear ticket reference and CLA checkbox. Add Linear ticket reference (FLA-X), complete CLA checkbox, and add testing instructions to fully satisfy the template requirements.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main features being added: the StreamReactions component and overflow emoji chip functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/message-reactions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…ssage-reactions

# Conflicts:
#	packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart
- Rename `stream_reaction_theme.dart` and its generated file to plural `stream_reactions_theme.dart`.
- Update all internal references and exports to match the new file name.
- Improve documentation and comments within `StreamReactionsThemeData`.
@xsahil03x
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
packages/stream_core_flutter/lib/src/components/reaction/stream_reactions.dart (1)

129-144: Consider making the hardcoded chip theme overridable.

The StreamEmojiChipTheme wrapping DefaultStreamReactions (lines 129-144) applies fixed styling that overrides the global emoji chip theme. This could prevent consumers from fully customizing reaction chip appearance via StreamEmojiChipTheme higher in the tree.

Consider allowing this to be influenced by a StreamReactionsThemeData property or making it opt-out.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/stream_core_flutter/lib/src/components/reaction/stream_reactions.dart`
around lines 129 - 144, The current StreamEmojiChipTheme wrapping
DefaultStreamReactions hardcodes chip styling (minimumSize, maximumSize,
emojiSize, backgroundColor, textStyle, padding) which prevents consumer
overrides; update the widget to derive these values from a higher-level theme or
props: check for a provided StreamReactionsThemeData (or add one) and merge its
StreamEmojiChipThemeData into the locally constructed StreamEmojiChipThemeData
before applying it, and expose an opt-out flag (e.g., useDefaultChipTheme) on
DefaultStreamReactions/props so callers can disable the local override; ensure
to look for symbols StreamEmojiChipTheme, StreamEmojiChipThemeData,
StreamReactionsThemeData, DefaultStreamReactions and props when making the
change.
apps/design_system_gallery/lib/components/reaction/stream_reactions.dart (1)

50-59: Keep max independent from overlap in the playground.

Overflow is orthogonal to overlap, but this hides the +N path whenever overlap is false. That makes detached layouts harder to exercise and lets large segmented sets get much wider than the available preview width.

♻️ Suggested tweak
+  final limitVisible = context.knobs.boolean(
+    label: 'Limit Visible',
+    initialValue: true,
+    description: 'Collapse extra reactions into a +N chip.',
+  );
-  final max = overlap
+  final max = limitVisible
       ? context.knobs.int.slider(
           label: 'Max Visible',
           initialValue: 4,
           min: 1,
           max: 6,
           divisions: 5,
           description: 'Reactions beyond this collapse into a +N chip.',
         )
       : null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/design_system_gallery/lib/components/reaction/stream_reactions.dart`
around lines 50 - 59, The playground currently ties the max visible reactions
knob to the overlap boolean so max is only configurable when overlap is true;
make max independent by always exposing the context.knobs.int.slider for max
(keep its label/limits) regardless of the overlap value and then use the
resulting max where reactions collapse into a "+N" chip — update any conditional
that creates max (refer to the max variable and overlap boolean and the
context.knobs.int.slider call) so the slider is rendered/assigned
unconditionally and the collapse behavior still respects overlap when
determining layout.
packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart (1)

192-205: Scope the no-scaling wrapper to the overflow badge.

MediaQuery.withNoTextScaling now applies to every descendant in props.children, so any custom avatar content also stops respecting the ambient text scale. If the goal is only to keep the +N badge stable, move the wrapper down to StreamBadgeCount and verify the stack at large text scales.

♻️ Suggested change
-    return MediaQuery.withNoTextScaling(
-      child: StreamAvatarTheme(
-        data: StreamAvatarThemeData(size: avatarSize),
-        child: StreamRow(
-          spacing: -diameter * props.overlap,
-          mainAxisSize: MainAxisSize.min,
-          children: [
-            ...visible,
-            if (extraCount > 0)
-              StreamBadgeCount(
-                label: '+$extraCount',
-                size: extraBadgeSize,
-              ),
-          ],
-        ),
-      ),
-    );
+    return StreamAvatarTheme(
+      data: StreamAvatarThemeData(size: avatarSize),
+      child: StreamRow(
+        spacing: -diameter * props.overlap,
+        mainAxisSize: MainAxisSize.min,
+        children: [
+          ...visible,
+          if (extraCount > 0)
+            MediaQuery.withNoTextScaling(
+              child: StreamBadgeCount(
+                label: '+$extraCount',
+                size: extraBadgeSize,
+              ),
+            ),
+        ],
+      ),
+    );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart`
around lines 192 - 205, The MediaQuery.withNoTextScaling wrapper is currently
applied around the whole avatar stack causing all descendant avatar content to
ignore textScaleFactor; restrict its scope to only the overflow badge by
removing MediaQuery.withNoTextScaling from around
StreamAvatarStack/props.children and instead wrapping only the StreamBadgeCount
instantiation (the '+$extraCount' widget created when extraCount > 0) with
MediaQuery.withNoTextScaling, preserving size inputs like extraBadgeSize and
avatarSize and then run visual checks at large text scales to verify avatars
still scale while the badge remains fixed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/design_system_gallery/lib/components/reaction/stream_reactions.dart`:
- Around line 50-59: The playground currently ties the max visible reactions
knob to the overlap boolean so max is only configurable when overlap is true;
make max independent by always exposing the context.knobs.int.slider for max
(keep its label/limits) regardless of the overlap value and then use the
resulting max where reactions collapse into a "+N" chip — update any conditional
that creates max (refer to the max variable and overlap boolean and the
context.knobs.int.slider call) so the slider is rendered/assigned
unconditionally and the collapse behavior still respects overlap when
determining layout.

In
`@packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart`:
- Around line 192-205: The MediaQuery.withNoTextScaling wrapper is currently
applied around the whole avatar stack causing all descendant avatar content to
ignore textScaleFactor; restrict its scope to only the overflow badge by
removing MediaQuery.withNoTextScaling from around
StreamAvatarStack/props.children and instead wrapping only the StreamBadgeCount
instantiation (the '+$extraCount' widget created when extraCount > 0) with
MediaQuery.withNoTextScaling, preserving size inputs like extraBadgeSize and
avatarSize and then run visual checks at large text scales to verify avatars
still scale while the badge remains fixed.

In
`@packages/stream_core_flutter/lib/src/components/reaction/stream_reactions.dart`:
- Around line 129-144: The current StreamEmojiChipTheme wrapping
DefaultStreamReactions hardcodes chip styling (minimumSize, maximumSize,
emojiSize, backgroundColor, textStyle, padding) which prevents consumer
overrides; update the widget to derive these values from a higher-level theme or
props: check for a provided StreamReactionsThemeData (or add one) and merge its
StreamEmojiChipThemeData into the locally constructed StreamEmojiChipThemeData
before applying it, and expose an opt-out flag (e.g., useDefaultChipTheme) on
DefaultStreamReactions/props so callers can disable the local override; ensure
to look for symbols StreamEmojiChipTheme, StreamEmojiChipThemeData,
StreamReactionsThemeData, DefaultStreamReactions and props when making the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4b6f9bb-7f5c-4549-b8b0-e15fd7a0a88f

📥 Commits

Reviewing files that changed from the base of the PR and between afb2a45 and cc06689.

📒 Files selected for processing (17)
  • apps/design_system_gallery/lib/app/gallery_app.directories.g.dart
  • apps/design_system_gallery/lib/components/common/stream_flex.dart
  • apps/design_system_gallery/lib/components/controls/stream_emoji_chip.dart
  • apps/design_system_gallery/lib/components/reaction/stream_reactions.dart
  • packages/stream_core_flutter/lib/src/components.dart
  • packages/stream_core_flutter/lib/src/components/avatar/stream_avatar_stack.dart
  • packages/stream_core_flutter/lib/src/components/common/stream_flex.dart
  • packages/stream_core_flutter/lib/src/components/controls/stream_emoji_chip.dart
  • packages/stream_core_flutter/lib/src/components/reaction/stream_reactions.dart
  • packages/stream_core_flutter/lib/src/factory/stream_component_factory.dart
  • packages/stream_core_flutter/lib/src/factory/stream_component_factory.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_reactions_theme.dart
  • packages/stream_core_flutter/lib/src/theme/components/stream_reactions_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme.g.theme.dart
  • packages/stream_core_flutter/lib/src/theme/stream_theme_extensions.dart

@codecov
Copy link

codecov bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 1.21951% with 162 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main-design-system@afb2a45). Learn more about missing BASE report.

Files with missing lines Patch % Lines
.../lib/src/components/reaction/stream_reactions.dart 0.00% 78 Missing ⚠️
...flutter/lib/src/components/common/stream_flex.dart 0.00% 34 Missing ⚠️
...lib/src/components/controls/stream_emoji_chip.dart 3.33% 29 Missing ⚠️
...b/src/theme/components/stream_reactions_theme.dart 9.09% 10 Missing ⚠️
...lib/src/components/avatar/stream_avatar_stack.dart 0.00% 9 Missing ⚠️
...tream_core_flutter/lib/src/theme/stream_theme.dart 0.00% 1 Missing ⚠️
...flutter/lib/src/theme/stream_theme_extensions.dart 0.00% 1 Missing ⚠️

❌ Your patch status has failed because the patch coverage (1.21%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@                  Coverage Diff                  @@
##             main-design-system      #67   +/-   ##
=====================================================
  Coverage                      ?   33.30%           
=====================================================
  Files                         ?      115           
  Lines                         ?     3534           
  Branches                      ?        0           
=====================================================
  Hits                          ?     1177           
  Misses                        ?     2357           
  Partials                      ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@xsahil03x xsahil03x merged commit f196b69 into main-design-system Mar 6, 2026
3 of 4 checks passed
@xsahil03x xsahil03x deleted the feat/message-reactions branch March 6, 2026 11:57
Sign up for free to 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