@100mslive/roomkit-react
Version:

155 lines (142 loc) • 4.21 kB
JSX
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useMedia } from 'react-use';
import {
selectIsLargeRoom,
selectLocalPeerID,
selectPeerNameByID,
useCustomEvent,
useHMSActions,
useHMSStore,
useHMSVanillaStore,
} from '@100mslive/react-sdk';
import { Box, Flex } from '../../Layout';
import { Text } from '../../Text';
import { config as cssConfig, keyframes } from '../../Theme';
import { EMOJI_REACTION_TYPE } from '../common/constants';
let emojiCount = 1;
const flyAndFade = keyframes({
'20%': { opacity: 1 },
'100%': { bottom: '60%', opacity: 0 },
});
const wiggleLeftRight = keyframes({
'0%': { marginLeft: '-50px' },
'100%': { marginLeft: '50px' },
});
const wiggleRightLeft = keyframes({
'0%': { marginLeft: '50px' },
'100%': { marginLeft: '-50px' },
});
const getStartingPoints = isMobile => {
let arr = [];
const min = 5;
const max = isMobile ? 30 : 20;
const inc = isMobile ? 8 : 5;
for (let i = min; i <= max; i += inc) {
arr.push(i);
}
return arr;
};
export function FlyingEmoji() {
const localPeerId = useHMSStore(selectLocalPeerID);
const vanillaStore = useHMSVanillaStore();
const hmsActions = useHMSActions();
const [emojis, setEmojis] = useState([]);
const isMobile = useMedia(cssConfig.media.md);
const isLargeRoom = useHMSStore(selectIsLargeRoom);
const startingPoints = useMemo(() => getStartingPoints(isMobile), [isMobile]);
const showFlyingEmoji = useCallback(
async ({ emojiId, senderId }) => {
if (!emojiId || !senderId || document.hidden) {
return;
}
let senderPeerName = vanillaStore.getState(selectPeerNameByID(senderId));
if (!senderPeerName && isLargeRoom) {
const sender = await hmsActions.getPeer(senderId);
senderPeerName = sender?.name;
}
const nameToShow = localPeerId === senderId ? 'You' : senderPeerName;
const startingPoint = startingPoints[emojiCount % startingPoints.length];
const id = emojiCount++;
setEmojis(emojis => {
return [
...emojis,
{
id: id,
emojiId: emojiId,
senderName: nameToShow,
startingPoint: `${startingPoint}%`,
wiggleType: Math.random() < 0.5 ? 0 : 1,
},
];
});
},
[vanillaStore, isLargeRoom, localPeerId, startingPoints, hmsActions],
);
useCustomEvent({
type: EMOJI_REACTION_TYPE,
onEvent: showFlyingEmoji,
});
useEffect(() => {
window.showFlyingEmoji = showFlyingEmoji;
}, [showFlyingEmoji]);
return (
<Box
css={{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
overflow: 'hidden',
pointerEvents: 'none',
userSelect: 'none',
zIndex: 999,
}}
>
{emojis.map(emoji => {
return (
<Flex
key={emoji.id}
css={{
left: emoji.startingPoint,
flexDirection: 'column',
alignItems: 'center',
position: 'absolute',
bottom: 0,
animation: `${flyAndFade()} 5s forwards, ${
emoji.wiggleType === 0 ? wiggleLeftRight() : wiggleRightLeft()
} 1s ease-in-out infinite alternate`,
}}
onAnimationEnd={() => setEmojis(emojis.filter(item => item.id !== emoji.id))}
>
<Box>
<em-emoji id={emoji.emojiId} size="48px" set="apple" />
</Box>
{emoji.senderName ? (
<Box
css={{
width: 'fit-content',
padding: '$2 $4',
background: '$surface_bright',
borderRadius: '$1',
}}
>
<Text
css={{
fontSize: '$space$6',
lineHeight: '$xs',
color: '$on_surface_high',
}}
>
{emoji.senderName}
</Text>
</Box>
) : (
''
)}
</Flex>
);
})}
</Box>
);
}