-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Initial implementation of the Side Pane #56490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
francoisl
merged 62 commits into
Expensify:main
from
software-mansion-labs:feature/right-pane
Mar 4, 2025
Merged
Changes from 60 commits
Commits
Show all changes
62 commits
Select commit
Hold shift + click to select a range
9e2f4e9
Initial implementation of the right pane
blazejkustra 21f586b
Close the right panel when resizing
blazejkustra b81640c
Merge branch 'main' into feature/right-pane
blazejkustra ecbf269
Change nvp name
blazejkustra fe55e51
add help button to the topbar
blazejkustra 37e2915
Clean the code after initial commits
blazejkustra 8eaa8b6
Create HelpButton
blazejkustra 0261b7c
Create SidePane
blazejkustra 01c27bf
Clean AuthScreens
blazejkustra d93de2a
Fix styles to incorporate side pane
blazejkustra 29937be
Add HelpButton to headerView
blazejkustra a887953
Add HelpButton to all necessaary components
blazejkustra 72a2f91
Rename to stay consistent
blazejkustra bb328e2
Merge branch 'main' into feature/right-pane
blazejkustra 5df31e0
Add additional padding for help pane
blazejkustra a5443c5
Move inline styles to utils
blazejkustra 550a645
Fix styles
blazejkustra 177f82e
Add comments for closing logic
blazejkustra e65ff94
Reorder the code a bit
blazejkustra 222d095
Add sidepane type
blazejkustra cbed9d9
Add translations
blazejkustra 1e1f794
Add sidePane inside of navigator
blazejkustra bbe2b77
Hide toplevelbottomtabbar when sidepane is visible
blazejkustra dd89146
Add the actual onyx type
blazejkustra 98b4b25
Clean up SidePane page, add screenwrapper to support mobiles
blazejkustra eee67f8
Add patch for react navigation
blazejkustra a6afa5d
Add explanation
blazejkustra 3964999
Adjust platform files for better compability
blazejkustra fb57a91
Fix patches
blazejkustra 3485e7c
Fix padding for side pane
blazejkustra eaee7c2
Fix styling and translations
blazejkustra 38566a8
Initialize getHelpContent
blazejkustra 396d3db
Create SidePane action file
blazejkustra a423982
Create substituteRouteParameters
blazejkustra 970c5cb
Fix substituteRouteParameters
blazejkustra b3e3ccd
Fix positioning for RHP
blazejkustra 41a6e44
Fix substituteRouteParameters
blazejkustra fafd1a6
Merge branch 'main' into feature/right-pane
blazejkustra 3c48a30
Show help pane on search page
blazejkustra 24bb2a4
Rearrange logic and create sweet animations
blazejkustra 5bb2b9e
Fix other navigators too!
blazejkustra 59b50e9
Refactor side pane logic and improve bottom tab visibility handling
blazejkustra 0117ad6
Refactor HelpButton visibility logic in TopBar and HelpButton components
blazejkustra c5aa2c7
Merge branch 'main' into feature/right-pane
blazejkustra f08a011
Fix typecheck
blazejkustra a53931a
Remove triggerSidePane
blazejkustra 9ec1975
Fix overlay on web
blazejkustra ad5a509
Improve how overlay and toplevelbottombar are displayed
blazejkustra ec692b7
Fix styling on natives
blazejkustra 5bb82b1
Hide overlay when in RHP
blazejkustra f5f71df
Bring back original change
blazejkustra 34202b1
Fix lint
blazejkustra 12b5fa6
Fix ReportScreen
blazejkustra e288a1c
Hide HelpButton
blazejkustra 41447cd
Hide sidePane when chaining languages
blazejkustra e438147
Fix backdrop edge cases
blazejkustra 35a026c
Rename SidePane properties
blazejkustra ac46ca0
Add JSDoc
blazejkustra 445d333
Bring back the old name for large screens
blazejkustra 4062a25
Merge branch 'main' of github.com:Expensify/App into feature/right-pane
blazejkustra 1ac677a
Merge branch 'main' of github.com:Expensify/App into feature/right-pane
blazejkustra 4ad6f71
Simplify logic in isSidePaneHidden function to return boolean directly
blazejkustra File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
diff --git a/node_modules/@react-navigation/core/lib/module/useDescriptors.js b/node_modules/@react-navigation/core/lib/module/useDescriptors.js | ||
index 76fdab1..75f315c 100644 | ||
--- a/node_modules/@react-navigation/core/lib/module/useDescriptors.js | ||
+++ b/node_modules/@react-navigation/core/lib/module/useDescriptors.js | ||
@@ -112,6 +112,19 @@ export default function useDescriptors(_ref, convertCustomScreenOptions) { | ||
} | ||
return o; | ||
}); | ||
+ const SidePane = customOptions.sidePane; | ||
+ let element = /*#__PURE__*/React.createElement(React.Fragment, { | ||
+ children: [/*#__PURE__*/React.createElement(SceneView, { | ||
+ navigation: navigation, | ||
+ route: route, | ||
+ screen: screen, | ||
+ routeState: state.routes[i].state, | ||
+ getState: getState, | ||
+ setState: setState, | ||
+ options: customOptions, | ||
+ clearOptions: clearOptions | ||
+ }), SidePane && /*#__PURE__*/React.createElement(SidePane, {})] | ||
+ }); | ||
acc[route.key] = { | ||
route, | ||
// @ts-expect-error: it's missing action helpers, fix later | ||
@@ -123,17 +136,10 @@ export default function useDescriptors(_ref, convertCustomScreenOptions) { | ||
}, /*#__PURE__*/React.createElement(NavigationContext.Provider, { | ||
value: navigation | ||
}, /*#__PURE__*/React.createElement(NavigationRouteContext.Provider, { | ||
- value: route | ||
- }, /*#__PURE__*/React.createElement(SceneView, { | ||
- navigation: navigation, | ||
- route: route, | ||
- screen: screen, | ||
- routeState: state.routes[i].state, | ||
- getState: getState, | ||
- setState: setState, | ||
- options: mergedOptions, | ||
- clearOptions: clearOptions | ||
- })))); | ||
+ value: route, | ||
+ children: element | ||
+ }, | ||
+ ))); | ||
}, | ||
options: mergedOptions | ||
}; | ||
diff --git a/node_modules/@react-navigation/core/src/useDescriptors.tsx b/node_modules/@react-navigation/core/src/useDescriptors.tsx | ||
index 2e4ee0f..11ece43 100644 | ||
--- a/node_modules/@react-navigation/core/src/useDescriptors.tsx | ||
+++ b/node_modules/@react-navigation/core/src/useDescriptors.tsx | ||
@@ -238,6 +238,23 @@ export default function useDescriptors< | ||
return o; | ||
}); | ||
|
||
+ const SidePane = (customOptions as any).sidePane; | ||
+ let element = ( | ||
+ <> | ||
+ <SceneView | ||
+ navigation={navigation} | ||
+ route={route} | ||
+ screen={screen} | ||
+ routeState={state.routes[i].state} | ||
+ getState={getState} | ||
+ setState={setState} | ||
+ options={customOptions} | ||
+ clearOptions={clearOptions} | ||
+ /> | ||
+ {SidePane && <SidePane />} | ||
+ </> | ||
+ ); | ||
+ | ||
acc[route.key] = { | ||
route, | ||
// @ts-expect-error: it's missing action helpers, fix later | ||
@@ -247,16 +264,7 @@ export default function useDescriptors< | ||
<NavigationBuilderContext.Provider key={route.key} value={context}> | ||
<NavigationContext.Provider value={navigation}> | ||
<NavigationRouteContext.Provider value={route}> | ||
- <SceneView | ||
- navigation={navigation} | ||
- route={route} | ||
- screen={screen} | ||
- routeState={state.routes[i].state} | ||
- getState={getState} | ||
- setState={setState} | ||
- options={mergedOptions} | ||
- clearOptions={clearOptions} | ||
- /> | ||
+ {element} | ||
</NavigationRouteContext.Provider> | ||
</NavigationContext.Provider> | ||
</NavigationBuilderContext.Provider> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React from 'react'; | ||
import type {StyleProp, ViewStyle} from 'react-native'; | ||
import {useOnyx} from 'react-native-onyx'; | ||
import Icon from '@components/Icon'; | ||
import * as Expensicons from '@components/Icon/Expensicons'; | ||
import {PressableWithoutFeedback} from '@components/Pressable'; | ||
import Tooltip from '@components/Tooltip'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import useResponsiveLayout from '@hooks/useResponsiveLayout'; | ||
import useTheme from '@hooks/useTheme'; | ||
import useThemeStyles from '@hooks/useThemeStyles'; | ||
import {triggerSidePane} from '@libs/actions/SidePane'; | ||
import CONST from '@src/CONST'; | ||
import ONYXKEYS from '@src/ONYXKEYS'; | ||
|
||
type HelpButtonProps = { | ||
style?: StyleProp<ViewStyle>; | ||
}; | ||
|
||
function HelpButton({style}: HelpButtonProps) { | ||
const styles = useThemeStyles(); | ||
const theme = useTheme(); | ||
const {translate} = useLocalize(); | ||
const [sidePane] = useOnyx(ONYXKEYS.NVP_SIDE_PANE); | ||
const [language] = useOnyx(ONYXKEYS.NVP_PREFERRED_LOCALE); | ||
const {isExtraLargeScreenWidth} = useResponsiveLayout(); | ||
|
||
if (!sidePane || language !== CONST.LOCALES.EN) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Tooltip text={translate('common.help')}> | ||
<PressableWithoutFeedback | ||
accessibilityLabel={translate('common.help')} | ||
style={[styles.flexRow, styles.touchableButtonImage, styles.pr2, style]} | ||
onPress={() => triggerSidePane(isExtraLargeScreenWidth ? !sidePane?.open : !sidePane?.openNarrowScreen, {shouldUpdateNarrowLayout: !isExtraLargeScreenWidth})} | ||
> | ||
<Icon | ||
src={Expensicons.QuestionMark} | ||
fill={theme.icon} | ||
/> | ||
</PressableWithoutFeedback> | ||
</Tooltip> | ||
); | ||
} | ||
|
||
HelpButton.displayName = 'HelpButton'; | ||
|
||
export default HelpButton; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from 'react'; | ||
import {View} from 'react-native'; | ||
import Text from '@components/Text'; | ||
import type {ThemeStyles} from '@styles/index'; | ||
|
||
const getHelpContent = (styles: ThemeStyles, route: string) => { | ||
return ( | ||
<View style={styles.ph5}> | ||
<Text style={[styles.textHeadlineH1, styles.mb4]}>Missing page for route</Text> | ||
<Text style={styles.textNormal}>{route}</Text> | ||
</View> | ||
); | ||
}; | ||
|
||
export default getHelpContent; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import {findFocusedRoute, useNavigationState} from '@react-navigation/native'; | ||
import React, {useCallback, useEffect, useRef} from 'react'; | ||
// eslint-disable-next-line no-restricted-imports | ||
import {Animated, View} from 'react-native'; | ||
import HeaderWithBackButton from '@components/HeaderWithBackButton'; | ||
import Backdrop from '@components/Modal/BottomDockedModal/Backdrop'; | ||
import ScreenWrapper from '@components/ScreenWrapper'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import useResponsiveLayout from '@hooks/useResponsiveLayout'; | ||
import useSidePane from '@hooks/useSidePane'; | ||
import useThemeStyles from '@hooks/useThemeStyles'; | ||
import {triggerSidePane} from '@libs/actions/SidePane'; | ||
import Navigation from '@libs/Navigation/Navigation'; | ||
import {substituteRouteParameters} from '@libs/SidePaneUtils'; | ||
import NAVIGATORS from '@src/NAVIGATORS'; | ||
import getHelpContent from './getHelpContent'; | ||
|
||
function SidePane({shouldShowOverlay = false}: {shouldShowOverlay?: boolean}) { | ||
const styles = useThemeStyles(); | ||
const {translate} = useLocalize(); | ||
|
||
const {isExtraLargeScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout(); | ||
const {sidePaneTranslateX, shouldHideSidePane, shouldHideSidePaneBackdrop} = useSidePane(); | ||
|
||
const {route, isInNarrowPaneModal} = useNavigationState((state) => { | ||
const params = (findFocusedRoute(state)?.params as Record<string, string>) ?? {}; | ||
const activeRoute = Navigation.getActiveRouteWithoutParams(); | ||
return {route: substituteRouteParameters(activeRoute, params), isInNarrowPaneModal: state.routes.some((r) => r.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR)}; | ||
}); | ||
|
||
const onClose = useCallback( | ||
(shouldUpdateNarrow = false) => { | ||
triggerSidePane(false, {shouldOnlyUpdateNarrowLayout: !isExtraLargeScreenWidth || shouldUpdateNarrow}); | ||
}, | ||
[isExtraLargeScreenWidth], | ||
); | ||
|
||
const sizeChangedFromLargeToNarrow = useRef(!isExtraLargeScreenWidth); | ||
useEffect(() => { | ||
// Close the side pane when the screen size changes from large to small | ||
if (!isExtraLargeScreenWidth && !sizeChangedFromLargeToNarrow.current) { | ||
onClose(true); | ||
sizeChangedFromLargeToNarrow.current = true; | ||
} | ||
|
||
// Reset the trigger when the screen size changes back to large | ||
if (isExtraLargeScreenWidth) { | ||
sizeChangedFromLargeToNarrow.current = false; | ||
} | ||
}, [isExtraLargeScreenWidth, onClose]); | ||
|
||
if (shouldHideSidePane) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<> | ||
<View> | ||
{shouldShowOverlay && !shouldHideSidePaneBackdrop && !isInNarrowPaneModal && ( | ||
<Backdrop | ||
onBackdropPress={onClose} | ||
style={styles.sidePaneOverlay} | ||
/> | ||
)} | ||
</View> | ||
<Animated.View style={[styles.sidePaneContainer(shouldUseNarrowLayout, isExtraLargeScreenWidth), {transform: [{translateX: sidePaneTranslateX.current}]}]}> | ||
<ScreenWrapper testID={SidePane.displayName}> | ||
<HeaderWithBackButton | ||
title={translate('common.help')} | ||
style={styles.headerBarDesktopHeight} | ||
onBackButtonPress={() => onClose(false)} | ||
onCloseButtonPress={() => onClose(false)} | ||
shouldShowBackButton={!isExtraLargeScreenWidth} | ||
shouldShowCloseButton={isExtraLargeScreenWidth} | ||
shouldDisplayHelpButton={false} | ||
/> | ||
{getHelpContent(styles, route)} | ||
</ScreenWrapper> | ||
</Animated.View> | ||
</> | ||
); | ||
} | ||
|
||
function SidePaneWithOverlay() { | ||
return <SidePane shouldShowOverlay />; | ||
} | ||
|
||
SidePane.displayName = 'SidePane'; | ||
|
||
export default SidePane; | ||
export {SidePaneWithOverlay, useSidePane as useAnimatedPaddingRight}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The help content depends on route value, while reloading the page, route will briefly become undefined which makes the help content return empty. We had an issue for it here: #62215
And We fixed it here: #62349