Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions src/components/WideRHPOverlayWrapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ import {
} from '@components/WideRHPContextProvider';

import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';

import Overlay from '@libs/Navigation/AppNavigator/Navigators/Overlay';

import variables from '@styles/variables';

import {useRoute} from '@react-navigation/native';
import React from 'react';

function SecondaryOverlay() {
const {shouldRenderSecondaryOverlayForRHPOnSuperWideRHP, shouldRenderSecondaryOverlayForRHPOnWideRHP, shouldRenderSecondaryOverlayForWideRHP, superWideRHPRouteKeys, wideRHPRouteKeys} =
useWideRHPState();
const theme = useTheme();

const route = useRoute();

Expand Down Expand Up @@ -46,6 +50,10 @@ function SecondaryOverlay() {
progress={secondOverlayRHPOnWideRHPProgress}
// If RHP is displayed on Wide RHP which is displayed above the Super Wide RHP, the secondary overlay's position left should be calculated from the left edge of the super wide RHP.
positionLeftValue={animatedReceiptPaneRHPWidth}
positionTopValue={variables.rhpFloatingCardMargin}
positionBottomValue={variables.rhpFloatingCardMargin}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
/>
);
}
Expand All @@ -55,6 +63,10 @@ function SecondaryOverlay() {
<Overlay
progress={secondOverlayWideRHPProgress}
positionLeftValue={modalStackOverlayWideRHPPositionLeft}
positionTopValue={variables.rhpFloatingCardMargin}
positionBottomValue={variables.rhpFloatingCardMargin}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
/>
);
}
Expand All @@ -64,6 +76,10 @@ function SecondaryOverlay() {
<Overlay
progress={secondOverlayRHPOnSuperWideRHPProgress}
positionLeftValue={modalStackOverlaySuperWideRHPPositionLeft}
positionTopValue={variables.rhpFloatingCardMargin}
positionBottomValue={variables.rhpFloatingCardMargin}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';

import type {OverlayStylesParams} from '@styles/index';
import type {Color} from '@styles/theme/types';
import variables from '@styles/variables';

import CONST from '@src/CONST';
Expand All @@ -25,10 +26,31 @@ type BaseOverlayProps = {

/** Overlay position from the right edge of the container */
positionRightValue?: number | Animated.Value | Animated.AnimatedAddition<number>;

/** Scrim background color override. Defaults to `theme.overlay`; the floating RHP passes the lighter `theme.rhpOverlay`. */
overlayColor?: Color;

/** Max opacity the scrim ramps up to. Defaults to `variables.overlayOpacity`; the floating RHP passes the lighter `rhpOverlayOpacity`. */
maxOpacity?: number;

/** Overlay position from the top edge of the container. The floating RHP overlays pass the card's inset so the scrim doesn't bleed past it. */
positionTopValue?: number;

/** Overlay position from the bottom edge of the container. The floating RHP overlays pass the card's inset so the scrim doesn't bleed past it. */
positionBottomValue?: number;
};

// The default value of positionLeftValue is equal to -2 * variables.sideBarWidth, because we need to stretch the overlay to cover the sidebar and the translate animation distance.
function BaseOverlay({onPress, progress, positionLeftValue = -2 * variables.sideBarWidth, positionRightValue = 0}: BaseOverlayProps) {
function BaseOverlay({
onPress,
progress,
positionLeftValue = -2 * variables.sideBarWidth,
positionRightValue = 0,
overlayColor,
maxOpacity,
positionTopValue,
positionBottomValue,
}: BaseOverlayProps) {
const styles = useThemeStyles();
const {current} = useCardAnimation();
const {translate} = useLocalize();
Expand All @@ -37,7 +59,11 @@ function BaseOverlay({onPress, progress, positionLeftValue = -2 * variables.side
<Animated.View
id="BaseOverlay"
aria-hidden
style={[styles.pFixed, styles.t0, styles.b0, styles.overlayBackground, styles.overlayStyles({progress: progress ?? current.progress, positionLeftValue, positionRightValue})]}
style={[
styles.pFixed,
overlayColor ? {backgroundColor: overlayColor} : styles.overlayBackground,
styles.overlayStyles({progress: progress ?? current.progress, positionLeftValue, positionRightValue, positionTopValue, positionBottomValue, maxOpacity}),
]}
>
<View style={[styles.flex1, styles.flexColumn]}>
{/* In the latest Electron version buttons can't be both clickable and draggable.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {

import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSidePanelState from '@hooks/useSidePanelState';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';

Expand Down Expand Up @@ -49,7 +50,7 @@ import type {View} from 'react-native';
import {useFocusEffect} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
// eslint-disable-next-line no-restricted-imports
import {Animated, DeviceEventEmitter} from 'react-native';
import {Animated, DeviceEventEmitter, Platform} from 'react-native';

import {NarrowPaneContextProvider} from './NarrowPaneContext';
import Overlay from './Overlay';
Expand Down Expand Up @@ -80,12 +81,17 @@ function SearchAdvancedFiltersWithContext(props: Record<string, unknown>) {
function SecondaryOverlay() {
const {shouldRenderSecondaryOverlayForWideRHP, shouldRenderSecondaryOverlayForRHPOnWideRHP, shouldRenderSecondaryOverlayForRHPOnSuperWideRHP} = useWideRHPState();
const {sidePanelOffset} = useSidePanelState();
const theme = useTheme();

if (shouldRenderSecondaryOverlayForWideRHP) {
return (
<Overlay
progress={secondOverlayWideRHPProgress}
positionRightValue={Animated.add(sidePanelOffset.current, animatedWideRHPWidth)}
positionRightValue={Animated.add(Animated.add(sidePanelOffset.current, animatedWideRHPWidth), variables.rhpFloatingCardMargin)}
positionTopValue={variables.rhpFloatingCardMargin}
positionBottomValue={variables.rhpFloatingCardMargin}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
onPress={() => Navigation.closeRHPFlow()}
/>
);
Expand All @@ -95,7 +101,11 @@ function SecondaryOverlay() {
return (
<Overlay
progress={secondOverlayRHPOnWideRHPProgress}
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth)}
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth + variables.rhpFloatingCardMargin)}
positionTopValue={variables.rhpFloatingCardMargin}
positionBottomValue={variables.rhpFloatingCardMargin}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
onPress={Navigation.dismissToPreviousRHP}
/>
);
Expand All @@ -105,7 +115,11 @@ function SecondaryOverlay() {
return (
<Overlay
progress={secondOverlayRHPOnSuperWideRHPProgress}
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth)}
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth + variables.rhpFloatingCardMargin)}
positionTopValue={variables.rhpFloatingCardMargin}
positionBottomValue={variables.rhpFloatingCardMargin}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
onPress={Navigation.dismissToSuperWideRHP}
/>
);
Expand Down Expand Up @@ -174,6 +188,7 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
const {windowWidth} = useWindowDimensions();
const modalStackScreenOptions = useModalStackScreenOptions();
const styles = useThemeStyles();
const theme = useTheme();
const {sidePanelOffset} = useSidePanelState();

// When a fullscreen route is pre-inserted under the RHP, disable the slide-out animation
Expand Down Expand Up @@ -220,6 +235,14 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {

const overlayPositionLeft = useMemo(() => -1 * calculateSuperWideRHPWidth(windowWidth), [windowWidth]);

// Floating RHP (web wide layout only): inset the card from the viewport edges and give it rounded corners, a 1px
// border, and a shadow. This replaces the full-bleed `r0`/`h100` anchoring; width stays driven by the animated
// RHP width. Narrow layout and native keep the full-bleed frame.
const isFloatingRHP = Platform.OS === 'web' && !shouldUseNarrowLayout;
const frameStyle = isFloatingRHP
? [styles.pAbsolute, styles.overflowHidden, styles.RHPFloatingCard, animatedWidthStyle]
: [styles.pAbsolute, styles.r0, styles.h100, styles.overflowHidden, animatedWidthStyle];

const screenListeners = useMemo(
() => ({
blur: () => {
Expand Down Expand Up @@ -284,6 +307,8 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
{!shouldUseNarrowLayout && (
<Overlay
positionLeftValue={overlayPositionLeft}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
onPress={handleOverlayPress}
/>
)}
Expand All @@ -296,7 +321,7 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
<RightModalDialogFrame
hasDialogSemantics={!isSmallScreenWidth}
onContainerRef={setContainerNodeFromRef}
style={[styles.pAbsolute, styles.r0, styles.h100, styles.overflowHidden, animatedWidthStyle]}
style={frameStyle}
>
<Stack.Navigator
parentRoute={route}
Expand Down Expand Up @@ -557,7 +582,11 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
{!shouldUseNarrowLayout && shouldRenderTertiaryOverlay && (
<Overlay
progress={thirdOverlayProgress}
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth)}
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth + variables.rhpFloatingCardMargin)}
positionTopValue={variables.rhpFloatingCardMargin}
positionBottomValue={variables.rhpFloatingCardMargin}
overlayColor={theme.rhpOverlay}
maxOpacity={variables.rhpOverlayOpacity}
onPress={Navigation.dismissToPreviousRHP}
/>
)}
Expand Down
22 changes: 21 additions & 1 deletion src/styles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3323,6 +3323,18 @@ const staticStyles = (theme: ThemeColors) =>
height: '100%',
},

// Floating RHP card (web wide layout only): inset from the viewport edges, rounded, 1px border, shadow.
// Anchoring replaces the card's `r0`/`h100`; width stays driven by the animated RHP width at the call site.
RHPFloatingCard: {
top: variables.rhpFloatingCardMargin,
right: variables.rhpFloatingCardMargin,
bottom: variables.rhpFloatingCardMargin,
borderRadius: variables.componentBorderRadiusLarge,
borderWidth: 1,
borderColor: theme.border,
boxShadow: theme.shadow,
},

invisible: {
position: 'absolute',
opacity: 0,
Expand Down Expand Up @@ -6845,18 +6857,26 @@ const dynamicStyles = (theme: ThemeColors) =>
progress,
positionLeftValue,
positionRightValue,
positionTopValue = 0,
positionBottomValue = 0,
maxOpacity = variables.overlayOpacity,
}: {
progress: OverlayStylesParams;
positionLeftValue: number | Animated.Value | Animated.AnimatedAddition<number>;
positionRightValue: number | Animated.Value | Animated.AnimatedAddition<number>;
positionTopValue?: number;
positionBottomValue?: number;
maxOpacity?: number;
}) =>
({
// We need to stretch the overlay to cover the sidebar and the translate animation distance.
left: positionLeftValue,
right: positionRightValue,
top: positionTopValue,
bottom: positionBottomValue,
opacity: progress.interpolate({
inputRange: [0, 0.5],
outputRange: [0, variables.overlayOpacity],
outputRange: [0, maxOpacity],
extrapolate: 'clamp',
}),
}) satisfies ViewStyle,
Expand Down
1 change: 1 addition & 0 deletions src/styles/theme/themes/dark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const darkTheme = {

// Additional keys
overlay: colors.productDark400,
rhpOverlay: colors.productDark300,
inverse: colors.productDark900,
shadow: '0px 4px 12px 0px rgba(2,18,4,0.24)',
componentBG: colors.productDark100,
Expand Down
1 change: 1 addition & 0 deletions src/styles/theme/themes/light.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const lightTheme = {

// Additional keys
overlay: colors.productLight400,
rhpOverlay: colors.productLight300,
inverse: colors.productLight900,
shadow: '0px 4px 12px 0px rgba(2,18,4,0.06)',
componentBG: colors.productLight100,
Expand Down
2 changes: 2 additions & 0 deletions src/styles/theme/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ type ThemeColors = {

// Additional keys
overlay: Color;
// Lighter scrim behind the floating RHP card (web wide layout only).
rhpOverlay: Color;
inverse: Color;
shadow: Color;
componentBG: Color;
Expand Down
4 changes: 4 additions & 0 deletions src/styles/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export default {
androidSafeAreaInsetsPercentage: 1,
sideBarWidth: 375,
sidePanelWidth: 375,
// Inset on the top/right/bottom edges of the floating RHP card (web wide layout only).
rhpFloatingCardMargin: 12,
// Screen inset shared by the top- and bottom-anchored growl containers so both stay in sync.
growlNotificationInset: 20,
receiptPaneRHPMaxWidth: 465,
Expand Down Expand Up @@ -160,6 +162,8 @@ export default {
sectionMenuItemHeightCompact: 44,
optionsListSectionHeaderHeight: getValueUsingPixelRatio(32, 38),
overlayOpacity: 0.72,
// Lighter scrim opacity for the floating RHP overlay (web), scoped so other modal backdrops keep `overlayOpacity`.
rhpOverlayOpacity: 0.5,
// fontSizeExtraSmall is fixed at 9, so the line height must never scale below the font's natural line height (~1.18em = 10.62),
// otherwise Android clamps the descent and clips descenders and underlines at small device font scales.
lineHeightXSmall: Math.max(getValueUsingPixelRatio(11, 17), 11),
Expand Down
Loading