Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion example/app/(tabs)/explore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { ThemedText } from '@/components/themed-text'
import { ThemedView } from '@/components/themed-view'
import { useThemeColor } from '@/hooks/use-theme-color'

type ChatExample = 'basic' | 'customized-rendering' | 'slack' | 'links' | 'reply'
type ChatExample = 'basic' | 'customized-rendering' | 'slack' | 'links' | 'reply' | 'reactions'

const examples: Array<{ id: ChatExample, title: string, description: string }> = [
{ id: 'basic', title: 'Basic Example', description: 'Basic chat with keyboard logging for testing' },
{ id: 'links', title: 'Links & Patterns', description: 'Phone numbers, emails, URLs, hashtags, and mentions' },
{ id: 'customized-rendering', title: 'Customized Rendering', description: 'Customized chat with all rendering options' },
{ id: 'slack', title: 'Slack Style', description: 'Slack-like message styling' },
{ id: 'reply', title: 'Reply Example', description: 'Example demonstrating reply functionality' },
{ id: 'reactions', title: 'Emoji Reactions', description: 'Long-press a message to react with an emoji' },
]

export default function ExploreScreen () {
Expand Down
4 changes: 4 additions & 0 deletions example/app/chat/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export default function ChatLayout () {
name='slack'
options={{ title: 'Slack Style' }}
/>
<Stack.Screen
name='reactions'
options={{ title: 'Emoji Reactions' }}
/>
</Stack>
)
}
Expand Down
3 changes: 3 additions & 0 deletions example/app/chat/reactions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ReactionsExample from '@/components/chat-examples/ReactionsExample'

export default ReactionsExample
138 changes: 138 additions & 0 deletions example/components/chat-examples/ReactionsExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import React, { useCallback, useMemo, useState } from 'react'
import { StyleSheet, View, useColorScheme } from 'react-native'
import { GiftedChat, IMessage, MessageReaction } from 'react-native-gifted-chat'

import messagesData from '../../example-expo/data/messages'
import { useKeyboardVerticalOffset } from '../../hooks/useKeyboardVerticalOffset'
import { getColorSchemeStyle } from '../../utils/styleUtils'

export interface IChatMessage extends IMessage {
reactions?: MessageReaction[]
}

const CURRENT_USER_ID = 1

export default function ReactionsExample () {
const [messages, setMessages] = useState<IChatMessage[]>(messagesData)
const colorScheme = useColorScheme()
const keyboardVerticalOffset = useKeyboardVerticalOffset()

const user = useMemo(() => ({
_id: CURRENT_USER_ID,
name: 'Developer',
}), [])

const onSend = useCallback((newMessages: IChatMessage[] = []) => {
setMessages(previousMessages =>
GiftedChat.append(previousMessages, newMessages)
)
}, [])

const handleReactionPress = useCallback((message: IChatMessage, emoji: string) => {
setMessages(previousMessages =>
previousMessages.map(m => {
if (m._id !== message._id)
return m

const existing = (m.reactions ?? []).find(r => r.emoji === emoji)

if (existing) {
const newUserIds = existing.userIds.includes(CURRENT_USER_ID)
? existing.userIds.filter(id => id !== CURRENT_USER_ID)
: [...existing.userIds, CURRENT_USER_ID]

return {
...m,
reactions: newUserIds.length === 0
? (m.reactions ?? []).filter(r => r.emoji !== emoji)
: (m.reactions ?? []).map(r =>
r.emoji === emoji ? { ...r, userIds: newUserIds } : r
),
}
}

return {
...m,
reactions: [...(m.reactions ?? []), { emoji, userIds: [CURRENT_USER_ID] }],
}
})
)
}, [])

const isDark = colorScheme === 'dark'

return (
<View style={[styles.container, getColorSchemeStyle(styles, 'container', colorScheme)]}>
<GiftedChat<IChatMessage>
messages={messages}
onSend={onSend}
user={user}
messagesContainerStyle={getColorSchemeStyle(styles, 'messagesContainer', colorScheme)}
textInputProps={{
style: getColorSchemeStyle(styles, 'composer', colorScheme),
}}
reactions={{
isEnabled: true,
onReactionPress: handleReactionPress,

// Full emoji browser — opens when user taps "+" in the quick picker
isFullPickerEnabled: true,
fullPickerLang: 'en',
fullPickerColumnCount: 6,

// Theme overrides for the EmojiChooser sheet
fullPickerTheme: {
light: {
searchbar: {
container: { backgroundColor: '#f3f4f6' },
textInput: {
backgroundColor: '#ffffff',
color: '#111827',
fontSize: 15,
},
},
toolbar: {
container: { backgroundColor: '#ffffff' },
},
},
dark: {
searchbar: {
container: { backgroundColor: '#1f2937' },
textInput: {
backgroundColor: '#374151',
color: '#f9fafb',
fontSize: 15,
},
},
toolbar: {
container: { backgroundColor: '#111827' },
},
},
},

fullPickerSearchBarProps: {
placeholderTextColor: isDark ? '#9ca3af' : '#6b7280',
},
}}
keyboardAvoidingViewProps={{ keyboardVerticalOffset }}
/>
</View>
)
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
container_dark: {
backgroundColor: '#000',
},
messagesContainer_dark: {
backgroundColor: '#000',
},
composer_dark: {
backgroundColor: '#1a1a1a',
color: '#fff',
},
})
5 changes: 4 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@
"react-native-safe-area-context": "~5.6.2",
"react-native-screens": "~4.16.0",
"react-native-web": "~0.21.2",
"react-native-worklets": "0.5.1"
"react-native-worklets": "0.5.1",
"@react-native-async-storage/async-storage": "^2.1.2",
"react-native-emoji-chooser": "^0.1.11",
"react-native-svg": "^15.11.2"
},
"devDependencies": {
"@babel/core": "^7.28.6",
Expand Down
Loading
Loading