Skip to content

Commit c1402c6

Browse files
committed
refactor: emoji picker v0.5
1 parent 9f1771e commit c1402c6

19 files changed

Lines changed: 410 additions & 74 deletions

File tree

packages/webapp/components/BottomSheet.tsx

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ import FilterModal from '@components/pages/document/components/FilterModal'
66
import NotificationModal from './notificationPanel/mobile/NotificationModal'
77
import ChatContainerMobile from './pages/document/components/chat/ChatContainerMobile'
88
import useKeyboardHeight from '@hooks/useKeyboardHeight'
9+
import { EmojiPanel } from './chat/components/EmojiPanel'
10+
import { CHAT_OPEN } from '@services/eventsHub'
911

1012
const BottomSheet = () => {
11-
const { activeSheet, closeSheet } = useSheetStore()
13+
const { activeSheet, closeSheet, sheetData } = useSheetStore()
1214
const chatRoom = useChatStore((state) => state.chatRoom)
1315
const closeChatRoom = useChatStore((state) => state.closeChatRoom)
1416
const destroyChatRoom = useChatStore((state) => state.destroyChatRoom)
1517
const setSheetContainerRef = useSheetStore((state) => state.setSheetContainerRef)
1618
const { height: keyboardHeight } = useKeyboardHeight()
1719
const { deviceDetect } = useStore((state) => state.settings)
18-
1920
const isDeviceIOS = useMemo(() => {
2021
return deviceDetect?.os() === 'iOS'
2122
}, [deviceDetect])
@@ -37,6 +38,12 @@ const BottomSheet = () => {
3738
return <NotificationModal />
3839
case 'filters':
3940
return <FilterModal />
41+
case 'emojiPicker':
42+
return (
43+
<EmojiPanel variant="mobile">
44+
<EmojiPanel.Selector />
45+
</EmojiPanel>
46+
)
4047
default:
4148
return null
4249
}
@@ -53,7 +60,13 @@ const BottomSheet = () => {
5360
return {
5461
id: 'chatroom_sheet',
5562
detent: 'full-height' as SheetProps['detent'],
56-
disableScrollLocking: true
63+
disableScrollLocking: true,
64+
disableDrag: true
65+
}
66+
case 'emojiPicker':
67+
return {
68+
id: 'emoji_picker_sheet',
69+
detent: 'content-height' as SheetProps['detent']
5770
}
5871
default:
5972
return {
@@ -73,9 +86,7 @@ const BottomSheet = () => {
7386
return {
7487
style: {
7588
paddingBottom: isDeviceIOS ? keyboardHeight : 0
76-
},
77-
disableDrag: true,
78-
disableScrollLocking: true
89+
}
7990
}
8091
default:
8192
return {}
@@ -86,12 +97,21 @@ const BottomSheet = () => {
8697
if (activeSheet === 'chatroom') {
8798
closeChatRoom()
8899
destroyChatRoom()
100+
} else if (activeSheet === 'emojiPicker' && sheetData.chatRoomState) {
101+
const { headingId } = sheetData.chatRoomState
102+
closeSheet()
103+
setTimeout(() => {
104+
PubSub.publish(CHAT_OPEN, {
105+
headingId: headingId,
106+
focusEditor: true,
107+
clearSheetState: true
108+
})
109+
}, 100)
110+
} else {
111+
closeSheet()
89112
}
90-
closeSheet()
91113
}
92114

93-
if (!activeSheet) return null
94-
95115
return (
96116
<Sheet
97117
className="bottom-sheet"

packages/webapp/components/chat/ChatRoom.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,21 @@ export const ChatRoom = forwardRef(
109109

110110
<div className="flex w-full flex-col items-center justify-center bg-transparent">
111111
{(!isMobile || (isMobile && !isEmojiBoxOpen)) && <ActionBar />}
112-
{pickEmoji && (
113-
<EmojiPickerWrapper
114-
isEmojiBoxOpen={isEmojiBoxOpen}
115-
emojiPickerPosition={emojiPickerPosition}
116-
closeEmojiPicker={closeEmojiPicker}
117-
handleEmojiSelect={handleEmojiSelect}
118-
ref={emojiPickerRef}
119-
/>
120-
)}
121112
</div>
122113

123114
<ScrollToBottomButton messagesContainer={messageContainerRef} />
124115
{children}
125116
</MessageWrapper>
117+
118+
{/* {pickEmoji && ( */}
119+
{/* <EmojiPickerWrapper
120+
isEmojiBoxOpen={isEmojiBoxOpen}
121+
emojiPickerPosition={emojiPickerPosition}
122+
closeEmojiPicker={closeEmojiPicker}
123+
handleEmojiSelect={handleEmojiSelect}
124+
ref={emojiPickerRef}
125+
/> */}
126+
{/* )} */}
126127
</div>
127128
)
128129
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react'
2+
import { EmojiSelector } from './Selector'
3+
import { Picker } from './Picker'
4+
import { EmojiPanelProvider } from './context/EmojiPanelContext'
5+
6+
const EmojiPanel = ({
7+
children,
8+
variant
9+
}: {
10+
children: React.ReactNode
11+
variant: 'mobile' | 'desktop'
12+
}) => {
13+
return (
14+
<EmojiPanelProvider variant={variant}>
15+
<div id="emoji_panel">{children}</div>
16+
</EmojiPanelProvider>
17+
)
18+
}
19+
20+
export default EmojiPanel
21+
22+
EmojiPanel.Selector = EmojiSelector
23+
EmojiPanel.Picker = Picker
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import EmojiPicker from '@emoji-mart/react'
2+
import data from '@emoji-mart/data/sets/14/native.json'
3+
import { useChatStore } from '@stores'
4+
import { useEmojiPanelContext } from './context/EmojiPanelContext'
5+
6+
type Props = {
7+
emojiSelectHandler: (emoji: any) => void
8+
}
9+
export const Picker = ({ emojiSelectHandler }: Props) => {
10+
const { variant } = useEmojiPanelContext()
11+
const { closeEmojiPicker, emojiPicker } = useChatStore()
12+
13+
return (
14+
<EmojiPicker
15+
data={data}
16+
dynamicWidth={variant === 'mobile' ? true : false}
17+
navPosition="bottom"
18+
previewPosition="none"
19+
searchPosition="sticky"
20+
skinTonePosition="search"
21+
{...(variant === 'mobile' && {
22+
emojiSize: 34,
23+
emojiButtonSize: 42
24+
})}
25+
emojiVersion="14"
26+
set="native"
27+
theme="light"
28+
onClickOutside={() => {
29+
if (emojiPicker.isOpen) closeEmojiPicker()
30+
}}
31+
onEmojiSelect={emojiSelectHandler}
32+
/>
33+
)
34+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from 'react'
2+
import { useChatStore, useSheetStore } from '@stores'
3+
import { CHAT_OPEN } from '@services/eventsHub'
4+
import { Picker } from './Picker'
5+
import { createPortal } from 'react-dom'
6+
import { useCloseOnResize } from '@hooks/useCloseOnResize'
7+
import { useEmojiPanelContext } from './context/EmojiPanelContext'
8+
9+
export const EmojiSelector = () => {
10+
const { variant } = useEmojiPanelContext()
11+
const { sheetData } = useSheetStore()
12+
const { emojiPicker, closeEmojiPicker } = useChatStore()
13+
const { editorInstance } = useChatStore((state) => state.chatRoom)
14+
15+
// TODO: this is only work for mobile
16+
const emojiSelectHandler = (emoji: any) => {
17+
if (variant === 'mobile') {
18+
const { headingId } = sheetData.chatRoomState
19+
20+
PubSub.publish(CHAT_OPEN, {
21+
headingId: headingId,
22+
focusEditor: true,
23+
insertContent: emoji.native,
24+
clearSheetState: true
25+
})
26+
} else {
27+
editorInstance?.commands.insertContent(emoji.native)
28+
closeEmojiPicker()
29+
}
30+
}
31+
32+
useCloseOnResize()
33+
34+
if (variant === 'desktop') {
35+
return createPortal(
36+
<div
37+
className=""
38+
style={{
39+
position: 'fixed',
40+
top: `${emojiPicker.position?.top || 0}px`,
41+
left: `${emojiPicker.position?.left || 0}px`,
42+
visibility: emojiPicker.isOpen ? 'visible' : 'hidden',
43+
zIndex: 999
44+
}}>
45+
<Picker emojiSelectHandler={emojiSelectHandler} />
46+
</div>,
47+
document.body
48+
)
49+
}
50+
51+
return <Picker emojiSelectHandler={emojiSelectHandler} />
52+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React, { createContext, useContext } from 'react'
2+
3+
type EmojiPanelContextType = {
4+
variant: 'mobile' | 'desktop'
5+
}
6+
7+
const EmojiPanelContext = createContext<EmojiPanelContextType | undefined>(undefined)
8+
9+
export const useEmojiPanelContext = () => {
10+
const context = useContext(EmojiPanelContext)
11+
if (!context) {
12+
throw new Error('useEmojiPanelContext must be used within EmojiPanelProvider')
13+
}
14+
return context
15+
}
16+
17+
export const EmojiPanelProvider: React.FC<{
18+
children: React.ReactNode
19+
variant: 'mobile' | 'desktop'
20+
}> = ({ children, variant }) => {
21+
return <EmojiPanelContext.Provider value={{ variant }}>{children}</EmojiPanelContext.Provider>
22+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as EmojiPanel } from './EmojiPanel'

packages/webapp/components/chat/components/MessageComposer/MessageComposer.tsx

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const MessageComposer = ({
6060
const { workspaceId } = useChatStore((state) => state.workspaceSettings)
6161
const editorRef = useRef<HTMLDivElement | null>(null)
6262
const [isToolbarOpen, setIsToolbarOpen] = useState(() => toolbarStorage.get())
63+
const setOrUpdateChatRoom = useChatStore((state) => state.setOrUpdateChatRoom)
6364

6465
const setEditMsgMemory = useChatStore((state) => state.setEditMessageMemory)
6566
const setReplyMsgMemory = useChatStore((state) => state.setReplyMessageMemory)
@@ -371,25 +372,6 @@ const MessageComposer = ({
371372
submitRef.current = () => submitMessage()
372373
}, [submitMessage])
373374

374-
useEffect(() => {
375-
// TODO: this is temporary
376-
setTimeout(() => {
377-
document.querySelector('.tiptap.ProseMirror')?.setAttribute('inputmode', 'text')
378-
document.querySelector('.tiptap.ProseMirror')?.setAttribute('enterkeyhint', 'send')
379-
}, 1000)
380-
}, [editor])
381-
382-
useEffect(() => {
383-
const setAttributes = () => {
384-
const firstChild = editorRef.current?.firstChild as HTMLElement | null
385-
if (firstChild) {
386-
firstChild.setAttribute('inputmode', 'text')
387-
firstChild.setAttribute('enterkeyhint', 'send')
388-
}
389-
}
390-
setAttributes()
391-
}, [editor])
392-
393375
// Handle Draft Memory
394376
useEffect(() => {
395377
return () => {
@@ -416,14 +398,6 @@ const MessageComposer = ({
416398
setAttributes()
417399
}, [editor, editorRef])
418400

419-
useEffect(() => {
420-
// TODO: this is temporary
421-
setTimeout(() => {
422-
document.querySelector('.tiptap.ProseMirror')?.setAttribute('inputmode', 'text')
423-
document.querySelector('.tiptap.ProseMirror')?.setAttribute('enterkeyhint', 'send')
424-
}, 1000)
425-
}, [editor])
426-
427401
// Save toolbar toggle state to localStorage
428402
useEffect(() => {
429403
toolbarStorage.set(isToolbarOpen)
@@ -433,6 +407,11 @@ const MessageComposer = ({
433407
setIsToolbarOpen(!isToolbarOpen)
434408
}, [setIsToolbarOpen, isToolbarOpen])
435409

410+
useEffect(() => {
411+
editor && setOrUpdateChatRoom('editorInstance', editor)
412+
editorRef.current && setOrUpdateChatRoom('editorRef', editorRef.current)
413+
}, [editor, editorRef])
414+
436415
const contextValue = {
437416
sendMsg,
438417
sendComment,

0 commit comments

Comments
 (0)