react-native-gifted-chat 3.2.3 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +450 -156
- package/package.json +9 -8
- package/src/Bubble/index.tsx +34 -2
- package/src/Bubble/types.ts +17 -4
- package/src/Day/index.tsx +2 -2
- package/src/Day/types.ts +3 -2
- package/src/GiftedChat/index.tsx +109 -23
- package/src/GiftedChat/types.ts +9 -3
- package/src/InputToolbar.tsx +62 -8
- package/src/Message/index.tsx +181 -21
- package/src/Message/types.ts +4 -0
- package/src/MessageReply.tsx +160 -0
- package/src/MessagesContainer/components/Item/index.tsx +17 -3
- package/src/MessagesContainer/index.tsx +16 -11
- package/src/MessagesContainer/types.ts +26 -3
- package/src/Models.ts +3 -0
- package/src/Reply/index.ts +1 -0
- package/src/Reply/types.ts +80 -0
- package/src/ReplyPreview.tsx +132 -0
- package/src/Send.tsx +8 -3
- package/src/__tests__/MessageReply.test.tsx +54 -0
- package/src/__tests__/ReplyPreview.test.tsx +41 -0
- package/src/__tests__/__snapshots__/GiftedChat.test.tsx.snap +69 -42
- package/src/__tests__/__snapshots__/InputToolbar.test.tsx.snap +11 -15
- package/src/__tests__/__snapshots__/MessageImage.test.tsx.snap +24 -18
- package/src/__tests__/__snapshots__/MessageReply.test.tsx.snap +181 -0
- package/src/__tests__/__snapshots__/ReplyPreview.test.tsx.snap +403 -0
- package/src/__tests__/__snapshots__/Send.test.tsx.snap +3 -0
- package/src/components/MessageReply.tsx +156 -0
- package/src/components/ReplyPreview.tsx +230 -0
- package/src/index.ts +6 -1
- package/src/types.ts +17 -16
- package/src/utils.ts +11 -3
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
ImageStyle,
|
|
5
|
+
Pressable,
|
|
6
|
+
StyleProp,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
Text,
|
|
9
|
+
TextStyle,
|
|
10
|
+
View,
|
|
11
|
+
ViewStyle,
|
|
12
|
+
} from 'react-native'
|
|
13
|
+
|
|
14
|
+
import { IMessage, ReplyMessage } from '../Models'
|
|
15
|
+
import { isSameUser } from '../utils'
|
|
16
|
+
|
|
17
|
+
export interface MessageReplyProps<TMessage extends IMessage = IMessage> {
|
|
18
|
+
/** The reply message to display */
|
|
19
|
+
replyMessage: ReplyMessage
|
|
20
|
+
/** The current message containing the reply */
|
|
21
|
+
currentMessage: TMessage
|
|
22
|
+
/** Position of the bubble (left or right) */
|
|
23
|
+
position: 'left' | 'right'
|
|
24
|
+
/** Container style for the reply */
|
|
25
|
+
containerStyle?: StyleProp<ViewStyle>
|
|
26
|
+
/** Container style for left position */
|
|
27
|
+
containerStyleLeft?: StyleProp<ViewStyle>
|
|
28
|
+
/** Container style for right position */
|
|
29
|
+
containerStyleRight?: StyleProp<ViewStyle>
|
|
30
|
+
/** Text style for the reply */
|
|
31
|
+
textStyle?: StyleProp<TextStyle>
|
|
32
|
+
/** Text style for left position */
|
|
33
|
+
textStyleLeft?: StyleProp<TextStyle>
|
|
34
|
+
/** Text style for right position */
|
|
35
|
+
textStyleRight?: StyleProp<TextStyle>
|
|
36
|
+
/** Image style for the reply */
|
|
37
|
+
imageStyle?: StyleProp<ImageStyle>
|
|
38
|
+
/** Callback when reply is pressed */
|
|
39
|
+
onPress?: (replyMessage: ReplyMessage) => void
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const styles = StyleSheet.create({
|
|
43
|
+
container: {
|
|
44
|
+
borderRadius: 8,
|
|
45
|
+
marginBottom: 4,
|
|
46
|
+
paddingHorizontal: 10,
|
|
47
|
+
paddingVertical: 6,
|
|
48
|
+
},
|
|
49
|
+
containerLeft: {
|
|
50
|
+
backgroundColor: 'rgba(0, 0, 0, 0.06)',
|
|
51
|
+
borderLeftColor: '#0084ff',
|
|
52
|
+
borderLeftWidth: 3,
|
|
53
|
+
},
|
|
54
|
+
containerRight: {
|
|
55
|
+
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
|
56
|
+
borderLeftColor: 'rgba(255, 255, 255, 0.6)',
|
|
57
|
+
borderLeftWidth: 3,
|
|
58
|
+
},
|
|
59
|
+
image: {
|
|
60
|
+
borderRadius: 4,
|
|
61
|
+
height: 40,
|
|
62
|
+
marginTop: 4,
|
|
63
|
+
width: 40,
|
|
64
|
+
},
|
|
65
|
+
text: {
|
|
66
|
+
fontSize: 13,
|
|
67
|
+
},
|
|
68
|
+
textLeft: {
|
|
69
|
+
color: '#333',
|
|
70
|
+
},
|
|
71
|
+
textRight: {
|
|
72
|
+
color: 'rgba(255, 255, 255, 0.9)',
|
|
73
|
+
},
|
|
74
|
+
username: {
|
|
75
|
+
fontWeight: '600',
|
|
76
|
+
marginBottom: 2,
|
|
77
|
+
},
|
|
78
|
+
usernameLeft: {
|
|
79
|
+
color: '#0084ff',
|
|
80
|
+
},
|
|
81
|
+
usernameRight: {
|
|
82
|
+
color: 'rgba(255, 255, 255, 0.9)',
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
export function MessageReply<TMessage extends IMessage = IMessage> ({
|
|
87
|
+
replyMessage,
|
|
88
|
+
currentMessage,
|
|
89
|
+
position,
|
|
90
|
+
containerStyle,
|
|
91
|
+
containerStyleLeft,
|
|
92
|
+
containerStyleRight,
|
|
93
|
+
textStyle,
|
|
94
|
+
textStyleLeft,
|
|
95
|
+
textStyleRight,
|
|
96
|
+
imageStyle,
|
|
97
|
+
onPress,
|
|
98
|
+
}: MessageReplyProps<TMessage>) {
|
|
99
|
+
const isCurrentUser = useMemo(
|
|
100
|
+
() => isSameUser(currentMessage, { user: replyMessage.user } as TMessage),
|
|
101
|
+
[currentMessage, replyMessage.user]
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
const displayName = useMemo(() => {
|
|
105
|
+
if (isCurrentUser)
|
|
106
|
+
return 'You'
|
|
107
|
+
|
|
108
|
+
return replyMessage.user?.name || 'Unknown'
|
|
109
|
+
}, [isCurrentUser, replyMessage.user?.name])
|
|
110
|
+
|
|
111
|
+
const handlePress = () => {
|
|
112
|
+
onPress?.(replyMessage)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const containerStyles = [
|
|
116
|
+
styles.container,
|
|
117
|
+
position === 'left' ? styles.containerLeft : styles.containerRight,
|
|
118
|
+
containerStyle,
|
|
119
|
+
position === 'left' ? containerStyleLeft : containerStyleRight,
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
const usernameStyles = [
|
|
123
|
+
styles.username,
|
|
124
|
+
position === 'left' ? styles.usernameLeft : styles.usernameRight,
|
|
125
|
+
textStyle,
|
|
126
|
+
position === 'left' ? textStyleLeft : textStyleRight,
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
const textStyles = [
|
|
130
|
+
styles.text,
|
|
131
|
+
position === 'left' ? styles.textLeft : styles.textRight,
|
|
132
|
+
textStyle,
|
|
133
|
+
position === 'left' ? textStyleLeft : textStyleRight,
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<Pressable onPress={handlePress}>
|
|
138
|
+
<View style={containerStyles}>
|
|
139
|
+
<Text style={usernameStyles} numberOfLines={1}>
|
|
140
|
+
{displayName}
|
|
141
|
+
</Text>
|
|
142
|
+
{replyMessage.text && (
|
|
143
|
+
<Text style={textStyles} numberOfLines={2}>
|
|
144
|
+
{replyMessage.text}
|
|
145
|
+
</Text>
|
|
146
|
+
)}
|
|
147
|
+
{replyMessage.image && (
|
|
148
|
+
<Image
|
|
149
|
+
source={{ uri: replyMessage.image }}
|
|
150
|
+
style={[styles.image, imageStyle]}
|
|
151
|
+
/>
|
|
152
|
+
)}
|
|
153
|
+
</View>
|
|
154
|
+
</Pressable>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
ImageStyle,
|
|
5
|
+
Pressable,
|
|
6
|
+
StyleProp,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
Text,
|
|
9
|
+
TextStyle,
|
|
10
|
+
View,
|
|
11
|
+
ViewStyle,
|
|
12
|
+
} from 'react-native'
|
|
13
|
+
import Animated, {
|
|
14
|
+
useAnimatedStyle,
|
|
15
|
+
useSharedValue,
|
|
16
|
+
withTiming,
|
|
17
|
+
Easing,
|
|
18
|
+
interpolate,
|
|
19
|
+
runOnJS,
|
|
20
|
+
} from 'react-native-reanimated'
|
|
21
|
+
|
|
22
|
+
import { useColorScheme } from '../hooks/useColorScheme'
|
|
23
|
+
import { ReplyMessage } from '../Models'
|
|
24
|
+
|
|
25
|
+
const ANIMATION_DURATION = 200
|
|
26
|
+
const ANIMATION_EASING = Easing.bezier(0.25, 0.1, 0.25, 1)
|
|
27
|
+
const DEFAULT_HEIGHT = 68
|
|
28
|
+
|
|
29
|
+
export interface ReplyPreviewProps {
|
|
30
|
+
/** The reply message to preview */
|
|
31
|
+
replyMessage: ReplyMessage
|
|
32
|
+
/** Callback to clear the reply */
|
|
33
|
+
onClearReply?: () => void
|
|
34
|
+
/** Container style */
|
|
35
|
+
containerStyle?: StyleProp<ViewStyle>
|
|
36
|
+
/** Text style */
|
|
37
|
+
textStyle?: StyleProp<TextStyle>
|
|
38
|
+
/** Image style */
|
|
39
|
+
imageStyle?: StyleProp<ImageStyle>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const styles = StyleSheet.create({
|
|
43
|
+
borderIndicator: {
|
|
44
|
+
backgroundColor: '#0084ff',
|
|
45
|
+
borderTopLeftRadius: 4,
|
|
46
|
+
height: '100%',
|
|
47
|
+
width: 4,
|
|
48
|
+
},
|
|
49
|
+
clearButton: {
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
borderRadius: 12,
|
|
52
|
+
height: 24,
|
|
53
|
+
justifyContent: 'center',
|
|
54
|
+
width: 24,
|
|
55
|
+
},
|
|
56
|
+
clearButtonText: {
|
|
57
|
+
fontSize: 18,
|
|
58
|
+
fontWeight: '600',
|
|
59
|
+
},
|
|
60
|
+
container: {
|
|
61
|
+
borderRadius: 8,
|
|
62
|
+
flexDirection: 'row',
|
|
63
|
+
marginBottom: 8,
|
|
64
|
+
marginHorizontal: 10,
|
|
65
|
+
overflow: 'hidden',
|
|
66
|
+
},
|
|
67
|
+
containerDark: {
|
|
68
|
+
backgroundColor: '#2c2c2e',
|
|
69
|
+
},
|
|
70
|
+
containerLight: {
|
|
71
|
+
backgroundColor: '#e9e9eb',
|
|
72
|
+
},
|
|
73
|
+
content: {
|
|
74
|
+
flex: 1,
|
|
75
|
+
paddingHorizontal: 10,
|
|
76
|
+
paddingVertical: 8,
|
|
77
|
+
},
|
|
78
|
+
image: {
|
|
79
|
+
borderRadius: 4,
|
|
80
|
+
height: 40,
|
|
81
|
+
marginRight: 8,
|
|
82
|
+
width: 40,
|
|
83
|
+
},
|
|
84
|
+
row: {
|
|
85
|
+
alignItems: 'center',
|
|
86
|
+
flexDirection: 'row',
|
|
87
|
+
},
|
|
88
|
+
text: {
|
|
89
|
+
fontSize: 14,
|
|
90
|
+
},
|
|
91
|
+
textDark: {
|
|
92
|
+
color: '#fff',
|
|
93
|
+
},
|
|
94
|
+
textLight: {
|
|
95
|
+
color: '#333',
|
|
96
|
+
},
|
|
97
|
+
username: {
|
|
98
|
+
color: '#0084ff',
|
|
99
|
+
fontSize: 13,
|
|
100
|
+
fontWeight: '600',
|
|
101
|
+
marginBottom: 2,
|
|
102
|
+
},
|
|
103
|
+
wrapper: {
|
|
104
|
+
overflow: 'hidden',
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
export function ReplyPreview ({
|
|
109
|
+
replyMessage,
|
|
110
|
+
onClearReply,
|
|
111
|
+
containerStyle,
|
|
112
|
+
textStyle,
|
|
113
|
+
imageStyle,
|
|
114
|
+
}: ReplyPreviewProps) {
|
|
115
|
+
const colorScheme = useColorScheme()
|
|
116
|
+
const isDark = colorScheme === 'dark'
|
|
117
|
+
|
|
118
|
+
const animationProgress = useSharedValue(0)
|
|
119
|
+
const contentHeight = useSharedValue(DEFAULT_HEIGHT)
|
|
120
|
+
|
|
121
|
+
// Animate in on mount
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
animationProgress.value = withTiming(1, {
|
|
124
|
+
duration: ANIMATION_DURATION,
|
|
125
|
+
easing: ANIMATION_EASING,
|
|
126
|
+
})
|
|
127
|
+
}, [animationProgress])
|
|
128
|
+
|
|
129
|
+
const handleClear = () => {
|
|
130
|
+
'worklet'
|
|
131
|
+
animationProgress.value = withTiming(0, {
|
|
132
|
+
duration: ANIMATION_DURATION,
|
|
133
|
+
easing: ANIMATION_EASING,
|
|
134
|
+
}, finished => {
|
|
135
|
+
if (finished && onClearReply)
|
|
136
|
+
runOnJS(onClearReply)()
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const wrapperAnimatedStyle = useAnimatedStyle(() => {
|
|
141
|
+
const height = interpolate(
|
|
142
|
+
animationProgress.value,
|
|
143
|
+
[0, 1],
|
|
144
|
+
[0, contentHeight.value]
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
const opacity = interpolate(
|
|
148
|
+
animationProgress.value,
|
|
149
|
+
[0, 0.5, 1],
|
|
150
|
+
[0, 0.5, 1]
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const translateY = interpolate(
|
|
154
|
+
animationProgress.value,
|
|
155
|
+
[0, 1],
|
|
156
|
+
[10, 0]
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
height,
|
|
161
|
+
opacity,
|
|
162
|
+
transform: [{ translateY }],
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
const displayName = replyMessage.user?.name || 'Unknown'
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<Animated.View style={[styles.wrapper, wrapperAnimatedStyle]}>
|
|
170
|
+
<View
|
|
171
|
+
style={[
|
|
172
|
+
styles.container,
|
|
173
|
+
isDark ? styles.containerDark : styles.containerLight,
|
|
174
|
+
containerStyle,
|
|
175
|
+
]}
|
|
176
|
+
onLayout={e => {
|
|
177
|
+
const newHeight = e.nativeEvent.layout.height + 8
|
|
178
|
+
// Animate height change smoothly when content changes
|
|
179
|
+
contentHeight.value = withTiming(newHeight, {
|
|
180
|
+
duration: ANIMATION_DURATION,
|
|
181
|
+
easing: ANIMATION_EASING,
|
|
182
|
+
})
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
<View style={styles.borderIndicator} />
|
|
186
|
+
<View style={styles.content}>
|
|
187
|
+
<View style={styles.row}>
|
|
188
|
+
{replyMessage.image && (
|
|
189
|
+
<Image
|
|
190
|
+
source={{ uri: replyMessage.image }}
|
|
191
|
+
style={[styles.image, imageStyle]}
|
|
192
|
+
/>
|
|
193
|
+
)}
|
|
194
|
+
<View style={{ flex: 1 }}>
|
|
195
|
+
<Text style={styles.username} numberOfLines={1}>
|
|
196
|
+
Replying to {displayName}
|
|
197
|
+
</Text>
|
|
198
|
+
{replyMessage.text && (
|
|
199
|
+
<Text
|
|
200
|
+
style={[
|
|
201
|
+
styles.text,
|
|
202
|
+
isDark ? styles.textDark : styles.textLight,
|
|
203
|
+
textStyle,
|
|
204
|
+
]}
|
|
205
|
+
numberOfLines={2}
|
|
206
|
+
>
|
|
207
|
+
{replyMessage.text}
|
|
208
|
+
</Text>
|
|
209
|
+
)}
|
|
210
|
+
</View>
|
|
211
|
+
</View>
|
|
212
|
+
</View>
|
|
213
|
+
<Pressable
|
|
214
|
+
style={styles.clearButton}
|
|
215
|
+
onPress={handleClear}
|
|
216
|
+
hitSlop={8}
|
|
217
|
+
>
|
|
218
|
+
<Text
|
|
219
|
+
style={[
|
|
220
|
+
styles.clearButtonText,
|
|
221
|
+
isDark ? styles.textDark : styles.textLight,
|
|
222
|
+
]}
|
|
223
|
+
>
|
|
224
|
+
×
|
|
225
|
+
</Text>
|
|
226
|
+
</Pressable>
|
|
227
|
+
</View>
|
|
228
|
+
</Animated.View>
|
|
229
|
+
)
|
|
230
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import * as utils from './utils'
|
|
2
|
+
|
|
1
3
|
export * from './GiftedChat'
|
|
2
4
|
export * from './Constant'
|
|
3
|
-
export
|
|
5
|
+
export { utils }
|
|
4
6
|
export * from './GiftedChatContext'
|
|
5
7
|
export * from './types'
|
|
6
8
|
export * from './linkParser'
|
|
9
|
+
export * from './Reply'
|
|
7
10
|
export { Actions } from './Actions'
|
|
8
11
|
export { Avatar } from './Avatar'
|
|
9
12
|
export { Bubble } from './Bubble'
|
|
@@ -21,4 +24,6 @@ export { Time } from './Time'
|
|
|
21
24
|
export { GiftedAvatar } from './GiftedAvatar'
|
|
22
25
|
export { MessageAudio } from './MessageAudio'
|
|
23
26
|
export { MessageVideo } from './MessageVideo'
|
|
27
|
+
export { MessageReply } from './components/MessageReply'
|
|
28
|
+
export { ReplyPreview } from './components/ReplyPreview'
|
|
24
29
|
export { useColorScheme } from './hooks/useColorScheme'
|
package/src/types.ts
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
export * from './Models'
|
|
2
2
|
|
|
3
|
-
export { ActionsProps } from './Actions'
|
|
4
|
-
export { AvatarProps } from './Avatar'
|
|
5
|
-
export {
|
|
3
|
+
export type { ActionsProps } from './Actions'
|
|
4
|
+
export type { AvatarProps } from './Avatar'
|
|
5
|
+
export type {
|
|
6
6
|
BubbleProps,
|
|
7
7
|
RenderMessageImageProps,
|
|
8
8
|
RenderMessageVideoProps,
|
|
9
9
|
RenderMessageAudioProps,
|
|
10
10
|
RenderMessageTextProps
|
|
11
11
|
} from './Bubble'
|
|
12
|
-
export { ComposerProps } from './Composer'
|
|
13
|
-
export { DayProps } from './Day'
|
|
14
|
-
export { GiftedAvatarProps } from './GiftedAvatar'
|
|
15
|
-
export { InputToolbarProps } from './InputToolbar'
|
|
16
|
-
export { LoadEarlierMessagesProps } from './LoadEarlierMessages'
|
|
17
|
-
export { MessageProps } from './Message'
|
|
18
|
-
export { MessagesContainerProps } from './MessagesContainer'
|
|
19
|
-
export { MessageImageProps } from './MessageImage'
|
|
20
|
-
export { MessageTextProps } from './MessageText'
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
export {
|
|
24
|
-
export {
|
|
12
|
+
export type { ComposerProps } from './Composer'
|
|
13
|
+
export type { DayProps } from './Day'
|
|
14
|
+
export type { GiftedAvatarProps } from './GiftedAvatar'
|
|
15
|
+
export type { InputToolbarProps, ReplyPreviewProps } from './InputToolbar'
|
|
16
|
+
export type { LoadEarlierMessagesProps } from './LoadEarlierMessages'
|
|
17
|
+
export type { MessageProps } from './Message'
|
|
18
|
+
export type { MessagesContainerProps } from './MessagesContainer'
|
|
19
|
+
export type { MessageImageProps } from './MessageImage'
|
|
20
|
+
export type { MessageTextProps } from './MessageText'
|
|
21
|
+
export type { MessageReplyProps } from './components/MessageReply'
|
|
22
|
+
export type { QuickRepliesProps } from './QuickReplies'
|
|
23
|
+
export type { SendProps } from './Send'
|
|
24
|
+
export type { SystemMessageProps } from './SystemMessage'
|
|
25
|
+
export type { TimeProps } from './Time'
|
package/src/utils.ts
CHANGED
|
@@ -14,9 +14,17 @@ export function renderComponentOrElement<TProps extends Record<string, any>>(
|
|
|
14
14
|
return React.cloneElement(component, props as any)
|
|
15
15
|
|
|
16
16
|
if (typeof component === 'function') {
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
// Check if it's a class component (has prototype.isReactComponent)
|
|
18
|
+
// Class components must use React.createElement
|
|
19
|
+
const isClassComponent = component.prototype && component.prototype.isReactComponent
|
|
20
|
+
|
|
21
|
+
if (isClassComponent)
|
|
22
|
+
return React.createElement(component as React.ComponentType<TProps>, props as any)
|
|
23
|
+
|
|
24
|
+
// For function components and render functions, call directly
|
|
25
|
+
// Using createElement with inline arrow functions causes unmount/remount
|
|
26
|
+
// when function reference changes, this matches v2.x behavior
|
|
27
|
+
return (component as (props: TProps) => React.ReactNode)(props)
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
// If it's neither, return it as-is
|