1- import React from 'react' ;
1+ import React , { Suspense , useEffect , useState } from 'react' ;
22import DelegateNoAccessModalProvider from './components/DelegateNoAccessModalProvider' ;
33import EmojiPicker from './components/EmojiPicker/EmojiPicker' ;
44import GrowlNotification from './components/GrowlNotification' ;
@@ -7,21 +7,47 @@ import ScreenShareRequestModal from './components/ScreenShareRequestModal';
77import UpdateAppModal from './components/UpdateAppModal' ;
88import * as EmojiPickerAction from './libs/actions/EmojiPickerAction' ;
99import { growlRef } from './libs/Growl' ;
10- import PopoverReportActionContextMenu from './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu' ;
1110import * as ReportActionContextMenu from './pages/inbox/report/ContextMenu/ReportActionContextMenu' ;
1211
12+ const LazyPopoverReportActionContextMenu = React . lazy ( ( ) => import ( './pages/inbox/report/ContextMenu/PopoverReportActionContextMenu' ) ) ;
13+
14+ // Maximum time (ms) the context menu mount can stay deferred before requestIdleCallback forces it to run,
15+ // guaranteeing mount even if the main thread never becomes idle.
16+ const IDLE_CALLBACK_TIMEOUT_MS = 2000 ;
17+
1318/**
1419 * Renders global modals and overlays that are mounted once at the top level.
1520 */
1621function GlobalModals ( ) {
22+ const [ shouldRenderContextMenu , setShouldRenderContextMenu ] = useState ( false ) ;
23+
24+ useEffect ( ( ) => {
25+ // Defer loading the context menu until after startup to avoid pulling in heavy
26+ // dependencies (ContextMenuActions, ReportUtils, ModifiedExpenseMessage, etc.)
27+ // during the ManualAppStartup span.
28+ const id = requestIdleCallback ( ( ) => setShouldRenderContextMenu ( true ) , { timeout : IDLE_CALLBACK_TIMEOUT_MS } ) ;
29+
30+ // Allow showContextMenu() to force eager mount if the user interacts before the idle callback fires.
31+ ReportActionContextMenu . registerEnsureContextMenuMounted ( ( ) => setShouldRenderContextMenu ( true ) ) ;
32+
33+ return ( ) => {
34+ cancelIdleCallback ( id ) ;
35+ ReportActionContextMenu . registerEnsureContextMenuMounted ( null ) ;
36+ } ;
37+ } , [ ] ) ;
38+
1739 return (
1840 < >
1941 < UpdateAppModal />
2042 { /* Those below are only available to the authenticated user. */ }
2143 < GrowlNotification ref = { growlRef } />
2244 < DelegateNoAccessModalProvider >
23- { /* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */ }
24- < PopoverReportActionContextMenu ref = { ReportActionContextMenu . contextMenuRef } />
45+ { shouldRenderContextMenu && (
46+ < Suspense fallback = { null } >
47+ { /* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */ }
48+ < LazyPopoverReportActionContextMenu ref = { ReportActionContextMenu . contextMenuRef } />
49+ </ Suspense >
50+ ) }
2551 </ DelegateNoAccessModalProvider >
2652 { /* eslint-disable-next-line react-hooks/refs -- module-level createRef, safe to pass as ref prop */ }
2753 < EmojiPicker ref = { EmojiPickerAction . emojiPickerRef } />
0 commit comments