Skip to content

fix: assorted UI/UX fixes (Giphy, polls, dialogs, composer, headers)#3081

Merged
oliverlaz merged 9 commits intomasterfrom
fix/giphy-attachment-sizing
Mar 31, 2026
Merged

fix: assorted UI/UX fixes (Giphy, polls, dialogs, composer, headers)#3081
oliverlaz merged 9 commits intomasterfrom
fix/giphy-attachment-sizing

Conversation

@oliverlaz
Copy link
Copy Markdown
Member

@oliverlaz oliverlaz commented Mar 31, 2026

🎯 Goal

Bundle of UI/UX fixes across multiple components.

πŸ›  Implementation details

fix(Attachment): use pixel-based sizing constraints for Giphy images

Giphy images used percentage-based CSS constraints which don't resolve to pixel values. Replaced with pixel-based constraints via var(--str-chat__attachment-max-width) and the clamped-height-from-original-image-dimensions mixin.

fix(Message): prevent editing Giphy messages

Giphy messages (command === 'giphy') are no longer editable since their content is generated by the /giphy command.

fix(Form): remove redundant onClick on SwitchField label

SwitchFieldLabel had both htmlFor and a programmatic onClick, causing the checkbox to toggle twice when clicking label text. Removed the redundant onClick.

fix(Poll): fall back to user ID instead of "Anonymous" for voters without a display name

PollVoteAuthor fell back to "Anonymous" when vote.user.name was falsy, making public polls appear anonymous. Now falls back to vote.user.id.

fix(Dialog): prevent dialog overlay from blocking pointer events

The dialog overlay expanded to the nearest positioned ancestor, blocking the channel list. Set pointer-events: none on the overlay with pointer-events: auto on dialog contents.

fix(MessageComposer): hide textarea scrollbar inside rounded compose area

Hidden with scrollbar-width: none, matching the pattern used in polls, reactions, and search.

fix(MessageComposer): restore pre-edit composer state when cancelling edit

When exiting edit mode, the composer restores to its pre-edit state using a WeakMap-based snapshot mechanism. The snapshot is discarded after a successful edit save.

fix(ChannelHeader, ThreadHeader): truly center title text

The title wasn't centered because flanking elements had different widths. Wrapped the toggle button and avatar/close button in always-rendered start/end container divs with flex: 1, so the center element is truly centered regardless of flanking content.

style(AudioPlayback): bump PlaybackRateButton min-width

Increased from 40px to 48px to prevent text clipping.

fix(ChannelList): scope dialog overlay with position: relative

The ChannelList lacked position: relative, so its dialog overlay (position: absolute; inset: 0) escaped to the nearest positioned ancestor higher in the tree β€” covering the entire sidebar when consumers override transform: none on the channel list.

fix(Modal): restore pointer events on GlobalModal

GlobalModal portals into .str-chat__dialog-overlay (which has pointer-events: none) without using DialogAnchor, so its content never received the .str-chat__dialog-contents class that restores pointer-events: auto. The modal was visible but completely click-through.

🎨 UI Changes

  • Giphy images properly size-constrained with CDN resizing
  • Giphy messages no longer show "Edit Message" in actions menu
  • Poll creation toggles respond correctly when clicking label text
  • Poll vote results show user ID instead of "Anonymous" for nameless users
  • Dialog overlay no longer blocks interaction with the channel list
  • Composer textarea no longer shows a scrollbar inside the rounded input area
  • Cancelling edit mode restores the composer to its pre-edit state
  • Channel and thread header titles are truly centered
  • ChannelList dialog overlay scoped to the channel list area
  • GlobalModal is interactive again (no longer click-through)

Giphy images used percentage-based max-height/max-width (100%) which
don't resolve to pixel values, causing getCSSSizeRestrictions to warn
about invalid sizing and preventing CDN image resizing from working.

Switch to pixel-based constraints via --str-chat__attachment-max-width
and add the clamped-height-from-original-image-dimensions mixin,
matching how regular image attachments are sized.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 31, 2026

Size Change: +776 B (+0.13%)

Total Size: 615 kB

πŸ“¦ View Changed
Filename Size Change
dist/cjs/index.js 237 kB +351 B (+0.15%)
dist/css/index.css 47.4 kB +82 B (+0.17%)
dist/es/index.mjs 236 kB +343 B (+0.15%)
ℹ️ View Unchanged
Filename Size
dist/cjs/audioProcessing.js 1.32 kB
dist/cjs/emojis.js 2.96 kB
dist/cjs/mp3-encoder.js 1.27 kB
dist/cjs/WithAudioPlayback.js 42.1 kB
dist/css/emoji-replacement.css 456 B
dist/es/audioProcessing.mjs 1.31 kB
dist/es/emojis.mjs 2.47 kB
dist/es/mp3-encoder.mjs 756 B
dist/es/WithAudioPlayback.mjs 42 kB

compressed-size-action

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 92.50000% with 3 lines in your changes missing coverage. Please review.
βœ… Project coverage is 79.18%. Comparing base (887a326) to head (69bb424).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
...mponents/MessageComposer/hooks/useSubmitHandler.ts 0.00% 1 Missing ⚠️
src/components/Poll/PollVote.tsx 0.00% 1 Missing ⚠️
src/context/MessageBounceContext.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3081      +/-   ##
==========================================
+ Coverage   79.08%   79.18%   +0.09%     
==========================================
  Files         426      427       +1     
  Lines       12155    12177      +22     
  Branches     3919     3919              
==========================================
+ Hits         9613     9642      +29     
+ Misses       2542     2535       -7     

β˜” 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.
  • πŸ“¦ JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…play name

The PollVoteAuthor component fell back to "Anonymous" when a voter had
no `name` set, making public polls appear anonymous. Now falls back to
the user's ID before "Anonymous".

Also fixes a double-click bug in SwitchField where the label had both
htmlFor and a programmatic onClick, causing the checkbox to toggle twice
(canceling itself out) when clicking the label text.

Also bumps PlaybackRateButton min-width from 40px to 48px.
@oliverlaz oliverlaz changed the title fix(Attachment): use pixel-based sizing constraints for Giphy images fix: Giphy attachment sizing, SwitchField double-click, Poll anonymous fallback Mar 31, 2026
The dialog overlay (`str-chat__dialog-overlay`) used position: absolute
with inset: 0, expanding to the nearest positioned ancestor. When a
DialogManagerProvider was rendered inside the sidebar (e.g. ActionsMenu),
the overlay covered the entire chat view, freezing the channel list.

Set pointer-events: none on the overlay so clicks pass through to
elements below, with pointer-events: auto on dialog contents. Removed
the now-unreachable overlay onClick handler and updated the document-level
click handler to treat clicks on the overlay element itself as outside
clicks.
@oliverlaz oliverlaz changed the title fix: Giphy attachment sizing, SwitchField double-click, Poll anonymous fallback fix: Giphy sizing, SwitchField toggle, Poll anonymous fallback, dialog overlay freeze Mar 31, 2026
…area

The textarea's native scrollbar looked jarring inside the rounded
compose area (border-radius: var(--radius-3xl)). Hide it with
scrollbar-width: none, matching the pattern used in polls, reactions,
and search components. Scroll functionality is preserved.
@oliverlaz oliverlaz changed the title fix: Giphy sizing, SwitchField toggle, Poll anonymous fallback, dialog overlay freeze fix: Giphy sizing, SwitchField toggle, Poll anonymous fallback, dialog overlay freeze, composer scrollbar Mar 31, 2026
Giphy messages (command === 'giphy') should not be editable since their
content is generated by the /giphy command. Added a check alongside the
existing poll exclusion in useUserRole.
@oliverlaz oliverlaz changed the title fix: Giphy sizing, SwitchField toggle, Poll anonymous fallback, dialog overlay freeze, composer scrollbar fix: Giphy sizing + non-editable, SwitchField toggle, Poll anonymous fallback, dialog overlay, composer scrollbar Mar 31, 2026
… edit

When exiting edit mode, the composer now restores to the state it was in
before editing began. If the composer had text, that text is shown; if
it was empty, it returns to the placeholder.

Uses a WeakMap-based snapshot mechanism that captures the full composer
state (text, attachments, link previews, location, polls, custom data)
before entering edit mode and restores it on cancel. The snapshot is
discarded (not restored) after a successful edit save.
@oliverlaz oliverlaz changed the title fix: Giphy sizing + non-editable, SwitchField toggle, Poll anonymous fallback, dialog overlay, composer scrollbar fix: Giphy sizing + non-editable, SwitchField, Poll anonymous, dialog overlay, composer scrollbar + edit restore Mar 31, 2026
@oliverlaz oliverlaz changed the title fix: Giphy sizing + non-editable, SwitchField, Poll anonymous, dialog overlay, composer scrollbar + edit restore fix: Giphy sizing + non-editable, Poll fixes, dialog overlay, composer scrollbar + edit restore Mar 31, 2026
Comment on lines -59 to -75
onClick={(event) => {
if (!dialogManager) return;
if (event.target !== event.currentTarget) return;
Object.values(dialogManager.state.getLatestValue().dialogsById).forEach(
(dialog) => {
if (!dialog.isOpen) return;
if (
!shouldCloseOnOutsideClick({
dialog,
managerCloseOnClickOutside: dialogManager.closeOnClickOutside,
})
)
return;
dialogManager.close(dialog.id);
},
);
}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why was this removed?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The dialog overlay (str-chat__dialog-overlay) used position: absolute with inset: 0, expanding to the nearest positioned ancestor. When a DialogManagerProvider was rendered inside the sidebar (e.g. ActionsMenu in the vite example), the overlay covered the entire chat view, freezing the channel list. Set pointer-events: none on the overlay so clicks pass through, with pointer-events: auto on .str-chat__dialog-contents. Removed the now-unreachable overlay onClick handler and updated the document-level click handler to treat clicks on the overlay element itself as outside clicks.

We now utilize pointer-events, and this event won't ever fire.

The channel/thread name wasn't centered because the flanking elements
(toggle button, avatar/close button) had different widths. Wrapped them
in always-rendered start/end container divs with flex: 1, so the center
element is truly centered regardless of flanking content. Applies to
both ChannelHeader and ThreadHeader.
@oliverlaz oliverlaz changed the title fix: Giphy sizing + non-editable, Poll fixes, dialog overlay, composer scrollbar + edit restore fix: assorted UI/UX fixes (Giphy, polls, dialogs, composer, headers) Mar 31, 2026
…l pointer events

The ChannelList lacked `position: relative`, so its dialog overlay
(`position: absolute; inset: 0`) escaped to the nearest positioned
ancestor higher in the treeβ€”covering the entire sidebar when consumers
override `transform: none` on the channel list.

The GlobalModal portals into `.str-chat__dialog-overlay` (which has
`pointer-events: none`) without using `DialogAnchor`, so its content
never received the `.str-chat__dialog-contents` class that restores
`pointer-events: auto`. The modal was visible but completely
click-through.
@oliverlaz oliverlaz merged commit 6c06e04 into master Mar 31, 2026
9 checks passed
@oliverlaz oliverlaz deleted the fix/giphy-attachment-sizing branch March 31, 2026 14:31
github-actions bot pushed a commit that referenced this pull request Mar 31, 2026
## [14.0.0-beta.5](v14.0.0-beta.4...v14.0.0-beta.5) (2026-03-31)

### Bug Fixes

* assorted UI/UX fixes (Giphy, polls, dialogs, composer, headers) ([#3081](#3081)) ([6c06e04](6c06e04))
* close CSS gaps, fix ChannelList dialog portal, and clean up icons ([#3079](#3079)) ([a47981f](a47981f))
* **Icons:** sync icon catalog with refreshed Line SVGs ([#3080](#3080)) ([9472f7b](9472f7b))
* **MessageList:** set width on message list scroll container ([#3077](#3077)) ([3f09362](3f09362))
* post-review `MessageReactionsDetail` adjustments ([#3082](#3082)) ([a82bdcb](a82bdcb))
* use link icon for link-type attachments ([#3083](#3083)) ([241209e](241209e))

### Features

* **examples:** add RTL direction toggle to vite example app ([#3084](#3084)) ([887a326](887a326))
* **examples:** refresh react tutorial app for v14 ([#3078](#3078)) ([86ada37](86ada37))
@stream-ci-bot
Copy link
Copy Markdown

πŸŽ‰ This PR is included in version 14.0.0-beta.5 πŸŽ‰

The release is available on:

Your semantic-release bot πŸ“¦πŸš€

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants