diff --git a/src/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberActions.defaults.tsx b/src/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberActions.defaults.tsx
index afcc3ff38..0f0e531e2 100644
--- a/src/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberActions.defaults.tsx
+++ b/src/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberActions.defaults.tsx
@@ -24,11 +24,11 @@ import { Alert } from '../../../../components/Dialog';
import { Button } from '../../../../components/Button';
import { Switch } from '../../../../components/Form';
import {
- IconAudio,
- IconMessageBubble,
- IconMute,
- IconNoSign,
- IconUserRemove,
+ IconAudio as DefaultIconAudio,
+ IconMessageBubble as DefaultIconMessageBubble,
+ IconMute as DefaultIconMute,
+ IconNoSign as DefaultIconNoSign,
+ IconUserRemove as DefaultIconUserRemove,
} from '../../../../components/Icons';
import { ListItemLayout } from '../../../../components/ListItemLayout';
import { GlobalModal } from '../../../../components/Modal';
@@ -80,25 +80,40 @@ export const useChannelMemberActionContext = () => {
const toError = (error: unknown) =>
error instanceof Error ? error : new Error('An unknown error occurred');
-const MemberMuteActionIcon = () => (
-
-);
+const MemberMuteActionIcon = () => {
+ const { icons: { IconMute = DefaultIconMute } = {} } = useComponentContext();
+ return (
+
+ );
+};
-const MemberUnmuteActionIcon = () => (
-
-);
+const MemberUnmuteActionIcon = () => {
+ const { icons: { IconAudio = DefaultIconAudio } = {} } = useComponentContext();
+ return (
+
+ );
+};
-const SendDirectMessageActionIcon = () => (
-
-);
+const SendDirectMessageActionIcon = () => {
+ const { icons: { IconMessageBubble = DefaultIconMessageBubble } = {} } =
+ useComponentContext();
+ return
;
+};
-const BlockUserActionIcon = () => (
-
-);
+const BlockUserActionIcon = () => {
+ const { icons: { IconNoSign = DefaultIconNoSign } = {} } = useComponentContext();
+ return (
+
+ );
+};
-const RemoveUserActionIcon = () => (
-
-);
+const RemoveUserActionIcon = () => {
+ const { icons: { IconUserRemove = DefaultIconUserRemove } = {} } =
+ useComponentContext();
+ return (
+
+ );
+};
const channelMemberDetailActionClassName = 'str-chat__channel-member-detail-action';
diff --git a/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersAddView.tsx b/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersAddView.tsx
index 711620f95..6cace9724 100644
--- a/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersAddView.tsx
+++ b/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersAddView.tsx
@@ -1,11 +1,15 @@
import { type SearchSourceState, type UserResponse, UserSearchSource } from 'stream-chat';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import { useChatContext, useTranslationContext } from '../../../../context';
+import {
+ useChatContext,
+ useComponentContext,
+ useTranslationContext,
+} from '../../../../context';
import { useStateStore } from '../../../../store';
import { Avatar } from '../../../../components/Avatar';
import { Checkbox } from '../../../../components/Form';
-import { IconMute } from '../../../../components/Icons';
+import { IconMute as DefaultIconMute } from '../../../../components/Icons';
import { ListItemLayout } from '../../../../components/ListItemLayout';
import { VirtualizedList } from '../../VirtualizedList';
import { Prompt } from '../../../../components/Dialog';
@@ -33,9 +37,12 @@ const EMPTY_USERS: UserResponse[] = [];
const computeUserItemKey = (_: number, user: UserResponse) => user.id;
-const MuteIndicator = () => (
-
-);
+const MuteIndicator = () => {
+ const { icons: { IconMute = DefaultIconMute } = {} } = useComponentContext();
+ return (
+
+ );
+};
const readOnlyRootProps = {
className: 'str-chat__channel-detail__channel-members-view__list-item',
diff --git a/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersBrowseView.tsx b/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersBrowseView.tsx
index 52dda9f8c..c3bc153ad 100644
--- a/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersBrowseView.tsx
+++ b/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersBrowseView.tsx
@@ -1,9 +1,13 @@
import type { ChannelMemberResponse } from 'stream-chat';
import React, { useCallback, useMemo } from 'react';
-import { useChatContext, useTranslationContext } from '../../../../context';
+import {
+ useChatContext,
+ useComponentContext,
+ useTranslationContext,
+} from '../../../../context';
import { Avatar } from '../../../../components/Avatar';
-import { IconMute } from '../../../../components/Icons';
+import { IconMute as DefaultIconMute } from '../../../../components/Icons';
import { ListItemLayout } from '../../../../components/ListItemLayout';
import { VirtualizedList } from '../../VirtualizedList';
import { Prompt } from '../../../../components/Dialog';
@@ -78,6 +82,7 @@ const ChannelMembersBrowseViewItem = ({
const TrailingSlot = useMemo(
() =>
function MemberTrailingSlot() {
+ const { icons: { IconMute = DefaultIconMute } = {} } = useComponentContext();
return (
{roleTranslation ? (
diff --git a/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersHeaderActions.defaults.tsx b/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersHeaderActions.defaults.tsx
index e125f3c5d..d78c575f0 100644
--- a/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersHeaderActions.defaults.tsx
+++ b/src/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersHeaderActions.defaults.tsx
@@ -15,7 +15,7 @@ import type {
ChannelMembersHeaderActionsProps,
ChannelMembersModeController,
} from './ChannelMembersView';
-import { IconUserAdd } from '../../../../components/Icons';
+import { IconUserAdd as DefaultIconUserAdd } from '../../../../components/Icons';
export type ChannelMembersHeaderActionType = 'addMembers' | (string & {});
@@ -91,6 +91,7 @@ const AddMembersMenuAction = ({
modeController,
}: ChannelMembersHeaderActionComponentProps) => {
const { t } = useTranslationContext();
+ const { icons: { IconUserAdd = DefaultIconUserAdd } = {} } = useComponentContext();
if (modeController.mode !== 'browse') return null;
diff --git a/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersAddView.test.tsx b/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersAddView.test.tsx
index a16c2e7d5..4935ba6c2 100644
--- a/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersAddView.test.tsx
+++ b/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersAddView.test.tsx
@@ -2,7 +2,11 @@ import { fireEvent, screen, waitFor } from '@testing-library/react';
import React from 'react';
import type { UserResponse } from 'stream-chat';
-import { useChatContext, useTranslationContext } from '../../../../../context';
+import {
+ useChatContext,
+ useComponentContext,
+ useTranslationContext,
+} from '../../../../../context';
import { useStateStore } from '../../../../../store';
import { ChannelMembersAddView } from '../ChannelMembersAddView';
import {
@@ -88,6 +92,8 @@ describe('ChannelMembersAddView', () => {
options?.count ? `${key}:${options.count}` : key,
} as ReturnType);
+ vi.mocked(useComponentContext).mockReturnValue({});
+
vi.mocked(useChatContext).mockReturnValue({
client: { user: { id: 'user-1' } },
mutes: [],
diff --git a/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersBrowseView.test.tsx b/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersBrowseView.test.tsx
index 99d8491b0..26a686cdb 100644
--- a/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersBrowseView.test.tsx
+++ b/src/plugins/ChannelDetail/Views/ChannelMembersView/__tests__/ChannelMembersBrowseView.test.tsx
@@ -2,7 +2,11 @@ import { fireEvent, screen } from '@testing-library/react';
import React from 'react';
import type { ChannelMemberResponse } from 'stream-chat';
-import { useChatContext, useTranslationContext } from '../../../../../context';
+import {
+ useChatContext,
+ useComponentContext,
+ useTranslationContext,
+} from '../../../../../context';
import { useStateStore } from '../../../../../store';
import { ChannelMembersBrowseView } from '../ChannelMembersBrowseView';
import { createChannel, emitChannelEvent, renderWithChannel } from './testUtils';
@@ -117,6 +121,7 @@ describe('ChannelMembersBrowseView', () => {
return key;
},
} as ReturnType);
+ vi.mocked(useComponentContext).mockReturnValue({});
vi.mocked(useChatContext).mockReturnValue({
mutes: [],
} as ReturnType);
diff --git a/src/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesEmptyList.tsx b/src/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesEmptyList.tsx
index 210c9610a..12784205b 100644
--- a/src/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesEmptyList.tsx
+++ b/src/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesEmptyList.tsx
@@ -1,7 +1,9 @@
-import { IconPin } from '../../../../components/Icons';
-import { useTranslationContext } from '../../../../context';
+import { IconPin as DefaultIconPin } from '../../../../components/Icons';
+import { useComponentContext, useTranslationContext } from '../../../../context';
export const PinnedMessagesEmptyList = () => {
+ const { icons: { IconPin = DefaultIconPin } = {} } = useComponentContext();
+
const { t } = useTranslationContext();
return (
diff --git a/src/plugins/ChannelDetail/Views/PinnedMessagesView/__tests__/PinnedMessagesView.test.tsx b/src/plugins/ChannelDetail/Views/PinnedMessagesView/__tests__/PinnedMessagesView.test.tsx
index d57a31766..1e5d211f6 100644
--- a/src/plugins/ChannelDetail/Views/PinnedMessagesView/__tests__/PinnedMessagesView.test.tsx
+++ b/src/plugins/ChannelDetail/Views/PinnedMessagesView/__tests__/PinnedMessagesView.test.tsx
@@ -6,6 +6,7 @@ import { fromPartial } from '@total-typescript/shoehorn';
import {
useChannelActionContext,
useChatContext,
+ useComponentContext,
useModalContext,
useTranslationContext,
} from '../../../../../context';
@@ -210,6 +211,8 @@ describe('PinnedMessagesView', () => {
tDateTimeParser: (input?: string | Date) => new Date(input ?? Date.now()),
} as ReturnType);
+ vi.mocked(useComponentContext).mockReturnValue({});
+
vi.mocked(useChatContext).mockReturnValue({
client: { userID: 'user-1' },
} as ReturnType);
diff --git a/src/plugins/Emojis/EmojiPicker.tsx b/src/plugins/Emojis/EmojiPicker.tsx
index 4972da647..5833ada11 100644
--- a/src/plugins/Emojis/EmojiPicker.tsx
+++ b/src/plugins/Emojis/EmojiPicker.tsx
@@ -1,10 +1,14 @@
import React, { useEffect, useState } from 'react';
import PickerImport from '@emoji-mart/react';
-import { useMessageComposerContext, useTranslationContext } from '../../context';
+import {
+ useComponentContext,
+ useMessageComposerContext,
+ useTranslationContext,
+} from '../../context';
import {
Button,
- IconEmoji,
+ IconEmoji as DefaultIconEmoji,
type PopperLikePlacement,
useMessageComposerController,
} from '../../components';
@@ -22,6 +26,10 @@ const Picker =
const isShadowRoot = (node: Node): node is ShadowRoot => !!(node as ShadowRoot).host;
export type EmojiPickerProps = {
+ /**
+ * @deprecated Use the `icons.IconEmoji` slot on `ComponentContext` (via ``) instead.
+ * Passing this prop still wins over the context slot for backwards compatibility.
+ */
ButtonIconComponent?: React.ComponentType;
buttonClassName?: string;
pickerContainerClassName?: string;
@@ -72,7 +80,9 @@ export const EmojiPicker = (props: EmojiPickerProps) => {
const { pickerContainerClassName, wrapperClassName } = classNames;
- const { ButtonIconComponent = IconEmoji } = props;
+ const { icons: { IconEmoji = DefaultIconEmoji } = {} } = useComponentContext();
+ const ResolvedButtonIconComponent = props.ButtonIconComponent ?? IconEmoji;
+
const pickerStyle = props.pickerProps?.style as React.CSSProperties | undefined;
useEffect(() => {
@@ -134,7 +144,7 @@ export const EmojiPicker = (props: EmojiPickerProps) => {
type='button'
variant='secondary'
>
- {ButtonIconComponent && }
+ {ResolvedButtonIconComponent && }
);