mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(app): honour motion settings in composer autocomplete previews (#1912)
This commit is contained in:
1 parent
0670380360
commit
7d02b7959f
5 files changed
+143
-100
No files matched your search
@@ -1,10 +1,10 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import {useAnimatedMediaVideoPlayback} from '@app/features/app/hooks/useAnimatedMediaPlayback';
|
|
||||||
import {useShouldAnimate} from '@app/features/app/hooks/useShouldAnimate';
|
import {useShouldAnimate} from '@app/features/app/hooks/useShouldAnimate';
|
||||||
import {type AutocompleteOption, isEmoji, isMeme, isSticker} from '@app/features/channel/components/Autocomplete';
|
import {type AutocompleteOption, isEmoji, isMeme, isSticker} from '@app/features/channel/components/Autocomplete';
|
||||||
import styles from '@app/features/channel/components/AutocompleteEmoji.module.css';
|
import styles from '@app/features/channel/components/AutocompleteEmoji.module.css';
|
||||||
import {AutocompleteItem} from '@app/features/channel/components/AutocompleteItem';
|
import {AutocompleteItem} from '@app/features/channel/components/AutocompleteItem';
|
||||||
|
import {AutocompleteMemePreview} from '@app/features/channel/components/AutocompleteMemePreview';
|
||||||
import * as EmojiPickerCommands from '@app/features/emoji/commands/EmojiPickerCommands';
|
import * as EmojiPickerCommands from '@app/features/emoji/commands/EmojiPickerCommands';
|
||||||
import {useStickerAnimation} from '@app/features/emoji/hooks/useStickerAnimation';
|
import {useStickerAnimation} from '@app/features/emoji/hooks/useStickerAnimation';
|
||||||
import type {FlatEmoji} from '@app/features/emoji/types/EmojiTypes';
|
import type {FlatEmoji} from '@app/features/emoji/types/EmojiTypes';
|
||||||
@@ -16,13 +16,12 @@ import {
|
|||||||
MEDIA_DESCRIPTOR,
|
MEDIA_DESCRIPTOR,
|
||||||
STICKERS_DESCRIPTOR,
|
STICKERS_DESCRIPTOR,
|
||||||
} from '@app/features/i18n/utils/CommonMessageDescriptors';
|
} from '@app/features/i18n/utils/CommonMessageDescriptors';
|
||||||
|
import {getEmojiRenderUrl} from '@app/features/messaging/utils/markdown/EmojiDetector';
|
||||||
import * as AvatarUtils from '@app/features/user/utils/AvatarUtils';
|
import * as AvatarUtils from '@app/features/user/utils/AvatarUtils';
|
||||||
import {msg} from '@lingui/core/macro';
|
import {msg} from '@lingui/core/macro';
|
||||||
import {useLingui} from '@lingui/react/macro';
|
import {useLingui} from '@lingui/react/macro';
|
||||||
import {MusicNoteIcon} from '@phosphor-icons/react';
|
|
||||||
import {observer} from 'mobx-react-lite';
|
import {observer} from 'mobx-react-lite';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import {useRef} from 'react';
|
|
||||||
|
|
||||||
const DEFAULT_EMOJI_DESCRIPTOR = msg({
|
const DEFAULT_EMOJI_DESCRIPTOR = msg({
|
||||||
message: 'Default emoji',
|
message: 'Default emoji',
|
||||||
@@ -34,53 +33,53 @@ const SectionHeading = observer(({children}: {children: React.ReactNode}) => (
|
|||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
const AutocompleteEmojiIcon = observer(({emoji}: {emoji: FlatEmoji}) => {
|
const AutocompleteEmojiIcon = observer(({emoji}: {emoji: FlatEmoji}) => {
|
||||||
const shouldAnimate = useShouldAnimate({kind: 'emoji'});
|
const isAnimatable = Boolean(emoji.animated);
|
||||||
|
const shouldAnimate = useShouldAnimate({
|
||||||
|
kind: 'emoji',
|
||||||
|
isAnimated: isAnimatable,
|
||||||
|
});
|
||||||
const {url: fallbackDisplayUrl} = getEmojiDisplayData(emoji);
|
const {url: fallbackDisplayUrl} = getEmojiDisplayData(emoji);
|
||||||
const displayUrl = emoji.id
|
const displayUrl =
|
||||||
? AvatarUtils.getEmojiURL({id: emoji.id, animated: Boolean(emoji.animated) && shouldAnimate})
|
getEmojiRenderUrl({
|
||||||
: (fallbackDisplayUrl ?? '');
|
id: emoji.id,
|
||||||
|
surrogateUrl: fallbackDisplayUrl ?? null,
|
||||||
|
isAnimatable,
|
||||||
|
animated: shouldAnimate,
|
||||||
|
jumbo: false,
|
||||||
|
}) ?? '';
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
draggable={false}
|
draggable={false}
|
||||||
className={styles.emojiIcon}
|
className={styles.emojiIcon}
|
||||||
src={displayUrl}
|
src={displayUrl}
|
||||||
alt={emoji.name}
|
alt={emoji.name}
|
||||||
|
aria-hidden={true}
|
||||||
data-flx="channel.autocomplete-emoji.emoji-icon"
|
data-flx="channel.autocomplete-emoji.emoji-icon"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const AutocompleteStickerIcon = observer(
|
const AutocompleteStickerIcon = observer(
|
||||||
({sticker, isInteracting}: {sticker: GuildSticker; isInteracting: boolean}) => {
|
({sticker, isInteracting}: {sticker: GuildSticker; isInteracting: boolean}) => {
|
||||||
const {shouldAnimate} = useStickerAnimation({isInteracting});
|
const {shouldAnimate} = useStickerAnimation({isInteracting, isAnimated: sticker.animated});
|
||||||
return (
|
return (
|
||||||
<div className={styles.stickerIconWrapper} data-flx="channel.autocomplete-emoji.sticker-icon-wrapper">
|
<div className={styles.stickerIconWrapper} data-flx="channel.autocomplete-emoji.sticker-icon-wrapper">
|
||||||
<img
|
<img
|
||||||
draggable={false}
|
draggable={false}
|
||||||
className={styles.stickerIcon}
|
className={styles.stickerIcon}
|
||||||
src={AvatarUtils.getStickerURL({id: sticker.id, animated: shouldAnimate, size: 320})}
|
src={AvatarUtils.getStickerURL({
|
||||||
|
id: sticker.id,
|
||||||
|
animated: shouldAnimate,
|
||||||
|
isAnimatable: sticker.animated,
|
||||||
|
size: 320,
|
||||||
|
})}
|
||||||
alt={sticker.name}
|
alt={sticker.name}
|
||||||
|
aria-hidden={true}
|
||||||
data-flx="channel.autocomplete-emoji.sticker-icon"
|
data-flx="channel.autocomplete-emoji.sticker-icon"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const AutocompleteMemeVideo = ({src}: {src: string}) => {
|
|
||||||
const videoRef = useRef<HTMLVideoElement>(null);
|
|
||||||
const playbackAllowed = useAnimatedMediaVideoPlayback(videoRef);
|
|
||||||
return (
|
|
||||||
<video
|
|
||||||
ref={videoRef}
|
|
||||||
src={src}
|
|
||||||
className={styles.memeVideo}
|
|
||||||
muted
|
|
||||||
autoPlay={playbackAllowed}
|
|
||||||
loop
|
|
||||||
playsInline
|
|
||||||
data-flx="channel.autocomplete-emoji.meme-video"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const AutocompleteEmoji = observer(
|
export const AutocompleteEmoji = observer(
|
||||||
({
|
({
|
||||||
onSelect,
|
onSelect,
|
||||||
@@ -214,31 +213,10 @@ export const AutocompleteEmoji = observer(
|
|||||||
description={option.meme.tags.length > 0 ? option.meme.tags.join(', ') : undefined}
|
description={option.meme.tags.length > 0 ? option.meme.tags.join(', ') : undefined}
|
||||||
icon={
|
icon={
|
||||||
<div className={styles.memeIconWrapper} data-flx="channel.autocomplete-emoji.meme-icon-wrapper">
|
<div className={styles.memeIconWrapper} data-flx="channel.autocomplete-emoji.meme-icon-wrapper">
|
||||||
{option.meme.contentType.startsWith('video/') || option.meme.contentType.includes('gif') ? (
|
<AutocompleteMemePreview
|
||||||
<AutocompleteMemeVideo
|
meme={option.meme}
|
||||||
src={option.meme.url}
|
data-flx="channel.autocomplete-emoji.autocomplete-meme-preview"
|
||||||
data-flx="channel.autocomplete-emoji.autocomplete-meme-video"
|
/>
|
||||||
/>
|
|
||||||
) : option.meme.contentType.startsWith('audio/') ? (
|
|
||||||
<div
|
|
||||||
className={styles.audioIconWrapper}
|
|
||||||
data-flx="channel.autocomplete-emoji.audio-icon-wrapper"
|
|
||||||
>
|
|
||||||
<MusicNoteIcon
|
|
||||||
className={styles.audioIcon}
|
|
||||||
weight="fill"
|
|
||||||
data-flx="channel.autocomplete-emoji.audio-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<img
|
|
||||||
draggable={false}
|
|
||||||
className={styles.memeIcon}
|
|
||||||
src={option.meme.url}
|
|
||||||
alt={option.meme.name}
|
|
||||||
data-flx="channel.autocomplete-emoji.meme-icon"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
isKeyboardSelected={currentIndex === keyboardFocusIndex}
|
isKeyboardSelected={currentIndex === keyboardFocusIndex}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import {useAnimatedMediaVideoPlayback} from '@app/features/app/hooks/useAnimatedMediaPlayback';
|
import {useAnimatedMediaVideoPlayback} from '@app/features/app/hooks/useAnimatedMediaPlayback';
|
||||||
|
import {useShouldAnimate} from '@app/features/app/hooks/useShouldAnimate';
|
||||||
import {type AutocompleteOption, isGif} from '@app/features/channel/components/Autocomplete';
|
import {type AutocompleteOption, isGif} from '@app/features/channel/components/Autocomplete';
|
||||||
import styles from '@app/features/channel/components/AutocompleteGif.module.css';
|
import styles from '@app/features/channel/components/AutocompleteGif.module.css';
|
||||||
import * as KlipyUtils from '@app/features/expressions/utils/KlipyUtils';
|
import * as KlipyUtils from '@app/features/expressions/utils/KlipyUtils';
|
||||||
import {GIFS_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
|
import {GIFS_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
|
||||||
|
import {buildStaticGifPreviewURL} from '@app/features/messaging/utils/MediaProxyUtils';
|
||||||
import {Scroller, type ScrollerHandle} from '@app/features/ui/components/Scroller';
|
import {Scroller, type ScrollerHandle} from '@app/features/ui/components/Scroller';
|
||||||
import {msg} from '@lingui/core/macro';
|
import {msg} from '@lingui/core/macro';
|
||||||
import {useLingui} from '@lingui/react/macro';
|
import {useLingui} from '@lingui/react/macro';
|
||||||
@@ -16,22 +18,56 @@ const NO_GIFS_FOUND_DESCRIPTOR = msg({
|
|||||||
message: 'No GIFs match',
|
message: 'No GIFs match',
|
||||||
comment: 'Empty-state text in the channel and chat autocomplete gif.',
|
comment: 'Empty-state text in the channel and chat autocomplete gif.',
|
||||||
});
|
});
|
||||||
const AutocompleteGifVideo = ({src}: {src: string}) => {
|
const PLAYABLE_PREVIEW_EXTENSION_PATTERN = /\.(mp4|webm|mov|m4v)(?:$|\?)/iu;
|
||||||
|
|
||||||
|
function isPlayablePreviewSource(value: string): boolean {
|
||||||
|
try {
|
||||||
|
return PLAYABLE_PREVIEW_EXTENSION_PATTERN.test(new URL(value).pathname);
|
||||||
|
} catch {
|
||||||
|
return PLAYABLE_PREVIEW_EXTENSION_PATTERN.test(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const AutocompleteGifVideo = ({src, motionAllowed}: {src: string; motionAllowed: boolean}) => {
|
||||||
const videoRef = useRef<HTMLVideoElement>(null);
|
const videoRef = useRef<HTMLVideoElement>(null);
|
||||||
const playbackAllowed = useAnimatedMediaVideoPlayback(videoRef);
|
const playbackAllowed = useAnimatedMediaVideoPlayback(videoRef, {shouldPlay: motionAllowed});
|
||||||
return (
|
return (
|
||||||
<video
|
<video
|
||||||
ref={videoRef}
|
ref={videoRef}
|
||||||
src={src}
|
|
||||||
className={styles.gifVideo}
|
className={styles.gifVideo}
|
||||||
muted
|
muted
|
||||||
autoPlay={playbackAllowed}
|
autoPlay={motionAllowed && playbackAllowed}
|
||||||
loop
|
loop
|
||||||
playsInline
|
playsInline
|
||||||
|
preload={motionAllowed ? 'auto' : 'metadata'}
|
||||||
|
src={src}
|
||||||
data-flx="channel.autocomplete-gif.gif-video"
|
data-flx="channel.autocomplete-gif.gif-video"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const AutocompleteGifPreview = observer(({src, isActive}: {src: string; isActive: boolean}) => {
|
||||||
|
const motionAllowed = useShouldAnimate({kind: 'gif', isHovering: isActive});
|
||||||
|
if (src.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (isPlayablePreviewSource(src)) {
|
||||||
|
return (
|
||||||
|
<AutocompleteGifVideo
|
||||||
|
src={src}
|
||||||
|
motionAllowed={motionAllowed}
|
||||||
|
data-flx="channel.autocomplete-gif.autocomplete-gif-video"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
src={motionAllowed ? src : buildStaticGifPreviewURL(src)}
|
||||||
|
alt=""
|
||||||
|
className={styles.gifVideo}
|
||||||
|
data-flx="channel.autocomplete-gif.gif-image"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
export const AutocompleteGif = observer(
|
export const AutocompleteGif = observer(
|
||||||
({
|
({
|
||||||
onSelect,
|
onSelect,
|
||||||
@@ -117,9 +153,10 @@ export const AutocompleteGif = observer(
|
|||||||
data-flx="channel.autocomplete-gif.gif-button.select"
|
data-flx="channel.autocomplete-gif.gif-button.select"
|
||||||
>
|
>
|
||||||
<div className={styles.gifVideoWrapper} data-flx="channel.autocomplete-gif.gif-video-wrapper">
|
<div className={styles.gifVideoWrapper} data-flx="channel.autocomplete-gif.gif-video-wrapper">
|
||||||
<AutocompleteGifVideo
|
<AutocompleteGifPreview
|
||||||
src={gif.proxy_src}
|
src={gif.proxy_src}
|
||||||
data-flx="channel.autocomplete-gif.autocomplete-gif-video"
|
isActive={isActive}
|
||||||
|
data-flx="channel.autocomplete-gif.autocomplete-gif-preview"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,30 +1,12 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import {useAnimatedMediaVideoPlayback} from '@app/features/app/hooks/useAnimatedMediaPlayback';
|
|
||||||
import {type AutocompleteOption, isMeme} from '@app/features/channel/components/Autocomplete';
|
import {type AutocompleteOption, isMeme} from '@app/features/channel/components/Autocomplete';
|
||||||
import styles from '@app/features/channel/components/AutocompleteEmoji.module.css';
|
import styles from '@app/features/channel/components/AutocompleteEmoji.module.css';
|
||||||
import {AutocompleteItem} from '@app/features/channel/components/AutocompleteItem';
|
import {AutocompleteItem} from '@app/features/channel/components/AutocompleteItem';
|
||||||
import {MusicNoteIcon} from '@phosphor-icons/react';
|
import {AutocompleteMemePreview} from '@app/features/channel/components/AutocompleteMemePreview';
|
||||||
import {observer} from 'mobx-react-lite';
|
import {observer} from 'mobx-react-lite';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import {useRef} from 'react';
|
|
||||||
|
|
||||||
const AutocompleteMemeVideo = ({src}: {src: string}) => {
|
|
||||||
const videoRef = useRef<HTMLVideoElement>(null);
|
|
||||||
const playbackAllowed = useAnimatedMediaVideoPlayback(videoRef);
|
|
||||||
return (
|
|
||||||
<video
|
|
||||||
ref={videoRef}
|
|
||||||
src={src}
|
|
||||||
className={styles.memeVideo}
|
|
||||||
muted
|
|
||||||
autoPlay={playbackAllowed}
|
|
||||||
loop
|
|
||||||
playsInline
|
|
||||||
data-flx="channel.autocomplete-meme.meme-video"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export const AutocompleteMeme = observer(
|
export const AutocompleteMeme = observer(
|
||||||
({
|
({
|
||||||
onSelect,
|
onSelect,
|
||||||
@@ -54,28 +36,10 @@ export const AutocompleteMeme = observer(
|
|||||||
description={option.meme.tags.length > 0 ? option.meme.tags.join(', ') : undefined}
|
description={option.meme.tags.length > 0 ? option.meme.tags.join(', ') : undefined}
|
||||||
icon={
|
icon={
|
||||||
<div className={styles.memeIconWrapper} data-flx="channel.autocomplete-meme.meme-icon-wrapper">
|
<div className={styles.memeIconWrapper} data-flx="channel.autocomplete-meme.meme-icon-wrapper">
|
||||||
{option.meme.contentType.startsWith('video/') || option.meme.contentType.includes('gif') ? (
|
<AutocompleteMemePreview
|
||||||
<AutocompleteMemeVideo
|
meme={option.meme}
|
||||||
src={option.meme.url}
|
data-flx="channel.autocomplete-meme.autocomplete-meme-preview"
|
||||||
data-flx="channel.autocomplete-meme.autocomplete-meme-video"
|
/>
|
||||||
/>
|
|
||||||
) : option.meme.contentType.startsWith('audio/') ? (
|
|
||||||
<div className={styles.audioIconWrapper} data-flx="channel.autocomplete-meme.audio-icon-wrapper">
|
|
||||||
<MusicNoteIcon
|
|
||||||
className={styles.audioIcon}
|
|
||||||
weight="fill"
|
|
||||||
data-flx="channel.autocomplete-meme.audio-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<img
|
|
||||||
draggable={false}
|
|
||||||
className={styles.memeIcon}
|
|
||||||
src={option.meme.url}
|
|
||||||
alt={option.meme.name}
|
|
||||||
data-flx="channel.autocomplete-meme.meme-icon"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
isKeyboardSelected={index === keyboardFocusIndex}
|
isKeyboardSelected={index === keyboardFocusIndex}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import {useAnimatedMediaVideoPlayback} from '@app/features/app/hooks/useAnimatedMediaPlayback';
|
||||||
|
import {useShouldAnimate} from '@app/features/app/hooks/useShouldAnimate';
|
||||||
|
import styles from '@app/features/channel/components/AutocompleteEmoji.module.css';
|
||||||
|
import type {FavoriteMeme} from '@app/features/expressions/models/FavoriteMeme';
|
||||||
|
import {buildStaticGifPreviewURL} from '@app/features/messaging/utils/MediaProxyUtils';
|
||||||
|
import {MusicNoteIcon} from '@phosphor-icons/react';
|
||||||
|
import {observer} from 'mobx-react-lite';
|
||||||
|
import {useRef} from 'react';
|
||||||
|
|
||||||
|
const AutocompleteMemeVideo = ({src}: {src: string}) => {
|
||||||
|
const videoRef = useRef<HTMLVideoElement>(null);
|
||||||
|
const playbackAllowed = useAnimatedMediaVideoPlayback(videoRef);
|
||||||
|
return (
|
||||||
|
<video
|
||||||
|
ref={videoRef}
|
||||||
|
className={styles.memeVideo}
|
||||||
|
muted
|
||||||
|
autoPlay={playbackAllowed}
|
||||||
|
loop
|
||||||
|
playsInline
|
||||||
|
preload="auto"
|
||||||
|
src={src}
|
||||||
|
data-flx="channel.autocomplete-meme-preview.meme-video"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const AutocompleteMemePreview = observer(({meme}: {meme: FavoriteMeme}) => {
|
||||||
|
const contentType = meme.contentType.toLowerCase();
|
||||||
|
const isAudioMeme = contentType.startsWith('audio/');
|
||||||
|
const isVideoMeme = contentType.startsWith('video/');
|
||||||
|
const isAnimatedImageMeme = !isVideoMeme && !isAudioMeme && contentType.includes('gif');
|
||||||
|
const motionAllowed = useShouldAnimate({kind: 'gif', isAnimated: isVideoMeme || isAnimatedImageMeme});
|
||||||
|
if (isAudioMeme) {
|
||||||
|
return (
|
||||||
|
<div className={styles.audioIconWrapper} data-flx="channel.autocomplete-meme-preview.audio-icon-wrapper">
|
||||||
|
<MusicNoteIcon
|
||||||
|
className={styles.audioIcon}
|
||||||
|
weight="fill"
|
||||||
|
data-flx="channel.autocomplete-meme-preview.audio-icon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isVideoMeme && motionAllowed) {
|
||||||
|
return (
|
||||||
|
<AutocompleteMemeVideo src={meme.url} data-flx="channel.autocomplete-meme-preview.autocomplete-meme-video" />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const needsStillFrame = (isVideoMeme || isAnimatedImageMeme) && !motionAllowed;
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
draggable={false}
|
||||||
|
className={styles.memeIcon}
|
||||||
|
src={needsStillFrame ? buildStaticGifPreviewURL(meme.url) : meme.url}
|
||||||
|
alt={meme.name}
|
||||||
|
aria-hidden={true}
|
||||||
|
data-flx="channel.autocomplete-meme-preview.meme-icon"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -10,15 +10,16 @@ import {observer} from 'mobx-react-lite';
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
|
||||||
const AutocompleteStickerIcon = observer(
|
const AutocompleteStickerIcon = observer(
|
||||||
({id, name, isInteracting}: {id: string; name: string; isInteracting: boolean}) => {
|
({id, name, animated, isInteracting}: {id: string; name: string; animated: boolean; isInteracting: boolean}) => {
|
||||||
const {shouldAnimate} = useStickerAnimation({isInteracting});
|
const {shouldAnimate} = useStickerAnimation({isInteracting, isAnimated: animated});
|
||||||
return (
|
return (
|
||||||
<div className={styles.stickerIconWrapper} data-flx="channel.autocomplete-sticker.sticker-icon-wrapper">
|
<div className={styles.stickerIconWrapper} data-flx="channel.autocomplete-sticker.sticker-icon-wrapper">
|
||||||
<img
|
<img
|
||||||
draggable={false}
|
draggable={false}
|
||||||
className={styles.stickerIcon}
|
className={styles.stickerIcon}
|
||||||
src={AvatarUtils.getStickerURL({id, animated: shouldAnimate, size: 320})}
|
src={AvatarUtils.getStickerURL({id, animated: shouldAnimate, isAnimatable: animated, size: 320})}
|
||||||
alt={name}
|
alt={name}
|
||||||
|
aria-hidden={true}
|
||||||
data-flx="channel.autocomplete-sticker.sticker-icon"
|
data-flx="channel.autocomplete-sticker.sticker-icon"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,6 +59,7 @@ export const AutocompleteSticker = observer(
|
|||||||
<AutocompleteStickerIcon
|
<AutocompleteStickerIcon
|
||||||
id={option.sticker.id}
|
id={option.sticker.id}
|
||||||
name={option.sticker.name}
|
name={option.sticker.name}
|
||||||
|
animated={option.sticker.animated}
|
||||||
isInteracting={index === keyboardFocusIndex || index === hoverIndex}
|
isInteracting={index === keyboardFocusIndex || index === hoverIndex}
|
||||||
data-flx="channel.autocomplete-sticker.autocomplete-sticker-icon"
|
data-flx="channel.autocomplete-sticker.autocomplete-sticker-icon"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in new issue
Block a user