Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ const ChatInputFormattingToolbar = ({
const [isInsertLinkOpen, setInsertLinkOpen] = useState(false);
const [isPopoverOpen, setPopoverOpen] = useState(false);
const popoverRef = useRef(null);
const emojiTimeoutRef = useRef(null);

const handleEmojiClose = () => {
if (emojiTimeoutRef.current) {
clearTimeout(emojiTimeoutRef.current);
}
emojiTimeoutRef.current = setTimeout(() => {
setEmojiOpen(false);
}, 300);
};

useEffect(() => {
return () => {
if (emojiTimeoutRef.current) {
clearTimeout(emojiTimeoutRef.current);
}
};
}, []);

const handleClickToOpenFiles = () => {
inputRef.current.click();
Expand Down Expand Up @@ -296,9 +314,8 @@ const ChatInputFormattingToolbar = ({
if (itemInFormatter) {
return (
<Tooltip
text={`${itemInFormatter.name} ${
itemInFormatter.shortcut && `(${itemInFormatter.shortcut})`
}`}
text={`${itemInFormatter.name} ${itemInFormatter.shortcut && `(${itemInFormatter.shortcut})`
}`}
position="top"
key={`formatter-${itemInFormatter.name}`}
>
Expand Down Expand Up @@ -341,10 +358,10 @@ const ChatInputFormattingToolbar = ({
<EmojiPicker
key="emoji-picker"
handleEmojiClick={(emoji) => {
setEmojiOpen(false);
handleEmojiClick(emoji);
handleEmojiClose();
}}
onClose={() => setEmojiOpen(false)}
onClose={handleEmojiClose}
positionStyles={css`
position: absolute;
bottom: 7rem;
Expand Down
98 changes: 58 additions & 40 deletions packages/react/src/views/EmojiPicker/EmojiPicker.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,71 @@
import React from 'react';
import React, { useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import EmojiPicker from 'emoji-picker-react';
import { css } from '@emotion/react';
import PropTypes from 'prop-types';
import { Box, Popup, useTheme } from '@embeddedchat/ui-elements';
import { Box, useTheme } from '@embeddedchat/ui-elements';
import getEmojiPickerStyles from './EmojiPicker.styles';

const CustomEmojiPicker = ({
handleEmojiClick,
positionStyles = css`
position: absolute;
top: 0;
right: 0;
`,
wrapperId = 'emoji-popup',
onClose = () => {},
onClose = () => { },
}) => {
const theme = useTheme();
const styles = getEmojiPickerStyles(theme);
const previewConfig = {
defaultEmoji: '1f60d',
defaultCaption: 'None',
showPreview: true,
const isMountedRef = useRef(true);

useEffect(() => {
isMountedRef.current = true;
return () => {
isMountedRef.current = false;
};
}, []);

const internalHandleEmojiClick = (emojiData, event) => {
if (isMountedRef.current) {
handleEmojiClick(emojiData, event);
}
};

return (
<Popup
positionStyles={positionStyles}
wrapperId={wrapperId}
onClose={onClose}
height="auto"
width="auto"
>
<Box css={styles.emojiPicker}>
<EmojiPicker
height={400}
width={350}
onEmojiClick={handleEmojiClick}
previewConfig={previewConfig}
searchDisabled={false}
emojiStyle="facebook"
lazyLoadEmojis
/>
</Box>
</Popup>
);
};
const portalStyles = {
position: 'fixed',
bottom: '100px',
left: '50%',
transform: 'translateX(-50%)',
zIndex: 99999,
backgroundColor: '#fff',
borderRadius: '12px',
boxShadow: '0px 8px 30px rgba(0,0,0,0.2)',
border: '1px solid #ebebeb',
width: 'min(350px, 90vw)',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
};

const pickerUI = (
<>
<div
onClick={onClose}
style={{ position: 'fixed', inset: 0, zIndex: 99998, background: 'rgba(0,0,0,0.05)' }}
/>

export default CustomEmojiPicker;
<div style={portalStyles}>
<Box style={{ padding: 0, margin: 0, border: 'none', display: 'block' }}>
<EmojiPicker
height={400}
width="100%"
onEmojiClick={internalHandleEmojiClick}
previewConfig={{ showPreview: true, defaultCaption: 'None' }}
emojiStyle="facebook"
lazyLoadEmojis
searchDisabled={false}
skinTonesDisabled
/>
</Box>
</div>
</>
);

CustomEmojiPicker.propTypes = {
handleEmojiClick: PropTypes.func,
return createPortal(pickerUI, document.body);
};

export default CustomEmojiPicker;
36 changes: 27 additions & 9 deletions packages/react/src/views/Message/MessageToolbox.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useContext, useMemo } from 'react';
import React, { useState, useContext, useMemo, useRef, useEffect } from 'react';
import {
Box,
Modal,
Expand Down Expand Up @@ -76,6 +76,24 @@ export const MessageToolbox = ({
const [isEmojiOpen, setEmojiOpen] = useState(false);

const [showDeleteModal, setShowDeleteModal] = useState(false);
const emojiTimeoutRef = useRef(null);

const handleEmojiClose = () => {
if (emojiTimeoutRef.current) {
clearTimeout(emojiTimeoutRef.current);
}
emojiTimeoutRef.current = setTimeout(() => {
setEmojiOpen(false);
}, 300);
};

useEffect(() => {
return () => {
if (emojiTimeoutRef.current) {
clearTimeout(emojiTimeoutRef.current);
}
};
}, []);

const handleOnClose = () => {
setShowDeleteModal(false);
Expand Down Expand Up @@ -108,10 +126,10 @@ export const MessageToolbox = ({
const canDeleteMessage = isAllowedToForceDeleteMessage
? true
: isAllowedToDeleteMessage
? true
: isAllowedToDeleteOwnMessage
? message.u._id === authenticatedUserId
: false;
? true
: isAllowedToDeleteOwnMessage
? message.u._id === authenticatedUserId
: false;

const options = useMemo(
() => ({
Expand All @@ -132,14 +150,14 @@ export const MessageToolbox = ({
star: {
label:
message.starred &&
message.starred.find((u) => u._id === authenticatedUserId)
message.starred.find((u) => u._id === authenticatedUserId)
? 'Unstar'
: 'Star',
id: 'star',
onClick: () => handleStarMessage(message),
iconName:
message.starred &&
message.starred.find((u) => u._id === authenticatedUserId)
message.starred.find((u) => u._id === authenticatedUserId)
? 'star-filled'
: 'star',
visible: true,
Expand Down Expand Up @@ -268,10 +286,10 @@ export const MessageToolbox = ({
{isEmojiOpen && (
<EmojiPicker
handleEmojiClick={(emoji) => {
setEmojiOpen(false);
handleEmojiClick(emoji, message, true);
handleEmojiClose();
}}
onClose={() => setEmojiOpen(false)}
onClose={handleEmojiClose}
positionStyles={
variantStyles.emojiPickerStyles || styles.emojiPickerStyles
}
Expand Down