Skip to content

Commit 25b2f0d

Browse files
Add icons to component context
1 parent 20936d6 commit 25b2f0d

95 files changed

Lines changed: 1151 additions & 416 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/components/Attachment/Geolocation.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import { useEffect } from 'react';
33
import { useRef, useState } from 'react';
44
import React from 'react';
55
import type { Coords, SharedLocationResponse } from 'stream-chat';
6-
import { useChatContext, useTranslationContext } from '../../context';
6+
import {
7+
useChatContext,
8+
useComponentContext,
9+
useTranslationContext,
10+
} from '../../context';
711
import { ExternalLinkIcon } from './icons';
8-
import { IconLocation } from '../Icons';
12+
import { IconLocation as DefaultIconLocation } from '../Icons';
913
import { Button } from '../Button';
1014

1115
export type GeolocationMapProps = Coords;
@@ -102,6 +106,7 @@ const DefaultGeolocationAttachmentMapPlaceholder = ({
102106
location,
103107
}: GeolocationAttachmentMapPlaceholderProps) => {
104108
const { t } = useTranslationContext();
109+
const { icons: { IconLocation = DefaultIconLocation } = {} } = useComponentContext();
105110

106111
return (
107112
<div

src/components/Attachment/Giphy.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
useComponentContext,
99
useTranslationContext,
1010
} from '../../context';
11-
import { IconGiphy } from '../Icons';
11+
import { IconGiphy as DefaultIconGiphy } from '../Icons';
1212
import { type CSSProperties, useLayoutEffect, useMemo, useRef, useState } from 'react';
1313
import type { ImageAttachmentConfiguration } from '../../types/types';
1414

@@ -78,9 +78,12 @@ export const Giphy = ({ attachment }: GiphyAttachmentProps) => {
7878
);
7979
};
8080

81-
const GiphyBadge = () => (
82-
<div className='str-chat__giphy-badge'>
83-
<IconGiphy />
84-
Giphy
85-
</div>
86-
);
81+
const GiphyBadge = () => {
82+
const { icons: { IconGiphy = DefaultIconGiphy } = {} } = useComponentContext();
83+
return (
84+
<div className='str-chat__giphy-badge'>
85+
<IconGiphy />
86+
Giphy
87+
</div>
88+
);
89+
};

src/components/Attachment/LinkPreview/Card.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import React from 'react';
22
import { BaseImage } from '../../BaseImage';
33
import { SafeAnchor } from '../../SafeAnchor';
44
import { useChannelStateContext } from '../../../context/ChannelStateContext';
5+
import { useComponentContext } from '../../../context';
56

67
import type { Attachment } from 'stream-chat';
78
import type { RenderAttachmentProps } from '../utils';
89
import type { Dimensions } from '../../../types/types';
9-
import { IconLink } from '../../Icons';
10+
import { IconLink as DefaultIconLink } from '../../Icons';
1011
import { UnableToRenderCard } from './UnableToRenderCard';
1112
import clsx from 'clsx';
1213

@@ -64,6 +65,7 @@ type CardContentProps = RenderAttachmentProps['attachment'];
6465
const CardContent = (props: CardContentProps) => {
6566
const { og_scrape_url, text, title, title_link } = props;
6667
const url = title_link || og_scrape_url;
68+
const { icons: { IconLink = DefaultIconLink } = {} } = useComponentContext();
6769

6870
return (
6971
<div className='str-chat__message-attachment-card--content'>

src/components/Attachment/LinkPreview/CardAudio.tsx

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { type AudioPlayerState, ProgressBar, useAudioPlayer } from '../../AudioPlayback';
2-
import { useMessageContext } from '../../../context';
2+
import { useComponentContext, useMessageContext } from '../../../context';
33
import { useStateStore } from '../../../store';
44
import { PlayButton } from '../../Button';
55
import type { AudioProps } from '../Audio';
66
import React from 'react';
7-
import { IconLink } from '../../Icons';
7+
import { IconLink as DefaultIconLink } from '../../Icons';
88
import { SafeAnchor } from '../../SafeAnchor';
99
import type { CardProps } from './Card';
1010

@@ -21,22 +21,25 @@ const SourceLink = ({
2121
author_name,
2222
showUrl,
2323
url,
24-
}: Pick<CardProps, 'author_name'> & { url: string; showUrl?: boolean }) => (
25-
<div
26-
className='str-chat__message-attachment-card--source-link'
27-
data-testid='card-source-link'
28-
>
29-
<IconLink />
30-
<SafeAnchor
31-
className='str-chat__message-attachment-card--url'
32-
href={url}
33-
rel='noopener noreferrer'
34-
target='_blank'
24+
}: Pick<CardProps, 'author_name'> & { url: string; showUrl?: boolean }) => {
25+
const { icons: { IconLink = DefaultIconLink } = {} } = useComponentContext();
26+
return (
27+
<div
28+
className='str-chat__message-attachment-card--source-link'
29+
data-testid='card-source-link'
3530
>
36-
{showUrl ? url : author_name || getHostFromURL(url)}
37-
</SafeAnchor>
38-
</div>
39-
);
31+
<IconLink />
32+
<SafeAnchor
33+
className='str-chat__message-attachment-card--url'
34+
href={url}
35+
rel='noopener noreferrer'
36+
target='_blank'
37+
>
38+
{showUrl ? url : author_name || getHostFromURL(url)}
39+
</SafeAnchor>
40+
</div>
41+
);
42+
};
4043

4144
const audioPlayerStateSelector = (state: AudioPlayerState) => ({
4245
durationSeconds: state.durationSeconds,

src/components/Attachment/ModalGallery.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Gallery as DefaultGallery, GalleryUI } from '../Gallery';
88
import { LoadingIndicator } from '../Loading';
99
import { GlobalModal, type ModalCloseSource } from '../Modal';
1010
import { useComponentContext, useTranslationContext } from '../../context';
11-
import { IconRetry } from '../Icons';
11+
import { IconRetry as DefaultIconRetry } from '../Icons';
1212
import { VideoThumbnail } from '../VideoPlayer/VideoThumbnail';
1313

1414
const MAX_VISIBLE_THUMBNAILS = 4;
@@ -144,6 +144,7 @@ const ThumbnailButton = ({
144144
showOverlay,
145145
}: ThumbnailButtonProps) => {
146146
const { t } = useTranslationContext();
147+
const { icons: { IconRetry = DefaultIconRetry } = {} } = useComponentContext();
147148
const imageUrl = item.imageUrl;
148149
const [isLoadFailed, setIsLoadFailed] = useState(false);
149150
const [isImageLoading, setIsImageLoading] = useState(Boolean(imageUrl));

src/components/Attachment/UnsupportedAttachment.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import React from 'react';
22
import type { Attachment } from 'stream-chat';
3-
import { useTranslationContext } from '../../context';
4-
import { IconUnsupportedAttachment } from '../Icons';
3+
import { useComponentContext, useTranslationContext } from '../../context';
4+
import { IconUnsupportedAttachment as DefaultIconUnsupportedAttachment } from '../Icons';
55

66
export type UnsupportedAttachmentProps = {
77
attachment: Attachment;
88
};
99

1010
export const UnsupportedAttachment = () => {
11+
const { icons: { IconUnsupportedAttachment = DefaultIconUnsupportedAttachment } = {} } =
12+
useComponentContext();
13+
1114
const { t } = useTranslationContext('UnsupportedAttachment');
1215
return (
1316
<div

src/components/Attachment/VisibilityDisclaimer.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import React from 'react';
2-
import { IconEyeFill } from '../Icons';
3-
import { useTranslationContext } from '../../context';
2+
import { IconEyeFill as DefaultIconEyeFill } from '../Icons';
3+
import { useComponentContext, useTranslationContext } from '../../context';
44

55
export const VisibilityDisclaimer = () => {
6+
const { icons: { IconEyeFill = DefaultIconEyeFill } = {} } = useComponentContext();
7+
68
const { t } = useTranslationContext();
79
return (
810
<div className='str-chat__visibility-disclaimer'>

src/components/Attachment/components/DownloadButton.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import React from 'react';
22
import clsx from 'clsx';
33
import { sanitizeUrl } from '@braintree/sanitize-url';
44

5-
import { useTranslationContext } from '../../../context';
6-
import { IconDownload } from '../../Icons';
5+
import { useComponentContext, useTranslationContext } from '../../../context';
6+
import { IconDownload as DefaultIconDownload } from '../../Icons';
77

88
export type DownloadButtonProps = {
99
/** Attachment asset URL (e.g. `asset_url`). */
@@ -25,6 +25,8 @@ export const DownloadButton = ({
2525
suggestedFileName,
2626
tooltipTitle,
2727
}: DownloadButtonProps) => {
28+
const { icons: { IconDownload = DefaultIconDownload } = {} } = useComponentContext();
29+
2830
const { t } = useTranslationContext();
2931
if (!assetUrl) return null;
3032
const href = sanitizeUrl(assetUrl);

src/components/Avatar/Avatar.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@ import React, {
66
useMemo,
77
useState,
88
} from 'react';
9-
import { IconUser } from '../Icons';
9+
import { useComponentContext } from '../../context';
10+
import { IconUser as DefaultIconUser } from '../Icons';
1011

1112
export type AvatarProps = {
12-
/** Custom icon rendered when there is no image and no initials */
13+
/**
14+
* Custom icon rendered when there is no image and no initials.
15+
* @deprecated Use the `icons.IconUser` slot on `ComponentContext` (via `<WithComponents overrides={{ icons: { IconUser: ... } }}>`) instead.
16+
* Passing this prop still wins over the context slot for backwards compatibility.
17+
*/
1318
FallbackIcon?: ComponentType<ComponentPropsWithoutRef<'svg'>>;
1419
/** URL of the avatar image */
1520
imageUrl?: string;
@@ -46,13 +51,15 @@ const getInitials = (name?: string) => {
4651
*/
4752
export const Avatar = ({
4853
className,
49-
FallbackIcon = IconUser,
54+
FallbackIcon,
5055
imageUrl,
5156
isOnline,
5257
size,
5358
userName,
5459
...rest
5560
}: AvatarProps) => {
61+
const { icons: { IconUser = DefaultIconUser } = {} } = useComponentContext();
62+
const ResolvedFallbackIcon = FallbackIcon ?? IconUser;
5663
const [error, setError] = useState(false);
5764

5865
useEffect(() => () => setError(false), [imageUrl]);
@@ -108,7 +115,7 @@ export const Avatar = ({
108115
{sizeAwareInitials}
109116
</div>
110117
)}
111-
{!sizeAwareInitials.length && <FallbackIcon />}
118+
{!sizeAwareInitials.length && <ResolvedFallbackIcon />}
112119
</>
113120
)}
114121
</div>

src/components/Badge/Badge.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import clsx from 'clsx';
22
import React, { type ComponentProps } from 'react';
3-
import { IconExclamationMarkFill } from '../Icons';
3+
import { useComponentContext } from '../../context';
4+
import { IconExclamationMarkFill as DefaultIconExclamationMarkFill } from '../Icons';
45

56
export type BadgeVariant =
67
| 'default'
@@ -47,8 +48,12 @@ export const ErrorBadge = ({
4748
className,
4849
size = 'sm',
4950
...rest
50-
}: Omit<BadgeProps, 'variant'>) => (
51-
<Badge {...rest} className={className} size={size} variant='error'>
52-
<IconExclamationMarkFill />
53-
</Badge>
54-
);
51+
}: Omit<BadgeProps, 'variant'>) => {
52+
const { icons: { IconExclamationMarkFill = DefaultIconExclamationMarkFill } = {} } =
53+
useComponentContext();
54+
return (
55+
<Badge {...rest} className={className} size={size} variant='error'>
56+
<IconExclamationMarkFill />
57+
</Badge>
58+
);
59+
};

0 commit comments

Comments
 (0)