Skip to content

Commit f131a6a

Browse files
authored
fix(MessageList): make pinned message highlight extend edge-to-edge (#3124)
### 🎯 Goal Make the pinned message highlight background extend to the edges of the message list container, matching the Figma design. Currently it only reaches the edges of the max-width scroll content area. ### 🛠 Implementation details Moves the pinned background from `.str-chat__message--pinned` to a pseudo-element on `.str-chat__li:has(.str-chat__message--pinned)` that extends `inset-inline: -9999px` beyond the max-width wrapper. The existing `overflow-x: hidden` on scroll containers (set by the `scrollable-y` mixin) clips it at the list edges — producing the full-width highlight. - Works for both `MessageList` and `VirtualizedMessageList` - Includes `@supports not selector(:has(a, b))` fallback that preserves the old behavior for browsers without `:has()` support - `isolation: isolate` creates a stacking context so the pseudo sits behind message content but above the list background - CSS-only change, no DOM/structural modifications ### 🎨 UI Changes **Before:** pinned highlight stops at the max-width content area edges **After:** pinned highlight extends to the message list container edges (matching design)
1 parent d6b1032 commit f131a6a

4 files changed

Lines changed: 64 additions & 3 deletions

File tree

examples/vite/src/AppSettings/state.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,14 @@ export type PanelLayoutSettingsState = {
4747
threadPanel: ThreadPanelLayoutSettingsState;
4848
};
4949

50+
export type MessageListSettingsState = {
51+
type: 'standard' | 'virtualized';
52+
};
53+
5054
export type AppSettingsState = {
5155
chatView: ChatViewSettingsState;
5256
messageActions: MessageActionsSettingsState;
57+
messageList: MessageListSettingsState;
5358
notifications: NotificationsSettingsState;
5459
panelLayout: PanelLayoutSettingsState;
5560
reactions: ReactionsSettingsState;
@@ -84,6 +89,9 @@ const defaultAppSettingsState: AppSettingsState = {
8489
markOwnUnread: false,
8590
},
8691
},
92+
messageList: {
93+
type: 'standard',
94+
},
8795
notifications: {
8896
verticalAlignment: 'bottom',
8997
},

examples/vite/src/AppSettings/tabs/General/GeneralTab.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { appSettingsStore, useAppSettingsState } from '../../state';
33

44
export const GeneralTab = () => {
55
const {
6+
messageList,
67
theme,
78
theme: { direction },
89
} = useAppSettingsState();
@@ -36,6 +37,33 @@ export const GeneralTab = () => {
3637
</Button>
3738
</div>
3839
</div>
40+
<div className='app__settings-modal__field'>
41+
<div className='app__settings-modal__field-label'>Message list</div>
42+
<div className='app__settings-modal__options-row'>
43+
<Button
44+
aria-pressed={messageList.type === 'standard'}
45+
className='app__settings-modal__option-button str-chat__button--outline str-chat__button--secondary str-chat__button--size-sm'
46+
onClick={() =>
47+
appSettingsStore.partialNext({
48+
messageList: { type: 'standard' },
49+
})
50+
}
51+
>
52+
Standard
53+
</Button>
54+
<Button
55+
aria-pressed={messageList.type === 'virtualized'}
56+
className='app__settings-modal__option-button str-chat__button--outline str-chat__button--secondary str-chat__button--size-sm'
57+
onClick={() =>
58+
appSettingsStore.partialNext({
59+
messageList: { type: 'virtualized' },
60+
})
61+
}
62+
>
63+
Virtualized
64+
</Button>
65+
</div>
66+
</div>
3967
</div>
4068
);
4169
};

examples/vite/src/ChatLayout/Panels.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Thread,
1414
ThreadList,
1515
TypingIndicator,
16+
VirtualizedMessageList,
1617
Window,
1718
WithComponents,
1819
WithDragAndDropUpload,
@@ -22,6 +23,7 @@ import {
2223
useThreadsViewContext,
2324
} from 'stream-chat-react';
2425

26+
import { useAppSettingsSelector } from '../AppSettings/state';
2527
import { DESKTOP_LAYOUT_BREAKPOINT } from './constants.ts';
2628
import { SidebarResizeHandle, ThreadResizeHandle } from './Resize.tsx';
2729
import { useSidebar } from './SidebarContext.tsx';
@@ -54,6 +56,7 @@ const ChannelThreadPanel = () => {
5456
const ResponsiveChannelPanels = () => {
5557
const { thread } = useChannelStateContext('ResponsiveChannelPanels');
5658
const isThreadOpen = !!thread;
59+
const { type: messageListType } = useAppSettingsSelector((s) => s.messageList);
5760

5861
return (
5962
<div
@@ -64,7 +67,11 @@ const ResponsiveChannelPanels = () => {
6467
<WithDragAndDropUpload className='app-chat-view__channel-main'>
6568
<Window>
6669
<ChannelHeader Avatar={ChannelAvatar} />
67-
<MessageList returnAllReadData />
70+
{messageListType === 'virtualized' ? (
71+
<VirtualizedMessageList returnAllReadData shouldGroupByUser />
72+
) : (
73+
<MessageList returnAllReadData />
74+
)}
6875
<AIStateIndicator />
6976
<MessageComposer
7077
focus

src/components/Message/styling/Message.scss

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,26 @@
527527
background-color: var(--str-chat__message-highlighted-background-color);
528528
}
529529

530-
.str-chat__message--pinned {
531-
background-color: var(--str-chat__message-pinned-background-color);
530+
.str-chat__li:has(.str-chat__message--pinned) {
531+
position: relative;
532+
isolation: isolate;
533+
534+
&::before {
535+
content: '';
536+
position: absolute;
537+
inset-block: 0;
538+
inset-inline: -9999px;
539+
background-color: var(--str-chat__message-pinned-background-color);
540+
z-index: -1;
541+
pointer-events: none;
542+
}
543+
}
544+
545+
/* Fallback for browsers without :has() support */
546+
@supports not selector(:has(a, b)) {
547+
.str-chat__message--pinned {
548+
background-color: var(--str-chat__message-pinned-background-color);
549+
}
532550
}
533551

534552
/* This rule won't be applied in browsers that don't support :has() */

0 commit comments

Comments
 (0)