@@ -26,6 +26,7 @@ function SavedForLaterContent() {
const THRESHOLD_RELATIVE_MINUTES = 59;
function RemindMeContent({ reminder }: { reminder: Reminder }) {
+ const { IconBell } = useComponentContextIcons();
const { t } = useTranslationContext();
const { timeLeftMs } = useStateStore(reminder?.state, reminderStateSelector) ?? {};
diff --git a/src/components/MessageActions/DownloadSubmenu.tsx b/src/components/MessageActions/DownloadSubmenu.tsx
index aa69552e6..6a899e1c3 100644
--- a/src/components/MessageActions/DownloadSubmenu.tsx
+++ b/src/components/MessageActions/DownloadSubmenu.tsx
@@ -1,12 +1,15 @@
import React from 'react';
-import { useMessageContext, useTranslationContext } from '../../context';
+import {
+ useComponentContextIcons,
+ useMessageContext,
+ useTranslationContext,
+} from '../../context';
import {
ContextMenuBackButton,
ContextMenuButton,
ContextMenuHeader,
useContextMenuContext,
} from '../Dialog';
-import { IconChevronLeft, IconDownload } from '../Icons';
import {
type DownloadableAttachment,
downloadAllAttachments,
@@ -18,6 +21,7 @@ const msgActionsBoxButtonClassName =
'str-chat__message-actions-list-item-button' as const;
export const DownloadSubmenuHeader = () => {
+ const { IconChevronLeft } = useComponentContextIcons();
const { returnToParentMenu: goBack } = useContextMenuContext();
const { t } = useTranslationContext();
return (
@@ -31,6 +35,7 @@ export const DownloadSubmenuHeader = () => {
};
export const DownloadSubmenu = () => {
+ const { IconDownload } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { message } = useMessageContext();
const { t } = useTranslationContext();
diff --git a/src/components/MessageActions/MessageActions.defaults.tsx b/src/components/MessageActions/MessageActions.defaults.tsx
index d5916e151..0e2648499 100644
--- a/src/components/MessageActions/MessageActions.defaults.tsx
+++ b/src/components/MessageActions/MessageActions.defaults.tsx
@@ -2,30 +2,6 @@
import React, { forwardRef, useState } from 'react';
import { GlobalModal } from '../Modal';
-import {
- IconAudio,
- IconBell,
- IconBellOff,
- IconBookmark,
- IconBookmarkRemove,
- IconCopy,
- IconDelete,
- IconDownload,
- IconEdit,
- IconEmoji,
- IconFlag,
- IconMore,
- IconMute,
- IconNoSign,
- IconNotification,
- IconPin,
- IconQuote,
- IconReply,
- IconRetry,
- IconThread,
- IconUnpin,
- IconUserCheck,
-} from '../Icons';
import { isMessageDeleted, isUserMuted } from '../Message/utils';
import { useMessageComposerController } from '../MessageComposer/hooks/useMessageComposerController';
import { savePreEditSnapshot } from '../MessageComposer/preEditSnapshot';
@@ -36,6 +12,7 @@ import { ReactionSelectorWithButton } from '../Reactions/ReactionSelectorWithBut
import {
useChatContext,
useComponentContext,
+ useComponentContextIcons,
useMessageContext,
useTranslationContext,
} from '../../context';
@@ -77,6 +54,7 @@ const getNotificationError = (error: unknown): Error | undefined => {
const DefaultMessageActionComponents = {
dropdown: {
React() {
+ const { IconEmoji } = useComponentContextIcons();
const { ReactionSelector = DefaultReactionSelector } = useComponentContext();
const { anchorReferenceElement } = useContextMenuContext();
const { isMyMessage, message, threadList } = useMessageContext();
@@ -135,6 +113,7 @@ const DefaultMessageActionComponents = {
);
},
ThreadReply() {
+ const { IconThread } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { handleOpenThread } = useMessageContext();
const { t } = useTranslationContext();
@@ -155,6 +134,7 @@ const DefaultMessageActionComponents = {
);
},
Quote() {
+ const { IconQuote } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { message } = useMessageContext();
const { t } = useTranslationContext();
@@ -188,6 +168,7 @@ const DefaultMessageActionComponents = {
);
},
Download() {
+ const { IconDownload } = useComponentContextIcons();
const { closeMenu, openSubmenu } = useContextMenuContext();
const { message } = useMessageContext();
const { t } = useTranslationContext();
@@ -223,6 +204,7 @@ const DefaultMessageActionComponents = {
);
},
Pin() {
+ const { IconPin, IconUnpin } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { handlePin, message } = useMessageContext();
const { addNotification } = useNotificationApi();
@@ -279,6 +261,7 @@ const DefaultMessageActionComponents = {
);
},
CopyMessageText() {
+ const { IconCopy } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { message } = useMessageContext();
const { t } = useTranslationContext();
@@ -298,6 +281,7 @@ const DefaultMessageActionComponents = {
);
},
Resend() {
+ const { IconRetry } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { handleRetry, message } = useMessageContext();
const { t } = useTranslationContext();
@@ -317,6 +301,7 @@ const DefaultMessageActionComponents = {
);
},
Edit() {
+ const { IconEdit } = useComponentContextIcons();
const messageComposer = useMessageComposerController();
const { message } = useMessageContext();
const { t } = useTranslationContext();
@@ -338,6 +323,7 @@ const DefaultMessageActionComponents = {
);
},
MarkUnread() {
+ const { IconNotification } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { handleMarkUnread, message } = useMessageContext();
const { addNotification } = useNotificationApi();
@@ -392,6 +378,7 @@ const DefaultMessageActionComponents = {
);
},
RemindMe() {
+ const { IconBell, IconBellOff } = useComponentContextIcons();
const { closeMenu, openSubmenu } = useContextMenuContext();
const { client } = useChatContext();
const { addNotification } = useNotificationApi();
@@ -455,6 +442,7 @@ const DefaultMessageActionComponents = {
);
},
SaveForLater() {
+ const { IconBookmark, IconBookmarkRemove } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { client } = useChatContext();
const { addNotification } = useNotificationApi();
@@ -532,6 +520,7 @@ const DefaultMessageActionComponents = {
);
},
Flag() {
+ const { IconFlag } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { handleFlag, message } = useMessageContext();
const { addNotification } = useNotificationApi();
@@ -580,6 +569,7 @@ const DefaultMessageActionComponents = {
);
},
Mute() {
+ const { IconAudio, IconMute } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { handleMute, message } = useMessageContext();
const { addNotification } = useNotificationApi();
@@ -639,6 +629,7 @@ const DefaultMessageActionComponents = {
);
},
Delete() {
+ const { IconDelete } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { addNotification } = useNotificationApi();
const { Modal = GlobalModal } = useComponentContext();
@@ -704,6 +695,7 @@ const DefaultMessageActionComponents = {
);
},
BlockUser() {
+ const { IconNoSign, IconUserCheck } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
const { client } = useChatContext();
const { message } = useMessageContext();
@@ -740,6 +732,7 @@ const DefaultMessageActionComponents = {
quick: {
// eslint-disable-next-line react/display-name
DropdownToggle: forwardRef
((_, ref) => {
+ const { IconMore } = useComponentContextIcons();
const { t } = useTranslationContext();
const { message, threadList } = useMessageContext();
const dropdownDialogIsOpen = useDialogIsOpen(
@@ -779,9 +772,12 @@ const DefaultMessageActionComponents = {
);
}),
React() {
- return ;
+ // No `ReactionIcon`: the component resolves the `IconEmoji` slot itself. Passing it from
+ // here would read the same value and only add a hop that invites a direct import later.
+ return ;
},
Reply() {
+ const { IconReply } = useComponentContextIcons();
const { handleOpenThread } = useMessageContext();
const { t } = useTranslationContext();
diff --git a/src/components/MessageActions/RemindMeSubmenu.tsx b/src/components/MessageActions/RemindMeSubmenu.tsx
index f90c8c243..f396008d6 100644
--- a/src/components/MessageActions/RemindMeSubmenu.tsx
+++ b/src/components/MessageActions/RemindMeSubmenu.tsx
@@ -1,5 +1,10 @@
import React from 'react';
-import { useChatContext, useMessageContext, useTranslationContext } from '../../context';
+import {
+ useChatContext,
+ useComponentContextIcons,
+ useMessageContext,
+ useTranslationContext,
+} from '../../context';
import { useNotificationApi } from '../Notifications';
import {
ContextMenuBackButton,
@@ -7,7 +12,6 @@ import {
ContextMenuHeader,
useContextMenuContext,
} from '../Dialog';
-import { IconChevronLeft } from '../Icons';
const getErrorMessage = (error: unknown, fallback: string) =>
error instanceof Error && error.message ? error.message : fallback;
@@ -23,6 +27,7 @@ const getNotificationError = (error: unknown): Error | undefined => {
};
export const RemindMeSubmenuHeader = () => {
+ const { IconChevronLeft } = useComponentContextIcons();
const { t } = useTranslationContext();
const { returnToParentMenu } = useContextMenuContext();
return (
diff --git a/src/components/MessageBounce/MessageBouncePrompt.tsx b/src/components/MessageBounce/MessageBouncePrompt.tsx
index 528776cac..87171900b 100644
--- a/src/components/MessageBounce/MessageBouncePrompt.tsx
+++ b/src/components/MessageBounce/MessageBouncePrompt.tsx
@@ -1,12 +1,12 @@
import type { MouseEventHandler } from 'react';
import React from 'react';
import {
+ useComponentContextIcons,
useMessageBounceContext,
useModalContext,
useTranslationContext,
} from '../../context';
import { Button } from '../Button';
-import { IconExclamationMark } from '../Icons';
import { Alert } from '../Dialog';
import type { PropsWithChildrenOnly } from '../../types/types';
@@ -14,6 +14,7 @@ export type MessageBouncePromptProps = PropsWithChildrenOnly;
// todo: shall we rename this to MessageBounceAlert?
export function MessageBouncePrompt({ children }: MessageBouncePromptProps) {
+ const { IconExclamationMark } = useComponentContextIcons();
const { handleDelete, handleEdit, handleRetry } = useMessageBounceContext();
const { t } = useTranslationContext();
const { close } = useModalContext();
diff --git a/src/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.tsx b/src/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.tsx
index 87b766672..3cf1d4df6 100644
--- a/src/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.tsx
+++ b/src/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.tsx
@@ -4,13 +4,12 @@ import {
type LocalAudioAttachment,
type LocalVoiceRecordingAttachment,
} from 'stream-chat';
-import { useTranslationContext } from '../../../context';
+import { useComponentContextIcons, useTranslationContext } from '../../../context';
import React, { useEffect } from 'react';
import clsx from 'clsx';
import { UploadProgressIndicator } from '../../Loading/UploadProgressIndicator';
import { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';
import { AttachmentPreviewRoot } from './utils/AttachmentPreviewRoot';
-import { IconExclamationMark, IconExclamationTriangleFill } from '../../Icons';
import { PlayButton } from '../../Button';
import {
type AudioPlayerState,
@@ -41,6 +40,7 @@ export const AudioAttachmentPreview = ({
handleRetry,
removeAttachments,
}: AudioAttachmentPreviewProps) => {
+ const { IconExclamationMark, IconExclamationTriangleFill } = useComponentContextIcons();
const { t } = useTranslationContext();
const { id, previewUri, uploadPermissionCheck, uploadProgress, uploadState } =
attachment.localMetadata ?? {};
diff --git a/src/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.tsx b/src/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.tsx
index 65b4a4ec7..4c2bf346a 100644
--- a/src/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.tsx
+++ b/src/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { useTranslationContext } from '../../../context';
+import { useComponentContextIcons, useTranslationContext } from '../../../context';
import { FileIcon } from '../../FileIcon';
import { UploadProgressIndicator } from '../../Loading/UploadProgressIndicator';
import { AttachmentUploadedSizeIndicator } from './AttachmentUploadedSizeIndicator';
@@ -7,7 +7,6 @@ import type { LocalAudioAttachment, LocalFileAttachment } from 'stream-chat';
import type { UploadAttachmentPreviewProps } from './types';
import { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';
import { AttachmentPreviewRoot } from './utils/AttachmentPreviewRoot';
-import { IconExclamationMark, IconExclamationTriangleFill } from '../../Icons';
export type FileAttachmentPreviewProps =
UploadAttachmentPreviewProps<
@@ -19,6 +18,7 @@ export const FileAttachmentPreview = ({
handleRetry,
removeAttachments,
}: FileAttachmentPreviewProps) => {
+ const { IconExclamationMark, IconExclamationTriangleFill } = useComponentContextIcons();
const { t } = useTranslationContext();
const { id, uploadPermissionCheck, uploadProgress, uploadState } =
attachment.localMetadata ?? {};
diff --git a/src/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.tsx b/src/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.tsx
index 1c9d996a0..444dc7da8 100644
--- a/src/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.tsx
+++ b/src/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.tsx
@@ -2,18 +2,22 @@ import type { LiveLocationPreview, StaticLocationPreview } from 'stream-chat';
import type { ComponentType } from 'react';
import React from 'react';
import { useTranslationContext } from '../../../context';
-import { IconLocation } from '../../Icons';
+import { useComponentContextIcons } from '../../../context';
import { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';
type GeolocationPreviewImageProps = {
location: StaticLocationPreview | LiveLocationPreview;
};
-const GeolocationPreviewImage = () => (
-
-
-
-);
+const GeolocationPreviewImage = () => {
+ const { IconLocation } = useComponentContextIcons();
+
+ return (
+
+
+
+ );
+};
export type GeolocationPreviewProps = {
location: StaticLocationPreview | LiveLocationPreview;
diff --git a/src/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.tsx b/src/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.tsx
index 951727d04..70c4cd814 100644
--- a/src/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.tsx
+++ b/src/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.tsx
@@ -4,7 +4,11 @@ import {
type LocalImageAttachment,
type LocalVideoAttachment,
} from 'stream-chat';
-import { useComponentContext, useTranslationContext } from '../../../context';
+import {
+ useComponentContext,
+ useComponentContextIcons,
+ useTranslationContext,
+} from '../../../context';
import { BaseImage as DefaultBaseImage } from '../../BaseImage';
import React, {
type KeyboardEvent,
@@ -14,7 +18,6 @@ import React, {
useState,
} from 'react';
import clsx from 'clsx';
-import { IconExclamationMark, IconRetry } from '../../Icons';
import { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';
import { Button } from '../../Button';
import { UploadProgressIndicator } from '../../Loading/UploadProgressIndicator';
@@ -34,6 +37,7 @@ export const MediaAttachmentPreview = ({
openPreview,
removeAttachments,
}: MediaAttachmentPreviewProps) => {
+ const { IconExclamationMark, IconRetry } = useComponentContextIcons();
const { t } = useTranslationContext();
const { BaseImage = DefaultBaseImage } = useComponentContext();
const [thumbnailPreviewError, setThumbnailPreviewError] = useState(false);
diff --git a/src/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.tsx b/src/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.tsx
index 857efea57..4e16ed5d2 100644
--- a/src/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.tsx
+++ b/src/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.tsx
@@ -1,7 +1,6 @@
import React from 'react';
import type { AnyLocalAttachment, LocalUploadAttachment } from 'stream-chat';
-import { IconUnsupportedAttachment } from '../../Icons';
-import { useTranslationContext } from '../../../context';
+import { useComponentContextIcons, useTranslationContext } from '../../../context';
import { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';
export type UnsupportedAttachmentPreviewProps<
@@ -18,6 +17,7 @@ export const UnsupportedAttachmentPreview = ({
attachment,
removeAttachments,
}: UnsupportedAttachmentPreviewProps) => {
+ const { IconUnsupportedAttachment } = useComponentContextIcons();
const { t } = useTranslationContext();
const { id } = attachment.localMetadata ?? {};
diff --git a/src/components/MessageComposer/AttachmentSelector/AttachmentSelector.tsx b/src/components/MessageComposer/AttachmentSelector/AttachmentSelector.tsx
index 177f40c3e..0910ac614 100644
--- a/src/components/MessageComposer/AttachmentSelector/AttachmentSelector.tsx
+++ b/src/components/MessageComposer/AttachmentSelector/AttachmentSelector.tsx
@@ -27,7 +27,12 @@ import { ShareLocationDialog as DefaultLocationDialog } from '../../Location';
import { PollCreationDialog as DefaultPollCreationDialog } from '../../Poll';
import { Portal } from '../../Portal/Portal';
import { UploadFileInput } from '../../ReactFileUtilities';
-import { useChannel, useComponentContext, useTranslationContext } from '../../../context';
+import {
+ useChannel,
+ useComponentContext,
+ useComponentContextIcons,
+ useTranslationContext,
+} from '../../../context';
import {
AttachmentSelectorContextProvider,
useAttachmentSelectorContext,
@@ -38,13 +43,6 @@ import { useStateStore } from '../../../store';
import type { TextComposerState } from 'stream-chat';
import clsx from 'clsx';
import { Button, type ButtonProps } from '../../Button';
-import {
- IconAttachment,
- IconCommand,
- IconLocation,
- IconPlus,
- IconPoll,
-} from '../../Icons';
import { useIsCooldownActive } from '../hooks/useIsCooldownActive';
import {
CommandsMenu,
@@ -62,6 +60,7 @@ const textComposerStateSelector = ({ command }: TextComposerState) => ({ command
const AttachmentSelectorMenuInitButtonIcon = ({ className }: { className?: string }) => {
const { AttachmentSelectorInitiationButtonContents } = useComponentContext();
+ const { IconPlus } = useComponentContextIcons();
if (AttachmentSelectorInitiationButtonContents) {
return (
@@ -175,6 +174,7 @@ export type AttachmentSelectorActionProps = {
export const DefaultAttachmentSelectorComponents = {
Command({ submenuHeader, submenuItems }: AttachmentSelectorActionProps) {
const { t } = useTranslationContext();
+ const { IconCommand } = useComponentContextIcons();
const { openSubmenu } = useContextMenuContext();
const commands = useMessageComposerCommands();
const hasEnabledCommands = commands.some(({ enabled }) => enabled);
@@ -202,6 +202,7 @@ export const DefaultAttachmentSelectorComponents = {
},
File() {
const { t } = useTranslationContext();
+ const { IconAttachment } = useComponentContextIcons();
const { fileInput } = useAttachmentSelectorContext();
const { closeMenu } = useContextMenuContext();
@@ -220,6 +221,7 @@ export const DefaultAttachmentSelectorComponents = {
},
Location({ openModalForAction }: AttachmentSelectorActionProps) {
const { t } = useTranslationContext();
+ const { IconLocation } = useComponentContextIcons();
const { closeMenu } = useContextMenuContext();
return (
= {
- ban: IconUserRemove,
- flag: IconFlag,
- giphy: IconGiphy,
- mute: IconMute,
- unban: IconUserAdd,
- unmute: IconAudio,
-};
-
export const CommandsMenuClassName = 'str-chat__context-menu--commands';
export const CommandsSubmenuHeader = () => {
const { t } = useTranslationContext();
const { returnToParentMenu } = useContextMenuContext();
+ const { IconChevronLeft } = useComponentContextIcons();
return (
= {
+ ban: IconUserRemove,
+ flag: IconFlag,
+ giphy: IconGiphy,
+ mute: IconMute,
+ unban: IconUserAdd,
+ unmute: IconAudio,
+ };
+
return (
({
useContextMenuContext: () => ({ closeMenu, returnToParentMenu }),
}));
-vi.mock('../../../../context', () => ({
- useMessageComposerContext: () => ({ textareaRef: { current: null } }),
- useTranslationContext: () => ({ t }),
-}));
+vi.mock('../../../../context', async (importOriginal) => {
+ const actual = await importOriginal();
+ return {
+ // The real hook: with no provider it returns the SDK icons, which is what these
+ // assertions are written against.
+ useComponentContextIcons: actual.useComponentContextIcons,
+ useMessageComposerContext: () => ({ textareaRef: { current: null } }),
+ useTranslationContext: () => ({ t }),
+ };
+});
vi.mock('../../hooks', () => ({
useMessageComposerCommands: () => commandsMock.value,
diff --git a/src/components/MessageComposer/CommandChip.tsx b/src/components/MessageComposer/CommandChip.tsx
index 33d4f6d17..440640fa4 100644
--- a/src/components/MessageComposer/CommandChip.tsx
+++ b/src/components/MessageComposer/CommandChip.tsx
@@ -1,13 +1,17 @@
import { useMessageComposerController } from './hooks';
import type { TextComposerState } from 'stream-chat';
-import { IconBolt, IconXmark } from '../Icons';
-import { useMessageComposerContext, useTranslationContext } from '../../context';
+import {
+ useComponentContextIcons,
+ useMessageComposerContext,
+ useTranslationContext,
+} from '../../context';
export type CommandChipProps = {
command?: TextComposerState['command'];
};
export const CommandChip = ({ command }: CommandChipProps) => {
+ const { IconBolt, IconXmark } = useComponentContextIcons();
const { textComposer } = useMessageComposerController();
const { textareaRef } = useMessageComposerContext();
const { t } = useTranslationContext();
diff --git a/src/components/MessageComposer/LinkPreviewList.tsx b/src/components/MessageComposer/LinkPreviewList.tsx
index 743d8e7fe..bfe57e862 100644
--- a/src/components/MessageComposer/LinkPreviewList.tsx
+++ b/src/components/MessageComposer/LinkPreviewList.tsx
@@ -8,7 +8,7 @@ import { useEnterLeaveHandlers } from '../Tooltip/hooks';
import { useMessageComposerController } from './hooks';
import { BaseImage } from '../BaseImage';
import { RemoveAttachmentPreviewButton } from './RemoveAttachmentPreviewButton';
-import { IconLink } from '../Icons';
+import { useComponentContextIcons } from '../../context';
export type LinkPreviewListProps = {
displayLinkCount?: number;
@@ -46,6 +46,7 @@ type LinkPreviewProps = {
};
export const LinkPreviewCard = ({ linkPreview }: LinkPreviewProps) => {
+ const { IconLink } = useComponentContextIcons();
const { linkPreviewsManager } = useMessageComposerController();
const { handleEnter, handleLeave, tooltipVisible } =
useEnterLeaveHandlers();
diff --git a/src/components/MessageComposer/MessageComposerActions.tsx b/src/components/MessageComposer/MessageComposerActions.tsx
index b1498fb34..7aa56aa09 100644
--- a/src/components/MessageComposer/MessageComposerActions.tsx
+++ b/src/components/MessageComposer/MessageComposerActions.tsx
@@ -5,6 +5,7 @@ import { SendButton as DefaultSendButton } from './SendButton';
import {
useChannel,
useComponentContext,
+ useComponentContextIcons,
useMessageComposerContext,
} from '../../context';
import { useAIState } from '../AIStateIndicator';
@@ -19,7 +20,6 @@ import { useIsCooldownActive } from './hooks/useIsCooldownActive';
import { AIStates } from 'stream-chat';
import type { AIState, MessageComposerState, TextComposerState } from 'stream-chat';
import { useStateStore } from '../../store';
-import { IconCheckmark, IconSend } from '../Icons';
import { useInertWhenHidden } from '../Accessibility';
// `AIStates` is imported from its owner rather than through the `../AIStateIndicator` barrel: that
@@ -39,6 +39,7 @@ const textComposerStateSelector = ({ command, text }: TextComposerState) => ({
});
export const MessageComposerActions = () => {
+ const { IconCheckmark, IconSend } = useComponentContextIcons();
const channel = useChannel();
const { hideSendButton } = useMessageComposerContext();
const messageComposer = useMessageComposerController();
diff --git a/src/components/MessageComposer/QuotedMessagePreview.tsx b/src/components/MessageComposer/QuotedMessagePreview.tsx
index 8e46f99b5..7b9364a1f 100644
--- a/src/components/MessageComposer/QuotedMessagePreview.tsx
+++ b/src/components/MessageComposer/QuotedMessagePreview.tsx
@@ -35,23 +35,14 @@ import {
import { useAttachmentContext } from '../../context/AttachmentContext';
import type { MessageContextValue } from '../../context';
import { RemoveAttachmentPreviewButton } from './RemoveAttachmentPreviewButton';
-import {
- IconCamera,
- IconFile,
- IconLink,
- IconLocation,
- IconNoSign,
- IconPlayFill,
- IconPoll,
- IconVideo,
- IconVoice,
-} from '../Icons';
import clsx from 'clsx';
import { BaseImage } from '../BaseImage';
import { FileIcon } from '../FileIcon';
import { QuotedMessageIndicator } from './QuotedMessageIndicator';
import { getRenderTextMentionEntities } from '../Message/renderText/rehypePlugins';
import { isDeletedMessage } from '../MessageList';
+import { useComponentContextIcons } from '../../context';
+import type { IconSlots } from '../Icons/slots';
const messageComposerStateStoreSelector = (state: MessageComposerState) => ({
quotedMessage: state.quotedMessage,
@@ -174,12 +165,26 @@ type PreviewType =
const getAttachmentIconWithType = (
quotedMessage: LocalMessage | MessageResponse | null,
giphyVersionName: GiphyVersions,
+ // Icons arrive as an argument rather than from the hook: this is a plain helper, called from a
+ // `useMemo` inside the component, so it is not a place a hook may run.
+ icons: Required,
): {
groupedAttachments: GroupedAttachments;
Icon: ComponentType;
PreviewImage: ReactElement | null;
previewType: PreviewType | null;
} => {
+ const {
+ IconCamera,
+ IconFile,
+ IconLink,
+ IconLocation,
+ IconNoSign,
+ IconPlayFill,
+ IconPoll,
+ IconVideo,
+ IconVoice,
+ } = icons;
const groupedAttachments = getGroupedAttachments(quotedMessage);
const result = {
groupedAttachments,
@@ -341,6 +346,7 @@ export const QuotedMessagePreviewUI = ({
// MERGE-RECONCILE: `giphyVersion` was read from the deleted ChannelStateContext;
// migrated to the PR's source (useAttachmentContext().giphyVersion — same as Giphy.tsx).
const { giphyVersion: giphyVersionName = 'fixed_height' } = useAttachmentContext();
+ const icons = useComponentContextIcons();
const quotedMessageText = useMemo(
() =>
@@ -374,7 +380,7 @@ export const QuotedMessagePreviewUI = ({
Icon: AttachmentIcon,
PreviewImage,
previewType,
- } = getAttachmentIconWithType(quotedMessage, giphyVersionName);
+ } = getAttachmentIconWithType(quotedMessage, giphyVersionName, icons);
let renderedText: ReactNode | undefined;
@@ -444,6 +450,7 @@ export const QuotedMessagePreviewUI = ({
};
}, [
giphyVersionName,
+ icons,
quotedMessage,
quotedMessageMentionEntities,
quotedMessageText,
diff --git a/src/components/MessageComposer/RemoveAttachmentPreviewButton.tsx b/src/components/MessageComposer/RemoveAttachmentPreviewButton.tsx
index 234b75ca7..34e2b2c7f 100644
--- a/src/components/MessageComposer/RemoveAttachmentPreviewButton.tsx
+++ b/src/components/MessageComposer/RemoveAttachmentPreviewButton.tsx
@@ -1,8 +1,7 @@
import clsx from 'clsx';
-import { IconXmarkSmall } from '../Icons';
import { Button } from '../Button';
import React, { type ComponentProps } from 'react';
-import { useTranslationContext } from '../../context';
+import { useComponentContextIcons, useTranslationContext } from '../../context';
import type { AttachmentLoadingState } from 'stream-chat';
export const RemoveAttachmentPreviewButton = ({
@@ -12,6 +11,7 @@ export const RemoveAttachmentPreviewButton = ({
}: ComponentProps<'button'> & {
uploadState?: AttachmentLoadingState;
}) => {
+ const { IconXmarkSmall } = useComponentContextIcons();
const { t } = useTranslationContext();
return (