Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
7d4be68
feat: migrate report actions to chronological LegendList
chrispader Sep 9, 2026
2a3323a
chore: merge main into LegendList report actions
chrispader Sep 9, 2026
d815c1a
chore: merge LegendList foundation updates
chrispader Sep 10, 2026
ba852b2
fix: address LegendList report action review
chrispader Sep 10, 2026
15312bb
chore: merge main into LegendList report actions
chrispader Sep 10, 2026
0a811f9
chore: merge main into LegendList report actions
chrispader Sep 10, 2026
750e92d
chore: merge main into LegendList report actions
chrispader Sep 10, 2026
332a7b3
fix: stabilize LegendList initial loading
chrispader Sep 10, 2026
e385011
chore: merge main into LegendList report actions
chrispader Sep 10, 2026
9117baa
chore: merge main into LegendList report actions
chrispader Sep 10, 2026
e5c4ec3
chore: merge main into LegendList report actions
chrispader Sep 10, 2026
3a782f9
test: model content growth in pagination test
chrispader Sep 10, 2026
fa5194f
fix: stabilize report actions loading behavior
chrispader Sep 10, 2026
52df1e9
refactor: remove compiled report memoization
chrispader Sep 11, 2026
c80ea5a
fix: allow report action menus to overflow list rows
chrispader Sep 14, 2026
5cb81be
chore: merge main into LegendList report actions
chrispader Sep 16, 2026
c873dca
chore: merge main into LegendList report actions
chrispader Sep 16, 2026
f91ebe0
chore: merge main into LegendList report actions
chrispader Sep 17, 2026
255f4d3
chore: merge main into LegendList report actions
chrispader Sep 17, 2026
62a7c0d
fix: supply report name in modified expense tests
chrispader Sep 17, 2026
0964d53
Merge branch 'main' into @chrispader/feat/legend-list-report-actions
chrispader Sep 17, 2026
09057d5
fix: address report actions list review feedback
chrispader Sep 18, 2026
61dc6ad
chore: merge main into report actions branch
chrispader Sep 18, 2026
ffa18ae
docs: explain report action recycling state
chrispader Sep 18, 2026
53f3b9f
Merge branch 'main' into @chrispader/feat/legend-list-report-actions
chrispader Sep 18, 2026
f12b575
fix: remove duplicate report list spacing
chrispader Sep 22, 2026
34b345d
fix: synchronize sent comment scrolling
chrispader Sep 22, 2026
da3b443
fix: preserve hydrated report list state
chrispader Sep 22, 2026
55cb72a
fix: refresh recycled unread marker rows
chrispader Sep 22, 2026
a5670fa
chore: merge main into report actions branch
chrispader Sep 22, 2026
8188df1
fix: keep report actions live across incomplete loads
chrispader Sep 24, 2026
9bd382a
fix: preserve local action scrolling without realtime echo jumps
chrispader Sep 24, 2026
f0b046a
fix: key recycled media state by action and image
chrispader Sep 24, 2026
a8fc4fa
fix: keep highlighted final action in view
chrispader Sep 24, 2026
6e7f045
test: verify unread and read thresholds from saved offset
chrispader Sep 24, 2026
ca78b55
refactor: share web report scroll-to-end implementation
chrispader Sep 24, 2026
59a5397
docs: note Android visible-position patch scope
chrispader Sep 24, 2026
d2f2cc8
fix: scroll after edited action layout settles
chrispader Sep 24, 2026
08e1f69
test: type captured list load callback
chrispader Sep 24, 2026
5c7ffc8
chore: merge main into LegendList report actions
chrispader Sep 24, 2026
84b0f19
fix: preserve Concierge tail when revealing history
chrispader Sep 24, 2026
a1e0d25
test: remove nonvirtualized report list benchmark
chrispader Sep 24, 2026
e37edb4
test: mock edited-action draft clearing
chrispader Sep 24, 2026
b43b59e
Merge branch 'main' into @chrispader/feat/legend-list-report-actions
chrispader Sep 24, 2026
e904b99
test: wait for edited action scroll frame
chrispader Sep 24, 2026
40f7719
chore: update LegendList to 3.4.0
chrispader Sep 24, 2026
a68ee3c
fix: cover warm report actions during initial layout
chrispader Sep 24, 2026
e117ffc
fix: render Concierge notification banner before chat scrolls to end
chrispader Sep 25, 2026
4adbdaa
fix: keep latest chat action visible after list measurement
chrispader Sep 25, 2026
c92613d
fix: preserve Concierge scroll position when showing history
chrispader Sep 25, 2026
7096033
fix: preserve unread message alignment at the latest action
chrispader Sep 29, 2026
c0751dd
fix: cancel report end corrections when the reader scrolls
chrispader Sep 29, 2026
0cb9d7b
fix: keep report scroll events flowing on web
chrispader Sep 29, 2026
0f53485
fix: keep chat skeleton visible until initial scrolling settles
chrispader Sep 29, 2026
b611f38
fix: resume end following after scrolling past a linked message
chrispader Sep 29, 2026
779eaac
fix: preserve chat content when clearing linked messages
chrispader Oct 1, 2026
5dab08a
chore: merge main into LegendList report actions
chrispader Oct 7, 2026
519cb5b
fix: prevent Android LegendList viewport flashes
chrispader Oct 8, 2026
8229bce
fix: keep linked messages visible after navigation and layout changes
chrispader Oct 8, 2026
ed4e31a
fix: emit web scroll events for chronological lists
chrispader Oct 8, 2026
d25f5b6
fix: preserve linked-message position through late layout
chrispader Oct 9, 2026
e83aec2
chore: merge main into LegendList report actions
chrispader Oct 9, 2026
b6c6df2
fix: preserve LegendList web scroll completion
chrispader Oct 13, 2026
40a2338
fix: resolve the current composer after focus delays
chrispader Oct 13, 2026
49ab56d
fix: avoid duplicate Android linked-message adjustments
chrispader Oct 13, 2026
e1bbfda
chore: merge main and resolve report scrolling conflicts
chrispader Oct 19, 2026
e8974de
chore: merge main into LegendList report actions
chrispader Oct 19, 2026
1de8343
fix: keyboard focus
chrispader Oct 19, 2026
bd9ce7c
fix: restore Android composer blur on keyboard dismissal
chrispader Oct 20, 2026
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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"@fullstory/react-native": "^1.10.2",
"@gorhom/portal": "^1.0.14",
"@invertase/react-native-apple-authentication": "^2.5.0",
"@legendapp/list": "^3.3.10",
"@legendapp/list": "^3.6.0",
"@lottiefiles/dotlottie-react": "0.13.5",
"@onfido/react-native-sdk": "15.1.0",
"@pusher/pusher-websocket-react-native": "^1.3.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
diff --git a/node_modules/@legendapp/list/react-native.js b/node_modules/@legendapp/list/react-native.js
index 0b730ec..9e14f1d 100644
--- a/node_modules/@legendapp/list/react-native.js
+++ b/node_modules/@legendapp/list/react-native.js
@@ -6097,4 +6097,12 @@ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
// src/components/Containers.native.tsx
+// Fabric positions and the MVCP anchor update through React. Commit the content
+// size with them so an imperative Animated update cannot clamp the old viewport.
+var useContainersSize = IsNewArchitecture ? function useContainersSizeState() {
+ const [size = 0] = useArr$(["totalSize"]);
+ return size;
+} : function useContainersSizeAnimated() {
+ return useValue$("totalSize");
+};
var ContainersLayer = typedMemo(function ContainersLayer2({
children,
freshDataTransitionEpoch,
@@ -6102,7 +6110,7 @@ var ContainersLayer = typedMemo(function ContainersLayer2({
}) {
const ctx = useStateContext();
const columnWrapperStyle = ctx.columnWrapperStyle;
- const animSize = useValue$("totalSize");
+ const animSize = useContainersSize();
const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
const style = horizontal ? {
diff --git a/node_modules/@legendapp/list/react-native.mjs b/node_modules/@legendapp/list/react-native.mjs
index a3d8d9a..1f2bcf9 100644
--- a/node_modules/@legendapp/list/react-native.mjs
+++ b/node_modules/@legendapp/list/react-native.mjs
@@ -6076,4 +6076,12 @@ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
// src/components/Containers.native.tsx
+// Fabric positions and the MVCP anchor update through React. Commit the content
+// size with them so an imperative Animated update cannot clamp the old viewport.
+var useContainersSize = IsNewArchitecture ? function useContainersSizeState() {
+ const [size = 0] = useArr$(["totalSize"]);
+ return size;
+} : function useContainersSizeAnimated() {
+ return useValue$("totalSize");
+};
var ContainersLayer = typedMemo(function ContainersLayer2({
children,
freshDataTransitionEpoch,
@@ -6081,7 +6089,7 @@ var ContainersLayer = typedMemo(function ContainersLayer2({
}) {
const ctx = useStateContext();
const columnWrapperStyle = ctx.columnWrapperStyle;
- const animSize = useValue$("totalSize");
+ const animSize = useContainersSize();
const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
const style = horizontal ? {
10 changes: 10 additions & 0 deletions patches/@legendapp/list/details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# `@legendapp/list` patches

### [@legendapp+list+3.6.0+001+synchronize-fabric-content-size.patch](@legendapp+list+3.6.0+001+synchronize-fabric-content-size.patch)

- Reason: On Android, the entire report-action list can briefly jump to older rows while item measurements settle. LegendList updates its content size through an imperative `Animated.Value`, while Fabric row positions and the scroll-preservation anchor update through React. An early content-size update can clamp the old viewport before the matching positions mount. Read the content size through the same React store on the New Architecture so these layout changes commit together.
- Scope: Both native module formats use the synchronized size on the New Architecture. The legacy architecture retains its animated size updates, and the web entries are unchanged. Native scroll preservation and the initial loading skeleton remain enabled.
- Upstream PR/issue: Pending submission after local validation. This patch is being developed locally as part of the LegendList migration.
- E/App issue: https://github.com/Expensify/App/pull/100733#issuecomment-5886543887
- PR introducing patch: https://github.com/Expensify/App/pull/100733
- Reproduction: Open an expense chat containing a report preview and messages with different heights. Wait for the actual rows to replace the skeleton. The highlighted preview should stay visible while measurements settle, without a frame displaying older rows. Also scroll through older history and return to the latest messages to check scroll preservation.
6 changes: 4 additions & 2 deletions patches/react-native/details.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

### [react-native+0.86.0+002+fixMVCPAndroid.patch](react-native+0.86.0+002+fixMVCPAndroid.patch)

- Reason: Fixes content jumping issues with `MaintainVisibleContentPosition` on Android, particularly in bidirectional pagination scenarios. The patch makes two key improvements:
- Reason: Fixes content jumping issues with `MaintainVisibleContentPosition` on Android, particularly in bidirectional pagination scenarios. The patch:
1. Changes when the first visible view is calculated - now happens on scroll events instead of during Fabric's willMountItems lifecycle, which was causing incorrect updates
2. Improves first visible view selection logic to handle Fabric's z-index-based view reordering by finding the view with the smallest position that's still greater than the scroll position
- Upstream PR/issue: https://github.com/facebook/react-native/pull/46247
3. Preserves a positioned, zero-sized first child as a scroll anchor. LegendList moves this anchor to compensate for item measurements. Selecting its surrounding container or rejecting its empty frame prevents native scroll compensation and makes the chat jump as estimated rows shrink. LegendList 3.6 places the anchor at its adjustment offset plus 10,000,000 pixels, beyond the viewport. The strict visibility check also prevents a fixed, zero-sized spacer at or above the scroll offset in another scroll view from taking over its visible-content anchor.
- Scope: This changes Android `MaintainVisibleContentPosition` for every React Native scroll view that enables it, not only the report-action list. Keep this in mind when updating React Native or investigating anchoring in other scroll views.
- Upstream PR/issue: https://github.com/facebook/react-native/pull/46247 (closed without merging; the zero-sized LegendList anchor fix is not covered there)
- E/App issue: 🛑
- PR Introducing Patch: https://github.com/Expensify/App/pull/46315 (introduced), https://github.com/Expensify/App/pull/45289 (refactored)

Expand Down

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MelvinBot Is the change to this patch reflected in the upstream react/react-native#46247?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No — none of this patch is upstream, and the new change in this PR isn't even part of #46247's diff.

Two separate gaps:

  1. maintainVisibleContentPosition fixes on Android was never merged. react-native-bot closed it as stale on 2026-04-05 after 180 days with no activity (merged: false, no merge commit). RN main today still has the original naive computeTargetView() — first-match loop, called from willMountItems. So points 1 and 2 in details.md are still patch-only.

  2. The change added here has no upstream counterpart at all. Allow Search command to run in support mode #46247 touches only view selection (z-index-aware) and when it runs (on scroll). It never special-cases a zero-sized anchor. Both new bits here are new behavior:

Suggestion: the Upstream PR/issue: line in details.md now points at a closed PR, which reads as "this is on its way upstream" when it isn't. Worth marking it closed/not-landed, and either filing a new upstream PR for the LegendList anchor case or setting it to 🛑 like the E/App issue: line.

How I checked
  • gh api repos/facebook/react-native/pulls/46247 → state: closed, merged: false, merged_at: null, closed_at: 2026-04-05T05:31:12Z
  • Last comment on the PR: react-native-bot: This PR was closed because it has been stalled for 7 days with no activity.
  • Compared Allow Search command to run in support mode #46247's diff of MaintainVisibleScrollPositionHelper.java against this PR's patch hunks — no width == 0 && height == 0 anchor branch, and willMountItemsInternal() stores the hit rect unconditionally with no zero-area guard.
  • Fetched MaintainVisibleScrollPositionHelper.kt from RN main to confirm the upstream refactor (onScroll() / didMountItemsInternal() / firstVisibleViewPosition) is absent.

view run

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chrispader at some point we need to get this merged upstream. I talked to Janic about this about a month ago, but Expensify didn't want to deal with the overhead of onboarding a new agency just for that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll look into it!

Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,16 @@ index 2bee605..ba26e7b 100644
for (i in config.minIndexForVisible until contentView.childCount) {
val child = contentView.getChildAt(i)

@@ -128,27 +135,49 @@ internal class MaintainVisibleScrollPositionHelper<ScrollViewT>(
@@ -128,27 +135,57 @@ internal class MaintainVisibleScrollPositionHelper<ScrollViewT>(
val position = if (horizontal) child.x + child.width else child.y + child.height

+ // Virtualized lists can use a zero-sized, positioned first child as their scroll anchor.
+ // Preserve it instead of choosing the container that holds all rendered items.
+ if (i == config.minIndexForVisible && child.width == 0 && child.height == 0 && position > currentScroll) {
+ firstVisibleView = child
+ break
+ }
+
// If the child is partially visible or this is the last child, select it as the anchor.
- if (position > currentScroll || i == contentView.childCount - 1) {
- firstVisibleViewRef = WeakReference(child)
Expand Down Expand Up @@ -70,7 +77,8 @@ index 2bee605..ba26e7b 100644
}
+ val frame = Rect()
+ firstVisibleView.getHitRect(frame)
+ if (frame.width() > 0 || frame.height() > 0) {
+ // Zero-sized anchors have a meaningful position even though they have no area.
+ if (frame.width() > 0 || frame.height() > 0 || frame.left != 0 || frame.top != 0) {
+ prevFirstVisibleFrame = frame
+ } else {
+ prevFirstVisibleFrame = null
Expand Down

This file was deleted.

28 changes: 0 additions & 28 deletions src/components/FlashList/InvertedFlashList/index.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/FlashList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {FlashList as ShopifyFlashList} from '@shopify/flash-list';
import React from 'react';

function FlashList<T>({onScroll: onScrollProp, inverted, ...restProps}: FlashListProps<T>) {
const emitComposerScrollEvents = useEmitComposerScrollEvents({enabled: true, inverted});
const emitComposerScrollEvents = useEmitComposerScrollEvents();

const handleScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
onScrollProp?.(e);
Expand Down
7 changes: 0 additions & 7 deletions src/components/FlashList/types.ts

This file was deleted.

37 changes: 14 additions & 23 deletions src/components/FlatList/FlatList/index.ios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import useThemeStyles from '@hooks/useThemeStyles';

import type {NativeScrollEvent, NativeSyntheticEvent} from 'react-native';

import React, {useCallback, useRef, useState} from 'react';
import {useRef, useState} from 'react';
import {FlatList} from 'react-native';

import type {CustomFlatListProps} from './types';
Expand All @@ -26,30 +26,21 @@ function CustomFlatList<T>({
}: CustomFlatListProps<T>) {
const [isScrolling, setIsScrolling] = useState(false);
const styles = useThemeStyles();
const handleScrollBegin = useCallback(
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
onMomentumScrollBegin?.(event);
setIsScrolling(true);
},
[onMomentumScrollBegin],
);
const handleScrollBegin = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
onMomentumScrollBegin?.(event);
setIsScrolling(true);
};

const handleScrollEnd = useCallback(
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
onMomentumScrollEnd?.(event);
setIsScrolling(false);
},
[onMomentumScrollEnd],
);
const handleScrollEnd = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
onMomentumScrollEnd?.(event);
setIsScrolling(false);
};

const emitComposerScrollEvents = useEmitComposerScrollEvents({enabled: !enableAnimatedKeyboardDismissal, inverted: restProps.inverted});
const handleScroll = useCallback(
(e: NativeSyntheticEvent<NativeScrollEvent>) => {
onScrollProp?.(e);
emitComposerScrollEvents();
},
[emitComposerScrollEvents, onScrollProp],
);
const emitComposerScrollEvents = useEmitComposerScrollEvents({enabled: !enableAnimatedKeyboardDismissal && !!restProps.inverted});
const handleScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
onScrollProp?.(e);
emitComposerScrollEvents();
};

const listRef = useRef<FlatListInnerRefType<T> | null>(null);
useFlatListHandle<T>({
Expand Down
2 changes: 1 addition & 1 deletion src/components/FlatList/FlatList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ function MVCPFlatList<T>({
};
}, []);

const emitComposerScrollEvents = useEmitComposerScrollEvents({enabled: true, inverted: restProps.inverted});
const emitComposerScrollEvents = useEmitComposerScrollEvents();
const handleScroll = useCallback(
(e: NativeSyntheticEvent<NativeScrollEvent>) => {
onScrollProp?.(e);
Expand Down
4 changes: 2 additions & 2 deletions src/components/KeyboardDismissibleFlatList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import {useAnimatedScrollHandler, useComposedEventHandler} from 'react-native-re

import {useKeyboardDismissibleFlatListActions} from './KeyboardDismissibleFlatListContext';

function KeyboardDismissibleFlatList<T>({onScroll: onScrollProp, inverted, ref, ...restProps}: AnimatedFlatListWithCellRendererProps<T>) {
function KeyboardDismissibleFlatList<T>({onScroll: onScrollProp, ref, ...restProps}: AnimatedFlatListWithCellRendererProps<T>) {
const {onScroll: onScrollHandleKeyboard} = useKeyboardDismissibleFlatListActions();

const emitComposerScrollEvents = useEmitComposerScrollEvents({enabled: true, inverted});
const emitComposerScrollEvents = useEmitComposerScrollEvents();

const additionalOnScroll = useAnimatedScrollHandler({
onScroll: emitComposerScrollEvents,
Expand Down
19 changes: 19 additions & 0 deletions src/components/LegendList/allowLegendListItemOverflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {isRecord} from '@libs/ObjectUtils';

import type {LegendListRef} from '@legendapp/list/react-native';

/**
* LegendList uses paint containment for web item containers, which clips descendants that render
* outside their row. Remove only paint containment so inline menus can overflow while layout and
* style containment keep the rest of the row isolated.
*/
function allowLegendListItemOverflow(list: LegendListRef | null, index: number): void {
const itemContainer: unknown = list?.getState().elementAtIndex(index);
if (!isRecord(itemContainer) || !isRecord(itemContainer.style) || typeof itemContainer.style.contain !== 'string') {
return;
}

itemContainer.style.contain = 'layout style';
}

export default allowLegendListItemOverflow;
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ function MoneyRequestReportActionsListContent({reportIDFromRoute, onLayout}: Mon
contentContainerStyle={[shouldUseNarrowLayout ? styles.pt4 : styles.pt3, shouldReserveBulkActionBarSpace && styles.bulkActionBarListSpacing]}
isLoadingInitialActions={isInitialReportLoadPending}
/* This list is not inverted, so the footer is the bottom of the message feed —
the same position the indicator occupies in the inverted ReportActionsList. */
the same position the indicator occupies in ReportActionsList. */
listFooterComponent={<ConciergeThinkingMessage reportID={report.reportID} />}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import LinkButton from '@components/Button/composed/LinkButton';
import type FlatListRefType from '@components/FlashList/types';

import useCopySelectionEvent from '@hooks/useCopySelectionEvent';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
Expand All @@ -18,6 +17,8 @@ import {getTransactionPendingAction} from '@libs/TransactionUtils';

import Navigation from '@navigation/Navigation';

import type ActionListRefType from '@pages/inbox/ActionListTypes';

import {resolveLayoutSpacing} from '@styles/layoutSpacing';

import CONST from '@src/CONST';
Expand Down Expand Up @@ -127,7 +128,7 @@ type MoneyRequestReportTransactionListProps = {
linkedReportActionID: string | undefined;

/** Ref forwarded to the underlying FlashList. */
listRef: FlatListRefType;
listRef: ActionListRefType;

/** Reports the unified list's last item index so the parent can jump to the bottom via scrollToIndex. */
onLastItemIndexChange?: (index: number) => void;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import FlashList from '@components/FlashList';
import type FlatListRefType from '@components/FlashList/types';

import useWindowDimensions from '@hooks/useWindowDimensions';

import type ActionListRefType from '@pages/inbox/ActionListTypes';
import useScrollToEditingReportAction from '@pages/inbox/report/useScrollToEditingReportAction';

import variables from '@styles/variables';
Expand Down Expand Up @@ -48,15 +48,13 @@ function unifiedListItemType(item: UnifiedListItem) {
}

type MoneyRequestReportFlashListProps = FlashListProps<UnifiedListItem> & {
/** Ref to the underlying list, shared via the ActionList context (typed for the legacy FlatList). */
ref: FlatListRefType;
/** Ref to the underlying list, shared via the common ActionList imperative API. */
ref: ActionListRefType;
};

/**
* Forwards the shared ActionList context ref to the underlying FlashList. That context slot predates this FlashList-based
* list and is still shared with the legacy report list, so it is typed for a FlatList. Mirroring InvertedFlashList, the
* ref is forwarded through @components/FlashList — which receives it as an untyped runtime prop — so no type assertion is
* needed. The scroll manager relies on the FlashList registering into this slot.
* Forwards the shared ActionList ref through @components/FlashList to the underlying list.
* FlashList implements the common imperative API consumed by the report scroll manager.
*/
function MoneyRequestReportFlashList(props: MoneyRequestReportFlashListProps) {
return (
Expand Down Expand Up @@ -93,7 +91,7 @@ type MoneyRequestReportUnifiedListProps = {
newTransactionID?: string;

/** Ref to the underlying list, shared via the ActionList context. */
listRef: FlatListRefType;
listRef: ActionListRefType;

accessibilityLabel: string;

Expand Down
Loading
Loading