Skip to content

Commit 4e524ec

Browse files
committed
add smooth fade-in/out of scroll to bottom element
1 parent c84bac4 commit 4e524ec

File tree

7 files changed

+49
-24
lines changed

7 files changed

+49
-24
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ interface QuickReplies {
417417
- **`minComposerHeight`** _(Object)_ - Custom min-height of the composer.
418418
- **`maxComposerHeight`** _(Object)_ - Custom max height of the composer.
419419

420-
* **`scrollToBottom`** _(Bool)_ - Enables the scroll to bottom Component (Default is false)
420+
* **`isScrollToBottomEnabled`** _(Bool)_ - Enables the scroll to bottom Component (Default is false)
421421
* **`scrollToBottomComponent`** _(Function)_ - Custom Scroll To Bottom Component container
422422
* **`scrollToBottomOffset`** _(Integer)_ - Custom Height Offset upon which to begin showing Scroll To Bottom Component (Default is 200)
423423
* **`scrollToBottomStyle`** _(Object)_ - Custom style for Bottom Component container

example/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ const App = () => {
275275
isLoadingEarlier={state.isLoadingEarlier}
276276
parsePatterns={parsePatterns}
277277
user={user}
278-
scrollToBottom
278+
isScrollToBottomEnabled
279279
onPressAvatar={onPressAvatar}
280280
onLongPressAvatar={onLongPressAvatar}
281281
onLongPress={handleLongPress}

example/example-gifted-chat/src/Chats.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const Chats = () => {
3636
}}
3737
alignTop
3838
alwaysShowSend
39-
scrollToBottom
39+
isScrollToBottomEnabled
4040
// showUserAvatar
4141
renderAvatarOnTop
4242
renderUsernameOnMessage

src/GiftedChat/index.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,6 @@ function GiftedChat<TMessage extends IMessage = IMessage> (
420420
]
421421
)
422422

423-
console.log('!')
424-
425423
return (
426424
<GiftedChatContext.Provider value={contextValues}>
427425
<ActionSheetProvider ref={actionSheetRef}>

src/GiftedChat/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { TimeProps } from '../Time'
3333
import MessageContainer, { AnimatedList, ListViewProps } from '../MessageContainer'
3434
import Bubble from '../Bubble'
3535

36-
export interface GiftedChatProps<TMessage extends IMessage = IMessage> extends Partial<Omit<typeof MessageContainer<TMessage>, 'scrollToBottom'>> {
36+
export interface GiftedChatProps<TMessage extends IMessage = IMessage> extends Partial<Omit<typeof MessageContainer<TMessage>, 'isScrollToBottomEnabled'>> {
3737
/* Message container ref */
3838
messageContainerRef?: RefObject<AnimatedList>
3939
/* text input ref */
@@ -50,8 +50,8 @@ export interface GiftedChatProps<TMessage extends IMessage = IMessage> extends P
5050
text?: string
5151
/* Controls whether or not the message bubbles appear at the top of the chat */
5252
alignTop?: boolean
53-
/* enables the scrollToBottom Component */
54-
scrollToBottom?: boolean
53+
/* enables the isScrollToBottomEnabled Component */
54+
isScrollToBottomEnabled?: boolean
5555
/* Scroll to bottom wrapper style */
5656
scrollToBottomStyle?: StyleProp<ViewStyle>
5757
initialText?: string

src/MessageContainer/index.tsx

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
LayoutChangeEvent,
88
} from 'react-native'
99
import { FlashList, ListRenderItemInfo } from '@shopify/flash-list'
10-
import Animated, { runOnJS, useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated'
10+
import Animated, { runOnJS, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'
1111
import { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes'
1212
import DayAnimated from './components/DayAnimated'
1313
import Item from './components/Item'
@@ -38,7 +38,7 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
3838
listViewProps,
3939
invertibleScrollViewProps,
4040
extraData = null,
41-
scrollToBottom = false,
41+
isScrollToBottomEnabled = false,
4242
scrollToBottomOffset = 200,
4343
alignTop = false,
4444
scrollToBottomStyle,
@@ -52,7 +52,12 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
5252
scrollToBottomComponent: scrollToBottomComponentProp,
5353
} = props
5454

55+
const scrollToBottomOpacity = useSharedValue(0)
5556
const [isScrollToBottomVisible, setIsScrollToBottomVisible] = useState(false)
57+
const scrollToBottomStyleAnim = useAnimatedStyle(() => ({
58+
opacity: scrollToBottomOpacity.value,
59+
}), [scrollToBottomOpacity])
60+
5661
const [hasScrolled, setHasScrolled] = useState(false)
5762

5863
const daysPositions = useSharedValue<DaysPositions>({})
@@ -105,21 +110,33 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
105110
layoutMeasurement: { height: layoutMeasurementHeight },
106111
} = event
107112

108-
if (inverted)
109-
if (contentOffsetY > scrollToBottomOffset!)
113+
const duration = 250
114+
115+
if (inverted) {
116+
if (contentOffsetY > scrollToBottomOffset!) {
110117
setIsScrollToBottomVisible(true)
111-
else
112-
setIsScrollToBottomVisible(false)
113-
else if (
118+
scrollToBottomOpacity.value = withTiming(1, { duration })
119+
} else {
120+
scrollToBottomOpacity.value = withTiming(0, { duration }, isFinished => {
121+
if (isFinished)
122+
runOnJS(setIsScrollToBottomVisible)(false)
123+
})
124+
}
125+
} else if (
114126
contentOffsetY < scrollToBottomOffset! &&
115127
contentSizeHeight - layoutMeasurementHeight > scrollToBottomOffset!
116-
)
128+
) {
117129
setIsScrollToBottomVisible(true)
118-
else
119-
setIsScrollToBottomVisible(false)
130+
scrollToBottomOpacity.value = withTiming(1, { duration })
131+
} else {
132+
scrollToBottomOpacity.value = withTiming(0, { duration }, isFinished => {
133+
if (isFinished)
134+
runOnJS(setIsScrollToBottomVisible)(false)
135+
})
136+
}
120137

121138
setHasScrolled(true)
122-
}, [handleOnScrollProp, inverted, scrollToBottomOffset])
139+
}, [handleOnScrollProp, inverted, scrollToBottomOffset, scrollToBottomOpacity])
123140

124141
const handleLayoutDayWrapper = useCallback((ref: unknown, id: string | number, createdAt: number) => {
125142
setTimeout(() => { // do not delete "setTimeout". It's necessary for get correct layout.
@@ -219,17 +236,27 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
219236
}, [scrollToBottomComponentProp])
220237

221238
const renderScrollToBottomWrapper = useCallback(() => {
239+
if (!isScrollToBottomVisible)
240+
return null
241+
222242
return (
223-
<View style={[stylesCommon.centerItems, styles.scrollToBottomStyle, scrollToBottomStyle]}>
243+
<Animated.View
244+
style={[
245+
stylesCommon.centerItems,
246+
styles.scrollToBottomStyle,
247+
scrollToBottomStyle,
248+
scrollToBottomStyleAnim,
249+
]}
250+
>
224251
<TouchableOpacity
225252
onPress={() => doScrollToBottom()}
226253
hitSlop={{ top: 5, left: 5, right: 5, bottom: 5 }}
227254
>
228255
{renderScrollBottomComponent()}
229256
</TouchableOpacity>
230-
</View>
257+
</Animated.View>
231258
)
232-
}, [scrollToBottomStyle, renderScrollBottomComponent, doScrollToBottom])
259+
}, [scrollToBottomStyle, renderScrollBottomComponent, doScrollToBottom, scrollToBottomStyleAnim, isScrollToBottomVisible])
233260

234261
const onLayoutList = useCallback((event: LayoutChangeEvent) => {
235262
listHeight.value = event.nativeEvent.layout.height
@@ -299,7 +326,7 @@ function MessageContainer<TMessage extends IMessage = IMessage> (props: MessageC
299326
{...listViewProps}
300327
onLayout={onLayoutList}
301328
/>
302-
{isScrollToBottomVisible && scrollToBottom
329+
{isScrollToBottomEnabled
303330
? renderScrollToBottomWrapper()
304331
: null}
305332
<DayAnimated

src/MessageContainer/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export interface MessageContainerProps<TMessage extends IMessage> {
2727
inverted?: boolean
2828
loadEarlier?: boolean
2929
alignTop?: boolean
30-
scrollToBottom?: boolean
30+
isScrollToBottomEnabled?: boolean
3131
scrollToBottomStyle?: StyleProp<ViewStyle>
3232
invertibleScrollViewProps?: object
3333
extraData?: object

0 commit comments

Comments
 (0)