From f1c044c79ecae291f14f869dd64815f58b1ec8c9 Mon Sep 17 00:00:00 2001 From: Oliver Lazoroski Date: Tue, 10 Mar 2026 11:31:31 +0100 Subject: [PATCH 1/3] fix: wrap attachment previews in message composer --- .../AttachmentPreviewList.tsx | 5 +- .../__tests__/AttachmentPreviewList.test.js | 3 +- .../__tests__/MessageInput.test.js | 2 +- .../AttachmentPreviewList.test.js.snap | 128 +++++++++--------- .../styling/AttachmentPreview.scss | 20 +-- 5 files changed, 84 insertions(+), 74 deletions(-) diff --git a/src/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.tsx b/src/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.tsx index 14b630402..fb9271f0f 100644 --- a/src/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.tsx +++ b/src/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.tsx @@ -62,7 +62,10 @@ export const AttachmentPreviewList = ({ if (!filteredAttachments.length && !location) return null; return ( -
+
{location && ( { it('does not render without attachments', async () => { await renderComponent(); - const attachmentList = screen.queryByTestId('attachment-list-scroll-container'); + const attachmentList = screen.queryByTestId(ATTACHMENT_PREVIEW_LIST_TEST_ID); expect(attachmentList).not.toBeInTheDocument(); }); diff --git a/src/components/MessageInput/__tests__/MessageInput.test.js b/src/components/MessageInput/__tests__/MessageInput.test.js index 319354a10..bdaf7c602 100644 --- a/src/components/MessageInput/__tests__/MessageInput.test.js +++ b/src/components/MessageInput/__tests__/MessageInput.test.js @@ -32,7 +32,7 @@ const FILE_PREVIEW_TEST_ID = 'attachment-preview-file'; const FILE_INPUT_TEST_ID = 'file-input'; const FILE_UPLOAD_RETRY_BTN_TEST_ID = 'file-preview-item-retry-button'; const SEND_BTN_TEST_ID = 'send-button'; -const ATTACHMENT_PREVIEW_LIST_TEST_ID = 'attachment-list-scroll-container'; +const ATTACHMENT_PREVIEW_LIST_TEST_ID = 'attachment-preview-list'; const UNKNOWN_ATTACHMENT_PREVIEW_TEST_ID = 'attachment-preview-unknown'; const cid = 'messaging:general'; diff --git a/src/components/MessageInput/__tests__/__snapshots__/AttachmentPreviewList.test.js.snap b/src/components/MessageInput/__tests__/__snapshots__/AttachmentPreviewList.test.js.snap index b66b86831..61133810d 100644 --- a/src/components/MessageInput/__tests__/__snapshots__/AttachmentPreviewList.test.js.snap +++ b/src/components/MessageInput/__tests__/__snapshots__/AttachmentPreviewList.test.js.snap @@ -11,47 +11,33 @@ exports[`AttachmentPreviewList should render custom BaseImage component 1`] = ` >
- + image-upload-1
@@ -82,50 +68,54 @@ exports[`AttachmentPreviewList should render custom BaseImage component 1`] = `
- image-upload-1
-
- +
+ +
+
+
+ image-upload-2
@@ -156,14 +146,28 @@ exports[`AttachmentPreviewList should render custom BaseImage component 1`] = `
- image-upload-2
+
diff --git a/src/components/MessageInput/styling/AttachmentPreview.scss b/src/components/MessageInput/styling/AttachmentPreview.scss index f612b6b3f..3755d23b9 100644 --- a/src/components/MessageInput/styling/AttachmentPreview.scss +++ b/src/components/MessageInput/styling/AttachmentPreview.scss @@ -95,16 +95,15 @@ @include utils.component-layer-overrides('attachment-preview-list'); padding: var(--spacing-xxs); display: flex; - align-items: center; - //justify-content: center; + align-items: flex-start; + align-content: flex-start; + flex-wrap: wrap; justify-content: flex-start; width: 100%; - min-width: 0; max-width: 100%; - overflow-x: auto; - flex: 1 1 auto; - overflow-y: hidden; + overflow: visible; + flex: 0 0 auto; gap: var(--spacing-md); } @@ -115,11 +114,12 @@ @include utils.component-layer-overrides('attachment-preview-file'); display: flex; align-items: center; + flex: 0 1 auto; gap: var(--spacing-sm); padding: var(--spacing-md); padding-right: var(--spacing-sm); - min-width: 224px; - max-width: 280px; + min-width: min(224px, 100%); + max-width: min(280px, 100%); } .str-chat__attachment-preview-audio { @@ -161,6 +161,7 @@ .str-chat__attachment-preview-media { @include utils.component-layer-overrides('attachment-preview-image'); + flex: 0 0 auto; width: 72px; height: 72px; cursor: pointer; @@ -283,7 +284,8 @@ .str-chat__attachment-preview-file__data { display: flex; align-items: center; - width: 160px; + width: min(160px, 100%); + max-width: 100%; gap: var(--spacing-xxs); color: var(--text-secondary); font-weight: var(--typography-font-weight-regular); From 1874a649eef25404f49f56ed8f96aafd474640ae Mon Sep 17 00:00:00 2001 From: Oliver Lazoroski Date: Tue, 10 Mar 2026 12:49:31 +0100 Subject: [PATCH 2/3] fix: make audio message take the full width; update tile sizes --- .../VoiceRecordingPreview.tsx | 5 --- .../VoiceRecordingPreviewSlot.tsx | 10 ++++- .../AttachmentPreviewList/index.ts | 2 +- .../__tests__/AttachmentPreviewList.test.js | 37 +++++++++++++++++-- .../styling/AttachmentPreview.scss | 13 +++++-- 5 files changed, 53 insertions(+), 14 deletions(-) delete mode 100644 src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreview.tsx diff --git a/src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreview.tsx b/src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreview.tsx deleted file mode 100644 index 87a94a1f7..000000000 --- a/src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreview.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import type { LocalVoiceRecordingAttachment } from 'stream-chat'; -import type { UploadAttachmentPreviewProps } from './types'; - -export type VoiceRecordingPreviewProps> = - UploadAttachmentPreviewProps>; diff --git a/src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreviewSlot.tsx b/src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreviewSlot.tsx index 21a586e1c..872c3e607 100644 --- a/src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreviewSlot.tsx +++ b/src/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreviewSlot.tsx @@ -1,9 +1,15 @@ import type { ComponentType } from 'react'; import React from 'react'; -import { isLocalVoiceRecordingAttachment } from 'stream-chat'; +import { + isLocalVoiceRecordingAttachment, + type LocalVoiceRecordingAttachment, +} from 'stream-chat'; import { useAttachmentsForPreview, useMessageComposer } from '../hooks'; import { AudioAttachmentPreview } from './AudioAttachmentPreview'; -import type { VoiceRecordingPreviewProps } from './VoiceRecordingPreview'; +import type { UploadAttachmentPreviewProps } from './types'; + +export type VoiceRecordingPreviewProps> = + UploadAttachmentPreviewProps>; export type VoiceRecordingPreviewSlotProps = { /** Custom UI component for each voice recording preview in the slot; defaults to AudioAttachmentPreview */ diff --git a/src/components/MessageInput/AttachmentPreviewList/index.ts b/src/components/MessageInput/AttachmentPreviewList/index.ts index 79f1c566a..ab116ba5b 100644 --- a/src/components/MessageInput/AttachmentPreviewList/index.ts +++ b/src/components/MessageInput/AttachmentPreviewList/index.ts @@ -6,8 +6,8 @@ export type { ImageAttachmentPreviewProps } from './ImageAttachmentPreview'; export type { UploadAttachmentPreviewProps as AttachmentPreviewProps } from './types'; export type { UnsupportedAttachmentPreviewProps } from './UnsupportedAttachmentPreview'; export type { MediaAttachmentPreviewProps } from './MediaAttachmentPreview'; -export type { VoiceRecordingPreviewProps } from './VoiceRecordingPreview'; export { VoiceRecordingPreviewSlot, + type VoiceRecordingPreviewProps, type VoiceRecordingPreviewSlotProps, } from './VoiceRecordingPreviewSlot'; diff --git a/src/components/MessageInput/__tests__/AttachmentPreviewList.test.js b/src/components/MessageInput/__tests__/AttachmentPreviewList.test.js index 912d7efbe..fd25f7487 100644 --- a/src/components/MessageInput/__tests__/AttachmentPreviewList.test.js +++ b/src/components/MessageInput/__tests__/AttachmentPreviewList.test.js @@ -1,7 +1,10 @@ import React, { act } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { AttachmentPreviewList } from '../AttachmentPreviewList'; +import { + AttachmentPreviewList, + VoiceRecordingPreviewSlot, +} from '../AttachmentPreviewList'; import { Channel } from '../../Channel'; import { Chat } from '../../Chat'; @@ -31,6 +34,7 @@ const renderComponent = async ({ attachments, channel: customChannel, client: customClient, + component: Component = AttachmentPreviewList, components, coords, editedMessage, @@ -62,10 +66,10 @@ const renderComponent = async ({ }, }} > - + ) : ( - + )} @@ -124,6 +128,33 @@ describe('AttachmentPreviewList', () => { }, ); + it('renders voice recordings in the dedicated full-width slot', async () => { + const CustomVoiceRecordingPreview = () => ( +
voice preview
+ ); + + await renderComponent({ + attachments: [ + generateVoiceRecordingAttachment({ + localMetadata: { + id: 'voice-recording-attachment-id', + uploadState: 'finished', + }, + title: 'voice-recording-finished', + }), + ], + component: VoiceRecordingPreviewSlot, + props: { + VoiceRecordingPreview: CustomVoiceRecordingPreview, + }, + }); + + const voicePreviewSlot = screen.getByTestId('voice-preview-slot'); + + expect(voicePreviewSlot).toBeInTheDocument(); + expect(screen.getByTestId('custom-voice-recording-preview')).toBeInTheDocument(); + }); + // voiceRecording is rendered in VoiceRecordingPreviewSlot (REACT-794), not in AttachmentPreviewList describe.each(['audio', 'file', 'image', 'unsupported', 'video'])( '%s attachments rendering', diff --git a/src/components/MessageInput/styling/AttachmentPreview.scss b/src/components/MessageInput/styling/AttachmentPreview.scss index 3755d23b9..eabeba41b 100644 --- a/src/components/MessageInput/styling/AttachmentPreview.scss +++ b/src/components/MessageInput/styling/AttachmentPreview.scss @@ -75,12 +75,19 @@ .str-chat__message-composer-voice-preview-slot { display: flex; - align-items: center; + align-items: stretch; width: 100%; padding: var(--spacing-xxs); min-width: 0; + > * { + flex: 1 1 100%; + min-width: 0; + max-width: 100%; + } + .str-chat__attachment-preview-audio { + flex: 1 1 auto; width: 100%; min-width: 0; max-width: none; @@ -118,8 +125,8 @@ gap: var(--spacing-sm); padding: var(--spacing-md); padding-right: var(--spacing-sm); - min-width: min(224px, 100%); - max-width: min(280px, 100%); + min-width: 290px; + max-width: 290px; } .str-chat__attachment-preview-audio { From b57238957cc9176381131d0c7acd102254a2fbf0 Mon Sep 17 00:00:00 2001 From: Oliver Lazoroski Date: Tue, 10 Mar 2026 13:19:40 +0100 Subject: [PATCH 3/3] fix: use correct colors for remove attachment preview button; revert unnecessary changes --- .../RemoveAttachmentPreviewButton.tsx | 3 --- .../styling/AttachmentPreview.scss | 19 +++++++------------ .../RemoveAttachmentPreviewButton.scss | 3 +-- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/components/MessageInput/RemoveAttachmentPreviewButton.tsx b/src/components/MessageInput/RemoveAttachmentPreviewButton.tsx index ae3964bf7..42a81328b 100644 --- a/src/components/MessageInput/RemoveAttachmentPreviewButton.tsx +++ b/src/components/MessageInput/RemoveAttachmentPreviewButton.tsx @@ -15,14 +15,11 @@ export const RemoveAttachmentPreviewButton = ({ const { t } = useTranslationContext(); return (