diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 5d8c20a600..44a053ad1b 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -1,4 +1,4 @@
-import React, { useState, useRef, useEffect } from 'react';
+import React, { useState, useRef } from 'react';
import { css } from '@emotion/react';
import {
Box,
@@ -17,6 +17,11 @@ import { getChatInputFormattingToolbarStyles } from './ChatInput.styles';
import formatSelection from '../../lib/formatSelection';
import InsertLinkToolBox from './InsertLinkToolBox';
+const MOBILE_BREAKPOINT = 499;
+
+const isMobileViewport = () =>
+ typeof window !== 'undefined' && window.innerWidth <= MOBILE_BREAKPOINT;
+
const ChatInputFormattingToolbar = ({
messageRef,
inputRef,
@@ -58,6 +63,14 @@ const ChatInputFormattingToolbar = ({
formatSelection(messageRef, item.pattern);
setPopoverOpen(false);
};
+ const openEmojiPicker = () => {
+ if (isMobileViewport()) {
+ messageRef.current?.blur?.();
+ }
+
+ setPopoverOpen(false);
+ setEmojiOpen(true);
+ };
const handleEmojiClick = (emojiEvent) => {
const [emoji] = emojiEvent.names;
const message = `${messageRef.current.value} :${emoji.replace(
@@ -92,7 +105,7 @@ const ChatInputFormattingToolbar = ({
disabled={isRecordingMessage}
onClick={() => {
if (isRecordingMessage) return;
- setEmojiOpen(true);
+ openEmojiPicker();
}}
>
@@ -106,7 +119,7 @@ const ChatInputFormattingToolbar = ({
disabled={isRecordingMessage}
onClick={() => {
if (isRecordingMessage) return;
- setEmojiOpen(true);
+ openEmojiPicker();
}}
>
@@ -341,6 +354,7 @@ const ChatInputFormattingToolbar = ({
handleEmojiClick(emoji);
}}
onClose={() => setEmojiOpen(false)}
+ useMobileBottomSheet={isMobileViewport()}
positionStyles={css`
position: absolute;
bottom: 7rem;
diff --git a/packages/react/src/views/EmojiPicker/EmojiPicker.js b/packages/react/src/views/EmojiPicker/EmojiPicker.js
index 6501eb8320..ee63acdfd4 100644
--- a/packages/react/src/views/EmojiPicker/EmojiPicker.js
+++ b/packages/react/src/views/EmojiPicker/EmojiPicker.js
@@ -1,10 +1,15 @@
-import React from 'react';
+import React, { useEffect } from 'react';
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, Popup, ReactPortal, useTheme } from '@embeddedchat/ui-elements';
import getEmojiPickerStyles from './EmojiPicker.styles';
+const MOBILE_BREAKPOINT = 499;
+
+const getIsMobileViewport = () =>
+ typeof window !== 'undefined' && window.innerWidth <= MOBILE_BREAKPOINT;
+
const CustomEmojiPicker = ({
handleEmojiClick,
positionStyles = css`
@@ -14,15 +19,55 @@ const CustomEmojiPicker = ({
`,
wrapperId = 'emoji-popup',
onClose = () => {},
+ useMobileBottomSheet = false,
}) => {
const theme = useTheme();
const styles = getEmojiPickerStyles(theme);
+ const isMobileBottomSheet = useMobileBottomSheet && getIsMobileViewport();
const previewConfig = {
defaultEmoji: '1f60d',
defaultCaption: 'None',
showPreview: true,
};
+ useEffect(() => {
+ if (!isMobileBottomSheet || typeof document === 'undefined') {
+ return undefined;
+ }
+
+ const previousOverflow = document.body.style.overflow;
+ document.body.style.overflow = 'hidden';
+
+ return () => {
+ document.body.style.overflow = previousOverflow;
+ };
+ }, [isMobileBottomSheet]);
+
+ if (isMobileBottomSheet) {
+ return (
+
+
+ event.stopPropagation()}
+ >
+
+
+
+
+
+ );
+ }
+
return (
{
background: ${theme.colors.primary};
}
`,
+ mobileSheetBackdrop: css`
+ position: fixed;
+ inset: 0;
+ z-index: ${(theme.zIndex?.modal || 1500) - 1};
+ background: ${alpha(theme.colors.foreground, 0.08)};
+ `,
+ mobileSheet: css`
+ position: fixed;
+ left: 0.5rem;
+ right: 0.5rem;
+ bottom: 0.5rem;
+ z-index: ${theme.zIndex?.modal || 1500};
+ display: flex;
+ flex-direction: column;
+ height: min(28rem, calc(100vh - 4rem));
+ max-height: min(28rem, calc(100vh - 4rem));
+ overflow: hidden;
+ border: 1px solid ${theme.colors.border};
+ border-radius: ${theme.radius};
+ background: ${theme.colors.background};
+ box-shadow: ${theme.shadows[2]};
+ padding-bottom: env(safe-area-inset-bottom, 0);
+
+ @supports (height: 100dvh) {
+ height: min(28rem, calc(100dvh - 4rem));
+ max-height: min(28rem, calc(100dvh - 4rem));
+ }
+ `,
+ mobileEmojiPicker: css`
+ height: 100%;
+
+ .EmojiPickerReact {
+ width: 100% !important;
+ height: 100% !important;
+ border: none;
+ border-radius: inherit;
+ }
+ `,
};
return styles;