@@ -45,14 +45,7 @@ import {
4545import { TouchableOpacity } from "react-native-gesture-handler" ;
4646import ImageViewing from "react-native-image-viewing" ;
4747import { useSafeAreaInsets } from "react-native-safe-area-context" ;
48- import Animated , {
49- FadeIn ,
50- FadeInUp ,
51- useSharedValue ,
52- withTiming ,
53- type LayoutAnimationsValues ,
54- type SharedValue ,
55- } from "react-native-reanimated" ;
48+ import Animated , { FadeIn , FadeInUp , type SharedValue } from "react-native-reanimated" ;
5649import { useThemeColor } from "../../lib/useThemeColor" ;
5750import { useFontFamily } from "../../lib/useFontFamily" ;
5851import { copyTextWithHaptic } from "../../lib/copyTextWithHaptic" ;
@@ -117,14 +110,6 @@ function formatMessageTime(input: string): string {
117110 return MESSAGE_TIME_FORMATTER . format ( timestamp ) ;
118111}
119112
120- // Rows shift when content above them grows (streaming text, work-log folds);
121- // animating the container position turns those jumps into slides. Applied
122- // conditionally — see the gated transition in ThreadFeed: while browsing
123- // history the animation must NOT run, or every estimate→actual size
124- // correction plays as a visible slide against the instant scroll-offset
125- // compensation from maintainVisibleContentPosition.
126- const FEED_ITEM_LAYOUT_DURATION_MS = 180 ;
127-
128113// Pre-measurement heights for getFixedItemSize, mirroring renderFeedEntry's
129114// classNames. The fold row's min-h-11 (44px) stays taller than its single
130115// text-sm line at every supported base font size (26px at the 22pt maximum),
@@ -1434,52 +1419,16 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
14341419 } ,
14351420 [ props . onHeaderMaterialVisibilityChange ] ,
14361421 ) ;
1437- // True while the viewport sits within ~one screen of the list end — the
1438- // only region where layout shifts should animate. Starts true because the
1439- // list opens pinned to the end.
1440- const nearListEnd = useSharedValue ( true ) ;
1441-
14421422 const handleScroll = useCallback (
14431423 ( event : NativeSyntheticEvent < NativeScrollEvent > ) => {
14441424 // anchorTopInset, not topContentInset: under automatic insets the list
14451425 // rests at contentOffset.y = -headerHeight (the inset lives only in
14461426 // UIKit's adjustedContentInset, so topContentInset is 0 here). Add the
14471427 // header height back or the material toggles a full header too late.
14481428 reportHeaderMaterialVisibility ( event . nativeEvent . contentOffset . y + anchorTopInset > 6 ) ;
1449- const { contentOffset, contentSize, layoutMeasurement } = event . nativeEvent ;
1450- nearListEnd . value =
1451- contentSize . height - layoutMeasurement . height - contentOffset . y < layoutMeasurement . height ;
14521429 } ,
1453- [ reportHeaderMaterialVisibility , anchorTopInset , nearListEnd ] ,
1430+ [ reportHeaderMaterialVisibility , anchorTopInset ] ,
14541431 ) ;
1455-
1456- // Gated variant of the 180ms feed layout slide. Instant while browsing
1457- // history: maintainVisibleContentPosition compensates the scroll offset in
1458- // the same frame a row's measured size lands, so an instant reposition is
1459- // invisible — animating it is exactly what made cold upward scrolls slide
1460- // and jump. Near the end the slide stays on: streaming growth and sends
1461- // shift rows at rest, where the animation is the thing preventing a hard
1462- // visual snap.
1463- const feedItemLayoutTransition = useMemo ( ( ) => {
1464- return ( values : LayoutAnimationsValues ) => {
1465- "worklet" ;
1466- const duration = nearListEnd . value ? FEED_ITEM_LAYOUT_DURATION_MS : 0 ;
1467- return {
1468- initialValues : {
1469- originX : values . currentOriginX ,
1470- originY : values . currentOriginY ,
1471- width : values . currentWidth ,
1472- height : values . currentHeight ,
1473- } ,
1474- animations : {
1475- originX : withTiming ( values . targetOriginX , { duration } ) ,
1476- originY : withTiming ( values . targetOriginY , { duration } ) ,
1477- width : withTiming ( values . targetWidth , { duration } ) ,
1478- height : withTiming ( values . targetHeight , { duration } ) ,
1479- } ,
1480- } ;
1481- } ;
1482- } , [ nearListEnd ] ) ;
14831432 const handleViewportLayout = useCallback ( ( event : LayoutChangeEvent ) => {
14841433 const nextWidth = Math . round ( event . nativeEvent . layout . width ) ;
14851434 const nextHeight = Math . round ( event . nativeEvent . layout . height ) ;
@@ -1817,7 +1766,6 @@ export const ThreadFeed = memo(function ThreadFeed(props: ThreadFeedProps) {
18171766 }
18181767 : { scrollIndicatorInsets : { top : topContentInset , bottom : 0 } } ) }
18191768 { ...( anchoredEndSpace ? { anchoredEndSpace } : { } ) }
1820- itemLayoutAnimation = { feedItemLayoutTransition }
18211769 // Patched LegendList prop (patches/@legendapp__list@3.2.0.patch):
18221770 // lets its scroll math clamp programmatic scrolls to -headerInset
18231771 // instead of 0, so initialScrollAtEnd/maintainScrollAtEnd on short
0 commit comments