Skip to content

Commit

Permalink
make message composer configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
abirc8010 committed Dec 28, 2024
1 parent 0cc4ce4 commit e3a962a
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 88 deletions.
14 changes: 12 additions & 2 deletions packages/react/src/views/ChatInput/AudioMessageRecorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import RCContext from '../../context/RCInstance';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';

const AudioMessageRecorder = () => {
const AudioMessageRecorder = (props) => {
const { displayName, popOverItemStyles } = props;
const videoRef = useRef(null);
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
Expand Down Expand Up @@ -138,7 +139,16 @@ const AudioMessageRecorder = () => {
}, [isRecorded, file]);

if (state === 'idle') {
return (
return displayName ? (
<Box
key="audio"
css={popOverItemStyles}
onClick={handleRecordButtonClick}
>
<Icon name="mic" size="1rem" />
<span>{displayName}</span>
</Box>
) : (
<ActionButton ghost square onClick={handleRecordButtonClick}>
<Icon size="1.25rem" name="mic" />
</ActionButton>
Expand Down
263 changes: 183 additions & 80 deletions packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ const ChatInputFormattingToolbar = ({
optionConfig = {
surfaceItems: ['emoji', 'formatter', 'audio', 'video', 'file'],
formatters: ['bold', 'italic', 'strike', 'code', 'multiline'],
smallScreenSurfaceItems: [
'emoji',
'popoverItems',
'audio',
'video',
'file',
],
popOverItems: ['formatter'],
},
}) => {
const { classNames, styleOverrides, configOverrides } = useComponentOverrides(
Expand All @@ -34,7 +42,11 @@ 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
);
Expand All @@ -59,7 +71,10 @@ const ChatInputFormattingToolbar = ({
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(
Expand All @@ -70,52 +85,141 @@ const ChatInputFormattingToolbar = ({
};

const chatToolMap = {
emoji:
isPopoverOpen && popOverItems.includes('emoji') ? (
<Box
key="emoji"
css={styles.popOverItemStyles}
disabled={isRecordingMessage}
onClick={() => {
setEmojiOpen(true);
}}
>
<Icon name="emoji" size="1rem" />
<span>emoji</span>
</Box>
) : (
<Tooltip text="Emoji" position="top" key="emoji-btn">
<ActionButton
square
ghost
disabled={isRecordingMessage}
onClick={() => {
setEmojiOpen(true);
}}
>
<Icon name="emoji" size="1.25rem" />
</ActionButton>
</Tooltip>
),

audio: (
<Tooltip text="Audio Message" position="top" key="audio">
<AudioMessageRecorder />
<AudioMessageRecorder
displayName={
isPopoverOpen && popOverItems.includes('audio') ? 'audio' : null
}
popOverItemStyles={styles.popOverItemStyles}
/>
</Tooltip>
),
video: (
<Tooltip text="Video Message" position="top" key="video">
<VideoMessageRecorder />
<VideoMessageRecorder
displayName={
isPopoverOpen && popOverItems.includes('video') ? 'video' : null
}
popOverItemStyles={styles.popOverItemStyles}
/>
</Tooltip>
),
file: (
<Tooltip text="Upload File" position="top" key="file">
file:
isPopoverOpen && popOverItems.includes('file') ? (
<Box
key="file"
css={styles.popOverItemStyles}
disabled={isRecordingMessage}
onClick={handleClickToOpenFiles}
>
<Icon name="attachment" size="1rem" />
<span>file</span>
</Box>
) : (
<Tooltip text="Upload File" position="top" key="file">
<ActionButton
square
ghost
disabled={isRecordingMessage}
onClick={handleClickToOpenFiles}
>
<Icon name="attachment" size="1.25rem" />
</ActionButton>
</Tooltip>
),
formatter: formatters
.map((name) => formatter.find((item) => item.name === name))
.map((item) =>
isPopoverOpen && popOverItems.includes('formatter') ? (
<>
<Box
key={item.name}
disabled={isRecordingMessage}
onClick={() => {
handleFormatterClick(item);
}}
css={styles.popOverItemStyles}
>
<Icon
disabled={isRecordingMessage}
name={item.name}
size="1rem"
/>
<span>{item.name}</span>
</Box>
</>
) : (
<Tooltip
text={item.name}
position="top"
key={`formatter-${item.name}`}
>
<ActionButton
square
disabled={isRecordingMessage}
ghost
onClick={() => {
formatSelection(messageRef, item.pattern);
}}
>
<Icon
disabled={isRecordingMessage}
name={item.name}
size="1.25rem"
/>
</ActionButton>
</Tooltip>
)
),
popoverItems: (
<Tooltip text="More" position="top" key="more-btn">
<ActionButton
square
ghost
disabled={isRecordingMessage}
onClick={handleClickToOpenFiles}
onClick={() => setPopoverOpen(true)}
>
<Icon name="attachment" size="1.25rem" />
<Icon name="kebab" size="1.25rem" />
</ActionButton>
</Tooltip>
),
};

const handleFormatterClick = (item) => {
formatSelection(messageRef, item.pattern);
setPopoverOpen(false);
};

return (
<Box
css={styles.chatFormat}
className={`ec-chat-input-formatting-toolbar ${classNames}`}
style={styleOverrides}
>
<Tooltip text="Emoji" position="top" key="emoji-btn">
<ActionButton
square
ghost
disabled={isRecordingMessage}
onClick={() => setEmojiOpen(true)}
>
<Icon name="emoji" size="1.25rem" />
</ActionButton>
</Tooltip>

<Box
css={css`
display: flex;
Expand All @@ -124,29 +228,35 @@ const ChatInputFormattingToolbar = ({
}
`}
>
{formatters
.map((name) => formatter.find((item) => item.name === name))
.map((item) => (
<Tooltip
text={item.name}
position="top"
key={`formatter-${item.name}`}
>
<ActionButton
square
disabled={isRecordingMessage}
ghost
onClick={() => formatSelection(messageRef, item.pattern)}
>
<Icon
disabled={isRecordingMessage}
name={item.name}
size="1.25rem"
/>
</ActionButton>
</Tooltip>
))}
{surfaceItems.map((key) => chatToolMap[key])}
</Box>
{isPopoverOpen && (
<Box ref={popoverRef} css={styles.popOverStyles}>
{popOverItems.map((name) => {
const itemInFormatter = formatter.find(
(item) => item.name === name
);
if (itemInFormatter) {
return (
<Box
key={itemInFormatter.name}
disabled={isRecordingMessage}
onClick={() => handleFormatterClick(itemInFormatter)}
css={styles.popOverItemStyles}
>
<Icon
disabled={isRecordingMessage}
name={itemInFormatter.name}
size="1rem"
/>
<span>{itemInFormatter.name}</span>
</Box>
);
}
return chatToolMap[name];
})}
</Box>
)}

<Box
css={css`
Expand All @@ -155,42 +265,35 @@ const ChatInputFormattingToolbar = ({
}
`}
>
<Tooltip text="More" position="top" key="more-btn">
<ActionButton
square
ghost
disabled={isRecordingMessage}
onClick={() => setPopoverOpen(true)}
>
<Icon name="kebab" size="1.25rem" />
</ActionButton>
</Tooltip>
</Box>

{isPopoverOpen && (
<Box ref={popoverRef} css={styles.popOverStyles}>
{formatters
.map((name) => formatter.find((item) => item.name === name))
.map((item) => (
<Box
key={item.name}
disabled={isRecordingMessage}
onClick={() => handleFormatterClick(item)}
css={styles.popOverItemStyles}
{smallScreenSurfaceItems.map((name) => {
const itemInFormatter = formatter.find((item) => item.name === name);
if (itemInFormatter) {
return (
<Tooltip
text={itemInFormatter.name}
position="top"
key={`formatter-${itemInFormatter.name}`}
>
<Icon
<ActionButton
square
disabled={isRecordingMessage}
name={item.name}
size="1rem"
/>
<span>{item.name}</span>
</Box>
))}
</Box>
)}

{surfaceItems.map((key) => chatToolMap[key])}

ghost
onClick={() =>
formatSelection(messageRef, itemInFormatter.pattern)
}
>
<Icon
disabled={isRecordingMessage}
name={itemInFormatter.name}
size="1.25rem"
/>
</ActionButton>
</Tooltip>
);
}
return chatToolMap[name];
})}
</Box>
{isEmojiOpen && (
<EmojiPicker
key="emoji-picker"
Expand Down
23 changes: 17 additions & 6 deletions packages/react/src/views/ChatInput/VideoMessageRecoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import RCContext from '../../context/RCInstance';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';

const VideoMessageRecorder = () => {
const VideoMessageRecorder = (props) => {
const { displayName, popOverItemStyles } = props;
const videoRef = useRef(null);
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
Expand Down Expand Up @@ -154,11 +155,21 @@ const VideoMessageRecorder = () => {

return (
<>
{state === 'idle' && (
<ActionButton ghost square onClick={handleRecordButtonClick}>
<Icon size="1.25rem" name="video-recorder" />
</ActionButton>
)}
{state === 'idle' &&
(displayName ? (
<Box
key="video"
css={popOverItemStyles}
onClick={handleRecordButtonClick}
>
<Icon name="video-recorder" size="1rem" />
<span>{displayName}</span>
</Box>
) : (
<ActionButton ghost square onClick={handleRecordButtonClick}>
<Icon size="1.25rem" name="video-recorder" />
</ActionButton>
))}

{state === 'recording' && (
<>
Expand Down

0 comments on commit e3a962a

Please sign in to comment.