diff --git a/src/app/components/message/layout/Stream.tsx b/src/app/components/message/layout/Stream.tsx index 0a9c8664..7fea81fe 100644 --- a/src/app/components/message/layout/Stream.tsx +++ b/src/app/components/message/layout/Stream.tsx @@ -6,8 +6,11 @@ import { useStreamLayoutDebug } from './streamDebug'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { Time } from '../Time'; -// Stream rows use a fixed `S400` gap so the rail-bridge offsets in -// layout.css.ts (StreamRailBridgeY = S400) match the gap between rows. +// Day-divider rows fall back to this `S400` MessageBase spacing variant +// (see RoomTimeline.renderDayDivider). Message rows force collapse=true +// in Message.tsx so their marginTop drops to 0 — the rail-bridge offsets +// still resolve against `StreamRailBridgeY = S400` and the small overlap +// over the tighter gap stays hidden by the dot halo. export const STREAM_MESSAGE_SPACING = '400' as const; // Sample timestamp used by the day-divider's invisible track-1 placeholder. @@ -159,10 +162,7 @@ export const StreamLayout = as<'div', StreamLayoutProps>( )} ref={railRef} /> - + ( className={classNames(css.MessageBase, className)} tabIndex={0} space={layout === 'channel' ? CHANNEL_MESSAGE_SPACING : STREAM_MESSAGE_SPACING} - collapse={collapse} + // Stream rows always render with collapsed marginTop (=0) so the + // bubble-to-bubble gap is uniform regardless of same-sender grouping. + // Total gap = 4×S100 (StreamRoot + MessageBase vertical padding on + // both sides) = 16px. The rail-bridge in layout.css.ts is still S400 + // each side — it overshoots slightly across the smaller gap, but the + // overlap lands inside DotColumn behind the dot halo and stays + // invisible. `collapse` still drives avatar/header visibility inside + // ChannelLayout — channel mode keeps the original behaviour. + collapse={layout === 'channel' ? collapse : true} highlight={highlight} selected={!!menuAnchor || !!emojiBoardAnchor} {...props}