Feat: emoji-mart in the Chatbar instead of a list

This commit is contained in:
DuckieTM 2024-03-24 15:49:30 +01:00
parent 659a715374
commit ae267e9430
6 changed files with 53 additions and 32 deletions

View File

@ -11,10 +11,13 @@
"eslint": "eslint src --ext .ts,.tsx"
},
"dependencies": {
"@emoji-mart/data": "^1.1.2",
"@emoji-mart/react": "^1.1.1",
"@nitrots/nitro-renderer": "file:submodules/renderer",
"@tanstack/react-virtual": "^3.0.0-beta.60",
"dompurify": "^3.0.9",
"emoji-toolkit": "^7.0.1",
"emoji-mart": "^5.5.2",
"emoji-toolkit": "8.0.0",
"react": "^18.2.0",
"react-bootstrap": "^2.7.2",
"react-dom": "^18.2.0",

View File

@ -1,7 +1,8 @@
import { FC, MouseEvent, useEffect, useRef, useState } from 'react';
import { Overlay, Popover } from 'react-bootstrap';
import { Base, Flex, Grid, NitroCardContentView } from '../../../../common';
import { emojiList } from './EmojiList';
import data from '@emoji-mart/data'
import Picker from '@emoji-mart/react'
interface ChatInputEmojiSelectorViewProps
{
@ -16,6 +17,16 @@ export const ChatInputEmojiSelectorView: FC<ChatInputEmojiSelectorViewProps> = p
const iconRef = useRef<HTMLDivElement>(null);
const componentRef = useRef<HTMLDivElement>(null);
const handleEmojiSelect = (emoji: any) => {
addChatEmoji(emoji.native);
setSelectorVisible(false);
}
const addEmojiToChat = (emoji: string) => {
setChatValue(chatValue + emoji);
setIsTyping(true);
};
const handleClickOutside = (event: MouseEvent) => {
const className = 'emoji-icon';
if (componentRef.current && !componentRef.current.contains(event.target as Node) && !(event.target as Element).classList.contains(className)) {
@ -48,19 +59,9 @@ export const ChatInputEmojiSelectorView: FC<ChatInputEmojiSelectorViewProps> = p
return (
<>
<Base pointer onClick={toggleSelector} innerRef={iconRef}>🙂</Base>
<Overlay show={selectorVisible} target={iconRef} placement="top">
<Popover className="nitro-chat-style-selector-container">
<NitroCardContentView overflow="hidden" className="bg-transparent">
<Grid columnCount={3} overflow="auto">
{emojiList && emojiList.length > 0 && emojiList.map((emojiId) => {
return (
<Flex center pointer key={emojiId} onClick={(event) => selectEmoji(emojiId)}>
<Base className="emoji" textColor="black" style={{ fontSize: '20px' }}>{emojiId}</Base>
</Flex>
);
})}
</Grid>
</NitroCardContentView>
<Overlay show={selectorVisible} target={iconRef} placement="top-end">
<Popover>
<Picker data={data} onEmojiSelect={handleEmojiSelect} />
</Popover>
</Overlay>
</>

View File

@ -78,7 +78,15 @@
}
.nitro-chat-input-container .input-sizer input{
width: calc(100% - 80px)!important;
width: auto;
min-width: 1em;
grid-area: 1 / 2;
margin: 0;
resize: none;
background: none;
appearance: none;
border: none;
outline: none;
}
.nitro-chat-style-selector-container {

View File

@ -218,11 +218,11 @@ export const ChatInputView: FC<{}> = props =>
return styleIds;
}, []);
const addEmojiToChat = (emoji: string) =>
{
const addEmojiToChat = (emoji: string) => {
setChatValue(chatValue + emoji);
setIsTyping(true);
}
};
useEffect(() =>
{
document.body.addEventListener('keydown', onKeyDownEvent);
@ -247,7 +247,16 @@ export const ChatInputView: FC<{}> = props =>
<div className="nitro-chat-input-container" onMouseEnter={ () => setShowInfohabboPages(true) } onMouseLeave={ () => setTimeout(() => setShowInfohabboPages(false), 100) }>
<div className="input-sizer align-items-center">
{ !floodBlocked &&
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => updateChatInput(event.target.value) } onMouseDown={ event => setInputFocus() } /> }
<input
ref={ inputRef }
type="text"
className="chat-input"
placeholder={ LocalizeText('widgets.chatinput.default') }
value={ chatValue }
maxLength={ maxChatLength }
onChange={ event => updateChatInput(event.target.value) }
onMouseDown={ event => setInputFocus() } />
}
{ floodBlocked &&
<Text variant="danger">{ LocalizeText('chat.input.alert.flood', [ 'time' ], [ floodBlockedSeconds.toString() ]) } </Text> }
</div>

File diff suppressed because one or more lines are too long

View File

@ -8,15 +8,15 @@ interface ChatWidgetMessageViewProps
chat: ChatBubbleMessage;
makeRoom: (chat: ChatBubbleMessage) => void;
bubbleWidth?: number;
selectedEmoji?: string;
}
export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
{
const { chat = null, makeRoom = null, bubbleWidth = RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL } = props;
export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props => {
const { chat = null, makeRoom = null, bubbleWidth = RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL, selectedEmoji } = props;
const [ isVisible, setIsVisible ] = useState(false);
const [ isReady, setIsReady ] = useState<boolean>(false);
const { onClickChat = null } = useOnClickChat();
const elementRef = useRef<HTMLDivElement>();
const elementRef = useRef<HTMLDivElement>();;
const getBubbleWidth = useMemo(() =>
{
@ -78,7 +78,8 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
}, [ chat, isReady, isVisible, makeRoom ]);
return (
<div ref={ elementRef } className={ `bubble-container newbubblehe ${ isVisible ? 'visible' : 'invisible' }` } onClick={ event => GetRoomEngine().selectRoomObject(chat.roomId, chat.senderId, RoomObjectCategory.UNIT) }>
<div ref={elementRef} className={`bubble-container newbubblehe ${isVisible ? 'visible' : 'invisible'}`} onClick={event => GetRoomEngine().selectRoomObject(chat.roomId, chat.senderId, RoomObjectCategory.UNIT)}>
{selectedEmoji && <span>{selectedEmoji}</span>}
{ (chat.styleId === 0) &&
<div className="user-container-bg" style={ { backgroundColor: chat.color } } /> }
<div className={ `chat-bubble bubble-${ chat.styleId } type-${ chat.type }` } style={ { maxWidth: getBubbleWidth } }>