IntroductionStreami18nReadme
Top Level Components
UI Components
Layout Components
Composition Components
Activity
Properties
activity
Record<string, unknown> & { attachments?: Attachments | undefined; text?: string | undefined; } & BaseActivity & Pick<Activity<Record<string, unknown>>, "time" | "foreign_id" | "id" | "analytics" | "extra_context" | "origin" | "score"> & { ...; }
required
Card
string | number | boolean | ReactElement<PropsWithElementAttributes<{ alt?: string | undefined; handleClose?: ((e: SyntheticEvent<Element, Event>) => void) | undefined; image?: string | null | undefined; nolink?: boolean | undefined; } & Pick<...>, HTMLAnchorElement>, string | ... 1 more ... | (new (props: any) => C...
({
alt,
images = [],
image: imageURL,
handleClose,
description,
nolink,
url,
title,
className,
style,
}: CardProps) => {
const sanitizedURL = useMemo(() => sanitizeURL(url), [url]);
const trimmedURL = useMemo(() => trimURL(sanitizedURL), [sanitizedURL]);
const [{ image }] = !imageURL && images.length ? images : [{ image: imageURL }];
return (
<a
href={nolink ? undefined : sanitizedURL}
target="blank"
rel="nofollow noreferrer noopener"
className={className ?? `raf-card ${image !== undefined ? 'raf-card--with-image' : ''}`}
style={style}
>
{handleClose && image ? (
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
) : null}
{image !== undefined && (
<div className="raf-card__image">
{image === null ? (
<AvatarIcon preserveAspectRatio="xMinYMin slice" />
) : (
<img src={image} alt={alt || title || description || ''} />
)}
</div>
)}
<div className="raf-card__content">
<div className="raf-card__content-left">
<p className="raf-card__title">{title}</p>
<p className="raf-card__url">{trimmedURL}</p>
<p className="raf-card__description">{description}</p>
</div>
{handleClose && image === undefined && (
<div className="raf-card__content-right">
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
</div>
)}
</div>
</a>
);
}
Content
string | number | boolean | ReactElement<PropsWithElementAttributes<{ activity: EnrichedActivity<UT, AT, CT, RT, CRT>; Card?: string | number | boolean | ReactElement<PropsWithElementAttributes<{ alt?: string | undefined; handleClose?: ((e: SyntheticEvent<Element, Event>) => void) | undefined; image?: string | ... 1...
<
UT extends DefaultUT = DefaultUT,
AT extends DefaultAT = DefaultAT,
CT extends UR = UR,
RT extends UR = UR,
CRT extends UR = UR
>({
activity,
Repost,
Card = DefaultCard,
className,
style,
...props
}: ActivityContentProps<UT, AT, CT, RT, CRT>) => {
const {
object,
text = (typeof object === 'string' ? object : '').trim(),
attachments: { og, images = [], files = [] } = {},
verb,
image,
} = activity;
return (
<div className={classNames('raf-activity__content', className)} style={style}>
{text && (
<div style={{ padding: '8px 16px' }}>
<p>{textRenderer(text, 'raf-activity', props.onClickMention, props.onClickHashtag)}</p>
</div>
)}
{og && (
<div style={{ padding: '8px 16px' }}>
{og.videos ? <Video og={og} /> : og.audios ? <Audio og={og} /> : smartRender(Card, og)}
</div>
)}
{typeof image === 'string' && (
<div style={{ padding: '8px 0' }}>
<Gallery images={[image]} />
</div>
)}
{!!images.length && (
<div style={{ padding: '8px 0' }}>
<Gallery images={images} />
</div>
)}
{!!files.length && (
<ol className="raf-activity__attachments">
{files.map(({ name, url, mimeType }, i) => (
<a href={sanitizeURL(url)} download key={i}>
<li className="raf-activity__file">
<FileIcon mimeType={mimeType} filename={name} /> {name}
</li>
</a>
))}
</ol>
)}
{verb === 'repost' &&
typeof object === 'object' &&
smartRender(Repost, {
...props,
activity: object as EnrichedActivity<UT, AT, CT, RT, CRT>,
})}
</div>
);
}
feedGroup
string | undefined
Footer
string | number | boolean | ReactElement<ActivityFooterProps<UT, AT, CT, RT, CRT>, string | ((props: any) => ReactElement<any, any> | null) | (new (props: any) => Component<any, any, any>)> | ComponentClass<...> | FunctionComponent<...> | null | undefined
Header
string | number | boolean | ReactElement<Pick<PropsWithElementAttributes<{ activity: EnrichedActivity<UT, AT, Record<string, unknown>, Record<string, unknown>, Record<string, unknown>>; Card?: string | number | boolean | ReactElement<PropsWithElementAttributes<{ ...; } & Pick<...>, HTMLAnchorElement>, string | ... 1...
<UT extends DefaultUT = DefaultUT, AT extends DefaultAT = DefaultAT>({
activity,
HeaderRight,
icon,
onClickUser,
style = { padding: '8px 16px' },
className,
}: ActivityHeaderProps<UT, AT>) => {
const { tDateTimeParser } = useTranslationContext();
const actor = userOrDefault<UT>(activity.actor);
const handleUserClick = useOnClickUser<UT>(onClickUser);
return (
<div style={style} className={className}>
<UserBar
username={actor.data.name}
avatar={actor.data.profileImage}
onClickUser={handleUserClick?.(actor)}
subtitle={HeaderRight ? humanizeTimestamp(activity.time, tDateTimeParser) : undefined}
timestamp={activity.time}
icon={icon}
Right={HeaderRight}
/>
</div>
);
}
HeaderRight
string | number | boolean | ReactElement<Record<string, unknown>, string | ((props: any) => ReactElement<any, any> | null) | (new (props: any) => Component<any, any, any>)> | ComponentClass<Record<...>, any> | FunctionComponent<...> | null | undefined
icon
string | undefined
onClickHashtag
WordClickHandler | undefined
onClickMention
WordClickHandler | undefined
onClickUser
((user: UserOrDefaultReturnType<UT>) => void) | undefined
Repost
string | number | boolean | ReactElement<PropsWithElementAttributes<{ activity: EnrichedActivity<UT, AT, CT, RT, CRT>; Card?: string | number | boolean | ReactElement<PropsWithElementAttributes<{ alt?: string | undefined; handleClose?: ((e: SyntheticEvent<Element, Event>) => void) | undefined; image?: string | ... 1...
<
UT extends DefaultUT = DefaultUT,
AT extends DefaultAT = DefaultAT,
CT extends UR = UR,
RT extends UR = UR,
CRT extends UR = UR
>({
Header = DefaultActivityHeader,
HeaderRight,
Content = DefaultActivityContent,
activity,
icon,
onClickHashtag,
onClickMention,
onClickUser,
}: ActivityProps<UT, AT, CT, RT, CRT>) => (
<div className="raf-card raf-activity raf-activity-repost">
{smartRender<ActivityHeaderProps<UT, AT>>(Header, { HeaderRight, icon, activity, onClickUser })}
{smartRender<ActivityContentProps<UT, AT, CT, RT, CRT>>(Content, { onClickMention, onClickHashtag, activity })}
</div>
)
userId
string | undefined
Basic usage
I just missed my train 😤
Activity with attached image and hashtag
Activity with enriched URL
Activity with custom header and content components
Nora Ferguson
You can customize your activity however you like!