Skip to content

Commit a47981f

Browse files
authored
fix: close CSS gaps, fix ChannelList dialog portal, and clean up icons (#3079)
### 🎯 Goal Fix several SDK CSS gaps that forced consumers to add workarounds, fix the ChannelList context menu appearing unstyled because its dialog portal rendered outside the themed `.str-chat` subtree, and fix icon issues left over from the Phosphor migration. ### 🛠 Implementation details **SDK CSS fixes:** - Add `min-height: 0` to `.str-chat__chat-view`, `.str-chat__chat-view__channels`, and `.str-chat__channel` — these are flex children that need the reset to prevent scrollable content from overflowing their containers - Add `width: 100%` to the `header-layout` mixin — headers (ChannelHeader, ThreadHeader) are flex items that need to span their parent's full width - Add `width: 100%` to `.str-chat__main-panel-inner` — it uses `align-items: center` which shrinks children, so it needs an explicit width to fill its parent - Add `scrollbar-gutter: stable` to the `scrollable-y` mixin — prevents layout shift when scrollbars appear/disappear - Remove incorrect `height: auto` override on `.str-chat__thread .str-chat__main-panel-inner` (and the now-redundant virtualized re-override) — the base `height: 100%` should apply in all cases **ChannelList dialog portal fix:** - Move `DialogManagerProvider` inside the `.str-chat` div so `DialogPortalDestination` renders within the themed subtree — this fixes context menus (mute, pin, etc.) appearing unstyled because `.str-chat .str-chat__context-menu` selectors didn't match and CSS variables didn't inherit **Icon fixes (post-Phosphor migration cleanup):** - Use `IconThreadFill` for the active threads tab in ChatView instead of the old `IconBubbleText6SolidChatMessage` (16×16 legacy icon) - Fix MessageActions CSS that overrode `fill='none'` on stroke-based Phosphor icons, causing the reply icon to appear filled on hover — replaced path-level `fill`/`stroke` overrides with `color` inheritance via `currentColor` - Remove 9 unused icon exports: `IconArrowRight`, `IconBubble3ChatMessage`, `IconBubbleText6SolidChatMessage`, `IconInfo`, `IconLightBulbSimple`, `IconMinus`, `IconMinusSmall`, `IconSettingsGear2`, `IconVoiceFill` **Example cleanup:** - Remove overrides from `examples/vite/src/index.scss` that are now handled by the SDK - Define `IconGear` and `IconLightBulb` locally in the vite example app (using `createIcon`) to replace removed SDK exports - Replace other removed icon imports with available alternatives - Add yellow tint to lightbulb icon in dark mode ### 🎨 UI Changes - Threads tab active icon now uses the correct filled thread bubble instead of the legacy icon - Reply icon in message action hover no longer appears filled - No other visual changes in the vite example app
1 parent 86ada37 commit a47981f

File tree

14 files changed

+48
-186
lines changed

14 files changed

+48
-186
lines changed

examples/vite/src/App.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { init, SearchIndex } from 'emoji-mart';
3434
import data from '@emoji-mart/data/sets/14/native.json';
3535
import { humanId } from 'human-id';
3636

37-
import { appSettingsStore, useAppSettingsSelector } from './AppSettings/state.ts';
37+
import { appSettingsStore, useAppSettingsSelector } from './AppSettings';
3838
import { DESKTOP_LAYOUT_BREAKPOINT } from './ChatLayout/constants.ts';
3939
import { ChannelsPanels, ThreadsPanels } from './ChatLayout/Panels.tsx';
4040
import {
@@ -60,7 +60,7 @@ import {
6060
getMessageUiVariant,
6161
getReactionsVariant,
6262
getSystemMessageVariant,
63-
} from './CustomMessageUi/index.tsx';
63+
} from './CustomMessageUi';
6464

6565
init({ data });
6666

@@ -191,7 +191,6 @@ const App = () => {
191191
() => initialSearchParams.get('thread'),
192192
[initialSearchParams],
193193
);
194-
const initialThreadOpen = useMemo(() => Boolean(initialThreadId), [initialThreadId]);
195194
const initialPanelLayout = useMemo(
196195
() => appSettingsStore.getLatestValue().panelLayout,
197196
[],

examples/vite/src/AppSettings/ActionsMenu/NotificationPromptDialog.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@ import {
55
addNotificationTargetTag,
66
IconArrowDown,
77
IconArrowLeft,
8-
IconArrowRight,
8+
IconChevronRight,
99
Button,
1010
DialogAnchor,
1111
IconRefresh,
1212
IconArrowUp,
1313
IconCheckmark,
14-
IconInfo,
14+
IconExclamationMark,
1515
IconClock,
1616
IconXmark,
17-
IconExclamationMark,
1817
IconExclamationTriangle,
1918
IconPlusSmall,
2019
NumericInput,
@@ -51,7 +50,7 @@ const severityIcons: Partial<
5150
Record<NotificationSeverity, React.ComponentType<{ className?: string }>>
5251
> = {
5352
error: IconExclamationMark,
54-
info: IconInfo,
53+
info: IconExclamationMark,
5554
loading: IconRefresh,
5655
success: IconCheckmark,
5756
warning: IconExclamationTriangle,
@@ -62,7 +61,7 @@ const directionIcons: Record<
6261
React.ComponentType<{ className?: string }>
6362
> = {
6463
bottom: IconArrowUp,
65-
left: IconArrowRight,
64+
left: IconChevronRight,
6665
right: IconArrowLeft,
6766
top: IconArrowDown,
6867
};

examples/vite/src/AppSettings/AppSettings.tsx

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
1+
import React from 'react';
12
import {
23
Button,
34
ChatViewSelectorButton,
5+
createIcon,
46
GlobalModal,
5-
IconBubble3ChatMessage,
67
IconBell,
78
IconEmoji,
8-
IconLightBulbSimple,
9-
IconSettingsGear2,
9+
IconMessageBubble,
1010
} from 'stream-chat-react';
1111
import { type ComponentType, useState } from 'react';
12+
13+
const IconGear = createIcon(
14+
'IconGear',
15+
<path d='M13.5667 8.00031C13.5667 7.81566 13.4743 7.64281 13.3206 7.54034L12.7503 7.16046C12.0815 6.71442 11.7583 5.90079 11.9388 5.11749L12.0472 4.64777C12.092 4.45315 12.034 4.24906 11.8929 4.10773C11.7515 3.96629 11.5467 3.90753 11.3519 3.95245L10.8831 4.06085C10.0996 4.24168 9.28525 3.91849 8.8392 3.24933L8.45932 2.67902C8.35689 2.52558 8.18474 2.43303 8.00034 2.43292C7.81575 2.43292 7.64286 2.5254 7.54037 2.67902L7.16049 3.24933C6.7145 3.91832 5.90097 4.24146 5.11752 4.06085L4.6478 3.95245C4.45304 3.90767 4.24908 3.9664 4.10776 4.10773C3.96643 4.24905 3.9077 4.45301 3.95248 4.64777L4.06088 5.11749C4.24149 5.90094 3.91835 6.71447 3.24936 7.16046L2.67905 7.54034C2.52543 7.64282 2.43295 7.81572 2.43295 8.00031C2.43306 8.18471 2.52561 8.35686 2.67905 8.45929L3.24936 8.83917C3.91852 9.28522 4.24171 10.0995 4.06088 10.8831L3.95248 11.3519C3.90756 11.5467 3.96632 11.7514 4.10776 11.8929C4.24909 12.034 4.45317 12.092 4.6478 12.0472L5.11752 11.9388C5.90082 11.7583 6.71445 12.0814 7.16049 12.7503L7.54037 13.3206C7.64284 13.4743 7.81569 13.5667 8.00034 13.5667C8.18484 13.5666 8.35691 13.4742 8.45932 13.3206L8.8392 12.7503C9.2574 12.123 9.99909 11.8004 10.7357 11.9114L10.8831 11.9388L11.3519 12.0472C11.5467 12.0922 11.7505 12.0334 11.8919 11.8919C12.0334 11.7504 12.0922 11.5467 12.0472 11.3519L11.9388 10.8831C11.7581 10.0996 12.0812 9.28525 12.7503 8.83917L13.3206 8.45929C13.4742 8.35688 13.5666 8.18481 13.5667 8.00031ZM9.23373 8.00031C9.23373 7.31925 8.68135 6.76708 8.00034 6.76691C7.31917 6.76691 6.76694 7.31914 6.76694 8.00031C6.76711 8.68132 7.31928 9.2337 8.00034 9.2337C8.68124 9.23353 9.23356 8.68121 9.23373 8.00031ZM10.433 8.00031C10.4328 9.34395 9.34398 10.4327 8.00034 10.4329C6.65654 10.4329 5.56692 9.34406 5.56674 8.00031C5.56674 6.6564 6.65643 5.56671 8.00034 5.56671C9.34409 5.56689 10.433 6.65651 10.433 8.00031ZM14.7669 8.00031C14.7668 8.58607 14.474 9.13337 13.9867 9.45831L13.4164 9.8382C13.1627 10.0072 13.0404 10.3155 13.1087 10.6126L13.2171 11.0823C13.355 11.6803 13.1744 12.3067 12.7406 12.7405C12.3067 13.1744 11.6803 13.355 11.0824 13.2171L10.6126 13.1087C10.3155 13.0403 10.0073 13.1627 9.83823 13.4163L9.45834 13.9866C9.1334 14.4739 8.5861 14.7668 8.00034 14.7669C7.41454 14.7669 6.86735 14.4739 6.54233 13.9866L6.16245 13.4163C5.99328 13.1626 5.6843 13.0402 5.38705 13.1087L4.9183 13.2171C4.32022 13.3552 3.69313 13.1746 3.25912 12.7405C2.82535 12.3066 2.64568 11.6802 2.78354 11.0823L2.89194 10.6126C2.96027 10.3155 2.83695 10.0072 2.58334 9.8382L2.01401 9.45831C1.52667 9.13338 1.23384 8.58608 1.23373 8.00031C1.23373 7.4144 1.52657 6.86729 2.01401 6.5423L2.58334 6.16241C2.83709 5.99325 2.96042 5.68417 2.89194 5.38702L2.78354 4.91827C2.64553 4.32022 2.82513 3.69309 3.25912 3.25909C3.69312 2.8251 4.32025 2.6455 4.9183 2.78351L5.38705 2.89191C5.6842 2.96039 5.99328 2.83706 6.16245 2.58331L6.54233 2.01398C6.86732 1.52654 7.41443 1.2337 8.00034 1.2337C8.58611 1.23381 9.13341 1.52663 9.45834 2.01398L9.83823 2.58331C10.0073 2.83692 10.3156 2.96024 10.6126 2.89191L11.0824 2.78351C11.6803 2.64565 12.3067 2.82532 12.7406 3.25909C13.1746 3.6931 13.3552 4.3202 13.2171 4.91827L13.1087 5.38702C13.0402 5.68427 13.1626 5.99325 13.4164 6.16241L13.9867 6.5423C14.4739 6.86732 14.7669 7.41451 14.7669 8.00031Z' />,
16+
{ viewBox: '0 0 16 16' },
17+
);
18+
19+
const IconLightBulb = createIcon(
20+
'IconLightBulb',
21+
<>
22+
<path d='M12.2328 6.66736C12.2328 4.32904 10.3378 2.43302 7.99945 2.43298C5.66113 2.43298 3.76508 4.32901 3.76508 6.66736C3.76509 8.03465 4.4128 9.25078 5.42035 10.0258C5.44202 10.0425 5.46556 10.0594 5.48871 10.0765C6.00058 10.4543 6.43207 11.0657 6.43207 11.8119V12.6664C6.43232 13.5319 7.13392 14.2338 7.99945 14.2338C8.86496 14.2337 9.56658 13.5318 9.56683 12.6664V11.8119C9.56683 11.0657 9.99831 10.4543 10.5102 10.0765C10.5335 10.0593 10.556 10.0424 10.5776 10.0258L10.7631 9.87537C11.6644 9.09822 12.2328 7.94919 12.2328 6.66736ZM13.433 6.66736C13.433 8.42299 12.6002 9.98457 11.31 10.9769C11.2807 10.9995 11.2513 11.0205 11.2231 11.0414C10.9238 11.2623 10.767 11.55 10.767 11.8119V12.6664C10.7668 14.1946 9.5277 15.4329 7.99945 15.433C6.47116 15.433 5.23213 14.1946 5.23187 12.6664V11.8119C5.23187 11.5827 5.11171 11.3346 4.88129 11.1283L4.77582 11.0424L4.6889 10.9769C3.39867 9.98457 2.56587 8.42301 2.56586 6.66736C2.56586 3.66628 4.99838 1.23376 7.99945 1.23376C11.0005 1.2338 13.433 3.6663 13.433 6.66736Z' />
23+
<path d='M10.1669 11.2338C10.4982 11.2338 10.7665 11.502 10.7665 11.8334C10.7665 12.1647 10.4982 12.433 10.1669 12.433H5.83193C5.50056 12.433 5.23232 12.1647 5.23232 11.8334C5.23232 11.502 5.50056 11.2338 5.83193 11.2338H10.1669Z' />
24+
</>,
25+
{ viewBox: '0 0 16 16' },
26+
);
1227
import { ActionsMenu } from './ActionsMenu';
1328
import { NotificationsTab } from './tabs/Notifications';
1429
import { ReactionsTab } from './tabs/Reactions';
@@ -19,7 +34,7 @@ type TabId = 'notifications' | 'reactions' | 'sidebar';
1934

2035
const tabConfig: { Icon: ComponentType; id: TabId; title: string }[] = [
2136
{ Icon: IconBell, id: 'notifications', title: 'Notifications' },
22-
{ Icon: IconBubble3ChatMessage, id: 'sidebar', title: 'Sidebar' },
37+
{ Icon: IconMessageBubble, id: 'sidebar', title: 'Sidebar' },
2338
{ Icon: IconEmoji, id: 'reactions', title: 'Reactions' },
2439
];
2540

@@ -36,14 +51,15 @@ const SidebarThemeToggle = ({ iconOnly = true }: { iconOnly?: boolean }) => {
3651
aria-selected={mode === 'dark'}
3752
className='app__settings-group_button'
3853
iconOnly={iconOnly}
39-
Icon={IconLightBulbSimple}
54+
Icon={IconLightBulb}
4055
isActive={mode === 'dark'}
4156
onClick={() =>
4257
appSettingsStore.partialNext({
4358
theme: { mode: nextMode },
4459
})
4560
}
4661
role='switch'
62+
style={{ color: mode === 'dark' ? '#facc15' : undefined }}
4763
text={mode === 'dark' ? 'Dark mode' : 'Light mode'}
4864
/>
4965
);
@@ -60,14 +76,14 @@ export const AppSettings = ({ iconOnly = true }: { iconOnly?: boolean }) => {
6076
<ChatViewSelectorButton
6177
className='app__settings-group_button'
6278
iconOnly={iconOnly}
63-
Icon={IconSettingsGear2}
79+
Icon={IconGear}
6480
onClick={() => setOpen(true)}
6581
text='Settings'
6682
/>
6783
<GlobalModal open={open} onClose={() => setOpen(false)}>
6884
<div className='app__settings-modal'>
6985
<header className='app__settings-modal__header'>
70-
<IconSettingsGear2 />
86+
<IconGear />
7187
Settings
7288
</header>
7389
<div className='app__settings-modal__body'>

examples/vite/src/index.scss

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,7 @@ body {
6161
width: 100%;
6262
}
6363

64-
.str-chat__chat-view,
65-
.str-chat__chat-view-channels,
66-
.str-chat__channel,
67-
.str-chat__window {
68-
min-height: 0;
69-
}
70-
7164
.str-chat__chat-view {
72-
height: 100%;
7365
container-type: inline-size;
7466
}
7567

@@ -179,74 +171,20 @@ body {
179171
min-width: 0;
180172
}
181173

182-
.str-chat__chat-view-channels {
183-
height: 100%;
184-
gap: 0;
185-
}
186-
187-
.str-chat__channel-list {
188-
height: 100%;
189-
}
190-
191-
.str-chat__main-panel {
192-
height: 100%;
193-
align-items: stretch;
194-
}
195-
196-
.str-chat__main-panel-inner {
197-
width: 100%;
198-
height: 100%;
199-
max-width: none;
200-
}
201-
202-
.str-chat__window {
203-
height: 100%;
204-
}
205-
206174
.app-loading-screen__window {
207175
width: 100%;
208176
}
209177

210-
.str-chat__channel-header,
211-
.str-chat__thread-header {
212-
width: 100%;
213-
max-width: none;
214-
}
215-
216178
.str-chat__list,
217179
.str-chat__virtual-list {
218180
display: block;
219-
scrollbar-gutter: stable;
220181
scrollbar-width: thin;
221182
}
222183

223-
.str-chat__message-input {
224-
width: 100%;
225-
//max-width: none;
226-
}
227-
228184
.str-chat__tooltip {
229185
z-index: 10;
230186
}
231187

232-
/* Threads view: thread detail takes all space (higher specificity than channel 360px rules). */
233-
.str-chat__chat-view .str-chat__chat-view__threads {
234-
.str-chat__dropzone-root--thread,
235-
.str-chat__thread-container {
236-
flex: 1 1 auto;
237-
min-width: 0;
238-
max-width: none;
239-
width: 100%;
240-
}
241-
}
242-
243-
.str-chat__thread-list-container .str-chat__thread-container {
244-
flex: 1 1 auto;
245-
min-width: 0;
246-
width: 100%;
247-
max-width: none;
248-
}
249-
250188
@media (max-width: 767px) {
251189
.app-chat-resize-handle {
252190
display: none;

src/components/Channel/styling/Channel.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
height: 100%;
55
display: flex;
66
flex-direction: column;
7+
min-height: 0;
78
position: relative;
89

910
.str-chat__container {

src/components/ChannelList/ChannelList.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,11 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
341341

342342
const showChannelList = !searchIsActive;
343343
return (
344-
<DialogManagerProvider id={`channel-list-dialog-manager-${stableId}`}>
345-
<ChannelListContextProvider
346-
value={{ channels, hasNextPage, loadNextPage, setChannels }}
347-
>
348-
<div className={className} ref={channelListRef}>
344+
<ChannelListContextProvider
345+
value={{ channels, hasNextPage, loadNextPage, setChannels }}
346+
>
347+
<div className={className} ref={channelListRef}>
348+
<DialogManagerProvider id={`channel-list-dialog-manager-${stableId}`}>
349349
<ChannelListHeader />
350350
{showChannelSearch && <Search />}
351351
{showChannelList && (
@@ -374,9 +374,9 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
374374
</ChannelListUI>
375375
)}
376376
<NotificationList panel='channel-list' />
377-
</div>
378-
</ChannelListContextProvider>
379-
</DialogManagerProvider>
377+
</DialogManagerProvider>
378+
</div>
379+
</ChannelListContextProvider>
380380
);
381381
};
382382

src/components/ChatView/ChatView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import React, {
1111
import { Button, type ButtonProps } from '../Button';
1212
import { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';
1313
import {
14-
IconBubbleText6SolidChatMessage,
1514
IconMessageBubble,
1615
IconMessageBubbleFill,
1716
IconThread,
17+
IconThreadFill,
1818
} from '../Icons';
1919
import { ThreadProvider } from '../Threads';
2020
import { UnreadCountBadge } from '../Threads/UnreadCountBadge';
@@ -273,7 +273,7 @@ export const ChatViewThreadsSelectorButton = ({
273273
const isActive = activeChatView === 'threads';
274274
return (
275275
<ChatViewSelectorButton
276-
ActiveIcon={IconBubbleText6SolidChatMessage}
276+
ActiveIcon={IconThreadFill}
277277
aria-selected={isActive}
278278
Icon={IconThread}
279279
iconOnly={iconOnly}
@@ -285,7 +285,7 @@ export const ChatViewThreadsSelectorButton = ({
285285
text={t('Threads')}
286286
>
287287
<UnreadCountBadge count={unreadThreadCount} position='top-right'>
288-
{isActive ? <IconBubbleText6SolidChatMessage /> : <IconThread />}
288+
{isActive ? <IconThreadFill /> : <IconThread />}
289289
</UnreadCountBadge>
290290
</ChatViewSelectorButton>
291291
);

src/components/ChatView/styling/ChatView.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
display: flex;
1919
width: 100%;
2020
height: 100%;
21+
min-height: 0;
2122
position: relative;
2223

2324
.str-chat__chat-view__selector {
@@ -136,6 +137,7 @@
136137
display: flex;
137138
flex-grow: 1;
138139
min-width: 0;
140+
min-height: 0;
139141
position: relative;
140142
}
141143

0 commit comments

Comments
 (0)