diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js index 9ff497a30f..53dbddf4bd 100644 --- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js +++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js @@ -11,7 +11,8 @@ import useMessageStore from '../../store/messageStore'; import { getCommonRecorderStyles } from './ChatInput.styles'; import useAttachmentWindowStore from '../../store/attachmentwindow'; -const AudioMessageRecorder = ({ disabled }) => { +const AudioMessageRecorder = (props) => { + const { disabled, displayName, popOverItemStyles } = props; const videoRef = useRef(null); const { theme } = useTheme(); const styles = getCommonRecorderStyles(theme); @@ -136,7 +137,17 @@ const AudioMessageRecorder = ({ disabled }) => { }, [isRecorded, file]); if (state === 'idle') { - return ( + return displayName ? ( + + + {displayName} + + ) : ( { disabled={!isUserAuthenticated || !canSendMsg || isRecordingMessage} placeholder={ isUserAuthenticated && canSendMsg - ? `Message #${channelInfo.name}` + ? `Message ${channelInfo.name ? `#${channelInfo.name}` : ''}` : isUserAuthenticated ? 'This room is read only' : 'Sign in to chat' diff --git a/packages/react/src/views/ChatInput/ChatInput.styles.js b/packages/react/src/views/ChatInput/ChatInput.styles.js index 21e7a24736..b193d06922 100644 --- a/packages/react/src/views/ChatInput/ChatInput.styles.js +++ b/packages/react/src/views/ChatInput/ChatInput.styles.js @@ -10,6 +10,10 @@ export const getChatInputStyles = (theme) => { &.focused { border: ${`1.5px solid ${theme.colors.ring}`}; } + @media (max-width: 500px) { + margin: 0; + width: 100%; + } `, editMessage: css` @@ -80,10 +84,27 @@ export const getChatInputFormattingToolbarStyles = ({ theme, mode }) => { position: relative; gap: 0.1rem; border-radius: 0 0 ${theme.radius} ${theme.radius}; - @media (max-width: 383px) { - display: grid; - grid-template-columns: repeat(5, 0.2fr); - } + `, + popOverStyles: css` + position: absolute; + bottom: 3rem; + left: 0; + width: 100%; + background: ${theme.colors.background}; + box-shadow: 0 -8px 10px ${mode === 'light' ? darken(theme.colors.background, 0.1) : lighten(theme.colors.background, 1)}; + border-radius: 8px; + padding: 1rem; + display: flex; + flex-direction: column; + align-items: flex-start; + z-index: 1300; + `, + popOverItemStyles: css` + display: flex; + gap: 0.5rem; + align-items: center; + cursor: pointer; + padding: 0.5rem; `, }; return styles; @@ -101,8 +122,8 @@ export const getCommonRecorderStyles = (theme) => { `, controller: css` - display: flex; gap: 0.15rem; + display: inline-flex; `, timer: css` diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js index 523b9ef976..5d8c20a600 100644 --- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js +++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; import { css } from '@emotion/react'; import { Box, @@ -24,6 +24,8 @@ const ChatInputFormattingToolbar = ({ optionConfig = { surfaceItems: ['emoji', 'formatter', 'link', 'audio', 'video', 'file'], formatters: ['bold', 'italic', 'strike', 'code', 'multiline'], + smallScreenSurfaceItems: ['emoji', 'video', 'audio', 'file'], + popOverItems: ['formatter', 'link'], }, }) => { const { classNames, styleOverrides, configOverrides } = useComponentOverrides( @@ -35,18 +37,27 @@ const ChatInputFormattingToolbar = ({ configOverrides.optionConfig?.surfaceItems || optionConfig.surfaceItems; const formatters = configOverrides.optionConfig?.formatters || optionConfig.formatters; - + const smallScreenSurfaceItems = + configOverrides.optionConfig?.smallScreenSurfaceItems || + optionConfig.smallScreenSurfaceItems; + const popOverItems = + configOverrides.optionConfig?.popOverItems || optionConfig.popOverItems; const isRecordingMessage = useMessageStore( (state) => state.isRecordingMessage ); const [isEmojiOpen, setEmojiOpen] = useState(false); const [isInsertLinkOpen, setInsertLinkOpen] = useState(false); + const [isPopoverOpen, setPopoverOpen] = useState(false); + const popoverRef = useRef(null); const handleClickToOpenFiles = () => { inputRef.current.click(); }; - + const handleFormatterClick = (item) => { + formatSelection(messageRef, item.pattern); + setPopoverOpen(false); + }; const handleEmojiClick = (emojiEvent) => { const [emoji] = emojiEvent.names; const message = `${messageRef.current.value} :${emoji.replace( @@ -73,77 +84,158 @@ const ChatInputFormattingToolbar = ({ }; const chatToolMap = { - emoji: ( - - { if (isRecordingMessage) return; setEmojiOpen(true); }} > - - - + + emoji + + ) : ( + + { + if (isRecordingMessage) return; + setEmojiOpen(true); + }} + > + + + + ), + + audio: ( + ), - audio: , - video: , - file: ( - - + ), + file: + isPopoverOpen && popOverItems.includes('file') ? ( + { if (isRecordingMessage) return; handleClickToOpenFiles(); }} > - - - - ), - link: ( - - + file + + ) : ( + + { + if (isRecordingMessage) return; + handleClickToOpenFiles(); + }} + > + + + + ), + link: + isPopoverOpen && popOverItems.includes('link') ? ( + { + if (isRecordingMessage) return; setInsertLinkOpen(true); }} > - - - - ), - formatter: formatters - .map((name) => formatter.find((item) => item.name === name)) - .map((item) => ( - + + link + + ) : ( + { if (isRecordingMessage) return; - formatSelection(messageRef, item.pattern); + setInsertLinkOpen(true); }} > - + - )), + ), + formatter: formatters + .map((name) => formatter.find((item) => item.name === name)) + .map((item) => + isPopoverOpen && popOverItems.includes('formatter') ? ( + <> + { + if (isRecordingMessage) return; + handleFormatterClick(item); + }} + css={styles.popOverItemStyles} + > + + {item.name} + + + ) : ( + + { + if (isRecordingMessage) return; + formatSelection(messageRef, item.pattern); + }} + > + + + + ) + ), }; return ( @@ -152,8 +244,95 @@ const ChatInputFormattingToolbar = ({ className={`ec-chat-input-formatting-toolbar ${classNames}`} style={styleOverrides} > - {surfaceItems.map((key) => chatToolMap[key])} + + {surfaceItems.map((key) => chatToolMap[key])} + + {isPopoverOpen && ( + + {popOverItems.map((name) => { + const itemInFormatter = formatter.find( + (item) => item.name === name + ); + if (itemInFormatter) { + return ( + handleFormatterClick(itemInFormatter)} + css={styles.popOverItemStyles} + > + + {itemInFormatter.name} + + ); + } + return chatToolMap[name]; + })} + + )} + + {smallScreenSurfaceItems.map((name) => { + const itemInFormatter = formatter.find((item) => item.name === name); + if (itemInFormatter) { + return ( + + + formatSelection(messageRef, itemInFormatter.pattern) + } + > + + + + ); + } + return chatToolMap[name]; + })} + {popOverItems.length > 0 && ( + + { + if (isRecordingMessage) return; + setPopoverOpen(!isPopoverOpen); + }} + > + + + + )} + {isEmojiOpen && ( )} diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js index eeb8c394e0..814c2093aa 100644 --- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js +++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js @@ -13,8 +13,9 @@ import useMessageStore from '../../store/messageStore'; import { getCommonRecorderStyles } from './ChatInput.styles'; import useAttachmentWindowStore from '../../store/attachmentwindow'; -const VideoMessageRecorder = ({ disabled }) => { +const VideoMessageRecorder = (props) => { const videoRef = useRef(null); + const { disabled, displayName, popOverItemStyles } = props; const { theme } = useTheme(); const styles = getCommonRecorderStyles(theme); @@ -146,18 +147,29 @@ const VideoMessageRecorder = ({ disabled }) => { return ( <> - {state === 'idle' && ( - - - - - - )} + + {displayName} + + ) : ( + + + + + + ))} {state === 'recording' && ( <> diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js index 1b6619ea95..61c5c8d05f 100644 --- a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js +++ b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js @@ -14,6 +14,11 @@ const getQuoteMessageStyles = (theme) => { border-radius: ${theme.radius}; max-width: 100%; box-sizing: border-box; + + @media (max-width: 500px) { + margin: 0; + width: 100%; + } `, avatarContainer: css`