Skip to content

Commit db7fa86

Browse files
authored
Merge pull request #42469 from dominictb/fix/40751
fix: customize size behavior of image component
2 parents c244fa1 + aa836b7 commit db7fa86

File tree

3 files changed

+53
-25
lines changed

3 files changed

+53
-25
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React, {createContext} from 'react';
2+
3+
type ImageBehaviorContextValue = {
4+
/**
5+
* Determine whether or not to set the aspect ratio of the container div based on the image's aspect ratio.
6+
*/
7+
shouldSetAspectRatioInStyle: boolean;
8+
};
9+
10+
const ImageBehaviorContext = createContext<ImageBehaviorContextValue>({
11+
shouldSetAspectRatioInStyle: true,
12+
});
13+
14+
function ImageBehaviorContextProvider({children, ...value}: {children: React.ReactNode} & ImageBehaviorContextValue) {
15+
return <ImageBehaviorContext.Provider value={value}>{children}</ImageBehaviorContext.Provider>;
16+
}
17+
18+
export {ImageBehaviorContext, ImageBehaviorContextProvider};

src/components/Image/index.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import React, {useCallback, useMemo, useState} from 'react';
1+
import React, {useCallback, useContext, useMemo, useState} from 'react';
22
import {withOnyx} from 'react-native-onyx';
33
import CONST from '@src/CONST';
44
import ONYXKEYS from '@src/ONYXKEYS';
55
import BaseImage from './BaseImage';
6+
import {ImageBehaviorContext} from './ImageBehaviorContextProvider';
67
import type {ImageOnLoadEvent, ImageOnyxProps, ImageOwnProps, ImageProps} from './types';
78

89
function Image({source: propsSource, isAuthTokenRequired = false, session, onLoad, objectPosition = CONST.IMAGE_OBJECT_POSITION.INITIAL, style, ...forwardedProps}: ImageProps) {
910
const [aspectRatio, setAspectRatio] = useState<string | number | null>(null);
1011
const isObjectPositionTop = objectPosition === CONST.IMAGE_OBJECT_POSITION.TOP;
1112

13+
const {shouldSetAspectRatioInStyle} = useContext(ImageBehaviorContext);
14+
1215
const updateAspectRatio = useCallback(
1316
(width: number, height: number) => {
1417
if (!isObjectPositionTop) {
@@ -30,7 +33,6 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, onLoa
3033
const {width, height} = event.nativeEvent;
3134

3235
onLoad?.(event);
33-
3436
updateAspectRatio(width, height);
3537
},
3638
[onLoad, updateAspectRatio],
@@ -59,12 +61,17 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, onLoa
5961
// eslint-disable-next-line react-hooks/exhaustive-deps
6062
}, [propsSource, isAuthTokenRequired]);
6163

64+
/**
65+
* If the image fails to load and the object position is top, we should hide the image by setting the opacity to 0.
66+
*/
67+
const shouldOpacityBeZero = isObjectPositionTop && !aspectRatio;
68+
6269
return (
6370
<BaseImage
6471
// eslint-disable-next-line react/jsx-props-no-spreading
6572
{...forwardedProps}
6673
onLoad={handleLoad}
67-
style={[style, aspectRatio ? {aspectRatio, height: 'auto'} : {}, isObjectPositionTop && !aspectRatio && {opacity: 0}]}
74+
style={[style, shouldSetAspectRatioInStyle && aspectRatio ? {aspectRatio, height: 'auto'} : {}, shouldOpacityBeZero && {opacity: 0}]}
6875
source={source}
6976
/>
7077
);

src/components/ReportActionItem/ReportActionItemImages.tsx

+25-22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import React from 'react';
33
import {View} from 'react-native';
44
import {Polygon, Svg} from 'react-native-svg';
5+
import {ImageBehaviorContextProvider} from '@components/Image/ImageBehaviorContextProvider';
56
import Text from '@components/Text';
67
import useStyleUtils from '@hooks/useStyleUtils';
78
import useTheme from '@hooks/useTheme';
@@ -65,28 +66,30 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report
6566
return (
6667
<View style={styles.reportActionItemImagesContainer}>
6768
<View style={[styles.reportActionItemImages, hoverStyle, heightStyle]}>
68-
{shownImages.map(({thumbnail, isThumbnail, image, transaction, isLocalFile, fileExtension, filename}, index) => {
69-
// Show a border to separate multiple images. Shown to the right for each except the last.
70-
const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1;
71-
const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {};
72-
return (
73-
<View
74-
key={`${index}-${image}`}
75-
style={[styles.reportActionItemImage, borderStyle, hoverStyle]}
76-
>
77-
<ReportActionItemImage
78-
thumbnail={thumbnail}
79-
fileExtension={fileExtension}
80-
image={image}
81-
isLocalFile={isLocalFile}
82-
filename={filename}
83-
transaction={transaction}
84-
isThumbnail={isThumbnail}
85-
isSingleImage={numberOfShownImages === 1}
86-
/>
87-
</View>
88-
);
89-
})}
69+
<ImageBehaviorContextProvider shouldSetAspectRatioInStyle={false}>
70+
{shownImages.map(({thumbnail, isThumbnail, image, transaction, isLocalFile, fileExtension, filename}, index) => {
71+
// Show a border to separate multiple images. Shown to the right for each except the last.
72+
const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1;
73+
const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {};
74+
return (
75+
<View
76+
key={`${index}-${image}`}
77+
style={[styles.reportActionItemImage, borderStyle, hoverStyle]}
78+
>
79+
<ReportActionItemImage
80+
thumbnail={thumbnail}
81+
fileExtension={fileExtension}
82+
image={image}
83+
isLocalFile={isLocalFile}
84+
filename={filename}
85+
transaction={transaction}
86+
isThumbnail={isThumbnail}
87+
isSingleImage={numberOfShownImages === 1}
88+
/>
89+
</View>
90+
);
91+
})}
92+
</ImageBehaviorContextProvider>
9093
</View>
9194
{remaining > 0 && (
9295
<View style={[styles.reportActionItemImagesMoreContainer]}>

0 commit comments

Comments
 (0)